Spring?+?ECharts實(shí)現(xiàn)數(shù)據(jù)可視化的案例詳解
一、成果
做好的demo是這個(gè)樣子的。
通過下拉框選擇查詢條件,點(diǎn)擊按鈕,調(diào)用后端接口查詢數(shù)據(jù),返回前端實(shí)現(xiàn)可視化。
二、數(shù)據(jù)準(zhǔn)備
計(jì)劃做一個(gè)學(xué)生成績成績數(shù)據(jù)的可視化,用到三張表:
學(xué)生表、課程表、成績表,如下:
三、具體實(shí)現(xiàn)
通過上面的成果展示圖可以看到,實(shí)現(xiàn)了兩個(gè)需求:
1. 展示某年每個(gè)學(xué)生各科分?jǐn)?shù)的柱狀圖
2. 展示近三年某個(gè)學(xué)生總分的折線圖
某年每個(gè)學(xué)生各科分?jǐn)?shù)的柱狀圖
后端
1. 按照年份查找所有學(xué)生所有科目的分?jǐn)?shù)
2. 把數(shù)據(jù)處理成ECharts柱狀圖方便接收的形式,傳給前端
3. 把所有年份數(shù)據(jù)(2021、2022、2023)查詢出來,給前端做下拉框的部分
4. 查出學(xué)生姓名,給前端做柱狀圖x軸信息
前端
1. 下拉框選擇年份
2. 導(dǎo)入ECharts柱狀圖,并且填充后端數(shù)據(jù)
后端代碼
ResultJson 規(guī)范返回值
@Data public class ResultJson { private Integer code; private String msg; private Object data; public ResultJson(Integer code, String msg, Object data) { this.code = code; this.msg = msg; this.data = data; } public static ResultJson success(Object data){ return success("成功",data); } public static ResultJson success(String msg,Object data){ return new ResultJson(200,msg,data); } }
實(shí)體類
@Data @TableName("t_score") public class Score { @TableId(type = IdType.AUTO) private Long id; @TableField private String sno; private String cno; private Integer score; private String year; }
Controller層
@RestController @RequestMapping("score") public class ScoreController { @Autowired ScoreService scoreService; @RequestMapping("listScore") public ResultJson listScore(String year){ return ResultJson.success(scoreService.listScore(year)); } @RequestMapping("listYears") public ResultJson listYears(){ return ResultJson.success(scoreService.listYears()); } }
Service層
public interface ScoreService extends IService<Score> { List<List<Object>> listScore(String year); List<String> listYears(); }
這里是認(rèn)定了只有數(shù)學(xué)、英語、語文三門科目的,是寫死的寫法,可以寫成靈活的形式,可以參考后面的需求2。
@Service public class ScoreServiceImpl extends ServiceImpl<ScoreMapper, Score> implements ScoreService { @Autowired ScoreMapper scoreMapper; @Override public List<List<Object>> listScore(String year) { List<StudentScore> studentScores = scoreMapper.listScore(year); List<StudentScore> order = studentScores.stream().sorted(Comparator.comparing(StudentScore::getStudentName) .thenComparing(StudentScore::getCourseName)).collect(Collectors.toList()); TreeMap<String, List<Integer>> treeMap = new TreeMap<>(); for(StudentScore studentScore : order){ String studentName = studentScore.getStudentName(); if(!treeMap.containsKey(studentName)){ treeMap.put(studentName,new ArrayList<>()); } treeMap.get(studentName).add(studentScore.getScore()); } List<List<Object>> lists = new ArrayList<>(); for(int i = 0; i < 4; i++){ lists.add(new ArrayList<>()); } treeMap.forEach((key,value)->{ lists.get(0).add(key); lists.get(1).add(value.get(0)); lists.get(2).add(value.get(1)); lists.get(3).add(value.get(2)); }); return lists; } @Override public List<String> listYears() { return scoreMapper.listYears(); }
Mapper層
@Mapper public interface ScoreMapper extends BaseMapper<Score> { List<StudentScore> listScore(String year); List<String> listYears(); }
ScoreMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace => mapper接口 類的全限定名 --> <mapper namespace="com.zqzw.echart.mapper.ScoreMapper"> <resultMap id="BaseResultMap" type="com.zqzw.echart.entity.StudentScore"> <id column="id" jdbcType="BIGINT" property="id"/> <result column="student_name" jdbcType="VARCHAR" property="studentName"/> <result column="course_name" jdbcType="VARCHAR" property="courseName"/> <result column="score" jdbcType="INTEGER" property="score"/> </resultMap> <select id="listScore" resultMap="BaseResultMap"> select student_name,course_name,score from t_score sc inner join t_student s on sc.sno = s.sno inner join t_course c on sc.cno = c.cno where year = #{year} </select> <select id="listYears" resultType="java.lang.String"> select distinct year from t_score order by year </select> </mapper>
前端代碼
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ECharts-Demo</title> </head> <body> <h1>成績查詢</h1> <div id="main" style="width: 600px;height:400px;" ></div> <select id="year" style = "width: 100px"></select> <button id = "b1" onclick="list();">某年每個(gè)學(xué)生的各科分?jǐn)?shù)</button> </body> </html> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script> <script src=" https://cdn.jsdelivr.net/npm/echarts@5.4.2/dist/echarts.min.js "></script> <script > const myChart = echarts.init(document.getElementById('main')); let option = { xAxis: { data: [] }, yAxis: {}, series: [ { type: 'bar', data: [] }, { type: 'bar', data: [] }, { type: 'bar', data: [] } ] }; $(function () { $.ajax({ url:"http://localhost:8080/score/listYears", dataType:"json", data:{}, type:"post", success:function (res) { var obj = document.getElementById("year"); obj.options.add(new Option(res.data[0],res.data[0],true)); for(var i = 1; i < res.data.length; i++){ obj.options.add(new Option(res.data[i],res.data[i])); } } }); }); function list(){ var obj = document.getElementById("year"); var index = obj.selectedIndex; if(index < 0){ index = 0; } var key = obj.options[index].value; $.ajax({ url:"http://localhost:8080/score/listScore", dataType:"json", data:{"year": key}, type:"post", success:function(res){ option.xAxis.data = res.data[0]; option.series[0].data = res.data[1]; option.series[1].data = res.data[2]; option.series[2].data = res.data[3]; myChart.clear(); myChart.setOption(option); }, error:function(){ } }); } </script>
近三年某個(gè)學(xué)生總分的折線圖
后端
1. 按照學(xué)號(hào)查出每年的總分
2. 把數(shù)據(jù)處理成ECharts柱狀圖方便接收的形式,傳給前端
3. 把所有學(xué)生姓名查詢出來,給前端做下拉框的部分
4. 查出年份數(shù)據(jù),給前端做柱狀圖x軸信息
前端
1. 下拉框顯示學(xué)生姓名,實(shí)際值是學(xué)號(hào)
2. 導(dǎo)入ECharts折線圖,并且填充后端數(shù)據(jù)
四、完整代碼
后端代碼
加上這個(gè)部分就是全部了,所以這里直接放出完整的代碼了
ResultJson不變
實(shí)體類
@Data @TableName("t_student") public class Student { @TableId(type = IdType.AUTO) private Long id; @TableField private String sno; @TableField("student_name") private String studentName; private Integer sex; }
@Data public class TotalScore extends Score{ private Integer totalScore; }
Controller層
@RestController @RequestMapping("score") public class ScoreController { @Autowired ScoreService scoreService; @RequestMapping("listScore") public ResultJson listScore(String year){ return ResultJson.success(scoreService.listScore(year)); } @RequestMapping("listYears") public ResultJson listYears(){ return ResultJson.success(scoreService.listYears()); } @RequestMapping("listTotal") public ResultJson listTotal(String sno){ return ResultJson.success(scoreService.listTotal(sno)); } @RequestMapping("listStudents") public ResultJson listStudents(){ return ResultJson.success(scoreService.listStudents()); } }
Service層
public interface ScoreService extends IService<Score> { List<List<Object>> listScore(String year); List<String> listYears(); List<List<Object>> listTotal(String sno); List<Student> listStudents(); }
@Service public class ScoreServiceImpl extends ServiceImpl<ScoreMapper, Score> implements ScoreService { @Autowired ScoreMapper scoreMapper; @Override public List<List<Object>> listScore(String year) { List<StudentScore> studentScores = scoreMapper.listScore(year); List<StudentScore> order = studentScores.stream().sorted(Comparator.comparing(StudentScore::getStudentName) .thenComparing(StudentScore::getCourseName)).collect(Collectors.toList()); TreeMap<String, List<Integer>> treeMap = new TreeMap<>(); for(StudentScore studentScore : order){ String studentName = studentScore.getStudentName(); if(!treeMap.containsKey(studentName)){ treeMap.put(studentName,new ArrayList<>()); } treeMap.get(studentName).add(studentScore.getScore()); } List<List<Object>> lists = new ArrayList<>(); for(int i = 0; i < 4; i++){ lists.add(new ArrayList<>()); } treeMap.forEach((key,value)->{ lists.get(0).add(key); lists.get(1).add(value.get(0)); lists.get(2).add(value.get(1)); lists.get(3).add(value.get(2)); }); return lists; } @Override public List<String> listYears() { return scoreMapper.listYears(); } @Override public List<List<Object>> listTotal(String sno) { List<TotalScore> totalScores = scoreMapper.listTotal(sno); List<List<Object>> result = new ArrayList<>(); result.add(new ArrayList<>()); result.add(new ArrayList<>()); for(TotalScore t : totalScores){ result.get(0).add(t.getYear()); result.get(1).add(t.getTotalScore()); } return result; } @Override public List<Student> listStudents() { return scoreMapper.listStudents(); } }
Mapper層
@Mapper public interface ScoreMapper extends BaseMapper<Score> { List<StudentScore> listScore(String year); List<String> listYears(); List<TotalScore> listTotal(String sno); List<Student> listStudents(); }
ScoreMapper.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!--namespace => mapper接口 類的全限定名 --> <mapper namespace="com.zqzw.echart.mapper.ScoreMapper"> <resultMap id="BaseResultMap" type="com.zqzw.echart.entity.StudentScore"> <id column="id" jdbcType="BIGINT" property="id"/> <result column="student_name" jdbcType="VARCHAR" property="studentName"/> <result column="course_name" jdbcType="VARCHAR" property="courseName"/> <result column="score" jdbcType="INTEGER" property="score"/> </resultMap> <select id="listScore" resultMap="BaseResultMap"> select student_name,course_name,score from t_score sc inner join t_student s on sc.sno = s.sno inner join t_course c on sc.cno = c.cno where year = #{year} </select> <select id="listYears" resultType="java.lang.String"> select distinct year from t_score order by year </select> <select id="listTotal" resultType="com.zqzw.echart.entity.TotalScore"> select sum(score) totalScore,year from t_score where sno = #{sno} group by year order by year </select> <select id="listStudents" resultType="com.zqzw.echart.entity.Student"> select student_name,sno from t_student </select> </mapper>
前端代碼
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ECharts-Demo</title> </head> <body> <h1>成績查詢</h1> <div id="main" style="width: 600px;height:400px;" ></div> <select id="year" style = "width: 100px"></select> <button id = "b1" onclick="list();">某年每個(gè)學(xué)生的各科分?jǐn)?shù)</button> <select id="student" style = "width: 100px"></select> <button id = "b2" onclick="listTotal();">某學(xué)生三年總分折線圖</button> </body> </html> <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script> <script src=" https://cdn.jsdelivr.net/npm/echarts@5.4.2/dist/echarts.min.js "></script> <script > const myChart = echarts.init(document.getElementById('main')); let option = { xAxis: { data: [] }, yAxis: {}, series: [ { type: 'bar', data: [] }, { type: 'bar', data: [] }, { type: 'bar', data: [] } ] }; let option1 = { xAxis: { type: 'category', data: [] }, yAxis: { type: 'value' }, series: [ { data: [], type: 'line', label: { show: false, position: 'bottom', textStyle: { fontSize: 10 } } } ] }; function initSelect1(){ $.ajax({ url:"http://localhost:8080/score/listStudents", dataType:"json", data:"{}", type:"post", success:function(res){ for(var i = 0; i< res.data.length; i++){ var obj = document.getElementById("student"); obj.options.add(new Option(res.data[i].studentName,res.data[i].sno)); } } }); } initSelect1(); $(function () { $.ajax({ url:"http://localhost:8080/score/listYears", dataType:"json", data:{}, type:"post", success:function (res) { var obj = document.getElementById("year"); obj.options.add(new Option(res.data[0],res.data[0],true)); for(var i = 1; i < res.data.length; i++){ obj.options.add(new Option(res.data[i],res.data[i])); } } }); }); function listTotal() { var obj = document.getElementById("student"); var index = obj.selectedIndex; var key = obj.options[index].value; $.ajax({ url: "http://localhost:8080/score/listTotal", data: {"sno": key}, dataType: "json", type: "post", success: function (res) { option1.xAxis.data = res.data[0]; for (var i = 1; i < res.data.length; i++) { option1.series[i - 1].data = res.data[i]; } myChart.clear(); myChart.setOption(option1); } }); } function list(){ var obj = document.getElementById("year"); var index = obj.selectedIndex; if(index < 0){ index = 0; } var key = obj.options[index].value; $.ajax({ url:"http://localhost:8080/score/listScore", //請(qǐng)求的url地址 dataType:"json", //返回格式為json data:{"year": key}, //參數(shù)值 type:"post", //請(qǐng)求方式 success:function(res){ option.xAxis.data = res.data[0]; option.series[0].data = res.data[1]; option.series[1].data = res.data[2]; option.series[2].data = res.data[3]; myChart.clear(); myChart.setOption(option); }, error:function(){ } }); } </script>
以上就是Spring + ECharts實(shí)現(xiàn)數(shù)據(jù)可視化的案例詳解的詳細(xì)內(nèi)容,更多關(guān)于Spring + ECharts數(shù)據(jù)可視化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
maven項(xiàng)目下solr和spring的整合配置詳解
這篇文章主要介紹了maven項(xiàng)目下solr和spring的整合配置詳解,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-11-11Java中的遞歸詳解(用遞歸實(shí)現(xiàn)99乘法表來講解)
這篇文章主要介紹了Java中的遞歸詳解(用遞歸實(shí)現(xiàn)99乘法表來講解),本文給出了普通的99乘法實(shí)現(xiàn)方法和用遞歸實(shí)現(xiàn)的方法,并對(duì)比它們的不同,體現(xiàn)出遞歸的運(yùn)用及理解,需要的朋友可以參考下2015-03-03spring boot--從controller到DAO操作
這篇文章主要介紹了spring boot--從controller到DAO操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06Mybatis #foreach中相同的變量名導(dǎo)致值覆蓋的問題解決
本文主要介紹了Mybatis #foreach中相同的變量名導(dǎo)致值覆蓋的問題解決,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-07-07mybatis-plus IdWorker生成的Id和返回給前臺(tái)的不一致的解決
這篇文章主要介紹了mybatis-plus IdWorker生成的Id和返回給前臺(tái)的不一致的解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03CentOS?7.9服務(wù)器Java部署環(huán)境配置的過程詳解
這篇文章主要介紹了CentOS?7.9服務(wù)器Java部署環(huán)境配置,主要包括ftp服務(wù)器搭建過程、jdk安裝方法以及mysql安裝過程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-07-07JAVA使用動(dòng)態(tài)代理對(duì)象進(jìn)行敏感字過濾代碼實(shí)例
這篇文章主要介紹了JAVA使用動(dòng)態(tài)代理對(duì)象進(jìn)行敏感字過濾代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-09-09Springboot接口返回參數(shù)及入?yún)SA加密解密的過程詳解
這篇文章主要介紹了Springboot接口返回參數(shù)及入?yún)SA加密解密,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2023-07-07java 啟動(dòng)exe程序,傳遞參數(shù)和獲取參數(shù)操作
這篇文章主要介紹了java 啟動(dòng)exe程序,傳遞參數(shù)和獲取參數(shù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01