Browse Source

修复项目结构:移除嵌套的 project/project 目录

范馨遥 3 weeks ago
parent
commit
7ded009901
  1. 0
      project/classes/application.properties
  2. 0
      project/classes/schema.sql
  3. 0
      project/classes/templates/analysis.html
  4. 0
      project/classes/templates/course-list.html
  5. 0
      project/classes/templates/error.html
  6. 0
      project/classes/templates/index.html
  7. 0
      project/courses.csv
  8. 0
      project/courses.json
  9. 0
      project/main/java/com/example/CourseAnalysis.java
  10. 0
      project/main/java/com/example/CourseSystemTest.java
  11. 0
      project/main/java/com/example/DatabaseUtil.java
  12. 0
      project/main/java/com/example/ExceptionDemo.java
  13. 0
      project/main/java/com/example/ExceptionTest.java
  14. 0
      project/main/java/com/example/ExportTest.java
  15. 0
      project/main/java/com/example/HnuCourseSystem.java
  16. 0
      project/main/java/com/example/Pair.java
  17. 0
      project/main/java/com/example/controller/CourseController.java
  18. 0
      project/main/java/com/example/crawler/CrawlerContext.java
  19. 0
      project/main/java/com/example/crawler/CrawlerService.java
  20. 0
      project/main/java/com/example/crawler/strategy/HnuParseStrategy.java
  21. 0
      project/main/java/com/example/crawler/strategy/ParseStrategy.java
  22. 0
      project/main/java/com/example/crawler/strategy/SduParseStrategy.java
  23. 0
      project/main/java/com/example/entity/Course.java
  24. 0
      project/main/java/com/example/exception/BizException.java
  25. 0
      project/main/java/com/example/exception/CrawlerException.java
  26. 0
      project/main/java/com/example/exception/NetworkException.java
  27. 0
      project/main/java/com/example/exception/ParseException.java
  28. 0
      project/main/java/com/example/export/CsvExporter.java
  29. 0
      project/main/java/com/example/export/ExportService.java
  30. 0
      project/main/java/com/example/export/Exporter.java
  31. 0
      project/main/java/com/example/export/JsonExporter.java
  32. 0
      project/main/java/com/example/repository/CourseRepository.java
  33. 0
      project/main/java/com/example/service/CourseService.java
  34. 0
      project/main/java/com/example/view/CourseView.java
  35. 33
      project/main/resources/application.properties
  36. 31
      project/main/resources/schema.sql
  37. 328
      project/main/resources/templates/analysis.html
  38. 169
      project/main/resources/templates/course-list.html
  39. 24
      project/main/resources/templates/error.html
  40. 318
      project/main/resources/templates/index.html
  41. 21
      project/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst
  42. 21
      project/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst
  43. 8
      project/run.bat

0
project/src/main/resources/application.properties → project/classes/application.properties

0
project/src/main/resources/schema.sql → project/classes/schema.sql

0
project/src/main/resources/templates/analysis.html → project/classes/templates/analysis.html

0
project/src/main/resources/templates/course-list.html → project/classes/templates/course-list.html

0
project/src/main/resources/templates/error.html → project/classes/templates/error.html

0
project/src/main/resources/templates/index.html → project/classes/templates/index.html

0
project/output/courses.csv → project/courses.csv

1 id courseCode courseName credit teacher department capacity enrolled classTime classRoom courseType semester createTime
2 1 CS101 计算机科学导论 3.0 李教授 计算机学院 100 95 必修课 2024-2025-1
3 2 MATH101 高等数学 5.0 王教授 数学学院 120 110 必修课 2024-2025-1
4 3 ENG101 大学英语 2.0 张教授 外国语学院 150 120 必修课 2024-2025-1

0
project/output/courses.json → project/courses.json

0
project/src/main/java/com/example/CourseAnalysis.java → project/main/java/com/example/CourseAnalysis.java

0
project/src/main/java/com/example/CourseSystemTest.java → project/main/java/com/example/CourseSystemTest.java

0
project/src/main/java/com/example/DatabaseUtil.java → project/main/java/com/example/DatabaseUtil.java

0
project/src/main/java/com/example/ExceptionDemo.java → project/main/java/com/example/ExceptionDemo.java

0
project/src/main/java/com/example/ExceptionTest.java → project/main/java/com/example/ExceptionTest.java

0
project/src/main/java/com/example/ExportTest.java → project/main/java/com/example/ExportTest.java

0
project/src/main/java/com/example/HnuCourseSystem.java → project/main/java/com/example/HnuCourseSystem.java

0
project/src/main/java/com/example/Pair.java → project/main/java/com/example/Pair.java

0
project/src/main/java/com/example/controller/CourseController.java → project/main/java/com/example/controller/CourseController.java

0
project/src/main/java/com/example/crawler/CrawlerContext.java → project/main/java/com/example/crawler/CrawlerContext.java

0
project/src/main/java/com/example/crawler/CrawlerService.java → project/main/java/com/example/crawler/CrawlerService.java

0
project/src/main/java/com/example/crawler/strategy/HnuParseStrategy.java → project/main/java/com/example/crawler/strategy/HnuParseStrategy.java

0
project/src/main/java/com/example/crawler/strategy/ParseStrategy.java → project/main/java/com/example/crawler/strategy/ParseStrategy.java

0
project/src/main/java/com/example/crawler/strategy/SduParseStrategy.java → project/main/java/com/example/crawler/strategy/SduParseStrategy.java

0
project/src/main/java/com/example/entity/Course.java → project/main/java/com/example/entity/Course.java

0
project/src/main/java/com/example/exception/BizException.java → project/main/java/com/example/exception/BizException.java

0
project/src/main/java/com/example/exception/CrawlerException.java → project/main/java/com/example/exception/CrawlerException.java

0
project/src/main/java/com/example/exception/NetworkException.java → project/main/java/com/example/exception/NetworkException.java

0
project/src/main/java/com/example/exception/ParseException.java → project/main/java/com/example/exception/ParseException.java

0
project/src/main/java/com/example/export/CsvExporter.java → project/main/java/com/example/export/CsvExporter.java

0
project/src/main/java/com/example/export/ExportService.java → project/main/java/com/example/export/ExportService.java

0
project/src/main/java/com/example/export/Exporter.java → project/main/java/com/example/export/Exporter.java

0
project/src/main/java/com/example/export/JsonExporter.java → project/main/java/com/example/export/JsonExporter.java

0
project/src/main/java/com/example/repository/CourseRepository.java → project/main/java/com/example/repository/CourseRepository.java

0
project/src/main/java/com/example/service/CourseService.java → project/main/java/com/example/service/CourseService.java

0
project/src/main/java/com/example/view/CourseView.java → project/main/java/com/example/view/CourseView.java

33
project/main/resources/application.properties

@ -0,0 +1,33 @@
spring.application.name=hnu-course-analysis
server.port=8084
# SQLite数据库配置
spring.datasource.url=jdbc:sqlite:course.db
spring.datasource.driver-class-name=org.sqlite.JDBC
spring.jpa.database-platform=org.hibernate.community.dialect.SQLiteDialect
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.open-in-view=false
spring.sql.init.mode=always
spring.sql.init.schema-locations=classpath:schema.sql
spring.thymeleaf.cache=false
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
logging.level.root=INFO
logging.level.com.example=DEBUG
# 湖南大学选课系统配置
crawler.hnu.login.url=https://jwxt.hnu.edu.cn/xtgl/login_login.html
crawler.hnu.username=your_username
crawler.hnu.password=your_password
crawler.hnu.course.list.url=https://jwxt.hnu.edu.cn/kbcx/xskbcx_cxXsKb.html
# Selenium配置
selenium.webdriver.chrome.driver.path=C:/chromedriver/chromedriver.exe
selenium.webdriver.headless=false

31
project/main/resources/schema.sql

@ -0,0 +1,31 @@
-- 湖南大学选课系统数据库初始化脚本
-- 创建课程表
CREATE TABLE IF NOT EXISTS courses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
course_code TEXT,
course_name TEXT,
credit REAL,
teacher TEXT,
department TEXT,
capacity INTEGER,
enrolled INTEGER,
class_time TEXT,
class_room TEXT,
course_type TEXT,
semester TEXT,
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- 插入测试数据
INSERT INTO courses (course_code, course_name, credit, teacher, department, capacity, enrolled, class_time, class_room, course_type, semester) VALUES
('CS101', '计算机科学导论', 3.0, '张教授', '计算机科学与技术学院', 100, 85, '周一 1-2节', 'A101', '必修课', '2024-2025-1'),
('CS102', '数据结构', 4.0, '李教授', '计算机科学与技术学院', 80, 70, '周二 3-4节', 'B202', '必修课', '2024-2025-1'),
('CS103', '算法设计', 3.0, '王教授', '计算机科学与技术学院', 60, 55, '周三 5-6节', 'C303', '选修课', '2024-2025-1'),
('MA101', '高等数学', 5.0, '赵教授', '数学学院', 120, 110, '周一 3-4节', 'D404', '必修课', '2024-2025-1'),
('EN101', '大学英语', 3.0, '刘教授', '外国语学院', 100, 90, '周二 1-2节', 'E505', '必修课', '2024-2025-1'),
('PH101', '大学物理', 4.0, '钱教授', '物理学院', 90, 85, '周三 1-2节', 'F606', '必修课', '2024-2025-1'),
('CH101', '大学化学', 3.0, '孙教授', '化学学院', 70, 65, '周四 3-4节', 'G707', '选修课', '2024-2025-1'),
('HI101', '中国近现代史', 2.0, '周教授', '历史学院', 150, 145, '周五 1-2节', 'H808', '必修课', '2024-2025-1'),
('PE101', '体育', 1.0, '吴教授', '体育学院', 50, 50, '周三 7-8节', '体育馆', '必修课', '2024-2025-1'),
('AR101', '艺术鉴赏', 2.0, '郑教授', '艺术学院', 80, 75, '周四 5-6节', '艺术楼', '选修课', '2024-2025-1');

328
project/main/resources/templates/analysis.html

@ -0,0 +1,328 @@
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>数据分析 - 湖南大学选课系统分析</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
background-color: #f8f9fa;
}
.hero {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 40px 0;
margin-bottom: 30px;
}
.card {
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
margin-bottom: 30px;
}
.card-header {
background-color: #667eea;
color: white;
border-radius: 10px 10px 0 0;
}
.btn-primary {
background-color: #667eea;
border-color: #667eea;
}
.btn-primary:hover {
background-color: #5a6fd8;
border-color: #5a6fd8;
}
</style>
</head>
<body>
<!-- 导航栏 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="/">湖南大学选课系统分析</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="/">首页</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/courses">课程列表</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/analysis">数据分析</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- 英雄区 -->
<div class="hero">
<div class="container">
<h1 class="display-4">数据分析</h1>
<p class="lead">深入分析选课系统数据,获取有价值的洞察</p>
</div>
</div>
<!-- 分析图表 -->
<div class="container mb-5">
<!-- 课程类型分布 -->
<div class="card">
<div class="card-header">
<h3>课程类型分布</h3>
</div>
<div class="card-body">
<div id="courseTypeChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
<!-- 院系分布 -->
<div class="card">
<div class="card-header">
<h3>院系课程分布</h3>
</div>
<div class="card-body">
<div id="departmentChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
<!-- 学分分布 -->
<div class="card">
<div class="card-header">
<h3>学分分布</h3>
</div>
<div class="card-body">
<div id="creditChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
<!-- 课程使用率 -->
<div class="card">
<div class="card-header">
<h3>课程容量使用率</h3>
</div>
<div class="card-body">
<div id="usageRateChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
<!-- 院系统计 -->
<div class="card">
<div class="card-header">
<h3>院系统计详情</h3>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-striped">
<thead>
<tr>
<th>院系</th>
<th>课程数</th>
<th>总学分</th>
<th>总容量</th>
<th>总已选</th>
<th>使用率</th>
</tr>
</thead>
<tbody>
<tr th:each="dept : ${departmentStats}">
<td th:text="${dept.key}"></td>
<td th:text="${dept.value.courseCount}"></td>
<td th:text="${dept.value.totalCredits}"></td>
<td th:text="${dept.value.totalCapacity}"></td>
<td th:text="${dept.value.totalEnrolled}"></td>
<td th:text="${#numbers.formatDecimal(dept.value.usageRate, 0, 1)}%"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- 页脚 -->
<footer class="bg-dark text-white py-4">
<div class="container text-center">
<p>&copy; 2024 湖南大学选课系统分析平台</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 初始化课程类型分布图表
fetch('/api/course-type-distribution')
.then(response => response.json())
.then(data => {
const types = Object.keys(data);
const counts = Object.values(data);
const chart = echarts.init(document.getElementById('courseTypeChart'));
chart.setOption({
title: {
text: '课程类型分布',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [{
name: '课程类型',
type: 'pie',
radius: '60%',
data: types.map((type, index) => ({
name: type,
value: counts[index]
})),
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
});
});
// 初始化院系分布图表
fetch('/api/department-distribution')
.then(response => response.json())
.then(data => {
const departments = Object.keys(data);
const counts = Object.values(data);
const chart = echarts.init(document.getElementById('departmentChart'));
chart.setOption({
title: {
text: '院系课程分布',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [{
name: '院系',
type: 'pie',
radius: '60%',
data: departments.map((dept, index) => ({
name: dept,
value: counts[index]
})),
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
});
});
// 初始化学分分布图表
fetch('/api/credit-distribution')
.then(response => response.json())
.then(data => {
const credits = Object.keys(data).map(Number).sort((a, b) => a - b);
const counts = credits.map(credit => data[credit]);
const chart = echarts.init(document.getElementById('creditChart'));
chart.setOption({
title: {
text: '学分分布',
left: 'center'
},
tooltip: {
trigger: 'axis'
},
xAxis: {
type: 'category',
data: credits.map(c => c + '学分'),
name: '学分'
},
yAxis: {
type: 'value',
name: '课程数'
},
series: [{
data: counts,
type: 'bar',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{offset: 0, color: '#667eea'},
{offset: 1, color: '#764ba2'}
])
}
}]
});
});
// 初始化课程使用率图表
fetch('/api/top-courses')
.then(response => response.json())
.then(data => {
const courseNames = data.map(item => item.course_name);
const enrolledCounts = data.map(item => item.enrolled);
const chart = echarts.init(document.getElementById('usageRateChart'));
chart.setOption({
title: {
text: '热门课程使用率',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: courseNames,
axisLabel: {
rotate: 45
}
},
yAxis: {
type: 'value',
name: '已选人数'
},
series: [{
data: enrolledCounts,
type: 'bar',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{offset: 0, color: '#667eea'},
{offset: 1, color: '#764ba2'}
])
}
}]
});
});
// 响应式调整
window.addEventListener('resize', function() {
const charts = ['courseTypeChart', 'departmentChart', 'creditChart', 'usageRateChart'];
charts.forEach(id => {
const chart = echarts.getInstanceByDom(document.getElementById(id));
if (chart) {
chart.resize();
}
});
});
</script>
</body>
</html>

169
project/main/resources/templates/course-list.html

@ -0,0 +1,169 @@
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>课程列表 - 湖南大学选课系统分析</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
background-color: #f8f9fa;
}
.hero {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 40px 0;
margin-bottom: 30px;
}
.card {
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
.table-container {
background: white;
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
padding: 20px;
}
.btn-primary {
background-color: #667eea;
border-color: #667eea;
}
.btn-primary:hover {
background-color: #5a6fd8;
border-color: #5a6fd8;
}
.status-badge {
padding: 5px 10px;
border-radius: 20px;
font-size: 0.8rem;
}
.status-high {
background-color: #f8d7da;
color: #721c24;
}
.status-medium {
background-color: #fff3cd;
color: #856404;
}
.status-low {
background-color: #d4edda;
color: #155724;
}
</style>
</head>
<body>
<!-- 导航栏 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="/">湖南大学选课系统分析</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link" href="/">首页</a>
</li>
<li class="nav-item">
<a class="nav-link active" href="/courses">课程列表</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/analysis">数据分析</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- 英雄区 -->
<div class="hero">
<div class="container">
<h1 class="display-4">课程列表</h1>
<p class="lead">查看所有课程的详细信息</p>
</div>
</div>
<!-- 课程列表 -->
<div class="container mb-5">
<div class="table-container">
<div class="d-flex justify-content-between align-items-center mb-4">
<h2>课程详情</h2>
<button class="btn btn-primary" onclick="crawlData()">
<i class="bi bi-download"></i> 刷新数据
</button>
</div>
<div class="table-responsive">
<table class="table table-striped table-hover">
<thead class="table-dark">
<tr>
<th>课程代码</th>
<th>课程名称</th>
<th>学分</th>
<th>教师</th>
<th>院系</th>
<th>容量</th>
<th>已选</th>
<th>使用率</th>
<th>上课时间</th>
<th>上课地点</th>
<th>课程类型</th>
</tr>
</thead>
<tbody>
<tr th:each="course : ${courses}">
<td th:text="${course.courseCode}"></td>
<td th:text="${course.courseName}"></td>
<td th:text="${course.credit}"></td>
<td th:text="${course.teacher}"></td>
<td th:text="${course.department}"></td>
<td th:text="${course.capacity}"></td>
<td th:text="${course.enrolled}"></td>
<td>
<span th:class="|status-badge ${course.enrolled * 100 / course.capacity > 80 ? 'status-high' : (course.enrolled * 100 / course.capacity > 50 ? 'status-medium' : 'status-low')}">
<span th:text="${#numbers.formatDecimal(course.enrolled * 100 / course.capacity, 0, 1)}%"></span>
</span>
</td>
<td th:text="${course.classTime}"></td>
<td th:text="${course.classRoom}"></td>
<td th:text="${course.courseType}"></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<!-- 页脚 -->
<footer class="bg-dark text-white py-4">
<div class="container text-center">
<p>&copy; 2024 湖南大学选课系统分析平台</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 爬取数据
function crawlData() {
fetch('/crawl', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert(data.message);
window.location.reload();
} else {
alert('爬取失败');
}
})
.catch(error => {
console.error('Error:', error);
alert('爬取失败');
});
}
</script>
</body>
</html>

24
project/main/resources/templates/error.html

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>错误页面</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container mt-5">
<div class="row justify-content-center">
<div class="col-md-6">
<div class="card">
<div class="card-body text-center">
<h1 class="text-danger">500 - 服务器内部错误</h1>
<p class="mt-3">服务器遇到了一个内部错误,请稍后再试。</p>
<a href="/" class="btn btn-primary mt-4">返回首页</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>

318
project/main/resources/templates/index.html

@ -0,0 +1,318 @@
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>湖南大学选课系统分析</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3/dist/echarts.min.js"></script>
<style>
body {
font-family: 'Microsoft YaHei', sans-serif;
background-color: #f8f9fa;
}
.hero {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
padding: 60px 0;
margin-bottom: 30px;
}
.card {
border-radius: 10px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
transition: transform 0.3s ease;
}
.card:hover {
transform: translateY(-5px);
}
.stat-card {
text-align: center;
padding: 20px;
}
.stat-value {
font-size: 2rem;
font-weight: bold;
color: #667eea;
}
.stat-label {
font-size: 1rem;
color: #6c757d;
}
.btn-primary {
background-color: #667eea;
border-color: #667eea;
}
.btn-primary:hover {
background-color: #5a6fd8;
border-color: #5a6fd8;
}
</style>
</head>
<body>
<!-- 导航栏 -->
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container">
<a class="navbar-brand" href="/">湖南大学选课系统分析</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav ms-auto">
<li class="nav-item">
<a class="nav-link active" href="/">首页</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/courses">课程列表</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/analysis">数据分析</a>
</li>
</ul>
</div>
</div>
</nav>
<!-- 英雄区 -->
<div class="hero">
<div class="container">
<h1 class="display-4">湖南大学选课系统数据分析平台</h1>
<p class="lead">实时爬取、分析和可视化展示选课系统数据</p>
<button class="btn btn-light btn-lg" onclick="crawlData()">
<i class="bi bi-download"></i> 爬取最新数据
</button>
</div>
</div>
<!-- 统计卡片 -->
<div class="container mb-5">
<div class="row">
<div class="col-md-3">
<div class="card stat-card">
<div class="card-body">
<div class="stat-value" th:text="${overallStats.totalCourses}"></div>
<div class="stat-label">总课程数</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card">
<div class="card-body">
<div class="stat-value" th:text="${overallStats.totalCredits}"></div>
<div class="stat-label">总学分</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card">
<div class="card-body">
<div class="stat-value" th:text="${overallStats.totalEnrolled}"></div>
<div class="stat-label">总已选人数</div>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card stat-card">
<div class="card-body">
<div class="stat-value" th:text="${#numbers.formatDecimal(overallStats.overallUsageRate, 0, 1)}%">
使用率
</div>
<div class="stat-label">总体使用率</div>
</div>
</div>
</div>
</div>
</div>
<!-- 热门课程 -->
<div class="container mb-5">
<h2 class="text-center mb-4">热门课程排行</h2>
<div class="card">
<div class="card-body">
<div id="topCoursesChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>
<!-- 课程类型分布 -->
<div class="container mb-5">
<h2 class="text-center mb-4">课程类型分布</h2>
<div class="card">
<div class="card-body">
<div id="courseTypeChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>
<!-- 院系分布 -->
<div class="container mb-5">
<h2 class="text-center mb-4">院系课程分布</h2>
<div class="card">
<div class="card-body">
<div id="departmentChart" style="width: 100%; height: 400px;"></div>
</div>
</div>
</div>
<!-- 页脚 -->
<footer class="bg-dark text-white py-4">
<div class="container text-center">
<p>&copy; 2024 湖南大学选课系统分析平台</p>
</div>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
<script>
// 爬取数据
function crawlData() {
fetch('/crawl', {
method: 'POST'
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert(data.message);
window.location.reload();
} else {
alert('爬取失败');
}
})
.catch(error => {
console.error('Error:', error);
alert('爬取失败');
});
}
// 初始化热门课程图表
fetch('/api/top-courses')
.then(response => response.json())
.then(data => {
const courseNames = data.map(item => item.course_name);
const enrolledCounts = data.map(item => item.enrolled);
const chart = echarts.init(document.getElementById('topCoursesChart'));
chart.setOption({
title: {
text: '热门课程排行',
left: 'center'
},
tooltip: {
trigger: 'axis',
axisPointer: {
type: 'shadow'
}
},
xAxis: {
type: 'category',
data: courseNames,
axisLabel: {
rotate: 45
}
},
yAxis: {
type: 'value',
name: '已选人数'
},
series: [{
data: enrolledCounts,
type: 'bar',
itemStyle: {
color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [
{offset: 0, color: '#667eea'},
{offset: 1, color: '#764ba2'}
])
}
}]
});
});
// 初始化课程类型分布图表
fetch('/api/course-type-distribution')
.then(response => response.json())
.then(data => {
const types = Object.keys(data);
const counts = Object.values(data);
const chart = echarts.init(document.getElementById('courseTypeChart'));
chart.setOption({
title: {
text: '课程类型分布',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [{
name: '课程类型',
type: 'pie',
radius: '60%',
data: types.map((type, index) => ({
name: type,
value: counts[index]
})),
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
});
});
// 初始化院系分布图表
fetch('/api/department-distribution')
.then(response => response.json())
.then(data => {
const departments = Object.keys(data);
const counts = Object.values(data);
const chart = echarts.init(document.getElementById('departmentChart'));
chart.setOption({
title: {
text: '院系课程分布',
left: 'center'
},
tooltip: {
trigger: 'item'
},
legend: {
orient: 'vertical',
left: 'left'
},
series: [{
name: '院系',
type: 'pie',
radius: '60%',
data: departments.map((dept, index) => ({
name: dept,
value: counts[index]
})),
emphasis: {
itemStyle: {
shadowBlur: 10,
shadowOffsetX: 0,
shadowColor: 'rgba(0, 0, 0, 0.5)'
}
}
}]
});
});
// 响应式调整
window.addEventListener('resize', function() {
const charts = ['topCoursesChart', 'courseTypeChart', 'departmentChart'];
charts.forEach(id => {
const chart = echarts.getInstanceByDom(document.getElementById(id));
if (chart) {
chart.resize();
}
});
});
</script>
</body>
</html>

21
project/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst

@ -0,0 +1,21 @@
com\example\DatabaseUtil.class
com\example\exception\ParseException.class
com\example\entity\Course.class
com\example\exception\NetworkException.class
com\example\Untitled_2.class
com\example\HnuCourseSystem.class
com\example\CourseAnalysis.class
com\example\ExceptionTest.class
com\example\crawler\CrawlerContext.class
com\example\crawler\strategy\ParseStrategy.class
com\example\crawler\strategy\SduParseStrategy.class
com\example\crawler\CrawlerService.class
com\example\view\CourseView.class
com\example\CourseSystemTest.class
com\example\crawler\strategy\HnuParseStrategy.class
com\example\exception\CrawlerException.class
com\example\service\CourseService.class
com\example\Pair.class
com\example\controller\CourseController.class
com\example\repository\CourseRepository.class
com\example\exception\BizException.class

21
project/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst

@ -0,0 +1,21 @@
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\crawler\strategy\HnuParseStrategy.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\controller\CourseController.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\exception\NetworkException.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\view\CourseView.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\CourseAnalysis.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\crawler\CrawlerService.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\exception\CrawlerException.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\CourseSystemTest.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\ExceptionTest.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\HnuCourseSystem.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\DatabaseUtil.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\Untitled-2.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\exception\BizException.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\crawler\CrawlerContext.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\crawler\strategy\SduParseStrategy.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\repository\CourseRepository.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\service\CourseService.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\crawler\strategy\ParseStrategy.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\exception\ParseException.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\entity\Course.java
C:\Users\范馨遥\.trae-cn\course-analysis\src\main\java\com\example\Pair.java

8
project/run.bat

@ -1,8 +0,0 @@
@echo off
echo 正在编译项目...
javac -d target/classes src/main/java/com/example/entity/Course.java src/main/java/com/example/DatabaseUtil.java src/main/java/com/example/CourseAnalysis.java src/main/java/com/example/HnuCourseSystem.java src/main/java/com/example/CourseSystemTest.java
echo 正在运行测试程序...
java -cp target/classes;C:\Users\范馨遥\.m2\repository\org\xerial\sqlite-jdbc\3.44.1.0\sqlite-jdbc-3.44.1.0.jar com.example.CourseSystemTest
pause
Loading…
Cancel
Save