这个作业属于哪个课程 | 软件工程-23年春季学期 |
---|---|
这个作业要求在哪里 | 结对第二次作业–编程实现 |
结对学号 | 222000202陈仕燊、222000212黄志腾 |
这个作业的目标 | 1、fork仓库,和伙伴商讨协作细节等。 2、编程实现。 3、撰写博客 |
其他参考文献 | CSDN、博客园 |
Gitcode仓库地址
前端代码规范地址
后端代码规范地址
项目部署地址
PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 30 | 30 |
• Estimate | • 估计这个任务需要多少时间 | 30 | 30 |
Development | 开发 | 2160 | 2270 |
• Analysis | • 需求分析(包括学习新技术) | 360 | 400 |
• Design Spec | • 生成设计文档 | 60 | 60 |
• Design Review | • 设计复审 | 45 | 40 |
• Coding Standard | • 代码规范(为目前的开发制定合适的规范) | 45 | 30 |
• Design | • 具体设计 | 90 | 60 |
• Coding | • 具体编码 | 1320 | 1500 |
• Code Review | • 代码复审 | 60 | 60 |
• Test | • 测试(接口测试、修改代码、提交修改) | 180 | 240 |
Reporting | 报告 | 140 | 70 |
• Test and use Repor | • 接口、使用报告 | 60 | 10 |
• Size Measurement | • 计算工作量 | 20 | 10 |
• Postmortem & Process Improved Plan | • 事后总结,并提出过程改进计划 | 60 | 60 |
合计 | 650 | 900 |
首页:其中是含有四种图片的轮播图,循环播放赛程期间的热点图片
前期任务分工
css同学有过一定的后端开发经验,并且对项目部署和数据库比较熟悉,所以由css同学负责后端接口设计和编写、数据库设计。因为css同学主动选择了后端,因此hzt同学只能选择前端了,虽然开发经验较少,但是审美比css同学好,所以完全能够胜任前端的任务。
博客和学习资源的分享:
//html的部分代码
//script的部分代码
methods: {
show (value) {
if (this.index === value) {
this.index = 0
this.isShow = !this.isShow
} else {
this.index = value
this.isShow = true
}
if (value === 1) this.comp = 'one'
if (value === 2) this.comp = 'two'
if (value === 3) this.comp = 'three'
if (value === 4) this.comp = 'four'
if (value === 5) this.comp = 'five'
if (value === 6) this.comp = 'six'
this.$route.meta.index = 0
}
},
// 左滑动
scrollLeft() {
const allLength = this.monitorList.length * 120
const boxLength = document.getElementById('list-box').clientWidth
if (allLength < boxLength) return
const listEl = document.getElementById('list')
const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
if (leftMove + boxLength - 360 < boxLength) {
// 到最开始的时候
listEl.style.left = '0px'
} else {
listEl.style.left = '-' + (leftMove - 360) + 'px'
}
},
// 右滑动
scrollRight() {
const allLength = this.monitorList.length * 120
const boxLength = document.getElementById('list-box').clientWidth
if (allLength < boxLength) return
const listEl = document.getElementById('list')
const leftMove = Math.abs(parseInt(window.getComputedStyle(listEl, null)?.left))
if (leftMove + boxLength + 360 > allLength) {
listEl.style.left = '-' + (allLength - boxLength) + 'px'
} else {
listEl.style.left = '-' + (leftMove + 360) + 'px'
}
},
//按钮的监听事件
show (value) {
this.num === value ? this.isShow = this.isShow : this.isShow = true
this.num = value
var _this = this
let s = ''
if (value >= 4) {
console.log(value)
let data = value - 4 + 116
let str_data = data.toString()
s = '/PairProject/matches?matchType=0' + str_data
} else {
let data = value + 1
let str_data = data.toString()
s = '/PairProject/matches?matchType=Q' + str_data
}
Axios({
method: 'get',
url: s
}).then(function (resp) {
_this.race_mes = resp.data
console.log(resp.data)
})
},
//跳转页面
goNavbar (value) {
this.$router.push({ path: '/navbar' })
console.log(value)
}
//router配置
{
path: '/navbar',
name: 'navbar',
component: () => import('@/components/navbar.vue'),
meta: {
index: 5,
showFooter: false
}
}
//数据获取
created () {
if (this.$route.meta.index === 5) {
this.num++
this.comp = 'five'
}
}
//界面显示
/**
* 根据已有的json文件获取选手数据并写入到数据库中
* @param filePath 选手json数据文件路径
* @throws IOException
*/
public static void getPlayersResult(String filePath) throws IOException
{
SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession sqlSession = factory.openSession();
Mapper mapper = sqlSession.getMapper(Mapper.class);
String json = fileToJson(filePath);
int id = 1;
Map playerMap = JSON.parseObject(json, Map.class);
List<HashMap> playerMapList = (List<HashMap>) playerMap.get("players");
for (HashMap map : playerMapList)
{
String uuid = (String) map.get("uuid");//获取选手信息
String fullName = (String) map.get("full_name");
String shortName = (String) map.get("short_name");
String gender = (String) map.get("gender");
Random random = new Random();
Integer ranking = getPlayerRanking(gender, (List<HashMap>) map.get("rankings"));
int randomInt = 90 - ranking * (1 + random.nextInt(1));
int ace = ranking != 0 && randomInt > 0 ? randomInt : 0;
int matches = 2 + random.nextInt(6);
String nationality = (String) ((HashMap) map.get("nationality")).get("name");
String url = (String) ((HashMap) ((HashMap) map.get("nationality")).get("flag")).get("url");//处理国籍的url
int index = url.lastIndexOf("/")+1;
String nationalityUrl = url.substring(index, index+2);
String profileUrl = map.get("image") != null ? (String) ((HashMap) map.get("image")).get("url") : " ";
Player player = new Player(id++, uuid, fullName, shortName,
gender, ranking, ace, matches, 0, nationality, nationalityUrl, profileUrl);
System.out.println(player);
mapper.addPlayer(player);
}
sqlSession.commit();
sqlSession.close();
getTeamResult(filePath);
}
/**
* 根据已有的json文件获取比赛数据并写入到数据库中
* @param matchType 比赛类型,Q1-Q4,Day1-Day14,draw等
* @throws IOException
*/
static public void getMatchesResult(String matchType) throws IOException
{
SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession sqlSession = factory.openSession();
Mapper mapper = sqlSession.getMapper(Mapper.class);
String filePath = "src/main/data/schedule/" + matchType + ".json";
Map matchMap = JSON.parseObject(fileToJson(filePath), Map.class);
List<HashMap> matchMapList = (List<HashMap>) matchMap.get("matches");
List<HashMap> roundMapList = (List<HashMap>) matchMap.get("rounds");
List<HashMap> courtMapList = (List<HashMap>) matchMap.get("courts");
List<HashMap> eventMapList = matchMap.get("events") == null ?
Arrays.asList((HashMap) matchMap.get("event")) : (List<HashMap>) matchMap.get("events");
int id = 1;
for (HashMap map : matchMapList)
{
String matchName = getValueByMap((String) map.get("event_uuid"), eventMapList);//获取比赛名字、比赛场地、轮次信息、比赛状态
String matchCourt = getValueByMap((String) map.get("court_id"), courtMapList);
String roundName = getValueByMap((String) map.get("round_id"), roundMapList);
String matchStatus = (String) ((HashMap) map.get("match_status")).get("name");
List<HashMap> teamList = (List<HashMap>) map.get("teams");
HashMap teamAMap = teamList.get(0), teamBMap = teamList.get(1);
String teamAUuid = (String) teamAMap.get("team_id");//获取A、B、胜利队伍的id,比赛开始时间、持续时间
String teamBUuid = (String) teamBMap.get("team_id");
String winnerTeamUuid = teamList.get(0).get("status") != null ? teamAUuid : teamBUuid;
String actualStartTime = (String) map.get("actual_start_time");
String duration = (String) map.get("duration");
List<HashMap> scoresAMap = (List<HashMap>) teamAMap.get("score");//获取A、B队分数
List<HashMap> scoresBMap = (List<HashMap>) teamBMap.get("score");
String scoresA = "", scoresB = "";
for (int j = 0; j < scoresAMap.size(); j++)
{
HashMap gameA = scoresAMap.get(j);
HashMap gameB = scoresBMap.get(j);
scoresA = scoresA + gameA.get("game") + "|";
scoresB = scoresB + gameB.get("game") + "|";
}
mapper.addMatch(new Match(id++, matchName, matchStatus, matchCourt, matchType, actualStartTime,
duration, teamAUuid, teamBUuid, winnerTeamUuid, scoresA, scoresB, roundName));
}
sqlSession.commit();
sqlSession.close();
}
/**
* 根据已有的json文件获取组队数据并写入到数据库中
* @param filePath
* @throws IOException
*/
public static void getTeamResult(String filePath) throws IOException
{
SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession sqlSession = factory.openSession();
Mapper mapper = sqlSession.getMapper(Mapper.class);
String json = fileToJson(filePath);
int id = 1;
Map teamMap = JSON.parseObject(json, Map.class);
List<HashMap> teamMapList = (List<HashMap>) teamMap.get("teams");
for (HashMap map : teamMapList)
{
String teamUuid = (String) map.get("uuid");
String seedString = map.get("seed") != null && !map.get("seed").equals("")? (String) map.get("seed") : "0";
Integer seed = map.get("seed") != null ? Integer.parseInt(seedString) : 0;
ArrayList<String> teamPlayerList = (ArrayList<String>) (map.get("players"));
for (String playerUuid : teamPlayerList)
{
mapper.addTeamRecord(new TeamRecord(id++, teamUuid, playerUuid, seed));
if(teamPlayerList.size() == 1)mapper.updatePlayerSeed(playerUuid, seed);
}
}
sqlSession.commit();
sqlSession.close();
}
/**
* match是用于数据库数据写入用的,传给前端的数据需要转换为AOMatch来实现数据的封装
* @param match
*/
public AOMatch(Match match)
{
this.matchName = match.getMatchName();
this.matchType = match.getMatchType();
this.matchStage = match.getRoundName();
this.matchLocation = match.getMatchCourt();
this.duration = match.getDuration();
this.winner = match.getWinnerTeamUuid().equals(match.getTeamAUuid()) ? 1 : 0;
this.scoresA = new ArrayList<>();
this.scoresB = new ArrayList<>();
this.teamA = new ArrayList<>();
this.teamB = new ArrayList<>();
String[] resA = match.getScoresA().split("\\|");
for (String str : resA)
{
if(str.matches("-?[0-9]+(\\\\.[0-9]+)?"))
{
this.scoresA.add(Integer.parseInt(str));
}
}
String[] resB = match.getScoresB().split("\\|");
for (String str : resB)
{
if(str.matches("-?[0-9]+(\\\\.[0-9]+)?"))
{
this.scoresB.add(Integer.parseInt(str));
}
}
SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession sqlSession = factory.openSession();
Mapper mapper = sqlSession.getMapper(Mapper.class);
teamA = mapper.selectPlayersByTeam(match.getTeamAUuid());
teamB = mapper.selectPlayersByTeam(match.getTeamBUuid());
sqlSession.close();
}
/**
* 根据参数值返回选手数据
* @param gender,值为M表示返回男性,值F表示返回女性,默认按ranking排序
* @param seed,true表示按seed排序
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
resp.setHeader("Access-Control-Allow-Origin", "*");
resp.setHeader("Access-Control-Allow-Methods", "*");
String gender = req.getParameter("gender");
String seed = req.getParameter("seed");
SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession sqlSession = factory.openSession();
Mapper mapper = sqlSession.getMapper(Mapper.class);
List<Player> players = new ArrayList<>();
List<Player> res = new ArrayList<>();
if (gender == null || gender.length() == 0)
players = mapper.selectPlayerAll();
else if (gender.equals("M"))
{
if(seed != null && seed.equals("true"))
players = mapper.selectMalePlayersOrderedBySeeds();
else
players = mapper.selectMalePlayersOrderedByRanking();
}
else if (gender.equals("F"))
{
if(seed != null && seed.equals("true"))
players = mapper.selectFemalePlayersOrderedBySeeds();
else
players = mapper.selectFemalePlayersOrderedByRanking();
}
sqlSession.close();
if(seed != null && seed.equals("true"))
{
for(int i=0; res.size() < 20 && i <players.size() ; i++)
{
if(res.size() == 0)
{
res.add(players.get(i));
continue;
}
if(res.get(res.size()-1).getSeeds() != players.get(i).getSeeds())
res.add(players.get(i));
}
}
else
{
for(int i=0 ; i<50; i++)
res.add(players.get(i));
}
String jsonString = JSON.toJSONString(res);
resp.getWriter().write(jsonString);
}
/**
* 根据参数值返回比赛数据
* @param matchType 可能取值为Q1-Q4,0116-0129,draws
* @param roundName 表示轮次
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
resp.setHeader("Access-Control-Allow-Origin", "*");
resp.setHeader("Access-Control-Allow-Methods", "*");
SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession sqlSession = factory.openSession();
Mapper mapper = sqlSession.getMapper(Mapper.class);
String matchType = req.getParameter("matchType");
String roundName = req.getParameter("roundName");
ArrayList<Match> matchArrayList = mapper.selectMatchesByCondition(matchType, roundName);
HashMap<String, ArrayList<AOMatch>> hashMap = new HashMap<>();
for(Match match : matchArrayList)
{
if(hashMap.containsKey(match.getMatchCourt()))
{
hashMap.get(match.getMatchCourt()).add(new AOMatch(match));
}
else
{
hashMap.put(match.getMatchCourt(), new ArrayList<>());
}
}
ArrayList<HashMap> hashMapArrayList = new ArrayList<>();//根据前端的需求改写返回的数据组织结构
for(String key: hashMap.keySet())
{
HashMap<String, Object> stringHashMap = new HashMap<>();
stringHashMap.put("matchLocation", key);
stringHashMap.put("matches",hashMap.get(key));
hashMapArrayList.add(stringHashMap);
}
String jsonString = JSON.toJSONString(hashMapArrayList);
resp.getWriter().write(jsonString);
}
/**
* 根据晋级关系和轮次顺序获取晋级图数据,并返回给前端
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException
{
resp.setHeader("Access-Control-Allow-Origin", "*");
resp.setHeader("Access-Control-Allow-Methods", "*");
SqlSessionFactory factory = SqlSessionFactoryUtil.getSqlSessionFactory();
SqlSession sqlSession = factory.openSession();
Mapper mapper = sqlSession.getMapper(Mapper.class);
Match finalMatch = mapper.selectDrawsMatchByCondition("", MyUtil.rounds.get(0));
ArrayList<ArrayList<Match>> matchArrayLists = new ArrayList<>();
ArrayList<ArrayList<AOMatch>> aoMatchArrayLists = new ArrayList<>();
matchArrayLists.add(new ArrayList<>());
aoMatchArrayLists.add(new ArrayList<>());
matchArrayLists.get(0).add(finalMatch);
aoMatchArrayLists.get(0).add(new AOMatch(finalMatch));
//根据晋级关系和轮次顺序获取晋级赛图数据
int roundCnt= 0;
while(roundCnt < MyUtil.rounds.size() - 1)
{
matchArrayLists.add(new ArrayList<>());
aoMatchArrayLists.add(new ArrayList<>());
for(Match match : matchArrayLists.get(roundCnt))
{
String teamAuuid = match.getTeamAUuid();
String teamBuuid = match.getTeamBUuid();
Match match1 = mapper.selectDrawsMatchByCondition(teamAuuid, MyUtil.rounds.get(roundCnt+1));
Match match2 = mapper.selectDrawsMatchByCondition(teamBuuid, MyUtil.rounds.get(roundCnt+1));
matchArrayLists.get(roundCnt+1).add(match1);
matchArrayLists.get(roundCnt+1).add(match2);
aoMatchArrayLists.get(roundCnt+1).add(new AOMatch(match1));
aoMatchArrayLists.get(roundCnt+1).add(new AOMatch(match2));
}
roundCnt++;
}
Collections.reverse(aoMatchArrayLists);
String jsonString = JSON.toJSONString(aoMatchArrayLists);
resp.getWriter().write(jsonString);
}
222000202同学对222000212队友的评价: hzt同学开发项目时时积极负责,能够及时完成任务,基本实现了所有项目需求。遇到问题时都会及时解决,如果遇到了解决不了的问题也会和我交流讨论,如果有需求变化也会及时和我说。我指出他的一些问题他也会及时改正,提出的建议也会虚心接受,进步速度很快。虽然这次作业的工作量很大,但是他也没有抱怨。希望他能够通过这次作业能力有所提升,继续打磨自己的编码水平。期待与他的下次合作。
222000212同学对222000202队友的评价: 此次解决过程中,css同学发挥了相对关键的作用。在过程中,他会经常性对我的前端设计提出正确性的建议,在不懂或不会的地方也会提供我思路,我们也经常进行交流,发现他对待作业的态度十分认真,对于一些细节上的实现也会严格对待,争取把结对作业做到最好,我十分庆幸此次作业与他合作,他真的帮助我许多。最后还是那句话,这个结对,没有他就不行了呀。