Apache ECharts是一个基于 JavaScript 的开源可视化图表库,在网页上实现数据的可视化,非常好用,来简单写一个demo,实践一下。
目录
一、成果
二、数据准备
三、具体实现
某年每个学生各科分数的柱状图
后端
前端
后端代码
前端代码
近三年某个学生总分的折线图
后端
前端
四、完整代码
后端代码
前端代码
一、成果
做好的demo是这个样子的。
通过下拉框选择查询条件,点击按钮,调用后端接口查询数据,返回前端实现可视化。
二、数据准备
计划做一个学生成绩成绩数据的可视化,用到三张表:
学生表、课程表、成绩表,如下:
三、具体实现
通过上面的成果展示图可以看到,实现了两个需求:
1. 展示某年每个学生各科分数的柱状图
2. 展示近三年某个学生总分的折线图
某年每个学生各科分数的柱状图
后端
1. 按照年份查找所有学生所有科目的分数
2. 把数据处理成ECharts柱状图方便接收的形式,传给前端
3. 把所有年份数据(2021、2022、2023)查询出来,给前端做下拉框的部分
4. 查出学生姓名,给前端做柱状图x轴信息
前端
1. 下拉框选择年份
2. 导入ECharts柱状图,并且填充后端数据
后端代码
ResultJson 规范返回值
@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);
}
}
实体类
@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;
}
@Data
public class StudentScore {
private Long id;
private String studentName;
private String courseName;
private Integer score;
}
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();
}
这里是认定了只有数学、英语、语文三门科目的,是写死的写法,可以写成灵活的形式,可以参考后面的需求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();">某年每个学生的各科分数</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>
近三年某个学生总分的折线图
后端
1. 按照学号查出每年的总分
2. 把数据处理成ECharts柱状图方便接收的形式,传给前端
3. 把所有学生姓名查询出来,给前端做下拉框的部分
4. 查出年份数据,给前端做柱状图x轴信息
前端
1. 下拉框显示学生姓名,实际值是学号
2. 导入ECharts折线图,并且填充后端数据
四、完整代码
后端代码
加上这个部分就是全部了,所以这里直接放出完整的代码了
ResultJson不变
实体类
@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();">某年每个学生的各科分数</button>
<br>
<select id="student" style = "width: 100px"></select>
<button id = "b2" onclick="listTotal();">某学生三年总分折线图</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", //请求的url地址
dataType:"json", //返回格式为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>