Spring + ECharts数据可视化

news2025/1/12 12:14:17

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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/703890.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Echarts设置X轴只显示刻度线,不显示X轴轴线

Echarts设置X轴只显示刻度线&#xff0c;不显示X轴轴线&#xff1a; option {xAxis: {......axisLine: {show: false,lineStyle: {color: red,}},......},...... } 效果&#xff1a; 上图中X轴轴线位置的横线&#xff0c;其实是yAxis的splitLine&#xff0c;将splitLine的sh…

(十九)数据编辑——属性编辑②

数据编辑——属性编辑② 使用键盘输入值并不是编辑表中值的唯一方式。在某些情况下&#xff0c;为了设置字段值&#xff0c;可能要对单条记录甚至是所有记录执行数学计算。ArcMap 中的字段计算器可以对所有或所选记录进行简单和高级计算。 此外&#xff0c;还可以基于字段计算…

Vue生态及实践 - vuex

目录 Vuex vuex基础 阶段小结&#xff08;vuex的四种对象&#xff09; vuex响应式原理 vuex.js的实现 index.js Module 局部状态 命名空间 跨模块访问数据 小结 目标 Vuex相关基本概念和使用方式vuex响应式原理过程vuex中如何进行模块式开发 Vue2.0是单向数据流的…

H5学习期间 问题文档(更新中)

目录 一、html与css中让标签 二、css鼠标滑入显示div 三、git报错解决方案 四、ul>li中给h1标签设置行高 一、html与css中让标签<li>在同一行显示 li标签一行显示 效果展示&#xff1a; 代码块&#xff1a; <!DOCTYPE html> <html lang"en"…

国内做MES系统的企业哪家好?

什么是MES&#xff1f;国内做MES系统的企业哪家好&#xff1f;下面分为两块跟大家详细讲解。 一、什么是MES&#xff1f; 1、概念&#xff1a; MES&#xff08;英文全称&#xff1a;Manufacturing Execution System&#xff09;制造执行系统&#xff0c;是面向车间生产的管理…

常用调用链等监控对比

1 了解监控 什么是监控&#xff1f; 指对计算机系统、网络、应用程序等进行实时、持续的管理和控制&#xff0c;以确保系统的性能、稳定性和安全性。 具体来说&#xff0c;监控可以通过收集和分析各种指标数据来实现&#xff0c;例如CPU、内存、网络、磁盘等硬件指标&#xf…

NamedPipeClientStream连接远程主机异常的处理

NamedPipeClientStream连接远程主机异常的处理 命名管道通讯测试异常解决方法&#xff1a; 命名管道通讯测试异常 在两个PC主机上测试命名管道通讯&#xff0c;设置服务器IP&#xff0c;初始化客户端时&#xff0c;会报无法访问路径异常。 解决方法&#xff1a; 在Windows功能…

软件测试项目案例去哪找【银行/金融/电商/外卖】

项目经验&#xff08;案例一&#xff09; 项目时间&#xff1a;2016-08 - 2017-07 项目名称&#xff1a;小花钱包&#xff08;Web&#xff09; 项目描述&#xff1a; 项目介绍 这个产品产是互联网金融理财服务平台&#xff0c;既可以发起投标&#xff0c;也可以借款&#xf…

使用Python实现.mat文件转换、读取

目录 一、前言 二、将excel文件转换为mat文件 三、读取mat文件并进行可视化 四、将mat文件转换为excel文件 一、前言 有时候我们拿到一个数据文件不是excel或者csv的怎么办呢&#xff1f;比如&#xff1a;你可恶的合作伙伴测实验数据时&#xff0c;用MATLAB丢给你一个mat…

【mac切换go不同版本】

1.需求是&#xff1a;mac本机想要同时拥有几个版本的go&#xff0c;并可以方便切换 第一种brew link切换失败&#xff0c;手动切换成功 第二种gvm方法失败 第三种docker成功 &#xff08;别看前面啰里八嗦&#xff0c;我只是记录一下&#xff0c;请直接跳到第三个&#xff09; …

【IMX6ULL驱动开发学习】14.Linux驱动开发 - GPIO中断(设备树 + GPIO子系统)

代码自取【14.key_tree_pinctrl_gpios_interrupt】&#xff1a; https://gitee.com/chenshao777/imx6-ull_-drivers 主要接口函数&#xff1a; 1. of_gpio_count&#xff08;获得GPIO的数量&#xff09; static inline int of_gpio_count(struct device_node *np)2. kzalloc…

uniapp项目或者vue项目 封装弹框组件

baseDialog组件代码: <template><view class"base-dialog" v-if"show"><view class"mask"></view><view class"Popmenu" :style"{ width }"><view class"header">{{ title …

怎么做好技术团队规划

一、做规划包括哪些东西 业务结果&#xff1a; 直白说就是业务层面的战绩&#xff0c;你团队打造了一个公司 GMV 占比超过 50%的商城&#xff0c;或者支撑了某个快速发展业务&#xff0c;这些都是业务结果&#xff0c;用业务数字来说话。 技术创新&#xff1a; 由技术人员发起…

【DBA专属】mysql-------->>>MMM高可用集群架构

Mysql---MMM高可用集群架构 目录 MMM安装部署 环境配置&#xff1a;&#xff08;所有主机配置&#xff09; 1、主机信息 2、关闭防火墙 3、同步时区 4、配置主机解析文件 5、配置ssh免密登录 6、所有机器安装epel源 数据库配置&#xff1a; 【所有数据库均做的配置】…

蜣螂优化算法(DBO)优化VMD参数,最小包络熵、样本熵、信息熵、排列熵(适应度函数可自行选择,一键修改)包含MATLAB源代码

蜣螂优化算法是华大学沈波教授团队&#xff0c;继麻雀搜索算法(Sparrow Search Algorithm&#xff0c;SSA&#xff09;之后&#xff0c;于2022年11月27日又提出的一种全新的群体智能优化算法。已有很多学者将算法用于实际工程问题中&#xff0c;今天咱们用蜣螂优化算法优化一下…

技术干货——Selenium Python使用技巧(二)

目录 进行自动跨浏览器测试 使用CSS定位器 WebElement的HTML源代码 鼠标悬停 关闭标签而不是浏览器 处理下拉菜单 复选框处理 通过CSS选择器选择元素 总结&#xff1a; 进行自动跨浏览器测试 您可能需要在多种情况下针对不同的浏览器&#xff08;例如Firefox&#xff…

软件测试工程师的工作内容?告诉你们什么是真正的测试工程师

目录 前言 1.何为软件测试工程师&#xff1f; 2.软件测试工程师的职责&#xff1f; 3.为什么要做软件测试&#xff1f; 4.软件测试的前途如何&#xff1f; 5.工具和思维谁更重要&#xff1f; 6.测试和开发相差大吗&#xff1f; 7.成为测试工程师的必备条件 8.测试的分…

shiro和redis一起使用

Shiro 缓存配置 当我们进行授权操作时,每次都会从数据库查询用户权限信息,为了提高授权性能,可以将用户权限信息查询出来以后进行缓存,下次授权时从缓存取数据即可。 Shiro 中内置缓存应用实现,其步骤如下: 第一步:在 SpringShiroConfig 中配置缓存 Bean 对象(Shiro 框架提供)…

Talk | 阿姆斯特丹大学博士生胡涛:计算机视觉中的标签效率学习

本期为TechBeat人工智能社区第509期线上Talk&#xff01; 北京时间6月29日(周四)20:00&#xff0c;阿姆斯特丹大学博士生—胡涛的Talk将准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “计算机视觉中的标签效率学习”&#xff0c;届时将从生成式学习、数…

Drools用户手册翻译——第二章 入门(上)

因为篇幅原因&#xff0c;所以分为上下两个部分&#xff0c;主要就是通过一个交通违章项目的例子&#xff0c;带你先粗略感受一下决策模型的使用流程&#xff0c;总体来说有详细&#xff0c;也有没说清的地方&#xff0c;如果想要了解一下决策模型&#xff0c;可以进来了解一下…