基于SpringBoot的疫情信息统计平台【完整项目源码】

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云解析 DNS,旗舰版 1个月
简介: 基于SpringBoot的疫情信息统计平台【完整项目源码】

Part 1


【学习目标】


1) SpringBoot框架 2) 业务功能的开发思路 3) 爬虫的底层原理 4) E-chart图标展示


【项目的诞生】


项目成员:项目经理 PM 产品经理 PD、 UI设计师 UED、 前端工程师 FE、后端工程师 RD、 测试工程师 QA、运维工程师 OP


【功能的诞生】


产品经理 -> 需求评审会 -> UI设计师(交互) -> UI评审 -> 技术 -> 技术方案设计 -> 开发(1/3) -> 测试和修改




2、postman(模拟http请求的工具)


验证分析出来的请求地址,在排除上下文环境后,是否依然能够拿到数据。


比如有的请求,依赖cookie、依赖动态的参数等等


Part 2


【解析数据】


(一) 认识JSON


JSON = JavaScript Object Notation (JavaScript对象表示法)


本质上,是存储和交换文本信息的语法。是一种轻量级的文本数据格式。


java领域内解析json的工具:gson 、 fastjson 、jackson


JSON 和 Java实体类image.png


image.pngimage.pngimage.png

(二) Gson


是google推出的,用来在json数据和java对象之间进行转换的类库。


Gson  gson = new Gson();

Gson  gson1 = new GsonBuilder().create();


// 将对象obj转化为json字符串

String jsonStr = gson.toJson(Obj);

// 将json字符串转化为java对象

T obj = gson.fromJson(jsonStr,class)

使用方式


1)引入gson依赖


       <dependency>

           <groupId>com.google.code.gson</groupId>

           <artifactId>gson</artifactId>

           <version>2.8.6</version>

       </dependency>

     

2)确认要转化的数据格式


import lombok.AllArgsConstructor;

import lombok.Data;


@Data @AllArgsConstructor

public class DataBean {


   private String area;

   private int nowConfirm;

   private int confirm;

   private int heal;

   private int dead;

}

3)解析文本数据


public class DataHandler {


   public static void main(String[] args) throws Exception{

       getData();

   }



   public static List<DataBean> getData() throws Exception {

//        Gson gson = new Gson();

       Gson gson1 = new GsonBuilder().create();

//        Map map = gson.fromJson(testStr,Map.class);

//        System.out.println(map);



       // 读取文件中的文本内容   然后再转化为java对象

//        File file = new File("tmp.txt");


       FileReader fr = new FileReader("tmp.txt");

       char[] cBuf = new char[1024];

       int cRead = 0;

       StringBuilder builder = new StringBuilder();

       while ((cRead = fr.read(cBuf)) > 0) {

           builder.append(new String(cBuf, 0, cRead));

       }


       fr.close();


//        System.out.println(builder.toString());

       Gson gson = new Gson();

       Map map = gson.fromJson(builder.toString(), Map.class);

       System.out.println(map);


       ArrayList areaList = (ArrayList) map.get("areaTree");

       Map dataMap = (Map) areaList.get(0);

       ArrayList childrenList = (ArrayList) dataMap.get("children");


       // 遍历然后转化

       List<DataBean> result = new ArrayList<>();


       for (int i = 0; i < childrenList.size(); i++) {

           Map tmp = (Map) childrenList.get(i);

           String name = (String)tmp.get("name");


           Map totalMap = (Map) tmp.get("total");

           double nowConfirm = (Double)totalMap.get("nowConfirm");

           double confirm = (Double)totalMap.get("confirm");

           double heal = (Double)totalMap.get("heal");

           double dead = (Double)totalMap.get("dead");


           DataBean dataBean = new DataBean(name,(int)nowConfirm,(int)confirm,

                   (int)heal,(int)dead);


           result.add(dataBean);

       }


       System.out.println(result);


       return result;

   }

}

Part 3


(三) 将数据展示在页面中


image.png


1、编写service和controller


public interface DataService extends IService<DataBean> {


   List<DataBean> list();


}

@Service

public class DataServiceImpl implements DataService {


   @Override

   public List<DataBean> list() {

       List<DataBean> result = null;


       try {

           result = DataHandler.getData();

       } catch (Exception e) {

           e.printStackTrace();

       }

       return result;

   }

}

@Controller

public class DataController {


   @Autowired

   private DataService dataService;


   @GetMapping("/")

   public String list(Model model){

       List<DataBean> list = dataService.list();

       model.addAttribute("dataList",list);

       return "list";

   }

 

}

2、编写页面(注意已引入thymeleaf的maven依赖)


<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

   <meta charset="UTF-8">

   <title>Title</title>

</head>

<body>



<h2>国内疫情情况如下</h2>

<br>


<table>

   <thead>

   <tr>

       <th>地区</th>

       <th>现有确诊</th>

       <th>累计确诊</th>

       <th>治愈</th>

       <th>死亡</th>

   </tr>

   </thead>

   <tbody>

   <tr th:each="data:${dataList}">

       <td th:text="${data.area}">name</td>

       <td th:text="${data.nowConfirm}">nowConfirm</td>

       <td th:text="${data.confirm}">confirm</td>

       <td th:text="${data.heal}">heal</td>

       <td th:text="${data.dead}">dead</td>

   </tr>

   </tbody>

</table>


</body>

</html>


(四) 转为实时数据


涉及知识点:用java代码模拟http请求


1、复习get和post请求


分别在使用场景、参数传递方式、数据大小限制、安全性等方面的异同


2、HttpURLConnection


连接时间和读取时间

连接时间:发送请求端 连接到  url目标地址端的时间

          受到距离长短和网络速度的影响

读取时间:指连接成功后  获取数据的时间

          受到数据量和服务器处理速度的影响

1) 通过创建url打开远程链接 (HttpURLConnection) 2) 设置相关参数(超时时间和请求头等等) 3) 发送请求 4) 接收结果(使用InputStream和BufferedReader)


public static String doGet(String urlStr) {

       HttpURLConnection conn = null;

       InputStream is = null;

       BufferedReader br = null;

       StringBuilder result = new StringBuilder();


       try {

           URL url = new URL(urlStr);

           // 通过url打开一个远程连接  强转类型

           conn = (HttpURLConnection) url.openConnection();

           conn.setRequestMethod("GET");


           // 连接时间和读取时间

           //  连接时间:发送请求端 连接到  url目标地址端的时间

           //            受到距离长短和网络速度的影响

           //  读取时间:指连接成功后  获取数据的时间

           //            受到数据量和服务器处理速度的影响

           conn.setConnectTimeout(15000);

           conn.setReadTimeout(60000);


           // 设定请求头参数的方式:如指定接收json数据   服务端的key值为content-type

//            conn.setRequestProperty("Accept", "application/json");


           // 发送请求

           conn.connect();


           if (conn.getResponseCode() != 200) {

               // TODO 此处应该增加异常处理

               return "error code";

           }


           is = conn.getInputStream();

           br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

           String line;

           // 逐行读取  不为空就继续

           while ((line = br.readLine()) != null) {

               result.append(line);

               System.out.print(line);

           }



       } catch (Exception e) {

           e.printStackTrace();

       } finally {

           try {

               if (br != null) br.close();

               if (is != null) is.close();


           } catch (Exception e) {

               e.printStackTrace();

           }

       }


       return result.toString();

   }


Part 4


(五) 使用Jsoup解析html格式数据


1、Jsoup 是html的解析器,可以解析html文本和直接解析URL地址。本质上是通过DOM、CSS以及类似jQuery的方法来取出和操作数据。


       Document document = Jsoup.parse(htmlStr);

       System.out.println(document);


       //通过标签名找到元素

       Elements elements = document.getElementsByTag("p");

       System.out.println(elements);


       document.getElementsById    //通过id找到元素

       Element element = document.select("a[href]");  

       //还支持使用正则表达式查找元素

2、提供不同数据源的切换查询


1)增加了controller方法


   @GetMapping("/list/{id}")

   public String listById(Model model, @PathVariable String id) {

       List<DataBean> list = dataService.listById(Integer.parseInt(id));

       model.addAttribute("dataList", list);

       return "list";

   }

@PathVariavle 将接收到的地址数据,映射到方法的参数中


2)完善service


   @Override

   public List<DataBean> listById(int id) {

       if (id == 2) {

           return JsoupHandler.getData();

       }

       return list();

   }

处理数据的方法


public static String urlStr = "https://ncov.dxy.cn/ncovh5/view/pneumonia?" +

           "scene=2&from=singlemessage&isappinstalled=0";


   public static ArrayList<DataBean> getData() {


       ArrayList<DataBean> result = new ArrayList<>();

       try {

           Document doc = Jsoup.connect(urlStr).get();

//            Elements scripts = doc.select("script");

           // 找到指定的标签数据

           Element oneScript = doc.getElementById("getAreaStat");


           String data = oneScript.data();

           // 字符串截取出json格式的数据

           String subData = data.substring(data.indexOf("["),

                   data.lastIndexOf("]") + 1);


//            System.out.println(subData);


           Gson gson = new Gson();

           ArrayList list = gson.fromJson(subData, ArrayList.class);


           for (int i = 0; i < list.size(); i++) {

               Map map = (Map) list.get(i);

               String name = (String) map.get("provinceName");

               double nowConfirm = (Double) map.get("currentConfirmedCount");

               double confirm = (Double) map.get("confirmedCount");

               double heal = (Double) map.get("curedCount");

               double dead = (Double) map.get("deadCount");


               DataBean dataBean = new DataBean(name, (int) nowConfirm, (int) confirm

                       , (int) heal, (int) dead);

               result.add(dataBean);

           }


       } catch (Exception e) {

           e.printStackTrace();

       }


       return result;

   }

(六) 增加数据存储逻辑


1、引入相关的依赖


       <dependency>

           <groupId>org.mybatis.spring.boot</groupId>

           <artifactId>mybatis-spring-boot-starter</artifactId>

           <version>2.1.0</version>

       </dependency>


       <dependency>

           <groupId>mysql</groupId>

           <artifactId>mysql-connector-java</artifactId>

           <scope>runtime</scope>

       </dependency>


       <dependency>

           <groupId>com.baomidou</groupId>

           <artifactId>mybatis-plus-boot-starter</artifactId>

           <version>3.2.0</version>

       </dependency>

2、配置数据库


spring.datasource.url=jdbc:mysql://localhost:3366/epidemic?serverTimezone=UTC&useUnicode=true&characterEncoding=utf8 //3366是MySQL数据库端口号

spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

spring.datasource.username=root //MySQL数据库管理用户名

spring.datasource.password=root //MySQL数据库管理用户密码

3、使用mybatis-plus进行增删改查的操作


1) 创建mapper


public interface DataMapper extends BaseMapper<DataBean> {


}

扫描mapper的注解 在主程序入口类中添加


@MapperScan("com.duing.mapper")

创建service及其实现类


注意泛型是要处理的实体类


public interface DataService extends IService<DataBean> {


}

// 泛型 分别是mapper 以及 实体类



@Service

public class DataServiceImpl extends ServiceImpl<DataMapper,DataBean>

       implements DataService {

     

}

4)改造实体类databean


此时要满足,存在无参构造器以及可被序列化 同时指定具体映射的表名 通过@TableName


@Data @AllArgsConstructor

@NoArgsConstructor

@TableName("illness")

public class DataBean implements Serializable {


   private String area;

   private int nowConfirm;

   private int confirm;

   private int heal;

   private int dead;

}

4、初始化数据存储的逻辑


@PostConstruct 修饰的方法,在服务器加载Servlet时运行,而且只执行一次


改造逻辑:首先将DataHandler声明为组件 @Component


   @Autowired

   private DataService dataService;

 

   @PostConstruct

   public void saveData() {

       try {

           List<DataBean> dataBeans = getData();

           // 先将数据清空  然后存储数据

           dataService.remove(null);

           dataService.saveBatch(dataBeans);


       } catch (Exception e) {

           e.printStackTrace();

       }


   }

@Scheduled


使用前需要在主程序入口类上打开开关


@EnableScheduling

在方法上使用注解的参数


1) @Scheduled(fixedRate = 10000) 指定频率的执行任务 从方法执行开始就计时 假设方法执行5s 那么第一次执行开始过了10s后,开始第二次执行


2) @Scheduled(fixedDelay = 10000) 指定间隔的执行任务 从方法执行完成开始计时 假设方法执行5s 那么第一次执行完成过了10s后,开始第二次执行


3) cron表达式 —— 计划执行的表达式 把六个位置用空格分隔,指代不同单位的时间,执行的规律 秒、分钟、小时、日期、月份、星期、(年,可选)


   // 配置定时执行的注解  支持cron表达式  

   // 每分钟执行一次  更改可参考cron表达式生成网站

   @Scheduled(cron = "0 0/1 * * * ?")

   public void updateData() {

       System.out.println("更新数据");

       saveData();

   }

Part 5


【展示数据Echarts】


是由百度前端技术部开发,基于js的数据可视化图表库。


https://echarts.apache.org/examples/zh/index.html#chart-type-line


image.png


分析图形展示的数据来源,然后请求数据后转化成我们需要的格式,传递给页面,通过Echarts渲染出来。


(一)折线图


image.png


1)分析的请求地址


https://view.inews.qq.com/g2/getOnsInfo?name=disease_other


可以获得json格式的数据,数据的key是chinaDayList


image.png


2)模拟请求


HttpClient使用,应用最广泛的处理http请求的工具。


<dependency>

   <groupId>org.apache.httpcomponents</groupId>

   <artifactId>httpclient</artifactId>

   <version>4.5.12</version>

</dependency>

public static String doGet(String urlStr) {


       // 提供了 闭合的httpclient对象

       CloseableHttpClient httpClient = null;

       // 也提供了  闭合的响应对象

       CloseableHttpResponse response = null;


       String result = null;


       try {

           // 使用默认创建方式

           httpClient = HttpClients.createDefault();

           // 创建一个get请求  传入url

           HttpGet httpGet = new HttpGet(urlStr);

           // 设置请求头的方式

           httpGet.addHeader("Accept", "application/json");


           // 设置请求参数  连接时间、数据读取时间(socketTimeOut)等  单位是ms

           //   ConnectionRequestTimeout  指从共享连接池中取出连接的超时时间

           RequestConfig requestConfig = RequestConfig.custom()

                   .setConnectTimeout(35000)

                   .setConnectionRequestTimeout(35000)

                   .setSocketTimeout(60000)

                   .build();


           // 设置配置参数

           httpGet.setConfig(requestConfig);

           // 执行请求

           response = httpClient.execute(httpGet);

           // 从返回对象中获取返回数据

           HttpEntity entity = response.getEntity();


           result = EntityUtils.toString(entity);


       }catch (Exception e){

           e.printStackTrace();

       }


       return result;

   }

解析出数据


public class GraphHandler {


   public static String urlStr = "https://view.inews.qq.com/g2/getOnsInfo?name=disease_other";


   public static List<GraphBean> getGraphData() {

       List<GraphBean> result = new ArrayList<>();


       String str = HttpClientUtil.doGet(urlStr);


       Gson gson = new Gson();

       Map map = gson.fromJson(str, Map.class);


       String subStr = (String) map.get("data");

       Map subMap = gson.fromJson(subStr, Map.class);


       ArrayList list = (ArrayList) subMap.get("chinaDayList");


       for (int i = 0; i < list.size(); i++) {

           Map tmp = (Map)list.get(i);


           String date = (String)tmp.get("date");

           double nowConfirm = (Double)tmp.get("nowConfirm");

           GraphBean graphBean = new GraphBean(date,(int)nowConfirm);

           result.add(graphBean);

       }


       return result;

   }


}

数据结构


@Data

@AllArgsConstructor

public class GraphBean {


   private String date;

   private int nowConfirm;

}

3)返回给页面渲染


   @GetMapping("/graph")

   public String graph(Model model) {

       List<GraphBean> list = GraphHandler.getGraphData();

       //  进一步改造数据格式

       //  因为前端需要的数据是  x轴所有数据的数组和y轴所有数据的数组


       ArrayList<String> dateList = new ArrayList<>();

       ArrayList<Integer> nowConfirmList = new ArrayList<>();


       for (int i = 0; i < list.size(); i++) {

           GraphBean graphBean = list.get(i);

           dateList.add(graphBean.getDate());

           nowConfirmList.add(graphBean.getNowConfirm());

       }


       model.addAttribute("dateList", new Gson().toJson(dateList));

       model.addAttribute("nowConfirmList", new Gson().toJson(nowConfirmList));

       return "graph";

   }

<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

   <meta charset="UTF-8">

   <title>Title</title>

   <script type="text/javascript" src="echarts/echarts.min.js"></script>

</head>

<body>



<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->

<div id="main" style="width: 600px;height:400px;"></div>


<!--在js中接收服务端返回数据-->

<script th:inline="javascript">

   // 基于准备好的dom,初始化echarts实例

   var myChart = echarts.init(document.getElementById('main'));


   var dateStr = [[${dateList}]];

   var nowConfirmStr = [[${nowConfirmList}]];


   // 指定图表的配置项和数据

   var option = {

       title: {  // 标题组件

           text: '全国现有确诊趋势'

       },

       tooltip: {  // 提示框组件

           trigger: 'axis'

       },

       legend: {  // 曲线含义说明

           data: ['现有确诊']

       },

       xAxis: {

           // 转化为json对象

           data: JSON.parse(dateStr)

       },

       yAxis: {

           type: 'value'

       },

       series: [{

           name: '现有确诊',

           data: JSON.parse(nowConfirmStr),

           type: 'line'

       }]

   };


   // 使用刚指定的配置项和数据显示图表。

   myChart.setOption(option);

</script>


</body>

</html>

Echars教程地址:[教程地址](https://echarts.apache.org/zh/tutorial.html#5 分钟上手 ECharts)


准备dom -> 通过js渲染数据 -> 使用[[${ sth }]] 接收服务端数据

-> 使用JSON.parse()解析json字符串 -> 获得渲染结果


Part 6


(二)折线图2


image.png


相关逻辑在 GraphAddBean对应的代码中


处理数据 -> 转化格式 -> 返回数据给echarts渲染


GraphHandler DataController *.html


1)GraphHandler


public static List<GraphAddBean> getGraphAddData(String str) {


       List<GraphAddBean> result = new ArrayList<>();


       Gson gson = new Gson();

       Map map = gson.fromJson(str, Map.class);


       String subStr = (String) map.get("data");

       Map subMap = gson.fromJson(subStr, Map.class);


       ArrayList list = (ArrayList) subMap.get("chinaDayAddList");


       for (int i = 0; i < list.size(); i++) {

           Map tmp = (Map) list.get(i);

           String date = (String) tmp.get("date");

           double addConfirm = (Double) tmp.get("confirm");

           double addSuspect = (Double) tmp.get("suspect");


           GraphAddBean graphAddBean = new GraphAddBean(date,

                   (int) addConfirm, (int) addSuspect);

           result.add(graphAddBean);

       }


       return result;

   }

2)DataController


@GetMapping("/graphAdd")

   public String graphAdd(Model model) {

       List<GraphAddBean> list = GraphHandler.getGraphAddData();


       ArrayList<String> dateList = new ArrayList<>();

       ArrayList<Integer> addConfirmList = new ArrayList<>();

       ArrayList<Integer> addSuspectList = new ArrayList<>();


       for (int i = 0; i < list.size(); i++) {

           GraphAddBean graphAddBean = list.get(i);

           dateList.add(graphAddBean.getDate());

           addConfirmList.add(graphAddBean.getAddConfirm());

           addSuspectList.add(graphAddBean.getAddSuspect());

       }


       model.addAttribute("dateList", new Gson().toJson(dateList));

       model.addAttribute("addConfirmList", new Gson().toJson(addConfirmList));

       model.addAttribute("addSuspectList", new Gson().toJson(addSuspectList));

       return "graphAdd";

   }

3)HTML


增加折线时,主要在legend和series中增加对应元素


<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

   <meta charset="UTF-8">

   <title>Title</title>

   <script type="text/javascript" src="echarts/echarts.min.js"></script>

</head>

<body>



<!-- 为 ECharts 准备一个具备大小(宽高)的 DOM -->

<div id="main" style="width: 600px;height:400px;"></div>


<!--在js中接收服务端返回数据-->

<script th:inline="javascript">

   // 基于准备好的dom,初始化echarts实例

   var myChart = echarts.init(document.getElementById('main'));


   var dateStr = [[${dateList}]];

   var addConfirmStr = [[${addConfirmList}]];

   var addSuspectStr = [[${addSuspectList}]];


   // 指定图表的配置项和数据

   var option = {

       title: {  // 标题组件

           text: '全国疫情新增趋势'

       },

       tooltip: {  // 提示框组件

           trigger: 'axis'

       },

       legend: {  // 曲线含义说明

           data: ['新增确诊', '新增疑似']

       },

       xAxis: {

           // 转化为json对象

           data: JSON.parse(dateStr)

       },

       yAxis: {

           type: 'value'

       },

       series: [{

           name: '新增确诊',

           data: JSON.parse(addConfirmStr),

           type: 'line'

       }, {

           name: '新增疑似',

           data: JSON.parse(addSuspectStr),

           type: 'line'

       }]

   };


   // 使用刚指定的配置项和数据显示图表。

   myChart.setOption(option);

</script>


</body>

</html>

(三)柱状图


image.png


先分析数据的来源 -> 经过对数据的处理和计算 -> 发送给前端组件进行渲染


对应在GraphColumnarBean相关的逻辑中


特别之处在于 拿到数据之后需要排序


@Data

@AllArgsConstructor

public class GraphColumnarBean implements Comparable<GraphColumnarBean> {


   private String area;

   private int fromAbroad;


   @Override

   public int compareTo(GraphColumnarBean o) {

       return o.getFromAbroad() - this.getFromAbroad();

   }

}

排序之后将前十的数据返回


   @GetMapping("/graphColumnar")

   public String graphColumnar(Model model) {

       List<GraphColumnarBean> list = GraphHandler.getGraphColumnarData();

       Collections.sort(list);


       ArrayList<String> nameList = new ArrayList<>();

       ArrayList<Integer> fromAbroadList = new ArrayList<>();


       for (int i = 0; i < 10; i++) {

           GraphColumnarBean bean = list.get(i);

           nameList.add(bean.getArea());

           fromAbroadList.add(bean.getFromAbroad());

       }


       model.addAttribute("nameList", new Gson().toJson(nameList));

       model.addAttribute("fromAbroadList", new Gson().toJson(fromAbroadList));

       return "graphColumnar";

   }

柱状图的数据示例


// 指定图表的配置项和数据

   var option = {

       title: {  // 标题组件

           text: '境外输入省市TOP10'

       },

       tooltip: {  // 提示框组件

           trigger: 'axis'

       },

       xAxis: {

           // 转化为json对象

           data: JSON.parse(nameStr)

       },

       yAxis: {

           type: 'value'

       },

       series: [

           {

               name: '境外输入',

               type: 'bar',

               barWidth: '60%',

               data: JSON.parse(fromAbroadStr)

           }

       ]

   };

(四)饼状图


image.png


对应在GraphPieBean相关的逻辑中


graphPie.html


   // 指定图表的配置项和数据

   var option = {

       title: {  // 标题组件

           text: '全国现有确诊构成'

       },

       tooltip: {  // 提示框组件

           trigger: 'axis'

       },

       series: [

           {

               type: 'pie',

               radius: '55%',

               center: ['50%', '60%'],

               data: JSON.parse(str)

           }

       ]

   };

Part 7


(五) 中国地图


image.png


引入新的js 【china.js】 数据来源已存储到表格中


map.html


<!DOCTYPE html>

<html lang="en" xmlns:th="http://www.thymeleaf.org">

<head>

   <meta charset="UTF-8">

   <title>Title</title>


   <script type="text/javascript" src="echarts/echarts.min.js"></script>

   <script type="text/javascript" src="echarts/china.js"></script>

</head>

<body>



<div id="main" style="width: 1000px;height:700px;"></div>

<script th:inline="javascript">

   var dataStr = [[${mapData}]];


   option = {

       title: {

           text: '疫情地图',

           subtext: '仅供参考',

           x: 'center'

       },

       tooltip: {

           trigger: 'item'

       },


       series: [

           {

               name: '现存确诊',

               type: 'map',

               mapType: 'china',

               roam: false,

               label: {

                   normal: {

                       // formatter: '{b}',

                       position: 'center',

                       show: true,

                       textStyle: {

                           color: 'rgba(0,0,0,0.4)'

                       }

                   },

                   emphasis: {

                       show: true

                   }

               },

               data: JSON.parse(dataStr)

           }

       ]

   };

   var chart = echarts.init(document.getElementById("main"))

   chart.setOption(option)


</script>


</body>

</html>

【国际化】


是对thymeleaf中消息表达式的一种应用, #{} , 提供的是对配置文件中信息的读取。


(一) 使用浏览器识别语种


1) 在resources目录下,创建mg文件夹,再继续创建 *.properties文件。


设置其中的key和value (注意:此时的编码格式需要在idea的设置中确认)


list.title = 疫情最新动态

list.h2 = 国内疫情情况如下

list.table.name1 = 地区

list.table.name2 = 现有确诊

list.table.name3 = 累计确诊

list.table.name4 = 治愈

list.table.name5 = 死亡

创建其他语种对应的配置文件,如 *_en_US.properties 和 *_zh_CN.properties


3)在html中更改对key值的引用方式,使用消息表达式


4)让spring找到国际化文件对应的位置,在application.properties中


spring.messages.basename = mg.list

验证方式 通过更改浏览器中 【设置】 - 【高级】 - 【语言】 - 【找到英语(美国)】,可以通过置顶,切换中英文显示。


本质原因是,因为请求的请求头中,会设置不同的Accept-Language的值。


(二)自定义切换语种


使用spring提供的国际化使用类 LocaleResolver


1) 页面中增加按钮


   <label>

       <a class="btn btn-sm" th:href="@{/(lan='zh_CN')}">中文</a>

       <a class="btn btn-sm" th:href="@{/(lan='en_US')}">英文</a>

   </label>

自定义LocaleResolver类的实现


public class MyLocaleResolver implements LocaleResolver {


   @Override

   public Locale resolveLocale(HttpServletRequest httpServletRequest) {

       String lan = httpServletRequest.getParameter("lan");

       Locale locale = Locale.getDefault();

       if (!StringUtils.isEmpty(lan)) {

           String[] split = lan.split("_");

           locale = new Locale(split[0], split[1]);

       }

       return locale;

   }


   @Override

   public void setLocale(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Locale locale) {


   }

}

2)注入spring


@Configuration

public class MyConfig {


   @Bean

   public LocaleResolver localeResolver() {

       return new MyLocaleResolver();

   }

}

验证 此时切换按钮时,可以看到不同语种的显示image.png


image.png

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
18天前
|
Java 容器
如何在SpringBoot项目中使用过滤器和拦截器
过滤器和拦截器是日常开发中常用技术,用于对特定请求进行增强处理,如插入自定义代码以实现特定功能。过滤器在请求到达 `servlet` 前执行,而拦截器在请求到达 `servlet` 后执行。`SpringBoot` 中的拦截器依赖于 `SpringBoot` 容器,过滤器则由 `servlet` 提供。通过实现 `Filter` 接口并重写 `doFilter()` 方法可实现过滤器;通过实现 `HandlerInterceptor` 接口并重写相应方法可实现拦截器。两者的主要区别在于执行时机的不同,需根据具体场景选择使用。
如何在SpringBoot项目中使用过滤器和拦截器
|
12天前
|
Java 关系型数据库 MySQL
创建一个SpringBoot项目,实现简单的CRUD功能和分页查询
【9月更文挑战第6天】该内容介绍如何使用 Spring Boot 实现具备 CRUD 功能及分页查询的项目。首先通过 Spring Initializr 创建项目并选择所需依赖;其次配置数据库连接,并创建实体类与数据访问层;接着构建服务层处理业务逻辑;最后创建控制器处理 HTTP 请求。分页查询可通过添加 URL 参数实现。
|
6天前
|
设计模式 Java 关系型数据库
【Java笔记+踩坑汇总】Java基础+JavaWeb+SSM+SpringBoot+SpringCloud+瑞吉外卖/谷粒商城/学成在线+设计模式+面试题汇总+性能调优/架构设计+源码解析
本文是“Java学习路线”专栏的导航文章,目标是为Java初学者和初中高级工程师提供一套完整的Java学习路线。
|
21天前
|
XML 前端开发 Java
还不会SpringBoot项目模块分层?来这手把手教你
本文详细介绍了如何为SpringBoot项目创建模块并进行合理的分层设计。通过逐步演示,从创建项目到构建各功能模块,再到具体代码实现,手把手教你实现整洁的代码分层。主要内容包括:创建依赖层、主启动层、模块层及其子模块(如共通层、控制器层、数据持久层等),并通过实例演示了从前端请求到后台服务调用的实际流程。适合SpringBoot初学者及有一定经验但需优化项目结构的开发者参考。
63 2
还不会SpringBoot项目模块分层?来这手把手教你
|
21天前
|
小程序 前端开发 Java
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
JavaDog Chat v1.0.0 是一款基于 SpringBoot、MybatisPlus 和 uniapp 的简易聊天软件,兼容 H5、小程序和 APP,提供丰富的注释和简洁代码,适合初学者。主要功能包括登录注册、消息发送、好友管理及群组交流。
45 0
SpringBoot+uniapp+uview打造H5+小程序+APP入门学习的聊天小项目
|
1天前
|
机器学习/深度学习 数据采集 JavaScript
ADR智能监测系统源码,系统采用Java开发,基于SpringBoot框架,前端使用Vue,可自动预警药品不良反应
ADR药品不良反应监测系统是一款智能化工具,用于监测和分析药品不良反应。该系统通过收集和分析病历、处方及实验室数据,快速识别潜在不良反应,提升用药安全性。系统采用Java开发,基于SpringBoot框架,前端使用Vue,具备数据采集、清洗、分析等功能模块,并能生成监测报告辅助医务人员决策。通过集成多种数据源并运用机器学习算法,系统可自动预警药品不良反应,有效减少药害事故,保障公众健康。
ADR智能监测系统源码,系统采用Java开发,基于SpringBoot框架,前端使用Vue,可自动预警药品不良反应
|
2天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的音乐推荐管理系统
基于Java+Springboot+Vue开发的音乐推荐管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的音乐推荐管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
35 8
基于Java+Springboot+Vue开发的音乐推荐管理系统
|
2天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的母婴商城管理系统
基于Java+Springboot+Vue开发的母婴商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的网上母婴商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
20 7
基于Java+Springboot+Vue开发的母婴商城管理系统
|
3天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的在线摄影预约管理系统
基于Java+Springboot+Vue开发的在线摄影预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的在线摄影管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
18 8
基于Java+Springboot+Vue开发的在线摄影预约管理系统
|
3天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的农产品商城管理系统
基于Java+Springboot+Vue开发的农产品商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。 通过学习基于Java的农产品商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 5
基于Java+Springboot+Vue开发的农产品商城管理系统