From b0b70ea5aac11d6961f7cd64b3dc00f4cf8bc291 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=B2=85?= <907037276@qq.com> Date: Thu, 3 Sep 2026 14:58:08 +0800 Subject: [PATCH] feat: persist project study time by student --- ...dentProjectStudyTimeSchemaInitializer.java | 28 ++++++++ .../StudentProjectStudyTimeController.java | 68 +++++++++++++++++++ .../dto/StudentProjectStudyTimeDTO.java | 22 ++++++ ...ProjectStudyTimeSchemaInitializerTest.java | 19 ++++++ 4 files changed, 137 insertions(+) create mode 100644 src/main/java/com/sztzjy/linkCommerce/config/StudentProjectStudyTimeSchemaInitializer.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentProjectStudyTimeController.java create mode 100644 src/main/java/com/sztzjy/linkCommerce/entity/dto/StudentProjectStudyTimeDTO.java create mode 100644 src/test/java/com/sztzjy/linkCommerce/config/StudentProjectStudyTimeSchemaInitializerTest.java diff --git a/src/main/java/com/sztzjy/linkCommerce/config/StudentProjectStudyTimeSchemaInitializer.java b/src/main/java/com/sztzjy/linkCommerce/config/StudentProjectStudyTimeSchemaInitializer.java new file mode 100644 index 0000000..e94af59 --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/config/StudentProjectStudyTimeSchemaInitializer.java @@ -0,0 +1,28 @@ +package com.sztzjy.linkCommerce.config; + +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +public class StudentProjectStudyTimeSchemaInitializer { + private final JdbcTemplate jdbcTemplate; + + public StudentProjectStudyTimeSchemaInitializer(JdbcTemplate jdbcTemplate) { + this.jdbcTemplate = jdbcTemplate; + } + + @PostConstruct + public void initialize() { + jdbcTemplate.execute("CREATE TABLE IF NOT EXISTS student_project_study_time (" + + "student_user_id varchar(64) NOT NULL," + + "teaching_class_id varchar(64) NOT NULL," + + "project_name varchar(128) NOT NULL," + + "study_seconds bigint NOT NULL DEFAULT 0," + + "create_time datetime NOT NULL," + + "update_time datetime NOT NULL," + + "PRIMARY KEY (student_user_id, teaching_class_id, project_name)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci"); + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentProjectStudyTimeController.java b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentProjectStudyTimeController.java new file mode 100644 index 0000000..e9b23dd --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/controller/stu/StudentProjectStudyTimeController.java @@ -0,0 +1,68 @@ +package com.sztzjy.linkCommerce.controller.stu; + +import com.sztzjy.linkCommerce.config.security.JwtUser; +import com.sztzjy.linkCommerce.config.security.TokenProvider; +import com.sztzjy.linkCommerce.entity.dto.StudentProjectStudyTimeDTO; +import com.sztzjy.linkCommerce.service.StudentTeachingClassResolver; +import com.sztzjy.linkCommerce.util.ResultEntity; +import org.apache.commons.lang3.StringUtils; +import org.springframework.http.HttpStatus; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; +import java.sql.Timestamp; +import java.util.Collections; +import java.util.List; + +@RestController +@RequestMapping("api/student/project-study-time") +public class StudentProjectStudyTimeController { + private static final int MAX_SECONDS_PER_RECORD = 300; + private final JdbcTemplate jdbcTemplate; + private final StudentTeachingClassResolver studentTeachingClassResolver; + + public StudentProjectStudyTimeController(JdbcTemplate jdbcTemplate, + StudentTeachingClassResolver studentTeachingClassResolver) { + this.jdbcTemplate = jdbcTemplate; + this.studentTeachingClassResolver = studentTeachingClassResolver; + } + + @PostMapping("/record") + public ResultEntity record(@RequestParam String projectName, + @RequestParam Integer durationSeconds, + HttpServletRequest request) { + JwtUser user = TokenProvider.getJWTUser(request); + String normalizedProjectName = StringUtils.trimToEmpty(projectName); + if (normalizedProjectName.isEmpty() || durationSeconds == null || durationSeconds <= 0) { + return new ResultEntity<>(HttpStatus.BAD_REQUEST, "项目名称和学习时长必须有效"); + } + int seconds = Math.min(durationSeconds, MAX_SECONDS_PER_RECORD); + String classId = studentTeachingClassResolver.resolveRequired(user); + Timestamp now = new Timestamp(System.currentTimeMillis()); + jdbcTemplate.update("INSERT INTO student_project_study_time (student_user_id, teaching_class_id, project_name, study_seconds, create_time, update_time) " + + "VALUES (?, ?, ?, ?, ?, ?) ON DUPLICATE KEY UPDATE study_seconds = study_seconds + VALUES(study_seconds), update_time = VALUES(update_time)", + user.getUserId(), classId, normalizedProjectName, seconds, now, now); + return new ResultEntity<>(HttpStatus.OK, "学习时长记录成功"); + } + + @GetMapping("/current") + public ResultEntity> current(HttpServletRequest request) { + JwtUser user = TokenProvider.getJWTUser(request); + String classId = studentTeachingClassResolver.resolveRequired(user); + List rows = jdbcTemplate.query( + "SELECT project_name, study_seconds FROM student_project_study_time WHERE student_user_id = ? AND teaching_class_id = ? ORDER BY project_name", + new Object[]{user.getUserId(), classId}, + (resultSet, index) -> { + StudentProjectStudyTimeDTO row = new StudentProjectStudyTimeDTO(); + row.setProjectName(resultSet.getString("project_name")); + row.setStudySeconds(resultSet.getLong("study_seconds")); + return row; + }); + return new ResultEntity<>(HttpStatus.OK, "查询成功", rows == null ? Collections.emptyList() : rows); + } +} diff --git a/src/main/java/com/sztzjy/linkCommerce/entity/dto/StudentProjectStudyTimeDTO.java b/src/main/java/com/sztzjy/linkCommerce/entity/dto/StudentProjectStudyTimeDTO.java new file mode 100644 index 0000000..4334deb --- /dev/null +++ b/src/main/java/com/sztzjy/linkCommerce/entity/dto/StudentProjectStudyTimeDTO.java @@ -0,0 +1,22 @@ +package com.sztzjy.linkCommerce.entity.dto; + +public class StudentProjectStudyTimeDTO { + private String projectName; + private Long studySeconds; + + public String getProjectName() { + return projectName; + } + + public void setProjectName(String projectName) { + this.projectName = projectName; + } + + public Long getStudySeconds() { + return studySeconds; + } + + public void setStudySeconds(Long studySeconds) { + this.studySeconds = studySeconds; + } +} diff --git a/src/test/java/com/sztzjy/linkCommerce/config/StudentProjectStudyTimeSchemaInitializerTest.java b/src/test/java/com/sztzjy/linkCommerce/config/StudentProjectStudyTimeSchemaInitializerTest.java new file mode 100644 index 0000000..a707325 --- /dev/null +++ b/src/test/java/com/sztzjy/linkCommerce/config/StudentProjectStudyTimeSchemaInitializerTest.java @@ -0,0 +1,19 @@ +package com.sztzjy.linkCommerce.config; + +import org.junit.jupiter.api.Test; +import org.springframework.jdbc.core.JdbcTemplate; + +import static org.mockito.ArgumentMatchers.contains; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +class StudentProjectStudyTimeSchemaInitializerTest { + @Test + void createsPerStudentPerClassProjectDurationTable() { + JdbcTemplate jdbcTemplate = mock(JdbcTemplate.class); + + new StudentProjectStudyTimeSchemaInitializer(jdbcTemplate).initialize(); + + verify(jdbcTemplate).execute(contains("student_project_study_time")); + } +}