软件工程实践——结对作业二

这个作业属于哪个课程软件工程实践2022年春-F班
这个作业要求在哪里软件工程实践——结对作业二
结对学号221900121 && 221900128
这个作业的目标完成上次结对作业模型的具体设计
其他参考文献CSDN

1、Git仓库与代码规范链接

Git仓库地址

2、项目部署链接

项目部署链接

3、PSP表格

PSPPersonal Software Process Stages预估耗时(分钟)实际耗时(分钟)
Planning计划
• Estimate• 估计这个任务需要多少时间13602150
Development开发
• Analysis• 需求分析 (包括学习新技术)2010
• Design Spec• 生成设计文档60100
• Design Review• 设计复审2030
• Coding Standard• 代码规范 (为目前的开发制定合适的规范)2030
• Design• 具体设计3050
• Coding• 具体编码9001060
• Code Review• 代码复审60100
• Test• 测试(自我测试,修改代码,提交修改)130550
Reporting报告
• Test Report• 测试报告3060
• Size Measurement• 计算工作量1020
• Postmortem & Process Improvement Plan• 事后总结, 并提出过程改进计划60100
合计13602150

4、成品展示

  • 奖牌地图:当鼠标悬停至某个参赛国时,显示其奖牌信息,同时可利用鼠标控制地图的缩放和移动。

map

  • 奖牌总榜:显示当前北京时间和奖牌榜列表,将中国对应一行高亮显示。

image-20220324161906498

  • 项目赛程:显示15个项目名称格子,点击任意一个项目,将会跳转至对应的项目赛程列表。

image-20220324161924143

  • 赛程列表:页面显示项目的赛程列表,每一行包含:时间大项比赛场馆比赛状态数据。而数据一列,对应不同比赛的成绩公报,点击后跳转至对应的详细赛程页面。

image-20220324162006660

  • 下拉列表进行分别对时间、项目、馆场进行查询。

select

  • 个人赛 以列表的形式展示数据,每一行包含:排名国家/地区姓名/代表队总成绩

image-20220324162517611

  • 参赛选手不止一位时,将其并列显示。

image-20220324162822045

  • 混合团体赛 同样以列表的形式展示数据,每一行包含:国家/姓名得分得分国家/姓名

image-20220324162700853

  • 国家赛 分成三个水平排列的块,左边为一国的出场名单,中间包含两小块:两国得分两队详细比分,右边为另一国的出场名单

image-20220324162627441

  • 了解更多:看起来很拉,主要介绍申奥的小故事以及冬奥会的吉祥物冰墩墩的来历

image-20220324162945840

5、结对讨论过程

项目分工

image-20220325191800539

  • 对于素材来源,由于在原型的设计过程中是由 WJD寻找的,所以由WJD整理素材之后发给RHL。

image-20220325191507424

  • 一开始地图的原型采用的是amcharts的组件,但是由于领土完整性原因,我们放弃了,改用echarts的地图。

image-20220325191607488

image-20220325191340857

小插曲

image-20220325191019911

6、设计实现过程

6.1 功能结构图

image-20220324183233910

6.2 项目设计与实现

设计过程主要分为两个部分,鸿林同学负责前端,建东同学负责后端和一部分前端。

前端的页面设计,主要按照原型进行设计,HTML设计结构,CSS设计样式、JavaScript用来进行地图的显示和数据的获取,配合Thymeleaf模板引擎 与后端 Spring Boot 进行数据交互。

地图部分使用echarts的地图组件进行渲染,奖牌信息通过发get请求到后端获得,同时在echarts参数option的tooltips的formatter设置function,将后台传来的奖牌信息渲染至页面。

后端使用 Controller 进行视图渲染和跳转。分别是 MedalsControllerMapControllerMatchesControllerMoreControllerDetailsController

对于需要提供数据的 Controller 都配置一个 Service ,通过前端传来的参数 给 Controller 提供对应的方法,分别是 MedalsServiceMatchesServiceDetailService

针对每一个页面设计不同的实体类 pojo,用来接收json数据的信息。分别是 MedalMatchResultInfoPersonResultTeamResultNationResult

对于数据,通过冬奥官网的API接口进行获取,设计 JsonUtil 类为 Service 提供方法,其中包含获取各类数据的方法,解析Json后装配进实体类中,返回给 Service 。

6.3 关键代码

  • 本次作业的核心主要是数据获取以及对JSON数据进行解析处理

奖牌数据获取与解析

public static List<Medal> getMedalList(String url) {
    RestTemplate template = new RestTemplate();
    List<Medal> list = new ArrayList<>();
    ResponseEntity<String> response = template.getForEntity(url, String.class);
    JSONArray matchList;
    try {
        String body = response.getBody();
        Assert.notNull(body, "响应数据为空!");
        // 去掉除json数据外其他的字符
        String replace = body.substring(body.indexOf("(") + 1, body.indexOf(")"));
        // 读取json数据
        matchList = JSON.parseObject(replace).getJSONObject("data").getJSONArray("medalsList");
        // 转换成实体类list
        list = matchList.toJavaList(Medal.class);
    } catch (Exception e) {
        logger.error("奖牌数据获取失败");
        e.printStackTrace();
    }
    return list;
}

赛程数据获取与解析

public static List<Match> getMatchList(String url) {
    RestTemplate template = new RestTemplate();
    List<Match> list = new ArrayList<>();
    ResponseEntity<String> response = template.getForEntity(url, String.class);
    JSONArray matchList;
    try {
        String body = response.getBody();
        Assert.notNull(body, "响应数据为空!");
        // 去掉除json数据外其他的字符
        String replace = body.substring(body.indexOf("(") + 1, body.indexOf(")"));
        // 读取json数据
        matchList = JSON.parseObject(replace).getJSONObject("data").getJSONArray("matchList");
        // 转换成实体类list
        list = matchList.toJavaList(Match.class);
    } catch (Exception e) {
        logger.error("赛程数据获取失败");
        e.printStackTrace();
    }
    return list;
}

详细赛况数据获取与解析

public static List<Object> getResult(String url) {
    RestTemplate template = new RestTemplate();
    ResponseEntity<String> response = template.getForEntity(url, String.class);
    List<Object> list = new ArrayList<>();

    boolean isPersonProject = true;

    try {
        String body = response.getBody();
        Assert.notNull(body, "响应数据为空!");
        // 去掉除json数据外其他的字符
        String replace = body.substring(body.indexOf("(") + 1, body.indexOf(")"));
        // 读取json数据 dataSourceList 字段下的数据
        JSONArray dataSourceList = JSON.parseObject(replace).getJSONObject("data").getJSONArray("dataSourceList");
        if (dataSourceList.isEmpty()) {
            return list;
        }
		// 读取 dataSourceList 下的 cards 结点
        JSONObject cards = dataSourceList.getJSONObject(0).getJSONObject("cards");
        // 读取 cards 下的 data 结点
        JSONArray data = cards.getJSONArray("data");
        // 读取 cards 下的 periods 结点
        JSONObject periods = cards.getJSONObject("periods");

        // 国家对抗赛 或 混合团体赛
        if (data.size() == 2) {
            isPersonProject = false;
            JSONObject home = data.getJSONObject(0);
            JSONObject away = data.getJSONObject(1);
            // 国家对抗赛
            if (periods != null) {
                for (int i = 0; i < data.size(); i++) {
                    NationResult result = new NationResult();
                    // 读取json数据并装配进实体对象中
                    result.setName(data.getJSONObject(i).getString("NocName"));
                    result.setNoc(data.getJSONObject(i).getString("Noc"));
                    result.setScore(data.getJSONObject(i).getString("Result"));
                    Map<String, String> map = new HashMap<>();
                    JSONArray jsonAthleteList = data.getJSONObject(i).getJSONArray("AthleteList");
                    for (int j = 0; j < jsonAthleteList.size(); j++) {
                        map.put(jsonAthleteList.getJSONObject(j).getString("Bib"),
                                jsonAthleteList.getJSONObject(j).getString("AthleteName"));
                    }
                    result.setAthleteMap(map);
                    JSONArray period = periods.getJSONArray("period");
                    List<String> periodScore = new ArrayList<>();
                    for (int j = 0; j < period.size(); j++) {
                        if (i == 0) {
                            periodScore.add(period.getJSONObject(j).getString("HomePeriodScore"));
                        } else {
                            periodScore.add(period.getJSONObject(j).getString("AwayPeriodScore"));
                        }
                    }
                    result.setPeriodScore(periodScore);
                    // 装配完毕后加入list
                    list.add(result);
                }
            } else {
                // 混合团体赛
                JSONArray homeAthleteJsonList = home.getJSONArray("AthleteList");
                JSONArray homeResultJsonList = home.getJSONArray("ResultItemList");
                JSONArray awayAthleteJsonList = away.getJSONArray("AthleteList");
                JSONArray awayResultJsonList = away.getJSONArray("ResultItemList");

                // 如果ResultItemList为空的话,说明可能是两人对战赛,用个人赛页面展示
                if (homeResultJsonList == null || homeResultJsonList.isEmpty()) {
                    isPersonProject = true;
                } else {
                    // 将json数据装配进实体对象中
                    // 混合团体赛第一行为国家名和分数
                    TeamResult result = new TeamResult();
                    result.setHomeAthleteName(home.getString("CompetitorName"));
                    result.setAwayAthleteName(away.getString("CompetitorName"));
                    result.setHomeScore(home.getString("Result"));
                    result.setAwayScore(away.getString("Result"));
                    list.add(result);
                    for (int i = 0; i < homeAthleteJsonList.size(); i++) {
                        // 混合团体赛从第二行开始为运动员姓名和各自得分
                        TeamResult result1 = new TeamResult();
                 result1.setHomeAthleteName(homeAthleteJsonList.getJSONObject(i).getString("AthleteName"));
                 result1.setAwayAthleteName(awayAthleteJsonList.getJSONObject(i).getString("AthleteName"));
                        result1.setHomeScore(homeResultJsonList.getJSONObject(i).getString("Result"));
                        result1.setAwayScore(awayResultJsonList.getJSONObject(i).getString("Result"));
                        // 装配完毕后加载进list
                        list.add(result1);
                    }
                }
            }
        }

        // 个人赛
        if (isPersonProject) {
            for (int i = 0; i < data.size(); i++) {
                // 将json数据装配进实体对象中
                PersonResult result = new PersonResult();
                JSONObject obj = data.getJSONObject(i);
                result.setRank(obj.getString("Rank"));
                result.setNation(obj.getString("NocName"));
                JSONArray jsonAthleteList = obj.getJSONArray("AthleteList");
                List<String> nameList = new ArrayList<>();
                for (int j = 0; j < jsonAthleteList.size(); j++) {
                    nameList.add(jsonAthleteList.getJSONObject(j).getString("AthleteName"));
                }
                result.setAthleteList(nameList);
                result.setScore(obj.getString("Result"));
                list.add(result);
            }
        }
    } catch (Exception e) {
        logger.error("详细赛况数据获取失败");
        e.printStackTrace();
    }
    return list;
}

赛程基本信息获取与解析

public static ResultInfo getInfo(String url) {
    RestTemplate template = new RestTemplate();
    ResponseEntity<String> response = template.getForEntity(url, String.class);
    ResultInfo info = new ResultInfo();
    try {
        String body = response.getBody();
        Assert.notNull(body, "响应数据为空!");
        String replace = body.substring(body.indexOf("(") + 1, body.indexOf(")"));
        JSONObject data = JSON.parseObject(replace).getJSONObject("data");
        info.setItemCodeName(data.getString("itemcodename"));
        info.setTitle(data.getString("title"));
        info.setVenueName(data.getString("venuename"));
        info.setDate(data.getDate("startdatecn"));
    } catch (Exception e) {
        logger.error("赛事信息获取失败");
        e.printStackTrace();
    }
    return info;
}

7、心路历程和收获

鸿林 对 建东 的评价:

​ 建东专业基础扎实,学习能力强,在结对作业的完成过程中给了我很多帮助,比如说在原型实现的过程中,元素悬浮效果难以实现,地 图的奖牌信息无法展示,我们共同百度,查阅相关资料,解决了很多困难,是一个非常适合合作,专业能力强的同学。

鸿林 的心路历程和收获:

​ 在本次结对作业过程中,从一开始的无从下手到后来的得心应手,经历了很多也成长了很多,学到了很多关于web前端开发的知识,对 之前学习过的html,css,javascript都复习了一遍,收获还是很大的。

建东 对 鸿林 的评价:

​ 鸿林在这次结对作业过程中,态度认真,对任何需要了解的知识都第一时间去学习,遇到难以解决的问题时愿意主动查找资料,愿意询 问,对结对作业的完成起到了很大的作用。

建东的心路历程和收获:

​ 在看到作业发布的时候,我就准备上手后端的工作,在本次结对过程中我利用已经学过的 Spring Boot 进行开发,但是在json的数据处 理的时候遇到了不少的困难,每一个页面的数据接口参数和json结构都各不相同,理清楚接口json数据真的是本次结对作业的一大困难 所在,其次也对前端和后端之间的联系和区别也有了更深刻的理解,对于git的使用也踩了不少坑,比如说如果没有commit就直接pull 的话会直接把辛辛苦苦写的代码给覆盖掉。收获就是长了心眼。

  • 0
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:游动-白 设计师:我叫白小胖 返回首页
评论

打赏作者

Kylenax

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值