# experiment3
**Repository Path**: Graycat-wj/experiment3
## Basic Information
- **Project Name**: experiment3
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 0
- **Created**: 2020-05-10
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 实验三 全球新型冠状病毒实时数据统计应用程序的设计与实现
#### 课程名称:企业级开发框架专题 学期:2020春季
|
实验名称 | 全球新型冠状病毒实时数据统计应用程序的设计与实现 | 实验序号 | 三 |
|
姓 名 | 林伟佳 | 学 号 | 201741404125 | 班 级 | 17软工1班 |
|
实验地点 | 网上 | 实验日期 | 2020/05/10 | 指导老师 | 黎志雄 |
|
教师评语 | | 实验成绩 | 评阅教师 |
| 百分制 | |
|
同组同学 | 无 |
#### 一、 实验目的
1、 掌握使用Spring框架自带的RestTemplate工具类爬取网络数据;
2、 掌握使用Spring框架自带的计划任务功能;
3、 掌握使用Apache Commons CSV组件解释CSV文件;
4、 掌握Java 8的Stream API处理集合类型数据;
5、 了解使用模板引擎或前端框架展示数据。
#### 二、 实验环境
1、 JDK 1.8或更高版本
2、 Maven 3.6+
3、 IntelliJ IDEA
4、 commons-csv 1.8+
#### 三、 实验任务
1、 通过IntelliJ IDEA的Spring Initializr向导创建Spring Boot项目。
2、 添加功能模块:spring MVC、lombok、commons-csv、thymeleaf等。
```
org.springframework.boot
spring-boot-starter-web
org.awaitility
awaitility
3.1.2
test
org.springframework.boot
spring-boot-starter-thymeleaf
org.apache.commons
commons-csv
1.8
org.projectlombok
lombok
true
```
3、 爬取全球冠状病毒实时统计数据。
由约翰·霍普金斯大学系统科学与工程中心(JHU CSSE)运营的2020年新型冠状病毒可视化仪表板的数据仓库,从该仓库中爬取全球新型冠状病毒最新的统计数据。
[Github仓库地址](https://github.com/CSSEGISandData/COVID-19)
该仓库会把全球新型冠状病毒最新的统计数据汇总到一个csv文件上
由于国内网络访问限制的原因,我们不能正常访问Github。老师已经克隆整个仓库,并上传到Gitee,方便大家进行实验。
[克隆的Gitee仓库地址](https://gitee.com/dgut-sai/COVID-19)
[克隆的Gitee仓库的csv文件地址](https://gitee.com/dgut-sai/COVID-19/blob/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv)
4、 使用Spring框架自带的RestTemplate工具类爬取数据。
先用脚本test.http测试下数据能否爬取
```
GET https://gitee.com/dgut-sai/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv
```
测试后发现不能直接GET爬取,

分析之后需要在请求头部加上`User-Agent: Mozilla/5.0`
之后创建爬取csv文件的代码:
```
public Resource fetchVirusDate( String url ){
RequestEntity requestEntity = RequestEntity
.get(URI.create(url))
.headers(httpHeaders -> httpHeaders.add("User-Agent","Mozilla/5.0"))
.build();
ResponseEntity exchange = new RestTemplate().exchange(requestEntity,Resource.class);
Resource body = exchange.getBody();
return body;
}
```
5、 分析csv文件的数据结构,定义model类。
```
public class VirusDate {
private String province; //省份或州
private String country; //国家
private double longitude; //经度
private double latitude; //纬度
private int latestTotal; //确诊总人数
private int raise; //新增人数
}
```
6、 使用Apache Commons CSV组件解释CSV文件。
查看[CSV的官方文档](https://commons.apache.org/proper/commons-csv/user-guide.html)可以知道,
record.get("Province/State") 可以获取记录某个字段名的值;
record.get(record.size() - 1) 可以获取记录最后一个字段的值;
record.get(index) 可以获取记录某个下标字段的值
所以我们通过解析csv文件可以把数据转换到List中,
```
public void changeIntoList( Resource body ) throws IOException {
if ( body!=null ) {
final Reader reader = new InputStreamReader(body.getInputStream());
final CSVParser pasre = new CSVParser(reader, CSVFormat.EXCEL.withHeader());
for ( CSVRecord record : pasre) {
confirmedList.add(VirusDate.builder()
.province(record.get(0))
.country(record.get(1))
.longitude(Double.parseDouble(record.get(2)))
.latitude(Double.parseDouble(record.get(3)))
.latestTotal(Integer.parseInt(record.get(record.size()-1)))
.raise( (Integer.parseInt(record.get(record.size()-1))) - (Integer.parseInt(record.get(record.size()-2))))
.build());
}
reader.close();
}
}
```
7、 使用Spring框架自带的计划任务功能定时更新统计数据。
要实现计划任务,首先通过在配置类上添加 @EnableScheduling 注解来开启对计划任务的支持,然后在要执行计划任务的方法上注解 @Scheduled,声明这是一个计划任务。
```
@Scheduled(cron = "${lwj.Schedules.updateVirusDateCron}")
public void scheduledGetDate() throws IOException {
changeIntoList(fetchVirusDate(DATA_URL));
}
```
其中 @Scheduled 注解中有以下几个参数:
1. cron:cron表示式,指定任务在特定时间执行;
2. fixedDelay:表示上一次任务执行完成后多久再次执行,参数类型这long,单位ms;
3. fixedDelayString:与fixedDelay含义一样,只是参数类型变为String;
4. fixedRate:表示按一定的频率执行任务,参数类型为long,单位ms;
5. fixedRateString: 与fixedRate的含义一样,只是将参数类型变为String;
6. initialDelay:表示延迟多久后再第一次執行任務,参数类型为long,單位ms;
7. initialDelayString:与initialDelay的含义一样,只是参数类型变为String;
8. zone:时区,默认为当前时区,一般不需要设置。
另外,可以在cron参数中使用${...}占位符,读取属性文件中的自定义属性配置cron参数
在属性文件中自定义属性配置cron表达式,如下图所示:

当cron="-"时,表示关闭计划任务。
8、 要确保应用程序启动时,获取一次统计数据。
通过实现InitializingBean接口确保启动应用程序时,获取一次统计数据。
```
/**
* @Auther: Graycat
* @Date: 2020/5/8 16:24
* Create by lwj.
*/
@Component
public class Initialzation implements InitializingBean {
@Autowired
GetDate getDate;
@Override
public void afterPropertiesSet() throws Exception {
getDate.getVirusDate();
// System.out.println("项目启动时初始化数据");
}
}
```
9、 单元测试。
编写一个单元测试测试是否正确把爬取的数据转换到list中。
```
@SpringBootTest
class Shiyan3ApplicationTests {
@Autowired
GetDate getDate;
@Test
void testDate() throws IOException {
//测试项目启动时是否正确把数据写进list中。
getDate.getVirusDate();
List list = getDate.confirmedList;
for (VirusDate item:list){
System.out.println(item.getCountry());
}
}
}
```
10、 定义Cotroller控制器。
```
/**
* @Auther: Graycat
* @Date: 2020/5/8 12:47
* Create by lwj.
*/
@Controller
public class MyController {
@RequestMapping("/getIndex")
public String index( HttpServletRequest request ){
request.getSession().setAttribute("virusList",GetDate.confirmedList);
return "index.html";
}
@RequestMapping("/search")
public String searchByCountry( String searchInput, HttpServletRequest request ){
List searchList = new ArrayList();
for ( VirusDate item : GetDate.confirmedList ){
if( item.getCountry().equals(searchInput) ){
searchList.add(item);
}
}
request.getSession().setAttribute("searchList",searchList);
return "searchResult.html";
}
}
```
11、 定义前端数据展示页面。

搜索功能:

#### 四、 实验要求
1、 实验项目push到码云的公开仓库,并把仓库网址登记在在线文档;
2、 从码云仓库下载项目的ZIP文件,并交由班长汇总;
3、 撰写实验报告,完成各个实验任务。各实验任务中的附图,是老师的演示代码,同学们应该模仿演示代码改为自己的代码。实验报告中必须完整描述各实验任务实现过程并附截图。
4、 网络空间安全学院实验报告模板(2019试行)
5、 实验三项目仓库登记表
6、 严禁抄袭。如果不想项目仓库给别人看到,可以设置为私有仓库,并把老师的码云账号(dgsai@vip.qq.com)加入到仓库开发者以便老师检查。