基于springboot+redis+国际化+定时任务的疫情项目已上线
Posted 步尔斯特
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于springboot+redis+国际化+定时任务的疫情项目已上线相关的知识,希望对你有一定的参考价值。
这是我自己做的一套疫情实时数据项目,有地图、折线图、表格
该项目涵盖了大部分springboot项目实际开发所必需的技术
目前已经上线,🔍公号【步尔斯特】获取源码,可直接拿走学习或复用,不谢。
文章目录
一、效果图
二、技术栈
- 基础框架(springboot + mybatis + mybatis-plus)
- 缓存数据(redis)
- 国际化(一键切换不同语种)
- 定时任务(定时更新数据)
- 爬虫
- 加密
- 感知数据变更,进行通知推送
- 日志监控
- 数据计算和二次存储(为图表服务 - 比如趋势图)
- 数据展示和渲染 Thymeleaf Echarts
- 模拟http请求
三、项目背景
模拟疫情数据展示网站,做出一个完整的数据采集、数据存储、数据计算、数据展示的疫情数据系统。
四、搜索引擎原理
链接人和内容
网页爬取 -》 网页去重 -》 网页分析 -》 内容保存(倒排索引)
关键字查询 -》 关键字分析 -》 去匹配内容 -》 筛选出比如100条数据 -》 数据排序 (可口可乐的秘方)
分类:
通用型爬虫 和 垂直型爬虫
疫情数据系统:
数据采集 -》 数据存储 -》 数据计算 -》 数据展示
五、数据分析
5.1 分析数据源
确认能够通过代码 获取到数据 (定位到具体的http请求)
5.2 获取疫情数据
-
国内各省份表格数据-对应请求
-
对应的数据格式:json
-
国外表格数据-对应请求
-
国内趋势数据
六、数据处理
6.1 初识json
json = javascript object notation (js对象表示法)
独立于语言,具有自我描述性
Gson -> From Google
new Gson().toJson(Object obj) 将对象转化为json字符串
new Gson().fromJson(String jsonStr, T.class) 将json字符串转化为对象
6.2 数据展示
controller - service - handler
数据加载到model中 返回给html渲染
@Controller
public class DataController
@Autowired
private DataService dataService;
@GetMapping("/")
public String list(Model model)
List<DataBean> beanList = dataService.list();
model.addAttribute("beanList", beanList);
return "list";
public interface DataService
List<DataBean> list();
@Service
public class DataServiceImpl implements DataService
@Override
public List<DataBean> list()
return MyDataHandler.getData();
<!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="bean:$beanList">
<td th:text="$bean.area">name</td>
<td th:text="$bean.nowConfirm">nowConfirm</td>
<td th:text="$bean.confirm">confirm</td>
<td th:text="$bean.heal">heal</td>
<td th:text="$bean.dead">dead</td>
</tr>
</tbody>
</table>
</body>
</html>
七、网络请求
HTTP
- “应用层协议”
- 了解HTTP不同版本的演进
- 了解GET和POST请求的区别
// 需要的参数url
// 创建一个远程的连接对象 设置方法类型 GET
// 设置相关参数 发送请求
// 通过io接收数据后返回
public static String doGet(String urlStr)
HttpURLConnection conn = null;
InputStream is = null;
BufferedReader br = null;
StringBuilder result = new StringBuilder();
try
// 创建远程url连接对象
URL url = new URL(urlStr);
// 打开一个连接
conn = (HttpURLConnection) url.openConnection();
// 设置为GET请求
conn.setRequestMethod("GET");
// 设置重要的参数 连接超时时间 和 读取超时时间
// 超时时间 更多被距离影响 读取时间 更多被数据量影响
conn.setConnectTimeout(15000);
conn.setReadTimeout(60000);
// header参数设置 可以不设置
conn.setRequestProperty("Accept", "application/json");
// 发送请求
conn.connect();
// 状态码 200 302 404 500 ?
// 如果比较时 可能出现空指针 把确定的值放在前面 可以避免
if (200 == conn.getResponseCode())
is = conn.getInputStream();
br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
String line;
while ((line = br.readLine()) != null)
result.append(line);
else
System.out.println("error responseCode :"
+ conn.getResponseCode());
catch (Exception e)
e.printStackTrace();
finally
try
if (br != null)
br.close();
if (is != null)
is.close();
catch (Exception e)
e.printStackTrace();
conn.disconnect();
return result.toString();
八、数据存储
8.1 Mybatis整合
SSM的整合 -> 入门课的整合 -> mybatis-plus的整合
明确数据结构 -> 创建mapper文件夹 -> 调用getData方法 将数据据存储到数据库中 -> 查询时从数据库中读取
a) 引入依赖
<!-- mybatis整合
mybatis-spring-boot-starter
mybatis-plus -boot-starter
mysql驱动-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
b) 配置数据库连接参数
spring.datasource.url=jdbc:mysql://localhost:3306/illness?characterEncoding=utf8
spring.datasource.username=root
spring.datasource.password=123456
c) 创建数据库
CREATE DATABASE /*!32312 IF NOT EXISTS*/`illness` /*!40100 DEFAULT CHARACTER SET utf8 */;
USE `illness`;
/*Table structure for table `epidemic` */
DROP TABLE IF EXISTS `epidemic`;
CREATE TABLE `epidemic` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`area` varchar(100) DEFAULT NULL,
`confirm` int(11) DEFAULT NULL,
`now_confirm` int(11) DEFAULT NULL,
`dead` int(11) DEFAULT NULL,
`heal` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=308 DEFAULT CHARSET=utf8;
d) 编写类及文件夹
将实体类对应到数据库的表中 属性和字段也需对应
需注意 属性的命名为驼峰命名法
如 nowConfirm 字段的命名是下划线分隔 如 now_confirm
可以使用@TableName和@TableField等注解指定对应关系
@Data
@NoArgsConstructor
@AllArgsConstructor
@TableName("epidemic")
public class DataBean implements Serializable
// Alt + Insert 调用 安装插件
private static final long serialVersionUID
= 4938260405189292371L;
// Alt + 7 查看类的方法
// 地区 累计确诊人数 现有确诊人数 死亡人数 治愈人数
private long id;
private String area;
// @TableField("all_confirm")
// 如果属性名和表中字段名 不一致 可以通过 TableField注解指定
private int confirm;
private int nowConfirm;
private int dead;
private int heal;
在主程序类上 增加@MapperScan注解 指定mapper类所在文件夹
在此文件夹下 创建mapper类 实战中 如表名叫user mapper会命名为UserMapper
@SpringBootApplication
@MapperScan("com.duing.mapper")
public class DataHandlerApplication
public static void main(String[] args)
SpringApplication.run(DataHandlerApplication.class, args);
public interface DataMapper extends BaseMapper<DataBean>
创建service接口及其实现类
整合mybatis-plus,用其提供的IService父接口 和 ServiceImpl实现父类
public interface DataService extends IService<DataBean>
@Service
public class DataServiceImpl
extends ServiceImpl<DataMapper,DataBean>
implements DataService
在controller中调用mybatis-plus实现的CRUD方法
@Controller
public class DataController
@Autowired
private DataService dataService;
@GetMapping("/")
public String list(Model model)
List<DataBean> beanList = dataService.list();
model.addAttribute("beanList", beanList);
return "list";
8.2 数据初始化及定时更新
在数据查询前,先将数据存储到数据库中,我们称之为数据初始化
可以在项目启动时,先采集一次数据存储到数据库中,然后再进行定期更新
而项目启动时执行且只执行一次的逻辑,可以使用注解 @PostConstruct
// 先将DataHandler托管到spring容器中 使用@Component
// 以便于获取到 dataService对象
@Component
public class DataHandler
@Autowired
private DataService dataService;
// 数据初始化
// 在服务器加载Servlet时运行 且 只运行一次
@PostConstruct
public void saveData()
List<DataBean> dataBeans = getData();
// mybatis-plus提供了可用的方法
// 删除全部数据 批量新增数据
dataService.remove(null);
dataService.saveBatch(dataBeans);
...
定时更新其实也是定时任务
可以通过注解@Scheduled + cron表达式来实现
Scheduled 英文原意是调度的意思 意思是我们将某段逻辑 按照指定的时间间隔 进行调度 即为定时处理
使用方式如下:
首先在入口类上 打开定时任务开关 使用注解 @EnableScheduling
@SpringBootApplication
@MapperScan("com.duing.mapper")
@EnableScheduling
public class DataHandlerApplication
public static void main(String[] args)
SpringApplication.run(DataHandlerApplication.class, args);
然后在方法上 使用 @Scheduled 搭配cron表达式 决定方法多久执行一次
// 定时更新
@Scheduled(cron = "0 0 0/1 * * ? ")
public void updateData()
System.out.println("要更新数据啦");
System.out.println("当前时间:" + dateFormat.format(new Date()));
List<DataBean> dataBeans = getData();
dataService.remove(null);
dataService.saveBatch(dataBeans);
其中cron表达式,是由6个表达不同时间单位的字段拼接而成
可以通过在线cron表达式生成器来生成
cron表达式几乎可以满足所有定时执行的需求
可以生成各类需求对应的表达式熟悉一下
除此之外,@Scheduled还支持固定时间间隔的参数设置
分别为 fixedRate 和 fixedDelay
// 固定频率任务 以ms为单位 10000代表每10s执行一次
// 使用时要注意间隔时间 和 任务消耗时间的 大小关系
// 如设置间隔10s 而方法需执行20s 那么方法会等待上一次执行完成才会执行
// 唤起方法真正的时间间隔为20s
@Scheduled(fixedRate = 10000)
public void updateData1()
// 固定间隔任务 上一次执行结束后 再隔10s进行下一次执行
// 如设置间隔10s 而方法需执行20s 那么会从上一次执行完成后开始计算 10s后开始下一次执行
// 唤起方法真正的时间间隔为30s
@Scheduled(fixedDelay = 10000)
public void updateData2()
九、图形化数据处理
9.1 折线图
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="js/echarts.min.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 600px;height:400px;"></div>
<script th:inline="javascript">
var dateStr = [[$dateList]];
var confirmStr = [[$confirmList]];
var suspectStr = [[$suspectList]];
// 基于准备好的dom 初始化实例
var mychart = echarts.init(document.getElementById("main"));
var option =
// 标题
title:
text: '全国疫情新增趋势'
,
legend:
data:['新增确诊','新增疑似']
,
// x轴的数据
xAxis:
data: dateStr
,
// y轴的数据类型
yAxis:
type:'value'
,
series:[
name: '新增确诊',
type: 'line',
data: confirmStr
,
name: '新增疑似',
type: 'line',
data: suspectStr
]
;
// 将参数设置进去
mychart.setOption(option);
</script>
</body>
</html>
9.2 地图
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="js/echarts.min.js"></script>
<script type="text/javascript" src="js/china.js"></script>
</head>
<body>
<!-- 为ECharts准备一个具备大小(宽高)的Dom -->
<div id="main" style="width: 1000px;height:700px;"></div>
<script th:inline="javascript">
var dataStr1 = [[$mapData1]];
var dataStr2 = [[$mapData2]];
// 基于准备好的dom 初始化实例
var mychart = echarts.init(document.getElementById("main"));
var option =
title:
text: '疫情地图',
subtext: '仅供参考',
x: 'center'
,
tooltip:
trigger: 'item'
,
legend:
orient: 'vertical',
left: 'left',
data: ['现有确诊', '累计确诊']
,
visualMap:
type: 'piecewise',
pieces以上是关于基于springboot+redis+国际化+定时任务的疫情项目已上线的主要内容,如果未能解决你的问题,请参考以下文章
SpringBoot使用SchedulingConfigurer实现多个定时任务多机器部署问题
SpringBoot + Redis 实现点赞功能的缓存和定时持久化(附源码)
Redis实战(12)-基于Redis的Key失效和定时任务调度实现订单超时未支付自动失效(延时队列)