首页 > 技术文章 > 结对作业(2/2)

sillyby 2020-03-14 16:58 原文

这个作业属于哪个课程 https://edu.cnblogs.com/campus/fzu/2020SpringW
这个作业要求在哪里 https://edu.cnblogs.com/campus/fzu/2020SpringW/homework/10456
这个作业的目标 采用web技术,结合寒假第二次作业的成果实现原型设计中的部分功能
结对学号 221701233、221701234
作业正文 https://www.cnblogs.com/sillyby/p/12492953.html
其他参考文献

Github仓库地址https://github.com/WallofWonder/InfectStatisticWeb

代码规范链接https://github.com/WallofWonder/InfectStatisticWeb/blob/master/codestyle.md

演示地址:阿里云 (初次加载比较慢,请耐心等待)

成果展示

全国疫情概览:

  • 展示现有确诊、现有疑似、现有重症、累计确诊、累计治愈、累计死亡等数据
  • 提供现有确诊、累计确诊的全国地图可视化展示

image-20200314115312816

切换地图数据

地图切换

省份详情:

image-20200314101130308

省份高亮

单击地图上的省份进入省详情页面:

省份详情

折线图的数据切换:

折线图

向下滚动可查看该省各市的疫情数据:

image-20200314120222248

未完成的扩展功能页面:

包括疫情新闻、同程查询、谣言鉴别

404-1584158871195

结对过程

作业发布后,我们首先讨论的是采用什么技术和框架来实现,我们决定采用springboot+vue的前后端分离技术来实现作业的要求,原因是我们其中一人在寒假学习过springboot,另一人学习过vue,而且都没有用学到的知识真正搭建过一个像样的东西,正好能拿这次作业练练手。

确定好所采用的技术之后,第一个问题是如何获取数据,为了方便拿到数据我们采用了天行数据的接口

我们根据所采用的技术指定了代码规范,接下来就是进行分工:

  • 221701233:后端、后端部分文档博客撰写、博客整合和发布
  • 221701234:前端、前端部分文档博客撰写、云服务器部署

之后,我们开始进行协作的磨合,由于负责前端的同学git还不是很熟练,两人之前也从未接触过正式的git协作,我们花了两天的时间进行git的知识储备和协作测试,大致摸清了协作流程之后,开始上手开发。

由于是前后端分离开发,我们可以同时进行项目的推进,并在开发过程中交流保持进度同步,互相测试代码的功能,并且共同解决一些难以解决的问题。

实现了基础功能后,进行紧张的代码复审和部署测试操作,在这个过程中遇到了许许多多的小毛病,但最后还是逐个解决了,并合作完成博客撰写。

结对过程截图

image-20200314112906722

image-20200314112816282

image-20200314112737775

遇到的主要困难以及克服过程

前后端跨域问题

image-20200314153817124

跨域

分析:经过查找资料,这应该是前后端分离所导致的问题,由于前后端分别运行在不同端口,之间的数据交互属于跨域,而因为浏览器收到同源策略(不同的域名, 不同端口, 不同的协议不允许共享资源的,保障浏览器安全。)的限制,当前域名的js只能读取同域名下的窗口属性。

解决方案:前端请求接口时加上http://头即可。

刻苦铭心的经历——代码丢失

起因:ddl的前一天,前端同学undo了一次commit,再次commit的时候github只提交了新增文件,而没有提交已有代码的修改,此时前端同学又从GitHub拉取了一次代码,导致对已有代码的修改丢失,一个下午的努力似乎付诸东流。

解决:大家都很紧张,乱了阵脚,熬夜寻找解决方案,最后的解决方法却十分简单——通过IDE的历史记录回滚恢复修改的代码,并再次commit,真的是虚惊一场。

针对该次事件的反思:可能表达语言水平有限,没法体现出我们当时心态有多崩,不过这个问题也反映出了我们对git的不熟练,导致这一星期许多时间都用在解决git多人协作的问题上了,严重拖慢了进度,只勉强完成了基础功能,为了后续的学习和团队实践我们两人都需要抓紧熟练git多人协作的使用了。

云服务器部署问题

前端同学在搭建过程中的探索已经总结并写成了一篇博客,在先贴上博客链接吧

https://www.cnblogs.com/QEEZ/p/12501197.html

主要的问题概括如下:

  • 后端链接数据库被拒绝访问,解决方法:linux数据库配置问题,安装时没有配好
  • 前端请求资源失败,解决方法:修改前端请求中的localhost为服务器的公网ip。

设计实现

我们决定采用springboot+vue的前后端分离技术来实现作业的要求。

确定好所采用的技术之后,第一个问题是如何获取数据,为了方便拿到数据我们采用了天行数据的接口,同时为了减轻第三方接口压力进行数据的持久化,前端发送至后端的请求是面向数据库的,而后端负责从第三方接口定时获取数据维护数据库,同时因为第三方接口返回的json数据繁杂,不符合前端需要的数据格式,后端需要对其进行过滤和整理。

image-20200314112003226

在前端的界面设计上大致遵循原型设计的风格,决定采用ElementUI组件库美化界面,同时嵌入Echarts完成对图表的绘制。

关键代码——后端

请求第三方接口的数据

初始化数据库时,为了获取过去20天的数据,需要以较高的频率调用第三方接口获取数据,用同一个apikey高频调用会出现不稳定情况,于是使用三个apikey分担压力。

/**
 * @param httpUrl 请求接口
 * @param httpArg 参数
 * @param tag     apiKey选择标识
 * @return 返回结果
 */
public static String request(String httpUrl, String httpArg, int tag) {
    BufferedReader reader = null;
    String result = null;
    StringBuffer sbf = new StringBuffer();
    String apiKey = "";

    if (tag == 0) {
        apiKey = API_KEY0;
    }
    else if (tag == 1) {
        apiKey = API_KEY1;
    }
    else if (tag == 2) {
        apiKey = API_KEY2;
    }
    httpUrl = httpUrl + "?key="
            + apiKey
            + ((httpArg == null) ? "" : httpArg);

    try {
        URL url = new URL(httpUrl);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        InputStream is = connection.getInputStream();
        reader = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        String strRead = null;
        while ((strRead = reader.readLine()) != null) {
            sbf.append(strRead);
            sbf.append("\r\n");
        }
        reader.close();
        result = sbf.toString();

    } catch (IOException e) {
        e.printStackTrace();
    }
    return result;
}

配置定时任务

为保证前端获取的数据的可靠性,设置每隔10分钟更新一次数据库。和启动时的初始化不同,定时任务只会更新当日数据,不会高频调用接口。

@Component
@Slf4j
public class ScheduledJob {

    @Resource(name = "provinceServiceImpl")
    ProvinceService provinceService;

    @Resource(name = "cityServiceImpl")
    CityService cityService;

    @Resource(name = "nationServiceImpl")
    NationService nationService;

    private DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    /**
     * 每10分钟更新一次数据库
     */
    @Scheduled(cron = "0 */10 * * * ? ")
    public void cronJob() {
        log.info("=========================== >> 更新数据库...");
        updateNationData();
        updateProvinceDataToday();
        upadateCityData();
        log.info("=========================== >> 数据库更新完成。");
    }

    /**
     * 应用启动时更新数据库
     */
    @PostConstruct
    public void updateAtStart() {
        log.info("=========================== >> 更新数据库...");
        updateNationData();
        updateProvinceData();
        upadateCityData();
        log.info("=========================== >> 数据库更新完成。");
    }
    
    ...
}

image-20200314164845549

定时任务的截图

推荐阅读