688
社区成员
发帖
与我相关
我的任务
分享| 这个作业属于哪个课程 | 2023年福大-软件工程实践-W班 |
|---|---|
| 这个作业要求在哪里 | 结对第二次作业--编程实现 |
| 结对学号 | 222000309,222000310 |
| 这个作业的目标 | 编程实现结对第一次作业原型设计作业的部分功能 |
| 其他参考文献 | 《构建之法》 |
m0_52688898 / pair_project 仓库地址
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 25 | 20 |
| • Estimate | • 估计这个任务需要多少时间 | 25 | 20 |
| Development | 开发 | 1800 | 2280 |
| • Analysis | • 需求分析 (包括学习新技术) | 500 | 720 |
| • Design Spec | • 生成设计文档 | 90 | 120 |
| • Design Review | • 设计复审 | 40 | 30 |
| • Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 40 |
| • Design | • 具体设计 | 40 | 50 |
| • Coding | • 具体编码 | 1200 | 1800 |
| • Code Review | • 代码复审 | 90 | 200 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 180 | 120 |
| Reporting | 报告 | 120 | 180 |
| • Test Repor | • 测试报告 | 90 | 120 |
| • Size Measurement | • 计算工作量 | 20 | 40 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 50 | 40 |
| 合计 | 2150 | 2890 |



前端的实现过程:
- 采用技术:Vue框架、响应式设计、Axios技术
- 设计思路:根据原型设计部分内容,前端部分组件结构应包括:导航栏、关于部分、选手排名、每日赛程、晋级图以及详细数据,数据获取主要采用存储在纯前端的数据部分,其中选手排名是采用前后端交互的方式进行
- 遇到的问题以及解决的方式:
- -1.使用elemen-ui时, 样式要求不符合自己的预期,修改了style样式却不生效
解决方式:由于<style> 标签中带有scoped属性导致不生效, 通过在样式选择器前添加 ::v-deep解决了问题- -2.使用vue语法动态引用图片链接时,图片加载不出来
解决方式: 通过 require(url) 引用的方式, 使图片成功加载- -3.由于不熟悉第三方组件, 在想配置各种属性时, 不知道具体措施
解决方式: 通过百度、CSDN、询问同学的方式得出其解决办法
后端的实现过程:
- 采用技术:tomcat、servlet、JDBC
- 设计思路:根据原型设计部分内容,将选手排名所需要的各项数据手动输入到数据库中,再创建继承自HttpServlet的类,用线性表存取数据,再将线性表转为JSON形式传送至前端
- 遇到的问题以及解决的方式:
- -前后端跨域问题
解决方法:调用setHeader方法,设置允许跨域的主机地址
//按需引入 ElementUI组件
import { Menu, MenuItem, Submenu } from 'element-ui';
...
//应用ElementUI
Vue.component(Menu.name, Menu);
Vue.component(MenuItem.name, MenuItem);
Vue.component(Submenu.name, Submenu);
...
//创建并暴露一个路由器
// router/index.js
export default new VueRouter({
routes: [
{
name: "Home",
path: '/',
redirect: "/Rank",
component: Home,
children: [
{
name: "Rank",
path: 'Rank',
component: Rank,
},
{
name: "Daily",
path: 'Daily',
component: Daily,
},
{
name: "Promotion",
path: 'Promotion',
component: Promotion,
},
{
name: "Detail",
path: 'Detail',
component: Detail,
},
],
},
{
name: "About",
path: '/About',
component: About,
},
]
})
<!-- 导航条组件, 由router属性配置路由跳转 -->
<div class="navigation">
<el-menu
:default-active="activeIndex"
class="el-menu-demo"
mode="horizontal"
router
>
<el-menu-item index="About">
<img src="../assets/icon.png" alt="澳网图标" id="icon" />
</el-menu-item>
<el-menu-item index="Rank">选手排名</el-menu-item>
<el-menu-item index="Daily">每日赛程</el-menu-item>
<el-menu-item index="Promotion">晋级图</el-menu-item>
</el-menu>
</div>
<!-- 使用vue2-org-tree插件实现晋级图树状展示 -->
<!-- render-content属性负责渲染每个树节点结构与样式 -->
<div class="tree">
<vue2-org-tree
:data="drawData"
:horizontal="true"
:render-content="showTree"
/>
</div>
<!-- v-for渲染每日赛程的天数, 并绑定click事件 -->
<!-- 通过selected参数判断点击的是哪一天,并绑定class样式渲染点击那一天的样式 -->
<el-row :gutter="30">
<el-col :span="8" v-for="key in 3" :key="key">
<el-card
shadow="always"
@click.native="show(key)"
:class="{ isActive: selected == key }"
>
Day{{ key }}
</el-card>
</el-col>
</el-row>
<!-- 每日赛程下方赛况卡片 -->
<div
class="scoresWrapper"
v-for="(item, index) in day[selected - 1]"
:key="index"
>
<h3>{{ item.court }}</h3>
<div class="scores">
<div
class="score"
@click="getDetail"
v-for="(score, key) in item.scores"
:key="key"
>
<div class="score-row">
<div class="score-header__title-wrapper">
<p class="score-header__title font-bold">{{ score.type }}</p>
<p class="score-header__subtitle">
{{ score.round }} • {{ item.court }}
</p>
</div>
<div class="score-header__status-wrapper">
<p class="score-header__status font-bold">Complete</p>
<p class="score-header__duration">{{ score.time }}</p>
</div>
</div>
<el-divider></el-divider>
<div class="score-row">
<div class="player-row__team-wrapper winner">
<span class="player-flag">
<img :src="score.win.flag" alt="flag" />
</span>
<p>
{{ score.win.name }} <span>{{ score.win.num }}</span>
</p>
</div>
<div class="player-row__score-wrapper">
<span class="player-row__score-badge winner">√</span>
<div class="player-row__score-game-wrapper">
<!-- compare函数判断哪方分数高,并加粗赢家的字体 -->
<p
class="player-row__score-game"
v-for="(rate, scoreIndex) in score.win.grade"
:key="scoreIndex"
:class="{
winner: compare(rate, score.lose.grade[scoreIndex]),
}"
>
{{ rate }}
</p>
</div>
</div>
</div>
<el-divider></el-divider>
<div class="score-row">
<div class="player-row__team-wrapper">
<span class="player-flag">
<img :src="score.lose.flag" alt="flag" />
</span>
<p>{{ score.lose.name }} <span></span></p>
</div>
<div class="player-row__score-wrapper">
<div class="player-row__score-badge"></div>
<div class="player-row__score-game-wrapper">
<p
class="player-row__score-game"
v-for="(rate, scoreIndex) in score.lose.grade"
:key="scoreIndex"
:class="{
winner: compare(rate, score.win.grade[scoreIndex]),
}"
>
{{ rate }}
</p>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
export default {
name: "Daily",
data() {
return {
selected: 1,
}
},
methods: {
getDetail() {
this.$router.push({
name: "Detail",
});
},
show(day) {
this.selected = day;
},
compare(rate1, rate2) {
return rate1 >= rate2;
},
},
};
</script>
<!--
isActive样式
.isActive {
background-color: rgb(0, 115, 178);
color: #fff;
}
winner样式
.winner {
font-weight: bold;
}
-->
<!-- 家页面,由导航栏点击时, 通过router-view渲染不同组件 -->
<!-- keep-alive标签负责缓存已经加载的组件,提高性能 -->
<div class="home">
<Navigation/>
<keep-alive>
<router-view></router-view>
</keep-alive>
</div>
<!-- 通过tab-pane构建关于介绍的界面 -->
<div class="about">
<h1><i class="el-icon-back" @click="goBack"></i> 澳网介绍</h1>
<el-tabs tab-position="left" type="border-card">
<el-tab-pane label="创立之初">...</el-tab-pane>
<el-tab-pane label="不断发展">...</el-tab-pane>
<el-tab-pane label="公开赛时代"></el-tab-pane>
</el-tabs>
</div>
<!-- 详细介绍组件 -->
<div class="detail">
<div class="set" v-for="(set, index) in sets" :key="index">
<h1>{{ set.h1 }}</h1>
<div class="setWrapper">
<div class="setHead">
<div class="player">
{{ set.setHead.player }} <span class="time"></span>
</div>
<div class="score">{{ set.setHead.score }}</div>
</div>
<div v-for="(setRow, key) in set.setRows" :key="key">
<el-divider></el-divider>
<div class="setRow">
<div class="playerWrapper">
<div class="player">
{{ setRow.player }} <span class="time">{{ setRow.time }}</span>
</div>
<div class="info">
{{ setRow.info }}
</div>
</div>
<div class="game">{{ setRow.game }}</div>
</div>
</div>
</div>
</div>
</div>
<!-- 添加 "scoped" 属性来限制这个CSS只属于该组件 -->
<style scoped>
.detail {
margin-top: 30px;
}
.set {
width: 60%;
margin: 0 auto;
}
.setWrapper {
border: 1px solid rgb(235, 235, 235);
padding: 10px;
}
.el-divider--horizontal {
margin: 8px 0;
background: 0 0;
border-top: 1px solid rgb(235, 235, 235);
}
/* 每轮的名字 */
h1 {
text-align: left;
}
/* 每轮的头部 */
.setHead {
text-align: left;
font-weight: bold;
}
.setHead .score {
font-size: 22px;
font-weight: bolder;
}
/* 每轮的行 */
.setRow .playerWrapper {
text-align: left;
display: inline-block;
width: 50%;
}
.setRow .game {
text-align: right;
display: inline-block;
width: 50%;
vertical-align: top;
font-weight: bold;
}
.setRow .info {
font-size: 10px;
color: rgb(165, 167, 167);
}
.player {
font-weight: bolder;
margin-bottom: 5px;
}
.player .time {
font-weight: normal;
}
</style>
{ //数据库连接
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://127.0.0.1:3306/daily_competition";
String username = "root";
String password = "123456";
Connection connection = DriverManager.getConnection(url,username,password);
String sql = "SELECT * FROM daily_competition.male_competitor_rank;";
Statement stmt = connection.createStatement();
//执行并读取查询数据
ResultSet rs = stmt.executeQuery(sql);
//用线性表存取数据
ArrayList<competitor> list = new ArrayList<competitor>();
while(rs.next())
{
competitor competitor_list = new competitor();
//从ResultSet中取值并把数据存到competition类中
competitor_list.setName(rs.getString(1));
competitor_list.setRank(rs.getInt(2));
competitor_list.setMatches(rs.getInt(3));
competitor_list.setAces(rs.getInt(4));
//将处理好的对象添加到线性表中
list.add(competitor_list);
}
//指定浏览器解析格式
resp.setCharacterEncoding("utf-8");
resp.setContentType("text/html");
//将线性表转为JSON形式,进行处理
JSONArray js = JSONArray.fromObject(list);
JSONObject jsonObject = new JSONObject();
jsonObject.put("tableData", js);
//将数据以utf-8形式转换为string类型
String competitors = new String(jsonObject.toString().getBytes(StandardCharsets.UTF_8), "UTF-8");
PrintWriter writer = resp.getWriter();
writer.write(competitors);
writer.close();
//数据库资源释放
rs.close();
stmt.close();
connection.close();
}
222000310:
这次项目主要负责了前端页面的相应开发,此前在软工数据库实践中学习过前端开发的相应知识点,但知识不用便会被遗忘,也让我深刻懂得了不管前端后端,编程能力绝对不是靠死记硬背就能提高的,而是要通过不断的动手实践,形成“肌肉记忆”,本次编程边动手边复习以前的知识,在开发过程中遇到了大大小小的问题,虽然最后通过百度、询问同学的方式解决了大部分问题,从总体来说效率并不算高,在今后要努力提高自己的编程开发经验,同时每一次的动手开发实践都是对自己的一次挑战
222000309:
这一次项目时间紧任务重,我原本主要应该负责后端部分的开发,将相关Json数据处理并存入数据库中,再将数据编写成Json格式后响应给浏览器,但是在囫囵吞枣般快速地学习了Javaweb的相关知识以后,我就匆匆上手写代码了,缺乏了与前端之间的交互和沟通,导致数据库的设计存在与前端需求的不匹配,再加上前后端交互之间的跨域以及部署云服务器等问题,最后我们还是决定将大部分数据存储在前端代码中。这一次较大的改动,浪费了不少时间,白费了不少力气,也提醒我以后再与其他人一起合作开发项目之前,应当提前确定相互的需求,结合任务时间以及自身水平等因素进行合理的分工。
222000310:
这是第二次进行组队合作了,通过上一次的组队配合,已经和队友达成了些许默契,前期的分工比上一次明确了许多,虽然这次工作量比起上次的模型开发大了许多,但效率也比上次高出许多,两个人对对方代码互相评价,互相促进,遇到问题时能积极协调的沟通,让我领会到了团队协同开发的乐趣。同时使用了git团队协作工具,把团队协作的难度降低了许多,总体而言这是次成功且意义巨大的合作项目(鼓掌)
222000309:
这次组队合作,我的队友几乎以一己之力完成了所有的编程任务,我只是负责了一些简单的数据处理和博客编写的任务,在整个项目中没有发挥很大的作用,实在是惭愧惭愧。