数据可视化插件echarts【前端】
前言
2024-4-12 16:08:09
以下内容源自《【前端】》
仅供学习交流使用
版权
禁止其他平台发布时删除以下此话
本文首次发布于CSDN平台
作者是CSDN@日星月云
博客主页是https://jsss-1.blog.csdn.net
禁止其他平台发布时删除以上此话
开源
日星月云 / echarts数据可视化
v1:二、入门demo
v2:三、动态数据
v3:四、动态数据
v4:六、注解优化
v5:七、项目开发
推荐
echarts入门教程(超级详细带案例)
数据可视化插件echarts
一、如何使用
1.1 下载
(1)从 npm 获取
npm install echarts --save
(2)从 CDN 获取
(3)从 GitHub 获取
1.2 找到js文件
在
node_modules\echarts\dist
中找到
echart.js
或
echarts.min,js
1.3 入门使用
<!DOCTYPEhtml><html><head><metacharset="utf-8"><title></title><!-- 01 导入js --><scriptsrc="js/echarts.js"></script><!-- 03 设置容器的样式 --><style>#container{width: 800px;height: 600px;}</style></head><body><!-- 02 创建个容器 --><divid="container"></div></body><script>//04 实例化echarts// 4.1 创建一个实例var echart = echarts.init(document.getElementById("container"))// 4.2 定义配置项var option ={// 图表的标题title:{text:"我的第一个图表"},// 图表的提示tooltip:{},// 图例legend:{data:["睡眠时长"]},// x轴线xAxis:{data:["周一","周二","周三","周四","周五","周六","周日"]},// y轴线yAxis:{},// 设置数据series:[{// 数据名称name:"睡眠时长",// 类型为柱状图type:"bar",// 数据datadata:[8,10,4,5,9,4,8]}]}// 4.3 更新配置
echart.setOption(option);// chart图表,set设置 Option选项 data数据 type类型 bar条(柱状条),series系列(数据) Axis轴线 xAxis水平轴线// legend传奇(图例) tooltip 提示 init初始化 document文档</script></html>
1.4 我的使用
下面的代码根据此代码修改
<!DOCTYPEhtml><html><head><metacharset="utf-8"><title></title><!-- 01 导入js --><scriptsrc="js/echarts.js"></script><!-- 03 设置容器的样式 --><style>#container{width: 800px;height: 600px;}</style></head><body><!-- 02 创建个容器 --><divid="container"></div></body><script>//实例化echarts// 1 创建一个实例var echart = echarts.init(document.getElementById("container"));let data1 =[175,160,153,121,156]let data2 =[200,140,205,162,175]let data3 =[]let data4 =['13:00','14:00','15:00','16:00','17:00']
data1.forEach((item1,index)=>{if(item1>data2[index]){
data3.push({yAxis: item1,//标注的Y轴位置xAxis: data4[index],//标注的X轴位置value: item1 //标注的value值})}else{
data3.push({yAxis: data2[index],//标注的Y轴位置xAxis: data4[index],//标注的X轴位置value: data2[index]//标注的value值})}})// 2 定义配置项var option ={backgroundColor:'white',grid:{top:'20%',left:'5%',right:'5%',bottom:'8%',containLabel:true},tooltip:{trigger:'axis',borderWidth:1,axisPointer:{type:'shadow'},extraCssText:'z-index:2'},legend:[{top:'top',left:'center',orient:'horizontal',data:['进水量','出水量'],itemWidth:15,itemHeight:10,itemGap:15,borderRadius:4,textStyle:{color:'#000',fontFamily:'Alibaba PuHuiTi',fontSize:14,fontWeight:400}}],xAxis:{type:'category',data: data4,axisLine:{show:false},axisTick:{show:false},axisLabel:{show:true,textStyle:{color:'#393939'//X轴文字颜色}}},yAxis:[{type:'value',name:'',nameTextStyle:{color:'#000',fontFamily:'Alibaba PuHuiTi',fontSize:14,fontWeight:600// padding: [0, 0, 0, 40], // 四个数字分别为上右下左与原位置距离},nameGap:30,// 表现为上下位置axisLine:{show:true,lineStyle:{color:'#eeeeee'}},axisTick:{show:false},axisLabel:{color:'#393939',fontSize:14},splitLine:{show:true,lineStyle:{color:'#eeeeee'}}}],series:[{name:'进水量',type:'line',showAllSymbol:true,//显示所有图形。//标记的图形为实心圆symbolSize:8,//标记的大小itemStyle:{//折线拐点标志的样式color:'white',borderWidth:'2',borderColor:'#5470c6',normal:{color:'#5470c6'//拐点颜色}},lineStyle:{color:'#5470c6'},markPoint:{data: data3
},data: data1
},{name:'出水量',type:'line',showAllSymbol:true,//显示所有图形。symbolSize:8,//标记的大小itemStyle:{//折线拐点标志的样式color:'white',borderWidth:'2',borderColor:'#91cc75',normal:{color:'#91cc75'//拐点颜色}},lineStyle:{color:'#91cc75'},data: data2
}]}// 3 更新配置
echart.setOption(option);</script></html>
二、前后端交互:入门demo
2.1 前端
html
<div class="data-container"></div>
js
$(document).ready(function(){list();});functionlist(){
$.ajax({type:"GET",url:SERVER_PATH+"/data/list",xhrFields:{withCredentials:true},success:function(result){if(result.status){alertBox(result.data.message);returnfalse;}init(result.data);}});}functioninit(dataLists){//实例化echarts// 1 创建一个实例var echart = echarts.init(document.querySelector(".data-container"));//进水量let data1 = dataLists.inWaterList;//出水量let data2 = dataLists.outWaterList;//标注let data3 =[]//横轴时间let data4 = dataLists.dateList;
data1.forEach((item1, index)=>{if(item1 > data2[index]){
data3.push({yAxis: item1,//标注的Y轴位置xAxis: data4[index],//标注的X轴位置value: item1 //标注的value值})}else{
data3.push({yAxis: data2[index],//标注的Y轴位置xAxis: data4[index],//标注的X轴位置value: data2[index]//标注的value值})}})// 2 定义配置项var option ={backgroundColor:'white',grid:{top:'20%',left:'5%',right:'5%',bottom:'8%',containLabel:true},tooltip:{trigger:'axis',borderWidth:1,axisPointer:{type:'shadow'},extraCssText:'z-index:2'},legend:[{top:'top',left:'center',orient:'horizontal',data:['进水量','出水量'],itemWidth:15,itemHeight:10,itemGap:15,borderRadius:4,textStyle:{color:'#000',fontFamily:'Alibaba PuHuiTi',fontSize:14,fontWeight:400}}],xAxis:{type:'category',data: data4,axisLine:{show:false},axisTick:{show:false},axisLabel:{show:true,textStyle:{color:'#393939'//X轴文字颜色}}},yAxis:[{type:'value',name:'',nameTextStyle:{color:'#000',fontFamily:'Alibaba PuHuiTi',fontSize:14,fontWeight:600// padding: [0, 0, 0, 40], // 四个数字分别为上右下左与原位置距离},nameGap:30,// 表现为上下位置axisLine:{show:true,lineStyle:{color:'#eeeeee'}},axisTick:{show:false},axisLabel:{color:'#393939',fontSize:14},splitLine:{show:true,lineStyle:{color:'#eeeeee'}}}],series:[{name:'进水量',type:'line',showAllSymbol:true,//显示所有图形。//标记的图形为实心圆symbolSize:8,//标记的大小itemStyle:{//折线拐点标志的样式color:'white',borderWidth:'2',borderColor:'#5470c6',normal:{color:'#5470c6'//拐点颜色}},lineStyle:{color:'#5470c6'},markPoint:{data: data3
},data: data1
},{name:'出水量',type:'line',showAllSymbol:true,//显示所有图形。symbolSize:8,//标记的大小itemStyle:{//折线拐点标志的样式color:'white',borderWidth:'2',borderColor:'#91cc75',normal:{color:'#91cc75'//拐点颜色}},lineStyle:{color:'#91cc75'},data: data2
}]}// 3 更新配置
echart.setOption(option);}
2.2 后端
entity
@lombok.Data@NoArgsConstructor@AllArgsConstructorpublicclassData{IntegerInWater;IntegerOutWater;Date date;}
controller
@GetMapping("/list")publicResponseModelgetDataList(){HashMap<String,Object> search = dataService.searchMap();returnnewResponseModel(search);}
service
publicHashMap<String,Object>searchMap(){HashMap<String,Object> map=newHashMap<>();List<Data> dataList =search();List<Integer> inWaterList =newArrayList<>();List<Integer> outWaterList =newArrayList<>();List<Date> dateList =newArrayList<>();for(Data data : dataList){
inWaterList.add(data.getInWater());
outWaterList.add(data.getOutWater());
dateList.add(data.getDate());}
map.put("inWaterList",inWaterList);
map.put("outWaterList",outWaterList);
map.put("dateList",dateList);return map;}publicList<Data>search(){return dataDao.list();}
mapper
@Select("SELECT * FROM test limit 20")List<Data>list();
三、前后端交互:动态数据
3.1 前端
js
$(document).ready(function (){list();});
function list(){
$.ajax({
type:"GET",
url:SERVER_PATH+"/data/list",
data:{
userId:1},
xhrFields:{withCredentials:true},
success: function (result){if(result.status){alertBox(result.data.message);returnfalse;}init(result.data);}});}
function init(dataLists){//实例化echarts// 1 创建一个实例var echart = echarts.init(document.querySelector(".data-container"));//进水量
let data1 = dataLists.rate1;//出水量
let data2 = dataLists.rate2;//横轴时间
let data4 = dataLists.date;//标注数据
let data3 =[];//只需修改以下对应
let names=["rate1","rate2"];
let datas=[data1,data2];
let colors=[
'#5470c6','#91cc75'
]//动态生成下面的数据for(let i=0;i<names.length;i++){
data3.push([]);}
datas.forEach((data, index)=>{
data.forEach((item, i)=>{
data3[index].push({
yAxis: item,// 标注的Y轴位置
xAxis: data4[i],// 标注的X轴位置
value: item // 标注的value值});});});
let seriesData=[];for(var i =0; i < datas.length; i++){
seriesData.push({
name: names[i],
type:'line',
showAllSymbol:true,//显示所有图形。//标记的图形为实心圆
symbolSize:8,//标记的大小
itemStyle:{//折线拐点标志的样式
color:'white',
borderWidth:'2',
borderColor: colors[i],
normal:{
color: colors[i]//拐点颜色}},
lineStyle:{
color: colors[i]},
markPoint:{
data: data3[i]},
data: datas[i]});}// 2 定义配置项var option ={
backgroundColor:'white',
grid:{
top:'20%',
left:'5%',
right:'5%',
bottom:'8%',
containLabel:true},
tooltip:{
trigger:'axis',
borderWidth:1,
axisPointer:{
type:'shadow'},
extraCssText: 'z-index:2',// formatter: function(params) {// var tooltipContent = params[0].name + '<br/>'; // 显示日期// params.forEach(function(param) {// tooltipContent += param.seriesName + ': ' + param.value + '<br>';// });// return tooltipContent;// }},
legend:[{
top:'top',
left:'center',
orient: 'horizontal',
data: names,
itemWidth:15,
itemHeight:10,
itemGap:15,
borderRadius:4,
textStyle:{
color:'#000',
fontFamily: 'AlibabaPuHuiTi',
fontSize:14,
fontWeight:400}}],
xAxis:{
type: 'category',
data: data4,
axisLine:{
show:false},
axisTick:{
show:false},
axisLabel:{
show:true,
textStyle:{
color: '#393939' //X轴文字颜色}}},
yAxis:[{
type:'value',
name: '',
nameTextStyle:{
color:'#000',
fontFamily: 'AlibabaPuHuiTi',
fontSize:14,
fontWeight:600// padding: [0, 0, 0, 40], // 四个数字分别为上右下左与原位置距离},
nameGap:30,// 表现为上下位置
axisLine:{
show:true,
lineStyle:{
color: '#eeeeee'
}},
axisTick:{
show:false},
axisLabel:{
color: '#393939',
fontSize:14},
splitLine:{
show:true,
lineStyle:{
color: '#eeeeee'
}}}],
series: seriesData
}// 3 更新配置
echart.setOption(option);}
3.2 后端
service
//返回数据链表publicHashMap<String,ArrayList>searchMap(Integer userId){HashMap<String,ArrayList> map=newHashMap<>();List<EldData> dataList =search(userId);List<String> fieldNames =newArrayList<>();Class<?> dataClass =EldData.class;// 获取 OldData 类的所有属性名Field[] fields = dataClass.getDeclaredFields();for(Field field : fields){
fieldNames.add(field.getName());
map.put(field.getName(),newArrayList<>());}for(EldData data : dataList){for(String fieldName : fieldNames){ArrayList<Object> rowData =map.get(fieldName);try{Field field = dataClass.getDeclaredField(fieldName);
field.setAccessible(true);
rowData.add(field.get(data));}catch(NoSuchFieldException|IllegalAccessException e){
e.printStackTrace();}
map.put(fieldName,rowData);}}return map;}//搜索数据publicList<EldData>search(Integer userId){String key=ELD_DATA+userId;Set set = redisTemplate.opsForZSet().reverseRange(key,0,19);// 获取分数最高的20个数据return set !=null?newArrayList<>(set):newArrayList<>();}
四、前后端交互:动态数据
后端name根据注解ChineseName
前端颜色是随机生成的
hashMap导致没有顺序,换成LinkedHashMap
在seachMap()中,重新定义
// HashMap<String,ArrayList> map=new HashMap<>();HashMap<String,ArrayList> map=newLinkedHashMap<>();
发现它是时间顺序是反这的
修改一下
//搜索数据// public List<EldData> search(Integer userId) {// String key= ELD_DATA +userId;// Set set = redisTemplate.opsForZSet().reverseRange(key, 0, limit-1);// 获取分数最高的20个数据//// return set !=null?new ArrayList<>(set):new ArrayList<>();//// }//搜索数据publicList<EldData>search(Integer userId){String key=ELD_DATA+userId;Set set = redisTemplate.opsForZSet().reverseRange(key,0, limit-1);// 获取分数最高的limit个数据if(set==null){returnnewArrayList<>();}ArrayList<EldData> resList =newArrayList<>(set);Collections.reverse(resList);return resList;}
4.1 前端
js
变成真实登录的用户
而不是固定userId是1
$(document).ready(function(){list();});functionlist(){var id=sessionStorage.getItem("id");
$.ajax({type:"GET",url:SERVER_PATH+"/data/list",data:{// userId: 1userId: id
},xhrFields:{withCredentials:true},success:function(result){if(result.status){alertBox(result.data.message);returnfalse;}init(result.data);}});}functioninit(dataLists){//实例化echarts// 1 创建一个实例var echart = echarts.init(document.querySelector(".data-container"));//横轴时间let datax = dataLists.date;//标注数据let data0 =[];//只需修改不需要展示的namevar noNeed=["id","date"];//原始数据的所有namelet keys=Object.keys(dataLists);//只需添加足够的颜色// let colors=[// '#5470c6','#91cc75'// ]//动态生成下面的数据,不需要修改//随机生成相同数量的颜色let colors=generateRandomColors(keys.length);//名称和对应的数据let names =[]let datas =[];
keys.forEach((name)=>{if(!noNeed.includes(name)){
names.push(name);
datas.push(dataLists[name]);}});for(let i=0;i<names.length;i++){
data0.push([]);}
datas.forEach((data, index)=>{
data.forEach((item, i)=>{
data0[index].push({yAxis: item,// 标注的Y轴位置xAxis: datax[i],// 标注的X轴位置value: item // 标注的value值});});});let seriesData=[];for(var i =0; i < datas.length; i++){
seriesData.push({name: names[i],type:'line',showAllSymbol:true,//显示所有图形。//标记的图形为实心圆symbolSize:8,//标记的大小itemStyle:{//折线拐点标志的样式color:'white',borderWidth:'2',borderColor: colors[i],normal:{color: colors[i]//拐点颜色}},lineStyle:{color: colors[i]},markPoint:{data: data0[i]},data: datas[i]});}// 2 定义配置项var option ={backgroundColor:'white',grid:{top:'20%',left:'5%',right:'5%',bottom:'8%',containLabel:true},tooltip:{trigger:'axis',borderWidth:1,axisPointer:{type:'shadow'},extraCssText:'z-index:2',// formatter: function(params) {// var tooltipContent = params[0].name + '<br/>'; // 显示日期// params.forEach(function(param) {// tooltipContent += param.seriesName + ': ' + param.value + '<br>';// });// return tooltipContent;// }},legend:[{top:'top',left:'center',orient:'horizontal',data: names,itemWidth:15,itemHeight:10,itemGap:15,borderRadius:4,textStyle:{color:'#000',fontFamily:'Alibaba PuHuiTi',fontSize:14,fontWeight:400}}],xAxis:{type:'category',data: datax,axisLine:{show:false},axisTick:{show:false},axisLabel:{show:true,textStyle:{color:'#393939'//X轴文字颜色}}},yAxis:[{type:'value',name:'',nameTextStyle:{color:'#000',fontFamily:'Alibaba PuHuiTi',fontSize:14,fontWeight:600// padding: [0, 0, 0, 40], // 四个数字分别为上右下左与原位置距离},nameGap:30,// 表现为上下位置axisLine:{show:true,lineStyle:{color:'#eeeeee'}},axisTick:{show:false},axisLabel:{color:'#393939',fontSize:14},splitLine:{show:true,lineStyle:{color:'#eeeeee'}}}],series: seriesData
}// 3 更新配置
echart.setOption(option);}functiongenerateRandomColors(num){let randomColors =[];let characters ='0123456789ABCDEF';for(let i =0; i < num; i++){let color ='#';for(let j =0; j <6; j++){
color += characters[Math.floor(Math.random()*16)];}
randomColors.push(color);}return randomColors;}
4.2 后端
ChineseName注解
packagecom.jsss.echarts.annotation;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public@interfaceChineseName{Stringvalue();}
EldData
packagecom.jsss.echarts.entity;importcom.jsss.echarts.annotation.ChineseName;importlombok.AllArgsConstructor;importlombok.Data;importlombok.EqualsAndHashCode;importlombok.NoArgsConstructor;importjava.sql.Date;importjava.util.Objects;@Data@NoArgsConstructor@AllArgsConstructorpublicclassEldData{@ChineseName("id")String id;@ChineseName("率1")Integer rate1;@ChineseName("率2")Integer rate2;@ChineseName("date")Date date;@Overridepublicbooleanequals(Object o){if(this== o)returntrue;if(o ==null||getClass()!= o.getClass())returnfalse;EldData eldData =(EldData) o;returnObjects.equals(id, eldData.id)&&Objects.equals(date, eldData.date);}@OverridepublicinthashCode(){returnObjects.hash(id, date);}@OverridepublicStringtoString(){return"EldData{"+"rate1="+ rate1 +", rate2="+ rate2 +", date="+ date +'}';}}
DataService
packagecom.jsss.echarts.service;importcom.jsss.echarts.annotation.ChineseName;importcom.jsss.echarts.entity.EldData;importcom.jsss.utils.Constant;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.data.redis.core.RedisTemplate;importorg.springframework.data.redis.serializer.StringRedisSerializer;importorg.springframework.stereotype.Service;importjava.lang.reflect.Field;importjava.util.*;@ServicepublicclassDataServiceimplementsConstant{@AutowiredRedisTemplate redisTemplate;//返回数据链表publicHashMap<String,ArrayList>searchMap(Integer userId){// HashMap<String,ArrayList> map=new HashMap<>();HashMap<String,ArrayList> map=newLinkedHashMap<>();List<EldData> dataList =search(userId);List<String> fieldNames =newArrayList<>();Class<?> dataClass =EldData.class;// 获取 OldData 类的所有属性名Field[] fields = dataClass.getDeclaredFields();for(Field field : fields){
fieldNames.add(field.getName());// map.put(field.getName(),new ArrayList<>());
map.put(field.getAnnotation(ChineseName.class).value(),newArrayList<>());}for(EldData data : dataList){for(String fieldName : fieldNames){// ArrayList<Object> rowData = map.get(fieldName);try{Field field = dataClass.getDeclaredField(fieldName);ArrayList<Object> rowData =map.get(field.getAnnotation(ChineseName.class).value());
field.setAccessible(true);
rowData.add(field.get(data));
map.put(field.getAnnotation(ChineseName.class).value(),rowData);}catch(NoSuchFieldException|IllegalAccessException e){
e.printStackTrace();}// map.put(fieldName, rowData);}}return map;}//搜索数据// public List<EldData> search(Integer userId) {// String key= ELD_DATA +userId;// Set set = redisTemplate.opsForZSet().reverseRange(key, 0, 19);// 获取分数最高的20个数据//// return set !=null?new ArrayList<>(set):new ArrayList<>();//// }//搜索数据publicList<EldData>search(Integer userId){String key=ELD_DATA+userId;Set set = redisTemplate.opsForZSet().reverseRange(key,0, limit-1);// 获取分数最高的limit个数据if(set==null){returnnewArrayList<>();}ArrayList<EldData> resList =newArrayList<>(set);Collections.reverse(resList);return resList;}// 将数据存储到有序集合中,分数为日期的时间戳publicbooleanaddData(Integer userId,EldData data){String key=ELD_DATA+userId;return redisTemplate.opsForZSet().add(key, data,data.getDate().getTime());}// 更新数据,先删除数据,后增加新数据publicbooleanupdateData(Integer userId,EldData oldData,EldData newData){long res=removeData(userId,oldData);if(res==0){//没有旧数据,就修改失败returnfalse;}returnaddData(userId, newData);}// 删除指定的数据publiclongremoveData(Integer userId,EldData data){String key=ELD_DATA+userId;return redisTemplate.opsForZSet().remove(key, data);}}
五、测试扩展性
5.0 开发说明
后端:
只需要更改EldData的属性就好了
并且添加对应注解
如果有一个属性没有注解会报错,由于searchMap()中默认是所有属性都有此注解。
如果有属性不需要前端展示,可以在前端noNeed中添加
也可以后端修改注解,增加need属性,增加代码逻辑
另外:注解也可增加:x轴属性
@ChineseName("id")String id;@ChineseName("率1")Integer rate1;@ChineseName("率2")Integer rate2;@ChineseName("率3")Integer rate3;@ChineseName("date")Date date;
前端:
修改横轴:
datax
怎么标注数据:
data0
以及不需要展示的
name
链表:
noNeed
//横轴时间
let datax = dataLists.date;
//标注数据
let data0 = [];
//只需修改不需要展示的name
var noNeed=["id","date"];
5.1 测试结果
5.2 Eld多加一个属性
packagecom.jsss.echarts.entity;importcom.jsss.echarts.annotation.ChineseName;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importjava.sql.Date;importjava.util.Objects;@Data@NoArgsConstructor@AllArgsConstructorpublicclassEldData{@ChineseName("id")String id;@ChineseName("率1")Integer rate1;@ChineseName("率2")Integer rate2;@ChineseName("率3")Integer rate3;@ChineseName("date")Date date;@Overridepublicbooleanequals(Object o){if(this== o)returntrue;if(o ==null||getClass()!= o.getClass())returnfalse;EldData eldData =(EldData) o;returnObjects.equals(id, eldData.id)&&Objects.equals(date, eldData.date);}@OverridepublicinthashCode(){returnObjects.hash(id, date);}}
5.3 加入测试数据
@AutowiredRedisTemplate redisTemplate;@AutowiredDataService dataService;Integer userId=1;//清空数据@Testpublicvoidrestore(){String key=ELD_DATA+userId;
redisTemplate.delete(key);testSearchMap();}@TestpublicvoidtestSearchMap(){HashMap<String,ArrayList> map = dataService.searchMap(userId);System.out.println(map);}@TestpublicvoidtestValidAdd(){EldData eldData=newEldData(Toolbox.getRandomString(),175,160,111,newDate(2024-1900,4-1,8));
dataService.addData(userId,eldData);
eldData=newEldData(Toolbox.getRandomString(),160,140,121,newDate(2024-1900,4-1,9));
dataService.addData(userId,eldData);
eldData=newEldData(Toolbox.getRandomString(),153,205,131,newDate(2024-1900,4-1,10));
dataService.addData(userId,eldData);
eldData=newEldData(Toolbox.getRandomString(),121,162,141,newDate(2024-1900,4-1,11));
dataService.addData(userId,eldData);
eldData=newEldData(Toolbox.getRandomString(),156,175,151,newDate(2024-1900,4-1,12));
dataService.addData(userId,eldData);testSearchMap();}
运行前端,登录admin:admin用户
在加入测试数据
userId=2
登录jsss:123456,也是可以的
2024-4-13 16:26:41
六、注解优化
6.0 开发说明
后端:
在EldData中
如果某个属性需要前端展示,就添加
ChineseName
注解
如果某个属性是横轴数据,其
value
值就是
datax
前端:
不需要修改任何代码
publicclassEldData{@ChineseName("率1")Integer rate1;@ChineseName("率2")Integer rate2;//没有注解,就不展示Integer rate3;//横轴的注解的值是datax@ChineseName("datax")Date date;}
6.1 测试结果
rate3没有注解
rate3添加注解
6.2 前端
对应的改一下这两个就行了
//横轴数据let datax = dataLists.datax;//不需要展示的namevar noNeed=["datax"];
6.2 后端
ChineseName
/**
* 如果某个属性需要展示,就添加`ChineseName`注解 <br>
* 如果某个属性是横轴数据,其`value`值是`datax` <br>
*/@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.FIELD)public@interfaceChineseName{//中文nameStringvalue();}
EldData
redis判断是根据序列化的结果判断是否相同,
equals和hashCode不起作用
packagecom.jsss.echarts.entity;importcom.jsss.echarts.annotation.ChineseName;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importlombok.ToString;importjava.sql.Date;@Data@NoArgsConstructor@AllArgsConstructor@ToStringpublicclassEldData{@ChineseName("率1")Integer rate1;@ChineseName("率2")Integer rate2;//没有注解,就不展示Integer rate3;//横轴的注解的值是datax@ChineseName("datax")Date date;}
DataService
//返回数据链表publicHashMap<String,ArrayList>searchMap(Integer userId){HashMap<String,ArrayList> map=newLinkedHashMap<>();List<EldData> dataList =search(userId);List<String> fieldNames =newArrayList<>();Class<?> dataClass =EldData.class;// 获取 OldData 类的所有被ChineseName注解的属性名Field[] fields = dataClass.getDeclaredFields();for(Field field : fields){//添加是否有注解的判断ChineseName chineseNameAnnotation = field.getAnnotation(ChineseName.class);if(chineseNameAnnotation!=null){
fieldNames.add(field.getName());
map.put(field.getAnnotation(ChineseName.class).value(),newArrayList<>());}}for(EldData data : dataList){for(String fieldName : fieldNames){try{Field field = dataClass.getDeclaredField(fieldName);
field.setAccessible(true);ArrayList<Object> rowData =map.get(field.getAnnotation(ChineseName.class).value());
rowData.add(field.get(data));
map.put(field.getAnnotation(ChineseName.class).value(),rowData);}catch(NoSuchFieldException|IllegalAccessException e){
e.printStackTrace();}}}return map;}//搜索数据publicList<EldData>search(Integer userId){String key=ELD_DATA+userId;Set set = redisTemplate.opsForZSet().reverseRange(key,0, limit-1);// 获取分数最高的limit个数据if(set==null){returnnewArrayList<>();}ArrayList<EldData> resList =newArrayList<>(set);Collections.reverse(resList);return resList;}
七、实际项目开发
加入分栏就更好了
EldData
packagecom.jsss.echarts.entity;importcom.jsss.echarts.annotation.ChineseName;importlombok.AllArgsConstructor;importlombok.Data;importlombok.NoArgsConstructor;importlombok.ToString;importjava.sql.Date;/**
* 字段名称 类型 字段说明 备注
* <p>
* HT Integer 通用-身高(HT) 单位:m
* WT Integer 通用-体重(WT) 单位:kg
* BMI Double 通用-身高体重指数(BMI) 正常范围 18.5~23.9,超重24.0~27.9,肥胖≥28.0
* SBP Integer 血压-收缩压(SBP) 正常成年人的收缩压范围为90-140毫米汞柱(mmHg)。
* DBP Integer 血压-舒张压(DBP) 正常成年人的舒张压范围为60-90毫米汞柱(mmHg)。
* Hb Integer 血常规-血红蛋白(Hb) 正常成年人的正常范围为120-175克/升。
* WBC Integer 血常规-白细胞计数(WBC) 正常成年人的白细胞计数范围为4-10 × 10^9/L。
* PLT Integer 血常规-血小板计数(PLT) 正常成年人的血小板计数范围为100-300 × 10^9/L。
* ALT Integer 肝功能-谷丙转氨酶(ALT) 正常成年人的ALT范围为10-40单位/升。
* AST Integer 肝功能-谷草转氨酶(AST) 正常成年人的AST范围为10-35单位/升。
* TBIL Double 肝功能-总胆红素(TBIL) 正常成年人的总胆红素范围为3.4-17.1毫摩尔/升。
* BUN Double 肾功能-血尿素氮(BUN) 正常成年人的BUN范围为2.5-7.1毫摩尔/升。
* Cr Integer 肾功能-血肌酐(Cr) 正常成年人的血肌酐范围为53-115微摩尔/升。
* TC Double 血脂-总胆固醇(TC) 正常成年人的总胆固醇范围为3.1-5.2毫摩尔/升。
* TG Double 血脂-甘油三酯(TG) 正常成年人的甘油三酯范围为0.4-1.7毫摩尔/升。
* LDL_C Double 血脂-低密度脂蛋白胆固醇(LDL-C) 正常成年人的LDL-C范围为2.6-3.4毫摩尔/升。
* FPG Double 血糖-空腹血糖(FPG) 正常成年人的空腹血糖范围为3.9-6.1毫摩尔/升。
* twohPG Double 血糖-餐后2小时血糖(2hPG) 正常成年人的餐后2小时血糖范围为3.9-7.8毫摩尔/升。
*/@Data@NoArgsConstructor@AllArgsConstructor@ToStringpublicclassEldData{@ChineseName("通用-身高(米)")IntegerHT;@ChineseName("通用-体重(千克)")IntegerWT;@ChineseName("通用-身高体重指数(千克/米2)")DoubleBMI;@ChineseName("血压-收缩压(毫米汞柱)")IntegerSBP;@ChineseName("血压-舒张压(毫米汞柱)")IntegerDBP;@ChineseName("血常规-血红蛋白(克/升)")IntegerHb;@ChineseName("血常规-白细胞计数(10^9/升)")IntegerWBC;@ChineseName("血常规-血小板计数(10^9/升)")IntegerPLT;@ChineseName("肝功能-谷丙转氨酶(单位/升)")IntegerALT;@ChineseName("肝功能-谷草转氨酶(单位/升)")IntegerAST;@ChineseName("肝功能-总胆红素(毫摩尔/升)")DoubleTBIL;@ChineseName("肾功能-血尿素氮(毫摩尔/升)")DoubleBUN;@ChineseName("肾功能-血肌酐(微摩尔/升)")IntegerCr;@ChineseName("血脂-总胆固醇(毫摩尔/升)")DoubleTC;@ChineseName("血脂-甘油三酯(毫摩尔/升)")DoubleTG;@ChineseName("血脂-低密度脂蛋白胆固醇(毫摩尔/升)")DoubleLDL_C;@ChineseName("血糖-空腹血糖(毫摩尔/升)")DoubleFPG;@ChineseName("血糖-餐后2小时血糖(毫摩尔/升)")Double twohPG;//横轴的注解的值是datax@ChineseName("datax")Date date;}
Constant
packagecom.jsss.utils;importcom.jsss.echarts.entity.EldData;importjava.sql.Date;publicinterfaceConstant{/**
* redis键:老人的体检数据
*/StringELD_DATA="eld_data:";EldDataMIN_DATA=newEldData(Integer.MIN_VALUE,Integer.MIN_VALUE,18.5,90,60,120,4,100,10,10,3.4,2.5,53,3.1,0.4,2.6,63.9,7.8,newDate(System.currentTimeMillis()));EldDataMAX_DATA=newEldData(Integer.MAX_VALUE,Integer.MAX_VALUE,23.9,140,90,175,10,300,40,35,17.1,7.1,115,5.2,1.7,2.4,6.1,7.8,newDate(System.currentTimeMillis()));}
测试数据
packagecom.jsss.echarts;importcom.jsss.echarts.entity.EldData;importcom.jsss.echarts.service.DataService;importcom.jsss.utils.Constant;importorg.junit.jupiter.api.Test;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.data.redis.core.RedisTemplate;importjava.sql.Date;importjava.util.ArrayList;importjava.util.HashMap;importjava.util.Random;@SpringBootTestpublicclassEchartsTestimplementsConstant{@AutowiredRedisTemplate redisTemplate;@AutowiredDataService dataService;Integer userId=1;Date date=newDate(2024-1900,4-1,14);@Testpublicvoidtest(){System.out.println(date);}//清空数据@Testpublicvoidrestore(){String key=ELD_DATA+userId;
redisTemplate.delete(key);testSearchMap();}@TestpublicvoidtestSearchMap(){HashMap<String,ArrayList> map = dataService.searchMap(userId);System.out.println(map);}@TestpublicvoidtestValidAdd(){EldData eldData=randomData();
eldData.setDate(newDate(2024-1900,4-1,8));
dataService.addData(userId,eldData);
eldData=randomData();
eldData.setDate(newDate(2024-1900,4-1,9));
dataService.addData(userId,eldData);
eldData=randomData();
eldData.setDate(newDate(2024-1900,4-1,10));
dataService.addData(userId,eldData);
eldData=randomData();
eldData.setDate(newDate(2024-1900,4-1,11));
dataService.addData(userId,eldData);
eldData=randomData();
eldData.setDate(newDate(2024-1900,4-1,12));
dataService.addData(userId,eldData);testSearchMap();}EldData minData=MIN_DATA;EldData maxData=MAX_DATA;publicEldDatarandomData(){EldData data=newEldData(randomInt(160,190),randomInt(45,80),randomDouble(minData.getBMI(),maxData.getBMI()),randomInt(minData.getSBP(),maxData.getSBP()),randomInt(minData.getDBP(),maxData.getDBP()),randomInt(minData.getHb(),maxData.getHb()),randomInt(minData.getWBC(),maxData.getWBC()),randomInt(minData.getPLT(),maxData.getPLT()),randomInt(minData.getALT(),maxData.getALT()),randomInt(minData.getAST(),maxData.getAST()),randomDouble(minData.getTBIL(),maxData.getTBIL()),randomDouble(minData.getBUN(),maxData.getBUN()),randomInt(minData.getCr(),maxData.getCr()),randomDouble(minData.getTC(),maxData.getTC()),randomDouble(minData.getTG(),maxData.getTG()),randomDouble(minData.getLDL_C(),maxData.getLDL_C()),randomDouble(minData.getFPG(),maxData.getFPG()),randomDouble(minData.getTwohPG(),maxData.getTwohPG()),newDate(System.currentTimeMillis()));return data;}publicIntegerrandomInt(int min,int max){Random random =newRandom();return random.nextInt(max - min +1)+ min;// 生成 min 到 max 范围内的随机 int 数}publicDoublerandomDouble(double min,double max){Random random =newRandom();return min +(max - min)* random.nextDouble();// 生成 min 到 max 范围内的随机 double 值}}
最后
2024-4-13 18:49:18
迎着日光月光星光,直面风霜雨霜雪霜。
版权归原作者 日星月云 所有, 如有侵权,请联系我们删除。