# 实验三 全球新型冠状病毒实时数据统计应用程序的设计与实现 **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、定义前端数据展示页面。


支持查询功能