本篇文章主要讲解如何使用 SpringBoot+Thymeleaf+Echarts、以及 SpringBoot+VUE3.0+Echarts 两种方式,实现 Web 应用中的图标显示功能。
一、Echarts 概述
ECharts是一款基于JavaScript的数据可视化图表库,提供直观,生动,可交互,可个性化定制的数据可视化图表。ECharts最初由百度团队开源,并于2018年初捐赠给Apache基金会,成为ASF孵化级项目。
官网地址:Apache ECharts
官方文档地址:快速上手 - 使用手册 - Apache ECharts
官方案例地址:Examples - Apache ECharts
二、SpringBoot+Thymeleaf+Echarts
2.1 数据准备
本案例以某高校某系的 2021-2023 年考研数据为基础显示相应的数据统计图,数据库表如下:
DROP TABLE IF EXISTS `exam_stat`;
CREATE TABLE `exam_stat` (
`id` int NOT NULL AUTO_INCREMENT,
`exam_year` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, -- 考研年份
`college` varchar(50) DEFAULT NULL, -- 学院
`major` varchar(50) DEFAULT NULL, -- 专业
`total_num` int DEFAULT NULL, -- 专业总人数
`exam_num` int DEFAULT NULL, -- 参加考试的人数
`online_num` int DEFAULT NULL, -- 上线的人数
`pass_num` int DEFAULT NULL, -- 录取的人数
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8mb3;
-- ----------------------------
-- Records of exam_stat
-- ----------------------------
INSERT INTO `exam_stat` VALUES ('1', '2021', '计算机学院', '计算机科学与技术', '50', '6', '5', '10');
INSERT INTO `exam_stat` VALUES ('2', '2021', '计算机学院', '自动化', '45', '17', '8', '6');
INSERT INTO `exam_stat` VALUES ('3', '2021', '计算机学院', '软件工程', '50', '13', '8', '4');
INSERT INTO `exam_stat` VALUES ('4', '2021', '计算机学院', '轨道交通信号控制', '39', '20', '9', '4');
INSERT INTO `exam_stat` VALUES ('5', '2021', '计算机学院', '软件工程(专升本)', '66', '10', '4', '2');
INSERT INTO `exam_stat` VALUES ('6', '2021', '计算机学院', '物联网工程', '37', '8', '1', '0');
INSERT INTO `exam_stat` VALUES ('7', '2022', '计算机学院', '计算机科学与技术', '135', '18', '7', '4');
INSERT INTO `exam_stat` VALUES ('8', '2022', '计算机学院', '自动化', '48', '16', '9', '7');
INSERT INTO `exam_stat` VALUES ('9', '2022', '计算机学院', '软件工程', '195', '57', '20', '5');
INSERT INTO `exam_stat` VALUES ('10', '2022', '计算机学院', '轨道交通信号控制', '35', '6', '6', '4');
INSERT INTO `exam_stat` VALUES ('11', '2022', '计算机学院', '物联网工程', '41', '19', '4', '1');
INSERT INTO `exam_stat` VALUES ('12', '2023', '计算机学院', '计算机科学与技术', '134', '21', '9', '4');
INSERT INTO `exam_stat` VALUES ('13', '2023', '计算机学院', '自动化', '50', '28', '13', '8');
INSERT INTO `exam_stat` VALUES ('14', '2023', '计算机学院', '软件工程', '176', '47', '20', '10');
INSERT INTO `exam_stat` VALUES ('15', '2023', '计算机学院', '轨道交通信号控制', '33', '15', '5', '2');
INSERT INTO `exam_stat` VALUES ('16', '2023', '计算机学院', '物联网工程', '84', '15', '3', '1');
INSERT INTO `exam_stat` VALUES ('17', '2023', '计算机学院', '网络空间安全', '50', '15', '4', '4');
2.2 准备前端页面
在项目中对应的 HTML 页面中,先新建一个 div,用来显示柱状图,简单设置一下样式,代码如下:
<div class="chart_div">
<div id = "dataByYear" style="width:500px;height: 300px"> </div>
<div class="chart_title">2021年-2023年考研参考学员数据对比</div>
</div>
这段代码中,id 为 dataByYear 的 div 是待会儿我们用来显示图表的 div。
2.3 从官网案例中复制代码
读者可以从官网案例地址中找到自己想要的图表样式,比如:柱状图、折线图等等,这里我使用如下的图表样式:
点击进去,选择到 js 代码,将其中的 option 代码复制出来,粘贴到项目代码中,如下图所示:
从效果图和代码图的对比,我们很容易发现里面需要需改的地方,首先图表的横向代码为:
也就是说,如果我们需要修改水平方向上显示的内容,可以更这个 xAxis 中的 data 数组。在本案例中,我们横向显示的是考研数据设计到的年份,而这个年份,我们需要根据后台数据库中的数据查询,看数据分别涉及的是哪些年份,于是我们首先定义一个数组 xdata,方便后续从后台拿取数据。
var xdata = [];
然后再将上面 xAxis 中的 data 替换成 xdata,如下图所示:
紧接着,我们去修改一下每个柱子的数据,通过对比分析,我们不难发现,案例源代码中的 series:中就是每个柱子对应的数据,如下图所示:
在本案例中,我们分别要显示专业总人数、参考人数、上线人数以及录取人数,而这些数据也是需要从后台的数据库中获取,因此我们和上面一样,先定义对应的数组,用来存放从后台查询出来的对应的数据,如下图所示:
然后,删除series 多余的项,保留四个,分别修改成对应的数据,如下所示:
series: [
{
name: '总人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: total_nums
},
{
name: '参考人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: exam_nums
},
{
name: '上线人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: online_nums
},
{
name: '通过人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: pass_nums
}
]
接下来,发送异步请求,从后台拿数据,分别设置到几个数组中,代码如下:
$.ajax({
type: "GET",
dataType: "json",
url: "/kyInfo/showDataByYear",
async: false,
success: function (obj) {
data = obj;
for (var i = 0; i < data.length; i++) {
xdata.push(data[i].exam_year);
var exam_map = data[i];
console.log(data[i]);
total_nums.push(exam_map.total_num);
exam_nums.push(exam_map.exam_num);
online_nums.push(exam_map.online_num);
pass_nums.push(exam_map.pass_num);
}
}
}
);
前端完整代码如下:
function showDataByYear(){
var chartDom = document.getElementById('dataByYear');
var myChart = echarts.init(chartDom);
var option;
var xdata = [];
var data;
var total_nums = []; // 专业总人数
var exam_nums = []; // 参考人数
var online_nums = []; // 上线人数
var pass_nums = []; // 录取人数
$.ajax({
type: "GET",
dataType: "json",
url: "/kyInfo/showDataByYear",
async: false,
success: function (obj) {
data = obj;
for (var i = 0; i < data.length; i++) {
xdata.push(data[i].exam_year);
var exam_map = data[i];
console.log(data[i]);
total_nums.push(exam_map.total_num);
exam_nums.push(exam_map.exam_num);
online_nums.push(exam_map.online_num);
pass_nums.push(exam_map.pass_num);
}
}
}
);
console.log(total_nums);
option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: xdata
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '总人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: total_nums
},
{
name: '参考人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: exam_nums
},
{
name: '上线人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: online_nums
},
{
name: '通过人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: pass_nums
}
]
};
myChart.setOption(option);
}
2.4 SpringBoot 后台查询数据
编写控制器代码,处理前端发送的showDataByYear 请求:
@RequestMapping("/showDataByYear")
@ResponseBody
public List<Map<String,Object>> showDataByYear(){
List<Map<String,Object>> data = kyInfoService.getDataByYear();
return data;
}
编写业务层代码,处理具体的业务逻辑
@Override
public List<Map<String, Object>> getDataByYear() {
QueryWrapper<ExamStat> lqw = new QueryWrapper<ExamStat>();
lqw.select("exam_year," +
"sum(total_num) as total_num," +
"sum(exam_num) as exam_num," +
"sum(online_num) as online_num," +
"sum(pass_num) as pass_num ");
lqw.groupBy("exam_year");
List<Map<String, Object>> statList = examStatMapper.selectMaps(lqw);
System.out.println(statList);
return statList;
}
本案例中使用的是 mybatis-plus,读者也可以使用 mybatis 或者其他的技术实现。
部署项目,启动测试,效果如图所示:
三、SpringBoot+vue3.0+Echarts
实际上 vue 的实现方式和 一般的 html 页面实现方式大同小异,仅仅是前端发送请求的时候有所差异,其他 echarts 相关的显示部分,和前面案例是一样的,Vue 发送请求代码如下:
await axios.post(
"/api/sysUser/showDataByYear",
).then(res=>{
const data = res.data
console.log(data);
for (var i = 0; i < data.length; i++) {
xdata.push(data[i].exam_year);
var exam_map = data[i];
console.log(data[i]);
total_nums.push(exam_map.total_num);
exam_nums.push(exam_map.exam_num);
online_nums.push(exam_map.online_num);
pass_nums.push(exam_map.pass_num);
}
});
注意,这里我们需要使用 await 实现同步请求,等待后端响应数据之后再渲染图表,否则如果渲染完毕图表此时后端数据还没返回,此时就会看到空的图表。
前端发送请求完整代码如下:
<script setup>
import {reactive,ref,onMounted} from 'vue';
import * as echarts from "echarts";
// import { formInstance } from 'element-plus';
import axios from 'axios';
import qs from 'querystring'
// js中获取状态管理中存的值
import { useStore } from 'vuex';
import { useRouter } from 'vue-router';
const router = useRouter();
const store = useStore();
onMounted(()=>{
showDataByYear();
});
const showDataByYear = async ()=>{
var chartDom = document.getElementById('dataByYear');
var myChart = echarts.init(chartDom);
var option;
var xdata = [];
var data = {};
var total_nums = [];
var exam_nums = [];
var online_nums = [];
var pass_nums = [];
// var res = await axios.get("/api/sysUser/showDataByYear");
// data = res.data;
await axios.post(
"/api/sysUser/showDataByYear",
).then(res=>{
const data = res.data
console.log(data);
for (var i = 0; i < data.length; i++) {
xdata.push(data[i].exam_year);
var exam_map = data[i];
console.log(data[i]);
total_nums.push(exam_map.total_num);
exam_nums.push(exam_map.exam_num);
online_nums.push(exam_map.online_num);
pass_nums.push(exam_map.pass_num);
}
});
console.log(total_nums);
option = {
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
legend: {},
grid: {
left: '3%',
right: '4%',
bottom: '3%',
containLabel: true
},
xAxis: [
{
type: 'category',
data: xdata
}
],
yAxis: [
{
type: 'value'
}
],
series: [
{
name: '总人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: total_nums
},
{
name: '参考人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: exam_nums
},
{
name: '上线人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: online_nums
},
{
name: '通过人数',
type: 'bar',
emphasis: {
focus: 'series'
},
data: pass_nums
}
]
};
myChart.setOption(option);
}
}
如有疑问,可宫粽好,墨轩学习网,一起交流,感谢阅读
给个不要钱的三连吧:关注+点赞+收藏 O(∩_∩)O哈哈~