# 实验三 全球新型冠状病毒实时数据统计应用程序的设计与实现
**Repository Path**: y1ip/springboot-experiment-3
## Basic Information
- **Project Name**: 实验三 全球新型冠状病毒实时数据统计应用程序的设计与实现
- **Description**: No description available
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-11-22
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
##
**东莞理工学院网络空间安全学院**
##### **课程名称** :企业级开发框架专题 **学期:2020秋季**
`实验名称`:实验三 全球新型冠状病毒实时数据统计应用程序的设计与实现 `实验序号`:三
`姓名`:叶薰馥 `学号`:201841413237 `班级`:18网工2班
`实验地址`: `实验日期`:2020-11-09 `同组同学`:无
`指导老师`:黎志雄 `教师评语`: `实验成绩`:
# 实验三 全球新型冠状病毒实时数据统计应用程序的设计与实现
#### 一、实验目的
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等;
添加功能模块:spring MVC、lombok、commons-csv等
3、爬取全球冠状病毒实时统计数据;
克隆的Gitee仓库的csv文件地址:https://gitee.com/dgut-sai/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv
4、使用Spring框架自带的RestTemplate工具类爬取数据;
使用 RestTemplate 工具类时,可以按如下所示设置请求头部并请求数据
```
//爬取全球新型冠状病毒统计数据的csv文件
RequestEntity requestEntity = RequestEntity
.get(URI.create(CORONA_VIRUS_DATA_URL))
.headers(httpHeaders -> httpHeaders.add("User-Agent","Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.183 Safari/537.36"))
.build();
ResponseEntity exchange = new RestTemplate().exchange(requestEntity,Resource.class);
Resource body = exchange.getBody();
```
```
//通过Resource对象的getInputStream方法获取csv文件的输入流
InputStream inputStream = body.getInputStream();
//从字节流转换为字符流
InputStreamReader inputStreamReader= new InputStreamReader(inputStream);
Reader in = new BufferedReader(inputStreamReader);
```
先实例化一个RequestEntity对象,再通过RestTemplate的exchange方法获取csv文件,这个文件的数据会封装到一个Resource对象中,最后通过Resource对象的getInputStream方法获取csv文件的输入流。
5、分析csv文件的数据结构,定义model类;
```
/**
* 创建model类RegionStats,即区域内新冠疫情状态
*/
@Data
public class RegionStats {
/**
* state表示州,country表示国家,latestTotalCases表示最新确诊病例,
* diffFromPrevDay表示相较于前一天增加的确诊病例
*/
private String state;
private String country;
private int latestTotalCases;
private int diffFromPrevDay;
}
```
6、使用Apache Commons CSV组件解释CSV文件 ;
```
//处理csv文件中的数据
Iterable records = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(in);
for (CSVRecord record : records) {
RegionStats regionStats = new RegionStats();
regionStats.setState(record .get("Province/State"));
regionStats.setCountry(record .get("Country/Region"));
regionStats.setLatestTotalCases(Integer.parseInt(record.get(record.size()-1)));
regionStats.setDiffFromPrevDay(Integer.parseInt(record.get(record.size()-1))-Integer.parseInt(record.get(record.size()-2)));
allRegionStats.add(regionStats);
}
```
为了方便应用程序处理,通常会把csv文件的每条记录转换为一个modle类的对象,即上一步中我们定义的model类。把所有的model类的对象组织为一个集合,如:List 。最终,这个csv文件会转换为一个List对象。然后根据实际的业务逻辑,访问这个List即可。定义一个Service组件处理csv文件的转换逻辑,并把最终转换后的List对象赋值给这个Service组件的成员属性,以便应用程序访问这个List对象。
7、 使用Spring框架自带的计划任务功能定时更新统计数据;
在属性文件中自定义属性配置cron表达式
在cron参数中使用${...}占位符,读取属性文件中的自定义属性配置cron参数,配置了每天凌晨1点执行定时任务,更新统计数据
8、要确保应用程序启动时,获取一次统计数据;
Spring为bean提供了初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法。因此,在CoronaVirusDataService类继承InitializingBean接口,在应用程序启动时,通过在afterPropertiesSet方法中调用fetchCoronaVirusData方法,就可以保证获取一次统计数据。
9、单元测试;
```
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE,classes = {CoronaVirusDataService.class})
class Exp3ApplicationTests {
@Autowired
CoronaVirusDataService coronaVirusDataService;
@Test
void testCoronaVirusService() {
assertTrue(coronaVirusDataService.getAllRegionStats().size()>100);
}
}
```
指定coronaVirusDataService类进行测试,精简单元测试环境。由于csv文件中存在许许多多地区,因此设置一个当读取的地区大于100的断言,则可保证程序是无错误的。
10、 定义Cotroller控制器;
```
@Controller
@RequiredArgsConstructor
public class HomeController {
//使用构造器注入CoronaVirusDataService
private final CoronaVirusDataService coronaVirusDataService;
@GetMapping("/")
public String home(Model model, String country){
List allStats;
if(country == null)
allStats = coronaVirusDataService.getAllRegionStats();
else
allStats = Collections.unmodifiableList(coronaVirusDataService.getAllRegionStats()
.parallelStream()
.filter(locationStats -> locationStats.getCountry().equals(country))
.collect(Collectors.toList()));
//设置查询条件
model.addAttribute("country",country);
//使用parallelStream统计数据
int totalReportedCases=allStats.parallelStream().mapToInt(RegionStats::getLatestTotalCases).sum();
int totalNewCases=allStats.parallelStream().mapToInt(RegionStats::getDiffFromPrevDay).sum();
model.addAttribute("regionStats",allStats);
model.addAttribute("totalReportedCases",totalReportedCases);
model.addAttribute("totalNewCases",totalNewCases);
//获取当前日期
model.addAttribute("localDate", LocalDate.now());
return "index";
}
}
```
定义一个控制器,用于返回数据给前端展示,利用List可以做到很方便地访问集合类型对象,parallelStream支持并行流,在处理csv文件中如此多的地区时,可以大大提升性能,filter方法支持设置过滤条件,用于查询地区,再利用Collections.unmodifiableList()收集为不可变的List集合。
11、定义前端数据展示页面。
支持查询功能