# 企业级开发课程-实验三 **Repository Path**: alizipeng/project03 ## Basic Information - **Project Name**: 企业级开发课程-实验三 - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2021-04-13 - **Last Updated**: 2021-05-23 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 实验三 全球新型冠状病毒实时数据统计应用程序的设计与实现 ## 1. 实验目的 1. 掌握使用Spring框架自带的RestTemplate工具类爬取网络数据; 2. 掌握使用Spring框架自带的计划任务功能; 3. 掌握使用Apache Commons CSV组件解释CSV文件; 4. 掌握Java 8的Stream API处理集合类型数据; 5. 了解使用模板引擎或前端框架展示数据。 ## 2. 实验环境 1. JDK 1.8或更高版本 2. Maven 3.6+ 3. IntelliJ IDEA 4. commons-csv 1.8+ ## 3.实验任务 ### 3.1 添加功能模块:spring MVC、lombok、commons-csv等。 ![1619484618251](resource/1619484618251.png) ### 3.2 爬取全球冠状病毒实时统计数据。 【创建实体类】 ```java package com.zipeng.entity; import lombok.Data; import lombok.ToString; /** * @author: zipeng Li * 2021/4/27 9:09 */ @Data @ToString public class RegionStats { /** * 州/省 */ private String state; /** * 国家 */ private String country; /** * 累计确诊人数 */ private int latestTotalCases; /** * 较前日增加确诊人数 */ private int diffFromPrevDay; } ``` 【编写爬取代码】 ```java /** * @author: zipeng Li * 2021/4/27 9:04 */ @Slf4j @Service public class DataService implements InitializingBean { /** * 每当程序启动,自动获取一次数据 * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { getData(); } private String Data_URL = "https://gitee.com/dgut-sai/COVID-19/raw/master/csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv"; private List list = new ArrayList<>(); /** * 每天凌晨1点执行计划任务,更新list成员变量 * @throws IOException */ @Scheduled(cron = "${zipeng.Schedules.updateCron}") public void getData() throws IOException { RequestEntity requestEntity = RequestEntity.get(Data_URL) .headers(httpHeaders -> httpHeaders.add("User-Agent", "Mozilla/5.8")) .build(); ResponseEntity exchange = new RestTemplate().exchange(requestEntity, Resource.class); Resource body = exchange.getBody(); if (body == null) { return; } Reader in = new BufferedReader(new InputStreamReader(body.getInputStream())); 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))); list.add(regionStats); } log.info("================数据更新成功==================="); } public List getList() { return list; } } ``` ### 3.3 使用Spring框架自带的计划任务功能定时更新统计数据 【开启计划任务】 ```java @EnableScheduling @SpringBootApplication public class Project03Application { public static void main(String[] args) { SpringApplication.run(Project03Application.class, args); } } ``` 【设置定时更新、增加线程数】 ```properties # 设计计划任务线程数 spring.task.scheduling.pool.size=20 # 自定义执行计划任务配置 zipeng.Schedules.updateCron=0 0 1 * * * ``` ![1619489940970](resource/1619489940970.png) ### 3.4 要确保应用程序启动时,获取一次统计数据 ![1619490168503](resource/1619490168503.png) ​ ### 3.5 单元测试 ```java /** * 单元测试 * {@link SpringBootTest.WebEnvironment.NONE} 表示不需要初始化Web环境 * {@link SpringBootTest#classes()} 指定配置类或组件类 */ @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE, classes = {DataService.class}) class Project03ApplicationTests { @Resource DataService dataService; @Test void testGetData() throws IOException { List list = dataService.getList(); for(RegionStats item: list){ System.out.println(item); } } } ``` ### 3.6 定义Controller控制器 【自定义返回结果】 ```java /** * @author: zipeng Li * 2021/4/27 10:34 * * 自定义返回结果 */ @Data public class R { /** * 描述信息 */ private String msg; /** * 返回的数据 */ private Map data = new HashMap<>(); public static R success(){ R r = new R(); r.setMsg("成功"); return r; } public static R error(){ R r = new R(); r.setMsg("失败"); return r; } public R message(String msg){ this.msg = msg; return this; } public R data(String key, Object value){ this.data.put(key, value); return this; } } ``` 【控制器】 ```java /** * @author: zipeng Li * 2021/4/27 9:12 */ @RestController @RequestMapping("/api") public class DataController { @Resource private DataService dataService; /** * 获取数据带查询 * @param country * @param state * @return */ @GetMapping("/search") public R searchData( @RequestParam(name = "country", required = false)String country, @RequestParam(name = "state", required = false)String state){ List list = dataService.getList(); if(list != null){ if (country != null) { list = list.stream().filter(item -> item.getCountry().equals(country)).collect(Collectors.toList()); } if (state != null){ list = list.stream().filter(item -> item.getState().equals(state)).collect(Collectors.toList()); } return R.success().message("数据查询成功").data("dataList", list); } return R.error().message("数据获取失败"); } } ``` ### 3.7 测试接口 ```java GET http://localhost:8080/api/search Accept: application/json ### GET http://localhost:8080/api/search?country=France Accept: application/json ### GET http://localhost:8080/api/search?country=France&state=Guadeloupe Accept: application/json ### ``` 【测试结果】 ![1619493778356](resource/1619493778356.png) ![1619493854962](resource/1619493854962.png)