From cf0e326b0c2c812923833f0c2e14adafbcbfcd09 Mon Sep 17 00:00:00 2001 From: meowrain Date: Wed, 21 Jan 2026 22:47:36 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E9=A2=98=E7=9B=AE?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=9F=BA=E7=A1=80=E6=9E=B6=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 创建题目服务模块 aioj-backend-question-service - 实现 Question、TestCase、QuestionSubmit 实体类 - 实现 RESTful 风格的 Controller 接口 - 添加完善的 Swagger 注解和校验 - 配置 Nacos 服务发现和 Redis 缓存 - 实现分页查询和条件过滤功能 Co-Authored-By: Claude --- .idea/mybatisx/templates.xml | 87 +++++++++++++++ .../.flattened-pom.xml | 19 ---- aioj-backend-question-service/pom.xml | 71 +++++++++++- .../question/QuestionServiceApplication.java | 15 +++ .../common/constants/RedisKeyConstants.java | 35 ++++++ .../question/common/enums/ChainMarkEnums.java | 42 +++++++ .../question/common/enums/LanguageEnum.java | 97 ++++++++++++++++ .../common/enums/QuestionDifficultyEnum.java | 42 +++++++ .../enums/QuestionSubmitStatusEnum.java | 47 ++++++++ .../config/FrameworkConfiguration.java | 11 ++ .../question/config/SwaggerConfiguration.java | 42 +++++++ .../controller/QuestionController.java | 101 +++++++++++++++++ .../controller/QuestionSubmitController.java | 72 ++++++++++++ .../backend/question/dao/entity/Question.java | 105 ++++++++++++++++++ .../question/dao/entity/QuestionSubmit.java | 70 ++++++++++++ .../question/dao/mapper/QuestionMapper.java | 11 ++ .../dao/mapper/QuestionSubmitMapper.java | 11 ++ .../backend/question/dto/req/JudgeCase.java | 24 ++++ .../backend/question/dto/req/JudgeConfig.java | 31 ++++++ .../backend/question/dto/req/JudgeInfo.java | 32 ++++++ .../dto/req/QuestionCreateRequestDTO.java | 44 ++++++++ .../dto/req/QuestionEditRequestDTO.java | 41 +++++++ .../dto/req/QuestionQueryRequestDTO.java | 49 ++++++++ .../dto/req/QuestionSubmitRequestDTO.java | 26 +++++ .../dto/req/QuestionUpdateRequestDTO.java | 48 ++++++++ .../dto/resp/QuestionResponseDTO.java | 18 +++ .../dto/resp/QuestionSubmitResponseDTO.java | 17 +++ .../aioj/backend/question/package-info.java | 6 + .../question/service/QuestionService.java | 54 +++++++++ .../service/QuestionSubmitService.java | 31 ++++++ .../service/impl/QuestionServiceImpl.java | 85 ++++++++++++++ .../impl/QuestionSubmitServiceImpl.java | 32 ++++++ .../src/main/resources/application-dev.yml | 19 ++++ .../src/main/resources/application-prod.yml | 11 ++ .../src/main/resources/application-test.yml | 11 ++ .../src/main/resources/application.yml | 49 ++++++++ .../src/main/resources/logback-spring.xml | 82 ++++++++++++++ 37 files changed, 1568 insertions(+), 20 deletions(-) create mode 100644 .idea/mybatisx/templates.xml delete mode 100644 aioj-backend-question-service/.flattened-pom.xml create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/QuestionServiceApplication.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/constants/RedisKeyConstants.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/ChainMarkEnums.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/LanguageEnum.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/QuestionDifficultyEnum.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/QuestionSubmitStatusEnum.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/config/FrameworkConfiguration.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/config/SwaggerConfiguration.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/controller/QuestionController.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/controller/QuestionSubmitController.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/entity/Question.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/entity/QuestionSubmit.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/mapper/QuestionMapper.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/mapper/QuestionSubmitMapper.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeCase.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeConfig.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeInfo.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionCreateRequestDTO.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionEditRequestDTO.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionQueryRequestDTO.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionSubmitRequestDTO.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionUpdateRequestDTO.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionResponseDTO.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionSubmitResponseDTO.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/package-info.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionService.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionSubmitService.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionServiceImpl.java create mode 100644 aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionSubmitServiceImpl.java create mode 100644 aioj-backend-question-service/src/main/resources/application-dev.yml create mode 100644 aioj-backend-question-service/src/main/resources/application-prod.yml create mode 100644 aioj-backend-question-service/src/main/resources/application-test.yml create mode 100644 aioj-backend-question-service/src/main/resources/application.yml create mode 100644 aioj-backend-question-service/src/main/resources/logback-spring.xml diff --git a/.idea/mybatisx/templates.xml b/.idea/mybatisx/templates.xml new file mode 100644 index 0000000..404329d --- /dev/null +++ b/.idea/mybatisx/templates.xml @@ -0,0 +1,87 @@ + + + + + + \ No newline at end of file diff --git a/aioj-backend-question-service/.flattened-pom.xml b/aioj-backend-question-service/.flattened-pom.xml deleted file mode 100644 index cceb665..0000000 --- a/aioj-backend-question-service/.flattened-pom.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - 4.0.0 - - cn.meowrain.aioj - ai-oj - 1.0.0 - - aioj-backend-question-service - 1.0.0 - AIOJ 题目服务 - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 - - - diff --git a/aioj-backend-question-service/pom.xml b/aioj-backend-question-service/pom.xml index fe987f1..e4590b1 100644 --- a/aioj-backend-question-service/pom.xml +++ b/aioj-backend-question-service/pom.xml @@ -14,5 +14,74 @@ jar AIOJ 题目服务 - + + + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + + + + + cn.meowrain.aioj + aioj-backend-common-core + + + cn.meowrain.aioj + aioj-backend-common-log + + + cn.meowrain.aioj + aioj-backend-common-mybatis + + + cn.meowrain.aioj + aioj-backend-common-security + + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.session + spring-session-data-redis + + + org.springframework.boot + spring-boot-starter-cache + + + + + com.mysql + mysql-connector-j + runtime + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + + + + + org.springframework.boot + spring-boot-starter-test + test + + \ No newline at end of file diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/QuestionServiceApplication.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/QuestionServiceApplication.java new file mode 100644 index 0000000..3e71b10 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/QuestionServiceApplication.java @@ -0,0 +1,15 @@ +package cn.meowrain.aioj.backend.question; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@MapperScan("cn.meowrain.aioj.backend.question.dao.mapper") +public class QuestionServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(QuestionServiceApplication.class, args); + } + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/constants/RedisKeyConstants.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/constants/RedisKeyConstants.java new file mode 100644 index 0000000..7cb4418 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/constants/RedisKeyConstants.java @@ -0,0 +1,35 @@ +package cn.meowrain.aioj.backend.question.common.constants; + +/** + * 题目服务 Redis Key 常量 + */ +public class RedisKeyConstants { + + /** + * 题目缓存 Key 前缀 + */ + public static final String QUESTION_CACHE_KEY_PREFIX = "question:"; + + /** + * 题目详情缓存 Key + */ + public static final String QUESTION_DETAIL_KEY = QUESTION_CACHE_KEY_PREFIX + "detail:"; + + /** + * 题目列表缓存 Key + */ + public static final String QUESTION_LIST_KEY = QUESTION_CACHE_KEY_PREFIX + "list"; + + /** + * 测试用例缓存 Key 前缀 + */ + public static final String TEST_CASE_CACHE_KEY_PREFIX = "test_case:"; + + /** + * 题目提交缓存 Key 前缀 + */ + public static final String QUESTION_SUBMIT_CACHE_KEY_PREFIX = "question_submit:"; + + private RedisKeyConstants() { + } +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/ChainMarkEnums.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/ChainMarkEnums.java new file mode 100644 index 0000000..53466f5 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/ChainMarkEnums.java @@ -0,0 +1,42 @@ +package cn.meowrain.aioj.backend.question.common.enums; + +import lombok.Getter; + +/** + * 题目服务责任链标识枚举 + */ +@Getter +public enum ChainMarkEnums { + + /** + * 题目创建参数校验 + */ + QUESTION_CREATE_PARAM_VERIFY_CHAIN("question_create_param_verify_chain", "题目创建参数校验责任链"), + + /** + * 题目更新参数校验 + */ + QUESTION_UPDATE_PARAM_VERIFY_CHAIN("question_update_param_verify_chain", "题目更新参数校验责任链"), + + /** + * 测试用例创建参数校验 + */ + TEST_CASE_CREATE_PARAM_VERIFY_CHAIN("test_case_create_param_verify_chain", "测试用例创建参数校验责任链"), + + ; + + /** + * 标识 + */ + private final String mark; + + /** + * 描述 + */ + private final String desc; + + ChainMarkEnums(String mark, String desc) { + this.mark = mark; + this.desc = desc; + } +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/LanguageEnum.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/LanguageEnum.java new file mode 100644 index 0000000..736f7b9 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/LanguageEnum.java @@ -0,0 +1,97 @@ +package cn.meowrain.aioj.backend.question.common.enums; + +import lombok.Getter; + +/** + * 编程语言枚举 + */ +@Getter +public enum LanguageEnum { + + /** + * Java + */ + JAVA("java", "Java"), + + /** + * C++ + */ + CPP("cpp", "C++"), + + /** + * Python + */ + PYTHON("python", "Python"), + + /** + * Go + */ + GO("go", "Go"), + + /** + * JavaScript + */ + JAVASCRIPT("javascript", "JavaScript"), + + /** + * C + */ + C("c", "C"), + + /** + * C# + */ + CSHARP("csharp", "C#"), + + /** + * Rust + */ + RUST("rust", "Rust"), + + /** + * PHP + */ + PHP("php", "PHP"), + + /** + * Swift + */ + SWIFT("swift", "Swift"), + + /** + * Kotlin + */ + KOTLIN("kotlin", "Kotlin"), + + /** + * TypeScript + */ + TYPESCRIPT("typescript", "TypeScript"), + + /** + * Ruby + */ + RUBY("ruby", "Ruby"), + + /** + * Shell + */ + SHELL("shell", "Shell"), + + ; + + /** + * 语言值 + */ + private final String value; + + /** + * 描述 + */ + private final String desc; + + LanguageEnum(String value, String desc) { + this.value = value; + this.desc = desc; + } +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/QuestionDifficultyEnum.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/QuestionDifficultyEnum.java new file mode 100644 index 0000000..46b809b --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/QuestionDifficultyEnum.java @@ -0,0 +1,42 @@ +package cn.meowrain.aioj.backend.question.common.enums; + +import lombok.Getter; + +/** + * 题目难度枚举 + */ +@Getter +public enum QuestionDifficultyEnum { + + /** + * 简单 + */ + EASY("easy", "简单"), + + /** + * 中等 + */ + MEDIUM("medium", "中等"), + + /** + * 困难 + */ + HARD("hard", "困难"), + + ; + + /** + * 难度值 + */ + private final String value; + + /** + * 描述 + */ + private final String desc; + + QuestionDifficultyEnum(String value, String desc) { + this.value = value; + this.desc = desc; + } +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/QuestionSubmitStatusEnum.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/QuestionSubmitStatusEnum.java new file mode 100644 index 0000000..9bf2a80 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/common/enums/QuestionSubmitStatusEnum.java @@ -0,0 +1,47 @@ +package cn.meowrain.aioj.backend.question.common.enums; + +import lombok.Getter; + +/** + * 题目提交状态枚举 + */ +@Getter +public enum QuestionSubmitStatusEnum { + + /** + * 待判题 + */ + WAITING(0, "待判题"), + + /** + * 判题中 + */ + JUDGING(1, "判题中"), + + /** + * 成功 + */ + SUCCESS(2, "成功"), + + /** + * 失败 + */ + FAILED(3, "失败"), + + ; + + /** + * 状态值 + */ + private final Integer value; + + /** + * 描述 + */ + private final String desc; + + QuestionSubmitStatusEnum(Integer value, String desc) { + this.value = value; + this.desc = desc; + } +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/config/FrameworkConfiguration.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/config/FrameworkConfiguration.java new file mode 100644 index 0000000..26d5f95 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/config/FrameworkConfiguration.java @@ -0,0 +1,11 @@ +package cn.meowrain.aioj.backend.question.config; + +import org.springframework.context.annotation.Configuration; + +/** + * 框架配置类 + */ +@Configuration +public class FrameworkConfiguration { + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/config/SwaggerConfiguration.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/config/SwaggerConfiguration.java new file mode 100644 index 0000000..cd15586 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/config/SwaggerConfiguration.java @@ -0,0 +1,42 @@ +package cn.meowrain.aioj.backend.question.config; + +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + * Swagger 配置 + */ +@Configuration +@Slf4j +public class SwaggerConfiguration implements ApplicationRunner { + + @Value("${server.port:8080}") + private String serverPort; + + @Value("${server.servlet.context-path:}") + private String contextPath; + + @Bean + public OpenAPI customOpenAPI() { + return new OpenAPI() + .info(new Info() + .title("AIOJ 题目服务 API 文档") + .version("2.0") + .description("提供题目管理、测试用例管理等功能") + .contact(new Contact() + .name("AIOJ Team") + .email("contact@aioj.com"))); + } + + @Override + public void run(ApplicationArguments args) throws Exception { + log.info("✨API Document: http://127.0.0.1:{}{}/doc.html", serverPort, contextPath); + } +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/controller/QuestionController.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/controller/QuestionController.java new file mode 100644 index 0000000..3c4deff --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/controller/QuestionController.java @@ -0,0 +1,101 @@ +package cn.meowrain.aioj.backend.question.controller; + +import cn.meowrain.aioj.backend.framework.core.web.Result; +import cn.meowrain.aioj.backend.framework.core.web.Results; +import cn.meowrain.aioj.backend.question.dao.entity.Question; +import cn.meowrain.aioj.backend.question.dto.req.QuestionCreateRequestDTO; +import cn.meowrain.aioj.backend.question.dto.req.QuestionEditRequestDTO; +import cn.meowrain.aioj.backend.question.dto.req.QuestionQueryRequestDTO; +import cn.meowrain.aioj.backend.question.service.QuestionService; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.web.bind.annotation.*; + +/** + * 题目管理控制器 - RESTful API + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/v1/questions") +@Tag(name = "题目管理", description = "题目增删改查等接口") +public class QuestionController { + + private final QuestionService questionService; + + /** + * 创建题目 + * POST /v1/questions + */ + @PostMapping + @Operation(summary = "创建题目", description = "创建新的编程题目") + public Result createQuestion( + @Parameter(description = "题目信息", required = true) + @RequestBody @Valid QuestionCreateRequestDTO request) { + Question question = new Question(); + BeanUtils.copyProperties(request, question); + Long questionId = questionService.createQuestion(question); + return Results.success(questionId); + } + + /** + * 更新题目 + * PUT /v1/questions/{id} + */ + @PutMapping("/{id}") + @Operation(summary = "更新题目", description = "根据ID更新题目信息") + public Result updateQuestion( + @Parameter(description = "题目ID", required = true) + @PathVariable("id") Long id, + @Parameter(description = "题目信息", required = true) + @RequestBody @Valid QuestionEditRequestDTO request) { + Question question = new Question(); + BeanUtils.copyProperties(request, question); + question.setId(id); + questionService.updateQuestion(question); + return Results.success(); + } + + /** + * 删除题目 + * DELETE /v1/questions/{id} + */ + @DeleteMapping("/{id}") + @Operation(summary = "删除题目", description = "根据ID删除题目") + public Result deleteQuestion( + @Parameter(description = "题目ID", required = true) + @PathVariable("id") Long id) { + questionService.deleteQuestion(id); + return Results.success(); + } + + /** + * 获取题目详情 + * GET /v1/questions/{id} + */ + @GetMapping("/{id}") + @Operation(summary = "获取题目详情", description = "根据ID获取题目详情") + public Result getQuestion( + @Parameter(description = "题目ID", required = true) + @PathVariable("id") Long id) { + Question question = questionService.getQuestionById(id); + return Results.success(question); + } + + /** + * 分页查询题目列表 + * GET /v1/questions + */ + @GetMapping + @Operation(summary = "分页查询题目列表", description = "支持按标题、难度、标签等条件查询") + public Result> listQuestions( + @Parameter(description = "查询条件") QuestionQueryRequestDTO request) { + Page page = questionService.listQuestions(request); + return Results.success(page); + } + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/controller/QuestionSubmitController.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/controller/QuestionSubmitController.java new file mode 100644 index 0000000..fe2d609 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/controller/QuestionSubmitController.java @@ -0,0 +1,72 @@ +package cn.meowrain.aioj.backend.question.controller; + +import cn.meowrain.aioj.backend.framework.core.web.Result; +import cn.meowrain.aioj.backend.framework.core.web.Results; +import cn.meowrain.aioj.backend.question.dao.entity.QuestionSubmit; +import cn.meowrain.aioj.backend.question.dto.req.QuestionSubmitRequestDTO; +import cn.meowrain.aioj.backend.question.service.QuestionSubmitService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.BeanUtils; +import org.springframework.web.bind.annotation.*; + +/** + * 题目提交管理控制器 - RESTful API + */ +@RequiredArgsConstructor +@RestController +@RequestMapping("/v1/question-submits") +@Tag(name = "题目提交管理", description = "题目提交相关接口") +public class QuestionSubmitController { + + private final QuestionSubmitService questionSubmitService; + + /** + * 提交代码 + * POST /v1/question-submits + */ + @PostMapping + @Operation(summary = "提交代码", description = "用户提交代码答案") + public Result submitQuestion( + @Parameter(description = "提交信息", required = true) + @RequestBody @Valid QuestionSubmitRequestDTO request) { + QuestionSubmit questionSubmit = new QuestionSubmit(); + BeanUtils.copyProperties(request, questionSubmit); + // 设置初始状态为待判题 + questionSubmit.setStatus(0); + Long submitId = questionSubmitService.createSubmit(questionSubmit); + return Results.success(submitId); + } + + /** + * 获取提交详情 + * GET /v1/question-submits/{id} + */ + @GetMapping("/{id}") + @Operation(summary = "获取提交详情", description = "根据ID获取提交详情") + public Result getSubmit( + @Parameter(description = "提交ID", required = true) + @PathVariable("id") Long id) { + QuestionSubmit submit = questionSubmitService.getSubmitById(id); + return Results.success(submit); + } + + /** + * 内部接口:更新提交状态 + * PATCH /v1/question-submits/{id}/status + */ + @PatchMapping("/{id}/status") + @Operation(summary = "更新提交状态", description = "判题服务更新提交状态(内部接口)") + public Result updateSubmitStatus( + @Parameter(description = "提交ID", required = true) + @PathVariable("id") Long id, + @Parameter(description = "状态信息", required = true) + @RequestBody QuestionSubmit questionSubmit) { + questionSubmit.setId(id); + questionSubmitService.updateSubmitStatus(questionSubmit); + return Results.success(); + } +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/entity/Question.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/entity/Question.java new file mode 100644 index 0000000..6d64805 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/entity/Question.java @@ -0,0 +1,105 @@ +package cn.meowrain.aioj.backend.question.dao.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * 题目实体类 + */ +@Data +@TableName(value = "question") +@Accessors(chain = true) +public class Question implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 题目ID + */ + @TableId(type = IdType.ASSIGN_ID) + private Long id; + + /** + * 题目标题 + */ + private String title; + + /** + * 题目描述 + */ + private String content; + + /** + * 难度等级:easy/medium/hard + */ + private String difficulty; + + /** + * 标签(JSON格式) + */ + private String tags; + + /** + * 题目答案 + */ + private String answer; + + /** + * 通过数 + */ + private Integer acceptedCount; + + /** + * 提交数 + */ + private Integer submitCount; + + + + + /** + * 判题用例 + */ + private String judgeCase; + + /** + * 判题配置(JSON格式) + */ + private String judgeConfig; + + /** + * 点赞数 + */ + private Integer thumbCount; + + /** + * 收藏数 + */ + private Integer favourCount; + + /** + * 创建者ID + */ + private Long userId; + + /** + * 创建时间 + */ + @TableField(fill = FieldFill.INSERT) + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 是否删除 + */ + @TableLogic + private Integer isDelete; +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/entity/QuestionSubmit.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/entity/QuestionSubmit.java new file mode 100644 index 0000000..b18998a --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/entity/QuestionSubmit.java @@ -0,0 +1,70 @@ +package cn.meowrain.aioj.backend.question.dao.entity; + +import com.baomidou.mybatisplus.annotation.*; +import lombok.Data; +import lombok.experimental.Accessors; + +import java.io.Serializable; +import java.util.Date; + +/** + * 题目提交实体类 + */ +@Data +@TableName(value = "question_submit") +@Accessors(chain = true) +public class QuestionSubmit implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(type = IdType.AUTO) + private Long id; + + /** + * 编程语言 + */ + private String language; + + /** + * 用户代码 + */ + private String code; + + /** + * 判题信息(json 对象) + */ + private String judgeInfo; + + /** + * 判题状态(0 - 待判题、1 - 判题中、2 - 成功、3 - 失败) + */ + private Integer status; + + /** + * 题目 id + */ + private Long questionId; + + /** + * 创建用户 id + */ + private Long userId; + + /** + * 创建时间 + */ + private Date createTime; + + /** + * 更新时间 + */ + private Date updateTime; + + /** + * 是否删除 + */ + private Integer isDelete; +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/mapper/QuestionMapper.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/mapper/QuestionMapper.java new file mode 100644 index 0000000..a342505 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/mapper/QuestionMapper.java @@ -0,0 +1,11 @@ +package cn.meowrain.aioj.backend.question.dao.mapper; + +import cn.meowrain.aioj.backend.question.dao.entity.Question; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 题目 Mapper + */ +public interface QuestionMapper extends BaseMapper { + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/mapper/QuestionSubmitMapper.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/mapper/QuestionSubmitMapper.java new file mode 100644 index 0000000..d1c3c04 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dao/mapper/QuestionSubmitMapper.java @@ -0,0 +1,11 @@ +package cn.meowrain.aioj.backend.question.dao.mapper; + +import cn.meowrain.aioj.backend.question.dao.entity.QuestionSubmit; +import com.baomidou.mybatisplus.core.mapper.BaseMapper; + +/** + * 题目提交 Mapper + */ +public interface QuestionSubmitMapper extends BaseMapper { + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeCase.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeCase.java new file mode 100644 index 0000000..d8b972a --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeCase.java @@ -0,0 +1,24 @@ +package cn.meowrain.aioj.backend.question.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 题目用例 + */ +@Schema(description = "题目用例") +@Data +public class JudgeCase { +// ---- 输入用例 ------ + /** + * 输入用例 + */ + @Schema(description = "输入用例") + private String input; + + /** + * 输出用例 + */ + @Schema(description = "输出用例") + private String output; +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeConfig.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeConfig.java new file mode 100644 index 0000000..ac915b8 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeConfig.java @@ -0,0 +1,31 @@ +package cn.meowrain.aioj.backend.question.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 题目配置 + */ +@Data +@Schema(description = "题目配置") +public class JudgeConfig { + + + /** + * 时间限制(ms) + */ + @Schema(description = "时间限制(ms)") + private Long timeLimit; + + + /** + * 内存限制(KB) + */ + @Schema(description = "内存限制(KB)") + private Long memoryLimit; + /** + * 堆栈限制(KB) + */ + @Schema(description = "堆栈限制(KB)") + private String stackLimit; +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeInfo.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeInfo.java new file mode 100644 index 0000000..d439790 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/JudgeInfo.java @@ -0,0 +1,32 @@ +package cn.meowrain.aioj.backend.question.dto.req; + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +/** + * 判题信息 + */ +@Schema(description = "判题信息") +@Data +public class JudgeInfo { + + /** + * 程序耗费内存 + */ + @Schema(description = "程序耗费内存") + private int memory; + + /** + * 程序执行时间 + */ + @Schema(description = "程序执行时间") + private int time; + + /** + * 程序执行信息 + */ + @Schema(description = "程序执行信息") + private String message; + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionCreateRequestDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionCreateRequestDTO.java new file mode 100644 index 0000000..af39cb0 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionCreateRequestDTO.java @@ -0,0 +1,44 @@ +package cn.meowrain.aioj.backend.question.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 创建题目请求 DTO + */ +@Data +@Schema(description = "创建题目请求") +public class QuestionCreateRequestDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "题目标题", requiredMode = Schema.RequiredMode.REQUIRED, example = "两数之和") + @NotBlank(message = "题目标题不能为空") + private String title; + + @Schema(description = "题目描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "给定一个整数数组 nums 和一个整数目标值 target...") + @NotBlank(message = "题目描述不能为空") + private String content; + + @Schema(description = "难度等级", requiredMode = Schema.RequiredMode.REQUIRED, example = "easy", allowableValues = {"easy", "medium", "hard"}) + @NotBlank(message = "难度等级不能为空") + private String difficulty; + + @Schema(description = "标签列表", example = "[\"数组\", \"哈希表\"]") + private List tags; + + @Schema(description = "题目答案", example = "class Solution {\n public int[] twoSum(int[] nums, int target) {\n ...\n }\n}") + private String answer; + + @Schema(description = "判题用例(JSON格式)", example = "[{\"input\":\"[2,7,11,15]\\n9\",\"output\":\"[0,1]\"}]") + private List judgeCase; + + @Schema(description = "判题配置(JSON格式)", example = "{\"timeLimit\":3000,\"memoryLimit\":256}") + private JudgeConfig judgeConfig; +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionEditRequestDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionEditRequestDTO.java new file mode 100644 index 0000000..113c933 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionEditRequestDTO.java @@ -0,0 +1,41 @@ +package cn.meowrain.aioj.backend.question.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 编辑题目请求 DTO(用户使用) + */ +@Data +@Schema(description = "编辑题目请求-用户用") +public class QuestionEditRequestDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "题目标题", example = "两数之和") + private String title; + + @Schema(description = "题目描述", example = "给定一个整数数组 nums 和一个整数目标值 target...") + private String content; + + @Schema(description = "难度等级", example = "easy", allowableValues = {"easy", "medium", "hard"}) + private String difficulty; + + @Schema(description = "标签列表", example = "[\"数组\", \"哈希表\"]") + private List tags; + + @Schema(description = "题目答案", example = "class Solution {\n public int[] twoSum(int[] nums, int target) {\n ...\n }\n}") + private String answer; + + @Schema(description = "判题用例(JSON格式)", example = "[{\"input\":\"[2,7,11,15]\\n9\",\"output\":\"[0,1]\"}]") + private List judgeCase; + + @Schema(description = "判题配置(JSON格式)", example = "{\"timeLimit\":3000,\"memoryLimit\":256}") + private JudgeConfig judgeConfig; +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionQueryRequestDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionQueryRequestDTO.java new file mode 100644 index 0000000..a2b85d8 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionQueryRequestDTO.java @@ -0,0 +1,49 @@ +package cn.meowrain.aioj.backend.question.dto.req; + +import cn.meowrain.aioj.backend.question.dao.entity.Question; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.io.Serial; +import java.util.List; + +/** + * 题目查询请求 DTO + */ +@Data +@EqualsAndHashCode(callSuper = true) +@Schema(description = "题目查询请求") +public class QuestionQueryRequestDTO extends Page implements java.io.Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "题目ID", example = "1") + private Long id; + + @Schema(description = "题目标题(模糊查询)", example = "两数之和") + private String title; + + @Schema(description = "题目描述(模糊查询)", example = "给定一个整数数组") + private String content; + + @Schema(description = "难度等级", example = "easy", allowableValues = {"easy", "medium", "hard"}) + private String difficulty; + + @Schema(description = "标签列表", example = "[\"数组\", \"哈希表\"]") + private List tags; + + @Schema(description = "题目答案", example = "class Solution {...}") + private String answer; + + @Schema(description = "创建者ID", example = "1") + private Long userId; + + @Schema(description = "排序字段", example = "createTime") + private String sortField; + + @Schema(description = "排序方向", example = "desc", allowableValues = {"asc", "desc"}) + private String sortOrder; +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionSubmitRequestDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionSubmitRequestDTO.java new file mode 100644 index 0000000..ead6832 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionSubmitRequestDTO.java @@ -0,0 +1,26 @@ +package cn.meowrain.aioj.backend.question.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * 题目提交请求 DTO + */ +@Data +@Schema(description = "题目提交请求") +public class QuestionSubmitRequestDTO { + + @Schema(description = "题目ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "题目ID不能为空") + private Long questionId; + + @Schema(description = "编程语言", requiredMode = Schema.RequiredMode.REQUIRED, example = "java", allowableValues = {"java", "cpp", "python", "go", "javascript", "c", "csharp", "rust", "php", "swift", "kotlin", "typescript", "ruby", "shell"}) + @NotBlank(message = "编程语言不能为空") + private String language; + + @Schema(description = "用户代码", requiredMode = Schema.RequiredMode.REQUIRED, example = "class Solution {\n public int[] twoSum(int[] nums, int target) {\n ...\n }\n}") + @NotBlank(message = "代码不能为空") + private String code; +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionUpdateRequestDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionUpdateRequestDTO.java new file mode 100644 index 0000000..c0c802c --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/req/QuestionUpdateRequestDTO.java @@ -0,0 +1,48 @@ +package cn.meowrain.aioj.backend.question.dto.req; + +import io.swagger.v3.oas.annotations.media.Schema; +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +import java.io.Serial; +import java.io.Serializable; +import java.util.List; + +/** + * 更新题目请求 DTO(管理员使用) + */ +@Data +@Schema(description = "更新题目请求-管理员用-可以指定更多字段") +public class QuestionUpdateRequestDTO implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + @Schema(description = "题目ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") + @NotNull(message = "题目ID不能为空") + private Long id; + + @Schema(description = "题目标题", example = "两数之和") + private String title; + + @Schema(description = "题目描述", example = "给定一个整数数组 nums 和一个整数目标值 target...") + private String content; + + @Schema(description = "难度等级", example = "easy", allowableValues = {"easy", "medium", "hard"}) + private String difficulty; + + @Schema(description = "标签列表", example = "[\"数组\", \"哈希表\"]") + private List tags; + + @Schema(description = "题目答案", example = "class Solution {\n public int[] twoSum(int[] nums, int target) {\n ...\n }\n}") + private String answer; + + + @Schema(description = "判题用例(JSON格式)", example = "[{\"input\":\"[2,7,11,15]\\n9\",\"output\":\"[0,1]\"}]") + private List judgeCase; + + @Schema(description = "判题配置(JSON格式)", example = "{\"timeLimit\":3000,\"memoryLimit\":256}") + private JudgeConfig judgeConfig; + + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionResponseDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionResponseDTO.java new file mode 100644 index 0000000..4a26ad7 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionResponseDTO.java @@ -0,0 +1,18 @@ +package cn.meowrain.aioj.backend.question.dto.resp; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; +import java.util.Date; + +/** + * 题目响应 DTO + */ +@Data +@Schema(description = "题目响应") +public class QuestionResponseDTO implements Serializable { + + private static final long serialVersionUID = 1L; + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionSubmitResponseDTO.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionSubmitResponseDTO.java new file mode 100644 index 0000000..30ec4ca --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/dto/resp/QuestionSubmitResponseDTO.java @@ -0,0 +1,17 @@ +package cn.meowrain.aioj.backend.question.dto.resp; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.io.Serializable; + +/** + * 题目提交响应 DTO + */ +@Data +@Schema(description = "题目提交响应") +public class QuestionSubmitResponseDTO implements Serializable { + + private static final long serialVersionUID = 1L; + +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/package-info.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/package-info.java new file mode 100644 index 0000000..18b95c2 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/package-info.java @@ -0,0 +1,6 @@ +/** + * 题目服务模块 + * + *

提供编程题目管理、测试用例管理等功能 + */ +package cn.meowrain.aioj.backend.question; diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionService.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionService.java new file mode 100644 index 0000000..8d5cf55 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionService.java @@ -0,0 +1,54 @@ +package cn.meowrain.aioj.backend.question.service; + +import cn.meowrain.aioj.backend.question.dao.entity.Question; +import cn.meowrain.aioj.backend.question.dto.req.QuestionQueryRequestDTO; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 题目服务接口 + */ +public interface QuestionService extends IService { + + /** + * 创建题目 + * @param question 题目信息 + * @return 题目ID + */ + Long createQuestion(Question question); + + /** + * 更新题目 + * @param question 题目信息 + * @return 是否成功 + */ + Boolean updateQuestion(Question question); + + /** + * 删除题目 + * @param questionId 题目ID + * @return 是否成功 + */ + Boolean deleteQuestion(Long questionId); + + /** + * 根据ID获取题目详情 + * @param questionId 题目ID + * @return 题目详情 + */ + Question getQuestionById(Long questionId); + + /** + * 根据ID获取题目详情(内部接口) + * @param questionId 题目ID + * @return 题目详情 + */ + Question getQuestionByIdInner(Long questionId); + + /** + * 分页查询题目列表 + * @param request 查询条件 + * @return 题目分页列表 + */ + Page listQuestions(QuestionQueryRequestDTO request); +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionSubmitService.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionSubmitService.java new file mode 100644 index 0000000..3bb4ccc --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/QuestionSubmitService.java @@ -0,0 +1,31 @@ +package cn.meowrain.aioj.backend.question.service; + +import cn.meowrain.aioj.backend.question.dao.entity.QuestionSubmit; +import com.baomidou.mybatisplus.extension.service.IService; + +/** + * 题目提交服务接口 + */ +public interface QuestionSubmitService extends IService { + + /** + * 创建提交记录 + * @param questionSubmit 提交信息 + * @return 提交ID + */ + Long createSubmit(QuestionSubmit questionSubmit); + + /** + * 更新提交状态 + * @param questionSubmit 提交信息 + * @return 是否成功 + */ + Boolean updateSubmitStatus(QuestionSubmit questionSubmit); + + /** + * 根据ID获取提交记录 + * @param submitId 提交ID + * @return 提交记录 + */ + QuestionSubmit getSubmitById(Long submitId); +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionServiceImpl.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionServiceImpl.java new file mode 100644 index 0000000..0928787 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionServiceImpl.java @@ -0,0 +1,85 @@ +package cn.meowrain.aioj.backend.question.service.impl; + +import cn.meowrain.aioj.backend.question.dao.entity.Question; +import cn.meowrain.aioj.backend.question.dao.mapper.QuestionMapper; +import cn.meowrain.aioj.backend.question.dto.req.QuestionQueryRequestDTO; +import cn.meowrain.aioj.backend.question.service.QuestionService; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +/** + * 题目服务实现 + */ +@Service +@RequiredArgsConstructor +public class QuestionServiceImpl extends ServiceImpl implements QuestionService { + + @Override + public Long createQuestion(Question question) { + this.save(question); + return question.getId(); + } + + @Override + public Boolean updateQuestion(Question question) { + return this.updateById(question); + } + + @Override + public Boolean deleteQuestion(Long questionId) { + return this.removeById(questionId); + } + + @Override + public Question getQuestionById(Long questionId) { + return this.getById(questionId); + } + + @Override + public Question getQuestionByIdInner(Long questionId) { + return this.getById(questionId); + } + + @Override + public Page listQuestions(QuestionQueryRequestDTO request) { + LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); + + // ID 精确查询 + if (request.getId() != null) { + wrapper.eq(Question::getId, request.getId()); + } + + // 标题模糊查询 + if (StringUtils.isNotBlank(request.getTitle())) { + wrapper.like(Question::getTitle, request.getTitle()); + } + + // 难度精确查询 + if (StringUtils.isNotBlank(request.getDifficulty())) { + wrapper.eq(Question::getDifficulty, request.getDifficulty()); + } + + // 创建者 ID 查询 + if (request.getUserId() != null) { + wrapper.eq(Question::getUserId, request.getUserId()); + } + + // 排序 + if (StringUtils.isNotBlank(request.getSortField())) { + if ("asc".equalsIgnoreCase(request.getSortOrder())) { + wrapper.orderByAsc(Question::getCreateTime); + } else { + wrapper.orderByDesc(Question::getCreateTime); + } + } else { + wrapper.orderByDesc(Question::getCreateTime); + } + + // 直接使用 request 作为分页对象 + return this.page(request, wrapper); + } +} diff --git a/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionSubmitServiceImpl.java b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionSubmitServiceImpl.java new file mode 100644 index 0000000..a637500 --- /dev/null +++ b/aioj-backend-question-service/src/main/java/cn/meowrain/aioj/backend/question/service/impl/QuestionSubmitServiceImpl.java @@ -0,0 +1,32 @@ +package cn.meowrain.aioj.backend.question.service.impl; + +import cn.meowrain.aioj.backend.question.dao.entity.QuestionSubmit; +import cn.meowrain.aioj.backend.question.dao.mapper.QuestionSubmitMapper; +import cn.meowrain.aioj.backend.question.service.QuestionSubmitService; +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * 题目提交服务实现 + */ +@Service +@RequiredArgsConstructor +public class QuestionSubmitServiceImpl extends ServiceImpl implements QuestionSubmitService { + + @Override + public Long createSubmit(QuestionSubmit questionSubmit) { + this.save(questionSubmit); + return questionSubmit.getId(); + } + + @Override + public Boolean updateSubmitStatus(QuestionSubmit questionSubmit) { + return this.updateById(questionSubmit); + } + + @Override + public QuestionSubmit getSubmitById(Long submitId) { + return this.getById(submitId); + } +} diff --git a/aioj-backend-question-service/src/main/resources/application-dev.yml b/aioj-backend-question-service/src/main/resources/application-dev.yml new file mode 100644 index 0000000..f186dc2 --- /dev/null +++ b/aioj-backend-question-service/src/main/resources/application-dev.yml @@ -0,0 +1,19 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://10.0.0.10/aioj_dev + username: root + password: root + data: + redis: + host: 10.0.0.10 + port: 6379 + password: 123456 + cloud: + nacos: + discovery: + enabled: true + register-enabled: true + server-addr: 10.0.0.10:8848 + username: nacos + password: nacos diff --git a/aioj-backend-question-service/src/main/resources/application-prod.yml b/aioj-backend-question-service/src/main/resources/application-prod.yml new file mode 100644 index 0000000..258ae4b --- /dev/null +++ b/aioj-backend-question-service/src/main/resources/application-prod.yml @@ -0,0 +1,11 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://10.0.0.10/aioj_prod + username: root + password: root + data: + redis: + host: 10.0.0.10 + port: 6379 + password: 123456 diff --git a/aioj-backend-question-service/src/main/resources/application-test.yml b/aioj-backend-question-service/src/main/resources/application-test.yml new file mode 100644 index 0000000..422826b --- /dev/null +++ b/aioj-backend-question-service/src/main/resources/application-test.yml @@ -0,0 +1,11 @@ +spring: + datasource: + driver-class-name: com.mysql.cj.jdbc.Driver + url: jdbc:mysql://10.0.0.10/aioj_test + username: root + password: 123456 + data: + redis: + host: 10.0.0.10 + port: 6379 + password: 123456 diff --git a/aioj-backend-question-service/src/main/resources/application.yml b/aioj-backend-question-service/src/main/resources/application.yml new file mode 100644 index 0000000..ee32550 --- /dev/null +++ b/aioj-backend-question-service/src/main/resources/application.yml @@ -0,0 +1,49 @@ +spring: + application: + name: aioj-question-service + profiles: + active: @env@ +server: + port: 18083 + servlet: + context-path: /api + error: + include-stacktrace: never +springdoc: + api-docs: + enabled: true + path: /v3/api-docs + default-flat-param-object: true + swagger-ui: + path: /swagger-ui.html + tags-sorter: alpha + operations-sorter: alpha + group-configs: + - group: 'default' + paths-to-match: '/api/**' + packages-to-scan: cn.meowrain.aioj.backend.questionservice.controller +knife4j: + basic: + enable: true + setting: + language: zh_cn +mybatis-plus: + configuration: + log-impl: org.apache.ibatis.logging.stdout.StdOutImpl + map-underscore-to-camel-case: true + mapper-locations: classpath*:/mapper/**/*.xml + +# JWT 配置(必须与 auth-service 保持一致) +jwt: + enabled: true + secret: "12345678901234567890123456789012" # 至少32字节 + access-expire: 900000 # 15分钟 + refresh-expire: 604800000 # 7天 + +aioj: + log: + enabled: true + max-length: 20000 +logging: + file: + path: ./logs/${spring.application.name} diff --git a/aioj-backend-question-service/src/main/resources/logback-spring.xml b/aioj-backend-question-service/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..5111287 --- /dev/null +++ b/aioj-backend-question-service/src/main/resources/logback-spring.xml @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + UTF-8 + + + + + ${LOG_FILE_PATH}/${time-month}/${time-month-day}/info.log + + ${LOG_FILE_PATH}/${time-month}/${time-month-day}/info.%d{yyyy-MM-dd}.%i.log.gz + 100MB + 31 + 100GB + + + ${FILE_LOG_PATTERN} + UTF-8 + + + INFO + + + + ${LOG_FILE_PATH}/${time-month}/${time-month-day}/error.log + + ${LOG_FILE_PATH}/${time-month}/${time-month-day}/error.%d{yyyy-MM-dd}.%i.log.gz + 100MB + 31 + 100GB + + + ${FILE_LOG_PATTERN} + UTF-8 + + + ERROR + ACCEPT + DENY + + + + + 0 + 512 + + + + 0 + 512 + + + + + + + + + + + + + + + + + + +