结对第二次作业——编程实现
| 这个作业属于哪个课程 | 2401_CS_SE_FZU |
|---|---|
| 这个作业要求在哪里 | 结对第二次作业——编程实现 |
| 结对学号 | 222200223,222200210 |
| 这个作业的目标 | 基于 Web 技术实现原型中的功能 |
| 其他参考文献 | 《构建之法》 |
目录
- 1.仓库链接和代码规范链接
- 1.1仓库链接
- 1.2代码规范链接
- 2.PSP表格
- 3.部署地址
- 4.成品展示
- 4.1导航栏
- 4.2主页
- 4.3奖牌榜
- 4.4每日赛程
- 4.5赛程详情
- 4.6对阵表
- 4.7了解更多
- 5.结对讨论过程
- 6.设计实现过程
- 6.1功能结构图
- 6.2分析与设计过程
- 6.2.1分析阶段
- 6.2.2设计阶段
- 6.3实现过程中的问题与解决方式
- 7.关键代码与思路说明
- 7.1数据获取关键代码:
- 7.2赛程关键代码
- 7.3详细赛况关键代码
- 8.心路历程和收获
- 9.评价结对队友
1.仓库链接和代码规范链接
1.1仓库链接
1.2代码规范链接
2.PSP表格
| PSP | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 30 | 30 |
| • Estimate | • 估计这个任务需要多少时间 | 30 | 30 |
| Development | 开发 | 1300 | 1610 |
| • Analysis | • 需求分析(包括学习新技术) | 300 | 350 |
| • Design Spec | • 生成设计文档 | 50 | 50 |
| • Design Review | • 设计复审 | 30 | 20 |
| • Coding Standard | • 代码规范(为目前的开发制定合适的规范) | 30 | 60 |
| • Design | • 具体设计 | 300 | 400 |
| • Coding | • 具体编码 | 400 | 720 |
| • Code Review | • 代码复审 | 30 | 60 |
| • Test | • 测试(自我测试,修改代码,提交修改) | 150 | 200 |
| Reporting | 报告 | 110 | 135 |
| • Test Report | • 测试报告 | 40 | 60 |
| • Size Measurement | • 计算工作量 | 30 | 15 |
| • Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 40 | 60 |
| 合计 | 1440 | 2025 |
3.部署地址
4.成品展示
4.1导航栏
附加功能导航栏:每个页面顶部都有设置导航栏,能够通过导航栏前往首页,奖牌榜页,赛程页面和了解更多页面。

4.2主页
主页提供轮播图来让用户观看精彩赛事图片

4.3奖牌榜
奖牌榜排名显示

4.4每日赛程
展示每一天的赛事,显示比赛类型(足球、七人制橄榄球、手球等),比赛时间,比赛项目,参赛国家和比赛比分,且获胜国家加粗显示
支持通过切换日期查看不同的赛程

4.5赛程详情
支持点击查看详细赛程信息

4.6对阵表
比赛晋级图是一种直观的展示比赛进程和结果的工具,它以图表的形式呈现了参赛在各个阶段的表现。
鼠标移动到某一场比赛需要高亮或显示边框提示。

4.7了解更多
介绍巴黎奥林匹克运动会的举办背景,通过丰富的图文使平台更具吸引力,引起人们对巴黎奥林匹克运动会的兴趣。

5.结对讨论过程




6.设计实现过程
6.1功能结构图

6.2分析与设计过程
6.2.1分析阶段
了解完本次作业要求后,通过分析可知本次作业主要展示2024巴黎奥运会的相关信息,包括奖牌榜、每日赛程和详细赛程,并且数据需要各自进行爬取。因此,我们决定使用后端进行对数据的爬取,运用JSP来处理大量的JSON数据文件,并动态加载不同日期或赛事的详细信息。
6.2.2设计阶段
设计思路:
- 首页:精彩画面轮播图。
- 奖牌榜:展示各个国家的奖牌排名。
- 每日赛程:显示所有日期的对应赛事,可通过选择日期跳转到相应位置。
- 详细赛况:每日赛程卡片支持点击查看详细赛况,展示比赛的成绩,本场比赛参赛国家等。
- 对阵表:以图表形式直观呈现各足球队伍的晋级路径和比赛结果。
扩展功能:
- 导航栏:每个页面顶部都有设置导航栏,能够通过导航栏前往首页,奖牌榜页,赛程页面和了解更多页面。
- 了解更多: 介绍一些官网的新闻和一些比赛视频。
6.3实现过程中的问题与解决方式
问题一:动态读取其他网页的数据不稳定并且耗时较长
解决方式:直接用后端将数据爬取成json文件,进行本地读取。
7.关键代码与思路说明
7.1数据获取关键代码:
- URL构建:根据给定的日期构建API请求URL。
- HTTP请求:使用HttpClient发送GET请求到指定URL。
- 响应处理:检查HTTP响应状态码,如果不是200,则抛出异常。
- 数据解析:如果请求成功,解析JSON响应数据。
public static void main(String[] args) {
String startDate = "2024-07-24";
String endDate = "2024-08-11";
LocalDate start = LocalDate.parse(startDate);
LocalDate end = LocalDate.parse(endDate);
List<Map<String, Object>> allResults = new ArrayList<>();
for (LocalDate date = start; !date.isAfter(end); date = date.plusDays(1)) {
try {
List<Map<String, Object>> dailyResults = fetchScheduleDataWithRetries(date.toString());
allResults.addAll(dailyResults);
} catch (Exception e) {
System.err.println("Error fetching data for date " + date + ": " + e.getMessage());
}
}
allResults.sort((map1, map2) -> map1.get("startDate").toString().compareTo(map2.get("startDate").toString()));
allResults.forEach(System.out::println);
}
public static List<Map<String, Object>> fetchScheduleData(String date) throws Exception {
String urlString = "https://sph-s-api.olympics.com/summer/schedules/api/CHI/schedule/day/" + date;
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(urlString))
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException("Failed to fetch data: HTTP error code " + response.statusCode());
}
return parseJsonData(response.body());
}
7.2赛程关键代码
这段代码是一个用于显示奥运会赛程的网页应用程序的片段。它使用了JSP(JavaServer Pages)技术来动态生成网页内容。以下是代码的详细思路:
日期选择器表单:用户可以通过表单选择日期来查看特定日期的奥运会赛程。
input元素用于选择日期,readonly属性表示用户不能直接输入日期,只能通过选择器选择。- 提交按钮用于提交所选日期。
后台逻辑(JSP脚本):
- 获取用户选择的日期:使用
request.getParameter("selectedDate")获取用户选择的日期参数。如果用户没有选择日期,默认设置为 "2024-07-24"。 - 构建JSON文件路径:根据所选日期构建对应的JSON文件路径,假设每个日期都有一个对应的JSON文件存储该日的赛事信息。
- 读取JSON文件:使用
JSONParser解析JSON文件内容,将赛事信息存储在JSONArray对象中。如果文件存在且解析成功,赛事信息将被加载到events数组中。
- 获取用户选择的日期:使用
前端展示(JSTL标签):
- 使用
<c:forEach>标签迭代events数组中的每个事件。 - 每个事件的信息被展示为一个链接,点击后可以查看该事件的详细信息。
- 显示赛事时间、项目名称和单位名称。
- 显示参赛者信息,包括国旗、参赛者名称和分数。分数较高的一方名称以粗体显示。
- 使用
<div class="content">
<div class="container">
<h1>奥运赛程</h1>
<!-- 日期选择器 -->
<form method="get">
<label for="datepicker">选择日期:</label>
<input type="text" id="datepicker" name="selectedDate" readonly />
<button type="submit">查看赛程</button>
</form>
<%
String selectedDate = request.getParameter("selectedDate");
if (selectedDate == null || selectedDate.isEmpty()) {
selectedDate = "2024-07-24"; // 默认日期
}
// 构建JSON文件路径
String filePath = application.getRealPath("/data/" + selectedDate + ".json");
File jsonFile = new File(filePath);
JSONArray events = new JSONArray();
if (jsonFile.exists()) {
JSONParser parser = new JSONParser();
try (BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(jsonFile), "UTF-8"))) {
Object obj = parser.parse(reader);
events = (JSONArray) obj;
} catch (Exception e) {
e.printStackTrace();
}
}
pageContext.setAttribute("events", events);
%>
<!-- 使用 JSTL 标签来迭代事件 -->
<c:forEach var="event" items="${events}">
<a href="detail.jsp?eventId=${event.id}" style="text-decoration:none;color:black;">
<div class="event">
<div class="time">${event.startDate.substring(11,16)}</div>
<div class="sport">
${event.disciplineName} - ${event.eventUnitName}
</div>
<!-- 显示竞争者 -->
<c:if test="${not empty event.competitor1Name}">
<div class="team">
<img src="https://gstatic.olympics.com/s1/t_original/static/noc/oly/3x2/180x120/${event.competitor1Noc}.png" alt="${event.competitor1Noc} flag" class="flag">
<span class="team-name" style="${event.mark1 > event.mark2 ? 'font-weight:bold;' : ''}">
${event.competitor1Name}
</span>
<div class="score-container">
<span class="score">${event.mark1}</span>
</div>
</div>
</c:if>
<c:if test="${not empty event.competitor2Name}">
<div class="team">
<img src="https://gstatic.olympics.com/s1/t_original/static/noc/oly/3x2/180x120/${event.competitor2Noc}.png" alt="${event.competitor2Noc} flag" class="flag">
<span class="team-name" style="${event.mark2 > event.mark1 ? 'font-weight:bold;' : ''}">
${event.competitor2Name}
</span>
<div class="score-container">
<span class="score">${event.mark2}</span>
</div>
</div>
</c:if>
</div>
</a>
</c:forEach>
</div>
</div>
7.3详细赛况关键代码
这段JavaScript代码用于在详细赛况上动态显示和分页展示比赛信息。它提供了一个交互式界面,让用户能够查看比赛详情并通过分页按钮浏览不同的比赛页。以下是代码的详细介绍:
数据初始化:
matches:包含比赛信息的数组,由服务器端通过gson.toJson(matches)转换为JSON格式并嵌入到JavaScript中。currentPage和itemsPerPage:用于控制分页逻辑,分别表示当前页码和每页显示的比赛数量。
函数定义:
**
renderMatches()**:- 清空现有的比赛容器内容。
- 根据
currentPage和itemsPerPage计算当前页应显示的比赛范围。 - 遍历当前页的比赛数据,生成HTML元素并插入到页面中。
- 每个比赛包括事件名称、参赛者信息(国旗、名字、得分)和比赛时间。
- 为每个比赛卡片添加点击事件监听器,以实现高亮显示效果。
**
updatePaginationButtons()**:- 更新分页按钮状态,使“上一页”按钮在第一页时禁用,“下一页”按钮在最后一页时禁用。
**
prevPage()和nextPage()**:- 分别用于切换到上一页和下一页,并重新渲染比赛信息。
**
highlightButton(button)**:- 用于高亮显示被点击的导航按钮,移除其他按钮的选中状态。
**
highlightMatch(matchDiv)**:- 用于高亮显示被点击的比赛卡片,移除其他卡片的选中状态。
事件绑定:
- 在页面加载完成后,调用
renderMatches()函数以初始化比赛展示。 - 默认高亮显示第一个导航按钮。
- 在页面加载完成后,调用
<script>
var matches = <%= gson.toJson(matches) %>;
var currentPage = 0;
var itemsPerPage = 3;
function renderMatches() {
var container = document.getElementById('matchContainer');
container.innerHTML = '';
var start = currentPage * itemsPerPage;
var end = Math.min(start + itemsPerPage, matches.length);
for (var i = start; i < end; i++) {
var match = matches[i];
var competitorsHtml = match.competitors.map(function(c) {
var flagUrl = "https://gstatic.olympics.com/s1/t_original/static/noc/oly/3x2/180x120/" + c.noc + ".png";
return '<div style="display:flex; align-items:center; justify-content:space-between;">' +
'<div><img src="' + flagUrl + '" alt="' + c.noc + ' Flag" style="height:20px; margin-right:5px;"> ' +
c.name + '</div><div>' + c.mark + '</div></div>';
}).join('');
var matchDiv = document.createElement('div');
matchDiv.className = 'match';
matchDiv.innerHTML = '<h3>' + match.eventUnitName + ', 比赛 ' + match.order + '</h3>' +
competitorsHtml +
'<p style="display:flex; justify-content:space-between;">' +
'<span>' + new Date(match.startDate).toLocaleString('zh-CN', { month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' }) +
'</span><span>已结束</span></p>';
// 添加点击事件监听器以实现高亮效果
matchDiv.addEventListener('click', function() {
highlightMatch(this);
});
container.appendChild(matchDiv);
}
updatePaginationButtons();
}
function updatePaginationButtons() {
var prevButton = document.querySelector('.pagination-buttons button:first-child');
var nextButton = document.querySelector('.pagination-buttons button:last-child');
prevButton.disabled = currentPage === 0;
nextButton.disabled = (currentPage + 1) * itemsPerPage >= matches.length;
}
function prevPage() {
if (currentPage > 0) {
currentPage--;
renderMatches();
}
}
function nextPage() {
if ((currentPage + 1) * itemsPerPage < matches.length) {
currentPage++;
renderMatches();
}
}
window.onload = function() {
renderMatches();
// 默认选中第一个按钮
var firstButton = document.querySelector('.nav-buttons .button');
highlightButton(firstButton);
};
function highlightButton(button) {
// 移除所有按钮的 'selected' 类
var buttons = document.getElementsByClassName('button');
for (var i = 0; i < buttons.length; i++) {
buttons[i].classList.remove('selected');
}
// 为点击的按钮添加 'selected' 类
button.classList.add('selected');
}
function highlightMatch(matchDiv) {
// 移除所有比赛卡片的 'selected' 类
var matches = document.getElementsByClassName('match');
for (var i = 0; i < matches.length; i++) {
matches[i].classList.remove('selected');
}
// 为点击的比赛卡片添加 'selected' 类
matchDiv.classList.add('selected');
}
</script>
8.心路历程和收获
222200223徐玮辰:
通过这个项目,我对前端需求的理解更加深入,这使我能够为队友提供更清晰、更易用的数据结构和接口。通过与队友的紧密合作,我也更加重视代码质量和可维护性,我们共同审查和优化代码,确保系统的稳定性和性能。最重要的是,我体验到了团队合作的价值和乐趣。与优秀的前端开发人员一起工作,不仅让我在技术上有所提升,也让我学会了如何更好地倾听、沟通和协作。这种团队合作的经验将在我未来的软件开发项目中发挥重要作用。
222200210苏臻炜:
在这次项目中,我最大的收获是团队合作带来的成长和自信。本次由我来进行jsp代码编写,队友进行数据的获取,让我拥有一次很好的jsp网页设计经验。这种经验让我对未来的项目挑战充满信心,我相信团队合作的力量能够带来更多的成功。同时,我也意识到软件工程是一条需要不断学习和改进的道路,每一次的实践都是一次宝贵的经验,让我能够不断反思和提升自己。通过这次实践,我对自己的能力和潜力有了更深的理解,并对未来充满期待。
9.评价结对队友
222200223徐玮辰:
队友富有远见和谋略,并且善于分配任务,可以成为一个可靠的小组或团队的核心人员。并且他的前端技术水平过硬,在项目中,他总是能够高效地调用我提供的数据,实现前端页面的创作。在他的帮助下我对前端技术有了更深刻的理解,受益匪浅。
222200210苏臻炜:
队友在团队合作中展现了出色的精神,始终保持认真负责的态度,时间观念强,所有任务都在规划下有序地完成。在项目中,队友的数据模块设计和实现为整个项目奠定了坚实的基础,他提供的清晰数据结构使我能够轻松理解和实现前端页面的功能。同时,队友对代码性能优化的关注给我留下了深刻的印象,我们共同克服了技术难题,取得了令人满意的成果。
相关推荐
弱电网下光伏并网逆变器序阻抗建模仿真复现扫频法【序阻抗判断稳定性】
内容概要:本文聚焦于弱电网条件下光伏并网逆变器的序阻抗建模与稳定性分析,系统阐述了基于扫频法的阻抗特性仿真与复现方法。通过构建正负序阻抗模型,深入剖析逆变器在弱电网环境中的动态响应特性,结合锁相环、电流环等关键控制环节对系统阻抗的影响机制,采用序阻抗稳定性判据评估多机并网或复杂电网条件下的系统稳定裕度。研究在Simulink平台中实现激励信号注入、频率响应采集与阻抗曲线绘制,为高比例新能源接入背景下并网系统的稳定性分析提供了可靠的仿真手段与理论支撑,尤其适用于SCI级别论文成果的复现与拓展验证。; 适合人群:电力电子、新能源并网技术及相关领域的硕士/博士研究生、科研人员,以及从事光伏逆变器、微电网稳定控制开发的工程技术人员。; 使用场景及目标:①掌握扫频法在电力电子装置阻抗建模中的具体实施流程;②理解并应用基于序阻抗的稳定性判据进行系统稳定边界分析;③用于高水平学术论文(如SCI期刊)中阻抗建模与稳定性分析部分的仿真复现与方法验证; 阅读建议:建议读者结合文中所述方法与提供的参考文献,自主搭建Simulink仿真模型,逐步完成扰动信号设计、数据采集、傅里叶分析及阻抗拟合全过程,深入探究控制参数变化对系统阻抗特性和稳定性的具体影响,强化理论与实践的融合能力。
三相并网逆变器虚拟阻抗+统一有源阻尼策略SVPWM+SPWM调制仿真
内容概要:本文档系统性地介绍了三相并网逆变器的核心控制技术及其在复杂电网环境下的仿真应用,重点涵盖虚拟阻抗与统一有源阻尼策略在SVPWM和SPWM调制方式下的实现方法,旨在提升逆变器的稳定性与电能质量。内容包括无功功率扰动孤岛检测、中点电位平衡控制、低电压穿越(LVRT)、模型预测控制(MPC)、正负序分离、电网前馈控制等关键技术,并扩展至风储联合调频、微电网下垂控制、虚拟同步发电机(VSG)、构网型逆变器等多种典型电力系统应用场景。所有技术均配有基于Simulink/Matlab平台的完整仿真模型、参考文献及说明文档,强调理论分析与仿真实践的深度融合,突出科研中“借力”与创新思维的重要性。; 适合人群:电气工程、自动化、新能源等相关专业的研究生、科研人员及从事电力电子与可再生能源系统开发的工程师;具备MATLAB/Simulink仿真基础和电力系统专业知识的技术人员。; 使用场景及目标:①开展三相并网逆变器控制策略的研究与优化设计;②复现高水平学术论文中的控制算法;③完成毕业课题、科研项目或工程仿真验证;④掌握虚拟阻抗、有源阻尼、SVPWM/SPWM调制、MPC、VSG等核心技术的建模与实现方法;⑤支撑微电网、构网型变流器等前沿方向的科研攻关。; 阅读建议:建议按照资源目录结构化学习,优先选择与自身研究方向契合的内容模块,结合提供的仿真模型、参考文献和说明材料进行实操演练,注重从理论推导到仿真实现的全过程理解,充分利用共享网盘资源深化技术掌握,提升科研效率与创新能力。
chromedriver-win32-159.0.8133.0(Canary).zip
chromedriver-win32-159.0.8133.0(Canary).zip
计算机“101计划”《人工智能引论》教学大纲+课件+实训案例
计算机“101计划”《人工智能引论》教学大纲+课件+实训案例
语音输入法离线语音输入转文字工具2.0支持双档本地识别模型,中英混说精准转写,纯离线运行保护隐私,让打字更高效.zip
大家好,我是大飞哥。日常打字时,频繁切换输入法、断网无法语音转写、或担心语音数据被传至云端,是许多办公族和内容创作者的共同痛点。这款离线语音输入工具 ,正是为此量身打造的 Windows 桌面语音辅助利器。它的核心使命就是按住快捷键说话,松开文字自动上屏,全程本地离线识别,让您在任何可输入文字的窗口内都能实现高效、私密的语音输入,彻底告别网络依赖与隐私焦虑。 在核心功能上,软件内置了两档本地语音识别模型,通过主界面下拉框即可随时切换。默认的“离线·标准”模式响应极快,支持中英混说且自带标点,非常适合日常聊天与文档撰写;而“离线·精准”模式则对纯中文、方言口音及长段落口述的识别准确度更高。更贴心的是,它具备实时预览与一键取消机制,说话过程中若发现说错,按下 Esc 即可取消,一个字都不会误输入;若目标窗口不支持直接写入,文字会自动存入剪贴板,方便您按 Ctrl+V 粘贴,确保每次发声都不白费。 这款工具在具体场景中的表现十分亮眼。对于办公白领,在填写表格、撰写邮件或使用微信、QQ 沟通时,无需频繁切换窗口,按住右键说话即可快速完成信息录入;对于程序员与文字工作者,在代码编辑器或文档中口述注释与段落,能显著提升创作效率;对于经常出差的商务人士,在飞机、高铁等断网环境下,它依然能稳定工作,不经过任何服务器,真正做到了“说了什么只有自己知道”,私密性极佳。 使用体验方面,软件将极简操作贯彻到底。解压后双击 大飞哥语音输入,右下角托盘出现蓝色话筒图标即代表准备就绪。用户只需将光标点进目标输入框,按住右 Alt说话,说完松开,文字便会自动写入。主界面提供了设置快捷键与开机自动启动选项,方便用户按习惯自定义组合键;关闭主窗口并不会退出程序,而是缩至托盘持续待命,彻底退出只需右键托盘或点击主界面按钮,逻辑清晰,零门槛上手。


