结对第二次作业——编程实现

这个作业属于哪个课程202302软件工程
这个作业要求在哪里结对第二次作业——编程实现
结对学号222100421 & 222100426
这个作业的目标Git的合作、实现原型中的功能,项目部署到云服务器
其他参考文献《构建之法》、Vue.js-渐近式框架SpringBoot 官方文档

目录

1. Git仓库地址和代码规范链接

GitCode仓库地址
代码规范地址

2. PSP表格

PSP StageChinese TranslationEstimated Time (minutes)Actual Time (minutes)
Planning计划3030
- Estimate- 估计这个任务需要多少时间3030
Development开发16451805
- Analysis- 需求分析 (包括学习新技术)300300
- Design Spec- 生成设计文档6070
- Design Review- 设计复审5045
- Coding Standard- 代码规范 (为目前的开发制定合适的规范)3035
- Design- 具体设计100120
- Coding- 具体编码800900
- Code Review- 代码复审6075
- Test- 测试(自我测试,修改代码,提交修改)5045
Reporting报告120130
- Test Report- 测试报告3040
- Size Measurement- 计算工作量56
- Postmortem & Process Improvement Plan- 事后总结, 并提出过程改进计划4040
Total合计16751835

3. 访问链接

3.1 项目地址

3.2 后端接口

4.成品展示

4.1 首页

  • 设置了轮播图循环展示网站图片,下方有最新消息的卡片显示最近的新闻。

在这里插入图片描述
home3

  • 网站的页脚部分。

footer

4.2 选手信息

展示所有的选手的信息,包括选手的国籍、姓名、性别、生日等,也爬取了对应国籍的头像和运动员的肖像,使界面更加丰富。[ 爬取行为仅用于课程教学]
在这里插入图片描述
player2

4.3 每日赛程

以每一个大日期为一个分栏,展示对应日期下的赛事安排。每个赛事安排显示对应的时间和比赛的名字。对决赛做出颜色的强调,显示为橙色,初赛和半决赛为灰色。
schdule1
schedule2

4.4 比赛详细结果

点击对应日期下的赛事即可查看比赛的详细情况,包括选手的排名、国家、总分、年龄、落后多少分等详细信息。点击不同的按钮可以查看不同比赛的数据,如 Final 和 Preliminary:

detail

4.5 奖牌榜

以每一行的形式展示国家的奖牌榜,包括金牌数、银牌数、铜牌数和国家的总数,显示对应国家的头像。
在这里插入图片描述


4.6 附加功能:了解更多

以图文的形式展示世锦赛的相关信息,引起对于世锦赛的兴趣。
more

5. 结对讨论过程

在开始项目之前,我们首先花了一些时间来评估不同的技术栈和框架。考虑到要展示选手信息、比赛赛况等内容。最终我们决定使用前端和后端分离的架构,选择Vue作为前端框架,使用Spring Boot作为后端框架。

5.1 讨论截图展示

结对伙伴宿舍比较近,更多的讨论是以面对面的形式。
讨论过程

6. 设计实现过程

6.1 后端

6.1.1 使用的技术及理由

后端这里我们使用了SpringBoot的框架进行开发,使用该框架可以带来许多开发的好处:

  1. 简化配置:SpringBoot提供了自动配置功能,可以根据项目的依赖和类路径自动配置应用>程序,减少了繁琐的配置过程。
  2. 内嵌服务器:SpringBoot内置了Tomcat、Jetty等常用的服务器,使得开发者无需手动配置服务器,只需运行应用程序即可。
  3. 快速启动:SpringBoot提供了快速的启动器(starter)和生产就绪的代码结构,可以快速搭建项目并开始开发,提高开发效率。
  4. 自动化配置:SpringBoot提供了大量的自动配置选项,简化了对组件的集成和配置过程。
6.1.2 主要任务

后端主要的任务就是爬取官网的数据(该爬取行为仅用于课程教学),然后对数据进行分析处理,最后将数据返回给前端。在开发前需要先从官网找到对应的获取数据的接口,如参数信息,资源请求路径等。

比如说对于运动员信息的接口,官网的地址是:https://api.worldaquatics.com/fina/competitions/3337/athletes,参数有gendercountryId分别代表运动员的性别和所属国家的Id,其他接口也是类似这样。

  • 提供的接口有下面几个(已部署到云服务器):
  1. 获取运动员信息接口:   /api/athletes
  2. 获取每程信息接口:      /api/schedule
  3. 获取奖章信息接口:      /api/medals
  4. 获取比赛详情接口:      /api/event/:id
6.1.3 实现

主要的架构就是MVC架构,由GameInfoController接收请求,GameInfoService处理业务逻辑,由于这里该项目中我们只是爬取数据进行处理,所以这里没有数据库操作,没有Dao层。由Service调用工具类JsonParseUtil将数据转换为Json格式,返回给前端,后端的难点就是对于Json数据的解析部分,对于接收请求和返回Json格式数据已由框架做好。


6.2 前端

6.2.1 使用的技术及理由

前端部分主要使用Vue.js框架进行开发,我们使用Vue框架的的理由是Vue简单易学、支持组件化开发、响应式数据绑定,且它十分灵活、性能优秀、社区支持和生态系统也很完善,有许多现成的组件可以使用,开发方便。

6.2.2 主要任务

开发的任务主要分为六大模块:首页、选手信息、每日赛程、比赛详细结果、奖牌榜、了解更多。每个模块进行组件化开发,如图每个文件夹代表对应的模块:
六大模块

6.2.3 实现

主要通过axios发送http请求获取后端数据,获取数据后将数据渲染到模板上,实现的难点、重点就是要实现每个组件不同的样式,主要的任务在于CSS部分的编写。

6.3 功能结构图

前功能结构图

7. 代码说明

7.1 前端

7.1.1 首页组件

使用Element-plus UI提供的轮播图组件

  <div class="container">
    <el-carousel height="570px" width="100%">
      <el-carousel-item v-for="(image, index) in images" :key="index">
        <img :src="image" class="carousel-image" alt="Slide" />
      </el-carousel-item>
    </el-carousel>
  </div>

7.1.2 选手信息组件

有一个子组件 AthleteItem.vue, 用来细致的展示一个运动员的信息
在index.vue中使用使用v-for循环遍历运动员信息,以Props传递运动员信息,交给每个子组件去显示。

<template>
  <div class="container">
    <div class="header">
      <ul>
        ... 省略展示的头信息
      </ul>
    </div>
    <AthleteItem
      v-for="athlete in athletes"
      :key="athlete.fullName ? athlete.fullName : 'defaultKey'"
      :athlete="athlete"
    />
  </div>
</template>

其中获取数据的接口是:

export const getAthletesAPI = (() => {
    return request({
        url: '/api/athletes',
        method: 'GET',
    })
})

发送http请求的实例由工具类提供:

import axios from 'axios'
const httpInstance = axios.create({
  baseURL: 'http://123.207.40.200',
  timeout: 5000
})
export default httpInstance

7.1.3 每日赛程组件

子组件SchedulePanel.vue 负责展示每一天的比赛信息,接收index.vue中通过props传递的schedule数据并展示出来。

<template>
  <div class="panel container">
    <h2 class="date">
      <strong>{{ schedule.date }}</strong>
    </h2>
    <div class="schedule-list">
      <div class="list"
        @click="handleClick(item)"
        v-for="(item, index) in schedule.eventInfos"
        :key="index"
      >
        <ul class="info">
          <li class="color"></li>
          <li class="time">
            {{ item.time.slice(0, 5) }}&nbsp;{{ computeName(item.time) }}
          </li>
          <li><img src="@/assets/images/small.png" alt="" /></li>
          <li class="discipline">{{ item.disciplineName }}</li>
          <li :class="item.name === 'Final' ? 'final' : 'normal'">
            {{ item.name }}
          </li>
          <li>{{ item.description }}</li>
        </ul>
      </div>
    </div>
  </div>
</template>

7.1.4 奖牌榜组件

主要展示奖牌的所有信息,包括排名、国家名称、各种奖牌数等。

<template>
  <div class="wrapper container">
    <ul>
      <li class="color"></li>
      <li class="rank font">{{ medal.rank }}</li>
      <li class="image"><img :src="imgPath" alt="" /></li>
      <li class="name font">{{ medal.countryName }}</li>
      ....
    </ul>
  </div>
</template>

数据的获取仍然调用提供的接口,在组件挂载完毕后发送请求获取数据:

<script setup>
import {getMedalsAPI} from '@/apis/medals'
import {ref, onMounted} from 'vue'
import MedalItem from './components/MedalItem.vue'
import MedalHeader from './components/MedalHeader.vue'

const medals = ref([])
const getMedal = async () => {
  const res = await getMedalsAPI()
  medals.value = res.data.data
};

onMounted(()=>{
   getMedal()
})
</script>

7.1.4 比赛的详情组件

根据不同赛事显示不同的数据,这里使用到了Element-plus的表格组件el-table来显示,可以实现列的定制化,传入数据源给表格组件即可自动绑定。

<template>
  <div>
    <el-button
      type="text"
      @click="goBack"
      style="font-size: 15px; margin-top: 15px"
    >
      返回每日赛程
    </el-button>
  </div>
  <div>
    <div class="button-container">
      <el-button v-if="data['Preliminary']"  @click="handleClick('Preliminary')" class="font normal">Preliminary</el-button>
      <el-button v-if="data['Semifinal']"  @click="handleClick('Semifinal')" class="font normal">Semifinal</el-button>
      <el-button v-if="data['Final']"  @click="handleClick('Final')" class="font orange">Final</el-button>
    </div>
  </div>
  <div>    
    <el-table :data="tableData" style="width: 100%" :header-cell-style="{background:'#eef1f6',color:'#606266', fontWeight: 'bold'}" >
      <el-table-column
        v-for="column in columns"
        :key="column.prop"
        :prop="column.prop"
        :label="column.label"
      >
        <template v-if="column.prop === 'country'" #default="{ row }">
          <div>
            <img
              :src="getCountryFlag(row.country)"
              style="width: 20px; height: 20px; margin-right: 10px"
            />
            <span>{{ row.country }}</span>
          </div>
        </template>
      </el-table-column>
    </el-table>
  </div>
</template>

7.1.5 前端路由

一级路由是/ 路由出口对应Layout组件,主要包括了Header和Footer,二级路由对应项目要求的几大模块,路由出口就是对应的模块的组件。

import { createRouter, createWebHistory } from 'vue-router'
import Layout from '@/views/Layout/index.vue'

const router = createRouter({
  history: createWebHistory(import.meta.env.BASE_URL),
  routes: [
    {
      path: '/', component: Layout,
      children: [
        { path: '', component: () => import('@/views/Home/index.vue') },
        { path: 'athletes', component: () => import('@/views/Athletes/index.vue') },
        { path: 'medals', component: () => import('@/views/Medals/index.vue') },
        { path: 'more', component: () => import('@/views/More/index.vue') },
        { path: 'schedule', component: () => import('@/views/Schedule/index.vue') },
        { path: 'detail/:id' , component: () => import('@/views/Detail/index.vue') },
      ]
    },
  ]
})

export default router

7.2 后端

7.2.1 选手信息接口

对应的实体类是Athlete.java

    @CrossOrigin
    @GetMapping("/athletes")
    public Result<List<Athlete>> getRank(){
        List<Athlete> athletes = gameInfoService.getAllAthletes();
        return athletes == null ? Result.error("读取数据出错!") : Result.success(athletes);
    }
7.2.2 每日赛程接口

对应的实体类是DailySchedule.java

    @CrossOrigin
    @GetMapping("/schedule")
    public Result<List<DailySchedule>> getDailySchedule() {
        List<DailySchedule> scheduleInfo = gameInfoService.getAllScheduleInfo();
        return scheduleInfo == null ? Result.error("读取数据失败") : Result.success(scheduleInfo);
    }
7.2.3 奖牌榜接口

对应的实体类是CountryMedal.java, 接口同上风格类型,这里就贴上解析json的代码。

  public static List<CountryMedal> parseAllCountryMedal(JSONObject jsonObject) {
        if (jsonObject == null) return null;

        JSONArray countries = jsonObject.getJSONObject("Medals")
                .getJSONArray("SportMedals").getJSONObject(0).getJSONArray("Countries");

        List<CountryMedal> countryMedals = new ArrayList<>();

        for (Object countryObj : countries) {
            JSONObject countryJson = (JSONObject) countryObj;
            //提取数据
            String countryName = countryJson.getStr("CountryCode");
            int rank = countryJson.getInt("Rank");
            int gold = countryJson.getJSONObject("Gold").getInt("Count");
            int silver = countryJson.getJSONObject("Silver").getInt("Count");
            int bronze = countryJson.getJSONObject("Bronze").getInt("Count");
            int total = countryJson.getInt("TotalCount");

            CountryMedal countryMedal = new CountryMedal(rank, countryName, gold, silver, bronze, total);
            countryMedals.add(countryMedal);
        }
        return countryMedals;
    }
7.2.4 比赛详情接口

对应的实体类是GameResult.java, 使用@PathVariable 读取路径中的id参数,根据id爬取官网数据并解析。( 爬取行为仅限于课程使用 )

    @CrossOrigin
    @GetMapping("/event/{id}")
    public Result<Map<String, List<GameResult>>> getEventDetail(@PathVariable("id") String id){
        Map<String, List<GameResult>> eventDetails = gameInfoService.getEventDetail(id);
        return eventDetails == null ? Result.error("读取数据出错!") : Result.success(eventDetails);
    }

解析json的代码太长,就不贴了。

8. 心路历程与收获

8.1 心路历程

  1. 确定技术栈和框架
    在开始项目之前,我们首先花了一些时间来评估不同的技术栈和框架。考虑到要展示选手信息、比赛赛况等内容。最终我们决定使用前端和后端分离的架构,选择Vue作为前端框架,使用Spring Boot作为后端框架。
  2. 规划项目结构
    选择了合适的技术栈和框架之后,我们花了一些时间来规划项目的结构。我创建了dev分支,并且邀请队友加入仓库。创建了一个基本的文件夹结构,前端的代码位于学号根目录下。并且确定了各个模块之间的交互方式。
  3. 分配任务
    考虑到这是一个团队作业,我和我的队友商讨了如何分配任务。我们决定采用敏捷开发的方式,将项目拆分成小的任务,并根据每个人的技能和兴趣来尽可能合理地分配任务。考虑到前端的内容还挺多,后端的同学完成后就加入前端一起开发。开发过程使用前后端联调来进行测试。

8.2 感想与收获

222100421的感想与收获: 这个项目让我学会了如何使用Git进行团队合作开发,以及如何规划和管理一个完整的项目。我学会了如何使用前端和后端技术来构建一个完整的Web应用,熟悉使用了较前沿的开发框架,并且提高了自己的编程能力和解决问题的能力。还学习了使用Docker容器启动nginx部署前端应用。总的来说收获满满,是一次非常不错的开发体验。

222100426的感想与收获:通过这个项目,我和我的队友之间建立了良好的沟通和合作机制。我们学会了如何分工合作、互相帮助,并且充分发挥了每个人的优势。这个项目不仅仅是一次作业,更是一次宝贵的实践经验。通过这个项目,我们更加深刻地理解了软件开发的流程和方法,对于将来的工作和学习都有很大的帮助。

8.3总结

完成这个项目是一次非常有意义的经历,我们从中收获良多。通过团队合作、技术实践以及项目规划,我们不仅提升了自己的技术能力,也培养了团队合作和沟通能力。这也是我们参与的一个完整的、从需求分析到原型设计再到编码实现、部署的一个完整的项目过程。我们相信这些经验和收获将对我们的未来发展产生重要影响。

9. 评价结对队友

222100421222100426: 在设计上注重细节,追求完美。学习知识的速度快,可以很快地理解后端的需求,高效的完成前端对应的功能。沟通能力强,可以很快地抓住问题的关键。

222100426222100421: 工作很高效,完成度高。做事细心,沟通能力也很强。对于难题有钻研精神,善于利用网上资源解决问题,学习速度快。

  • 19
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值