fix: [1+66]
This commit is contained in:
parent
676cf30e44
commit
46adeb5622
|
@ -0,0 +1,100 @@
|
|||
package com.guwan.backend.Handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.guwan.backend.service.CourseService;
|
||||
import com.guwan.backend.service.WebSocketService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CourseWebSocketHandler extends TextWebSocketHandler {
|
||||
|
||||
|
||||
@Autowired
|
||||
private WebSocketService webSocketService;
|
||||
|
||||
@Autowired
|
||||
private CourseService courseService;
|
||||
|
||||
// 存储每个课程的在线用户
|
||||
private static final Map<String, Set<WebSocketSession>> courseSessions = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) {
|
||||
log.info("Course detail WebSocket connection established: {}", session.getId());
|
||||
String courseId = getCourseIdFromSession(session);
|
||||
courseSessions.computeIfAbsent(courseId, k -> ConcurrentHashMap.newKeySet()).add(session);
|
||||
broadcastStudentCount(courseId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
|
||||
log.info("Course detail received message from {}: {}", session.getId(), message.getPayload());
|
||||
try {
|
||||
JsonNode jsonNode = new ObjectMapper().readTree(message.getPayload());
|
||||
String type = jsonNode.get("type").asText();
|
||||
String courseId = jsonNode.get("courseId").asText();
|
||||
|
||||
if ("JOIN_COURSE".equals(type)) {
|
||||
courseSessions.computeIfAbsent(courseId, k -> ConcurrentHashMap.newKeySet()).add(session);
|
||||
broadcastStudentCount(courseId);
|
||||
} else if ("LEAVE_COURSE".equals(type)) {
|
||||
courseSessions.getOrDefault(courseId, Collections.emptySet()).remove(session);
|
||||
broadcastStudentCount(courseId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error handling course detail message", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
|
||||
log.info("Course detail WebSocket connection closed: {}, status: {}", session.getId(), status);
|
||||
String courseId = getCourseIdFromSession(session);
|
||||
courseSessions.getOrDefault(courseId, Collections.emptySet()).remove(session);
|
||||
broadcastStudentCount(courseId);
|
||||
}
|
||||
|
||||
private String getCourseIdFromSession(WebSocketSession session) {
|
||||
String path = session.getUri().getPath();
|
||||
return path.substring(path.lastIndexOf('/') + 1);
|
||||
}
|
||||
|
||||
private void broadcastStudentCount(String courseId) {
|
||||
int count = courseSessions.getOrDefault(courseId, Collections.emptySet()).size();
|
||||
// 更新持久化的学习人数
|
||||
courseService.updateStudentCount(courseId, count);
|
||||
// 广播给课程详情页
|
||||
String message = String.format(
|
||||
"{\"type\":\"STUDENT_COUNT_UPDATE\",\"courseId\":\"%s\",\"count\":%d}",
|
||||
courseId, count
|
||||
);
|
||||
|
||||
courseSessions.getOrDefault(courseId, Collections.emptySet())
|
||||
.forEach(session -> {
|
||||
try {
|
||||
if (session.isOpen()) {
|
||||
session.sendMessage(new TextMessage(message));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error broadcasting to course detail", e);
|
||||
}
|
||||
});
|
||||
|
||||
// 通过WebSocketService广播给首页
|
||||
webSocketService.broadcastStudentCount(courseId, count);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package com.guwan.backend.Handler;
|
||||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.guwan.backend.service.CourseService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@Slf4j
|
||||
@Component
|
||||
public class CoursesWebSocketHandler extends TextWebSocketHandler {
|
||||
|
||||
@Autowired
|
||||
private CourseService courseService;
|
||||
private static final Set<WebSocketSession> sessions = ConcurrentHashMap.newKeySet();
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) {
|
||||
log.info("Home page WebSocket connection established: {}", session.getId());
|
||||
sessions.add(session);
|
||||
// 连接建立时,发送所有课程的当前学习人数
|
||||
sendAllCourseCounts(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) {
|
||||
log.info("Home page received message from {}: {}", session.getId(), message.getPayload());
|
||||
try {
|
||||
JsonNode jsonNode = new ObjectMapper().readTree(message.getPayload());
|
||||
String type = jsonNode.get("type").asText();
|
||||
|
||||
if ("STUDENT_COUNT_UPDATE".equals(type)) {
|
||||
// 转发消息给所有首页连接的客户端
|
||||
broadcastMessage(message.getPayload());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("Error handling home page message", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) {
|
||||
log.info("Home page WebSocket connection closed: {}, status: {}", session.getId(), status);
|
||||
sessions.remove(session);
|
||||
}
|
||||
|
||||
public void broadcastMessage(String message) {
|
||||
sessions.forEach(session -> {
|
||||
try {
|
||||
if (session.isOpen()) {
|
||||
session.sendMessage(new TextMessage(message));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error broadcasting to home page", e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void sendAllCourseCounts(WebSocketSession session) {
|
||||
try {
|
||||
// 获取所有课程的学习人数
|
||||
Map<String, Integer> allCounts = courseService.getAllCourseCounts();
|
||||
|
||||
// 发送每个课程的学习人数
|
||||
allCounts.forEach((courseId, count) -> {
|
||||
String message = String.format(
|
||||
"{\"type\":\"STUDENT_COUNT_UPDATE\",\"courseId\":\"%s\",\"count\":%d}",
|
||||
courseId, count
|
||||
);
|
||||
try {
|
||||
if (session.isOpen()) {
|
||||
session.sendMessage(new TextMessage(message));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("Error sending course count", e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
log.error("Error sending all course counts", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
package com.guwan.backend;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
public class JudgeEngine {
|
||||
|
||||
// 假设用户代码已编译好,类名为 Solution
|
||||
public static void main(String[] args) throws Exception {
|
||||
// 1. 取出测试用例
|
||||
String inputJson = "{\"nums\": [2,7,11,15], \"target\": 9}";
|
||||
String outputJson = "[0,1]";
|
||||
List<String> paramList = Arrays.asList("nums", "target");
|
||||
|
||||
// 2. 反序列化参数
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
Map<String, Object> paramMap = mapper.readValue(inputJson, Map.class);
|
||||
|
||||
// 3. 构造参数数组(按 paramList 顺序)
|
||||
Object[] params = new Object[paramList.size()];
|
||||
for (int i = 0; i < paramList.size(); i++) {
|
||||
String key = paramList.get(i);
|
||||
Object value = paramMap.get(key);
|
||||
// 类型转换:如果是数组,需转为 int[]
|
||||
if (key.equals("nums")) {
|
||||
// value 是 List<Integer>,转为 int[]
|
||||
List<Integer> list = (List<Integer>) value;
|
||||
int[] arr = list.stream().mapToInt(Integer::intValue).toArray();
|
||||
params[i] = arr;
|
||||
} else if (key.equals("target")) {
|
||||
params[i] = ((Number) value).intValue();
|
||||
}
|
||||
// 其他类型可按需扩展
|
||||
}
|
||||
|
||||
// 4. 反射调用用户代码
|
||||
Class<?> clazz = Class.forName("Solution");
|
||||
Method method = clazz.getMethod("twoSum", int[].class, int.class);
|
||||
Object instance = clazz.getDeclaredConstructor().newInstance();
|
||||
Object result = method.invoke(instance, params);
|
||||
|
||||
// 5. 反序列化期望输出
|
||||
int[] expected = mapper.readValue(outputJson, int[].class);
|
||||
|
||||
// 6. 比对结果
|
||||
if (Arrays.equals((int[]) result, expected)) {
|
||||
System.out.println("通过");
|
||||
} else {
|
||||
System.out.println("不通过");
|
||||
System.out.println("期望: " + Arrays.toString(expected));
|
||||
System.out.println("实际: " + Arrays.toString((int[]) result));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,12 @@
|
|||
package com.guwan.backend.config;
|
||||
|
||||
import com.guwan.backend.Handler.CourseWebSocketHandler;
|
||||
import com.guwan.backend.Handler.CoursesWebSocketHandler;
|
||||
import com.guwan.backend.websocket.ChatWebSocketHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.WebSocketHandler;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||
|
@ -10,9 +15,17 @@ import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry
|
|||
@EnableWebSocket
|
||||
public class WebSocketConfig implements WebSocketConfigurer {
|
||||
|
||||
@Autowired
|
||||
private CourseWebSocketHandler courseWebSocketHandler;
|
||||
@Autowired
|
||||
private CoursesWebSocketHandler coursesWebSocketHandler;
|
||||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
registry.addHandler(new ChatWebSocketHandler(), "/ws/chat")
|
||||
.addHandler(coursesWebSocketHandler, "/ws/courses") // 首页
|
||||
.addHandler(courseWebSocketHandler, "/ws/course/{courseId}")
|
||||
.setAllowedOrigins("*"); // 允许所有来源
|
||||
}
|
||||
|
||||
}
|
|
@ -6,54 +6,49 @@ import java.util.List;
|
|||
* 安全相关常量配置
|
||||
*/
|
||||
public class SecurityConstants {
|
||||
|
||||
|
||||
/**
|
||||
* API接口白名单
|
||||
* 这些路径可以直接访问,不需要认证
|
||||
*/
|
||||
public static final List<String> WHITE_LIST = List.of(
|
||||
"/faceTest","/compareFaces",
|
||||
"/challenge",
|
||||
"/ws/**",
|
||||
"/faceTest", "/compareFaces",
|
||||
"/minio/**",
|
||||
|
||||
|
||||
"/bs/user/getEmailCode",
|
||||
|
||||
|
||||
"/exam/api/paper/**",
|
||||
"/bs/user/login",
|
||||
"/bs/user/register",
|
||||
"/bs/courses/**",
|
||||
"/api/common/**", //公共接口
|
||||
"/demo/**", // 测试接口
|
||||
"/demo/**", // 测试接口
|
||||
"/api/products",
|
||||
"/api/user/register", // 用户注册
|
||||
"/api/user/login", // 用户登录
|
||||
"/api/user/getEmailCode", // 获取邮箱验证码
|
||||
"/api/user/getPhoneCode", // 获取手机验证码
|
||||
"/chat.html",
|
||||
"/api/user/register", // 用户注册
|
||||
"/api/user/login", // 用户登录
|
||||
"/api/user/getEmailCode", // 获取邮箱验证码
|
||||
"/api/user/getPhoneCode", // 获取手机验证码
|
||||
"/chat.html",
|
||||
"/daxz.html/**",
|
||||
|
||||
"/polling-chat.html",
|
||||
"/log-viewer.html",
|
||||
|
||||
"/ws/chat/**",
|
||||
|
||||
"/api/polling-chat/**",
|
||||
|
||||
"/v3/api-docs/**", // Swagger API文档
|
||||
"/swagger-ui/**", // Swagger UI
|
||||
"/swagger-ui.html", // Swagger UI HTML
|
||||
"/swagger-resources/**", // Swagger 资源
|
||||
"/webjars/**" // Swagger UI 相关资源
|
||||
"/polling-chat.html",
|
||||
"/log-viewer.html",
|
||||
"/ws/chat/**",
|
||||
"/api/polling-chat/**",
|
||||
"/v3/api-docs/**", // Swagger API文档
|
||||
"/swagger-ui/**", // Swagger UI
|
||||
"/swagger-ui.html", // Swagger UI HTML
|
||||
"/swagger-resources/**", // Swagger 资源
|
||||
"/webjars/**" // Swagger UI 相关资源
|
||||
);
|
||||
|
||||
|
||||
/**
|
||||
* 静态资源白名单
|
||||
* 这些路径用于访问静态资源,不需要认证
|
||||
*/
|
||||
public static final List<String> STATIC_RESOURCES = List.of(
|
||||
"/static/**", // 静态资源目录
|
||||
"/public/**", // 公共资源目录
|
||||
"/error" // 错误页面
|
||||
"/static/**", // 静态资源目录
|
||||
"/public/**", // 公共资源目录
|
||||
"/error" // 错误页面
|
||||
|
||||
);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.guwan.backend.controller;
|
||||
|
||||
import com.guwan.backend.common.Result;
|
||||
import com.guwan.backend.pojo.bo.CodeRunResult;
|
||||
import com.guwan.backend.pojo.bo.TestCaseBO;
|
||||
import com.guwan.backend.pojo.dto.SubmitCodeDTO;
|
||||
import com.guwan.backend.pojo.response.ChallengesVO;
|
||||
import com.guwan.backend.service.ChallengesService;
|
||||
import com.guwan.backend.service.TestCaseAssemblyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/challenge")
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class ChallengeController {
|
||||
|
||||
private final ChallengesService challengesService;
|
||||
private final TestCaseAssemblyService testCaseAssemblyService;
|
||||
|
||||
@GetMapping
|
||||
public Result getChallenge() {
|
||||
List<ChallengesVO> challenge = challengesService.getChallenge();
|
||||
|
||||
return Result.success(challenge);
|
||||
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public Result submitCode(@RequestBody SubmitCodeDTO submitCodeDTO) {
|
||||
|
||||
CodeRunResult codeRunResult = challengesService.submitCode(submitCodeDTO);
|
||||
|
||||
return Result.success(codeRunResult);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -7,6 +7,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|||
import com.guwan.backend.common.Result;
|
||||
import com.guwan.backend.pojo.dto.BSCategory;
|
||||
import com.guwan.backend.pojo.entity.Course;
|
||||
import com.guwan.backend.pojo.response.courseDetail.CourseDetailVO;
|
||||
import com.guwan.backend.service.BSCategoryService;
|
||||
import com.guwan.backend.service.CourseService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
@ -63,12 +64,12 @@ public class CourseController {
|
|||
|
||||
}
|
||||
|
||||
@GetMapping("/getCourseDetail")
|
||||
public Result getCourseDetail(@RequestParam("courseId") String courseId) {
|
||||
@GetMapping("/getCourseDetail/{courseId}")
|
||||
public Result getCourseDetail(@PathVariable("courseId") String courseId) {
|
||||
|
||||
courseService.getCourseDetail(courseId);
|
||||
CourseDetailVO courseDetail = courseService.getCourseDetail(courseId);
|
||||
|
||||
return Result.success();
|
||||
return Result.success(courseDetail);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.github.dockerjava.api.model.*;
|
|||
import com.github.dockerjava.core.DockerClientBuilder;
|
||||
import com.github.dockerjava.core.command.ExecStartResultCallback;
|
||||
import com.github.dockerjava.httpclient5.ApacheDockerHttpClient;
|
||||
import com.guwan.backend.pojo.bo.TestCaseBO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
@ -167,7 +168,7 @@ public class DockerController {
|
|||
@GetMapping("/judge")
|
||||
public ResponseEntity<Map<String, Object>> judgeCode() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
List<TestCase> testCases = new ArrayList<>();
|
||||
List<TestCaseBO> testCases = new ArrayList<>();
|
||||
|
||||
// 真实用户提交的C++代码(示例:A+B问题)
|
||||
String cppCode =
|
||||
|
@ -181,11 +182,11 @@ public class DockerController {
|
|||
"}";
|
||||
|
||||
// 定义测试用例
|
||||
testCases.add(new TestCase("1 2", "3")); // 基础测试
|
||||
testCases.add(new TestCase("-5 8", "3")); // 负数测试
|
||||
testCases.add(new TestCase("1000000 2000000", "3000000")); // 大数测试
|
||||
testCases.add(new TestCase("", "")); // 错误输入测试
|
||||
testCases.add(new TestCase("3", "")); // 不完整输入测试
|
||||
testCases.add(new TestCaseBO("1 2", "3")); // 基础测试
|
||||
testCases.add(new TestCaseBO("-5 8", "3")); // 负数测试
|
||||
testCases.add(new TestCaseBO("1000000 2000000", "3000000")); // 大数测试
|
||||
testCases.add(new TestCaseBO("", "")); // 错误输入测试
|
||||
testCases.add(new TestCaseBO("3", "")); // 不完整输入测试
|
||||
|
||||
String containerId = null;
|
||||
try {
|
||||
|
@ -219,7 +220,7 @@ public class DockerController {
|
|||
// 3. 执行测试用例
|
||||
List<Map<String, Object>> caseResults = new ArrayList<>();
|
||||
for (int i = 0; i < testCases.size(); i++) {
|
||||
TestCase testCase = testCases.get(i);
|
||||
TestCaseBO testCase = testCases.get(i);
|
||||
Map<String, Object> caseResult = new HashMap<>();
|
||||
caseResult.put("case_id", i + 1);
|
||||
caseResult.put("input", testCase.input);
|
||||
|
@ -304,16 +305,6 @@ public class DockerController {
|
|||
}
|
||||
|
||||
// 测试用例类
|
||||
static class TestCase {
|
||||
String input;
|
||||
String expectedOutput;
|
||||
|
||||
public TestCase(String input, String expectedOutput) {
|
||||
this.input = input;
|
||||
this.expectedOutput = expectedOutput;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,10 +3,8 @@ package com.guwan.backend.controller;
|
|||
import com.guwan.backend.common.Result;
|
||||
import com.guwan.backend.util.MinioUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
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 org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/minio")
|
||||
|
@ -23,4 +21,14 @@ public class MinioController {
|
|||
return Result.success(fileName);
|
||||
}
|
||||
|
||||
@PostMapping("/uploadFile")
|
||||
public Result uploadFile(@RequestParam String bucketName,
|
||||
@RequestPart("file") MultipartFile file,
|
||||
@RequestParam String folder) {
|
||||
String fileName = minioUtil.uploadFile(bucketName, file, folder);
|
||||
String fileUrl = minioUtil.getFileUrl(bucketName, fileName);
|
||||
String url = minioUtil.getUrl(fileUrl);
|
||||
return Result.success(url);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
package com.guwan.backend.factory;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.guwan.backend.mapper.SlideMapper;
|
||||
import com.guwan.backend.pojo.entity.Section;
|
||||
import com.guwan.backend.pojo.entity.Slide;
|
||||
import com.guwan.backend.pojo.response.courseDetail.*;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class SectionVOFactory {
|
||||
|
||||
private final SlideMapper sliderMapper;
|
||||
|
||||
public BaseSectionVO fromSection(Section section) {
|
||||
switch (String.valueOf(section.getType())) {
|
||||
case "video":
|
||||
VideoSectionVO video = new VideoSectionVO();
|
||||
BeanUtils.copyProperties(section, video);
|
||||
video.setType("video");
|
||||
video.setDuration(section.getDuration() + ":00");
|
||||
video.setUrl(section.getUrl());
|
||||
return video;
|
||||
case "pdf":
|
||||
PdfSectionVO pdf = new PdfSectionVO();
|
||||
BeanUtils.copyProperties(section, pdf);
|
||||
pdf.setType("pdf");
|
||||
pdf.setUrl(section.getUrl());
|
||||
pdf.setDownloadable(true);
|
||||
return pdf;
|
||||
case "ppt":
|
||||
PptSectionVO ppt = new PptSectionVO();
|
||||
BeanUtils.copyProperties(section, ppt);
|
||||
ppt.setType("ppt");
|
||||
String pptId = ppt.getId();
|
||||
List<Slide> slideList = sliderMapper.selectList(new LambdaQueryWrapper<Slide>().eq(Slide::getSectionId, pptId));
|
||||
slideList.sort(Comparator.comparingInt(Slide::getOrderNumber));
|
||||
|
||||
List<SlideVO> slideVOS = slideList.stream()
|
||||
.map(slide -> {
|
||||
SlideVO vo = new SlideVO();
|
||||
BeanUtils.copyProperties(slide, vo);
|
||||
return vo;
|
||||
})
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ppt.setSlides(slideVOS);
|
||||
return ppt;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported type: " + section.getType());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
package generator.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 课程表
|
||||
* @TableName course
|
||||
*/
|
||||
@TableName(value ="course")
|
||||
@Data
|
||||
public class Course implements Serializable {
|
||||
/**
|
||||
* 课程ID
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 课程标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 课程描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 分类编码
|
||||
*/
|
||||
private String categoryId;
|
||||
|
||||
/**
|
||||
* 分类名称
|
||||
*/
|
||||
private String categoryName;
|
||||
|
||||
/**
|
||||
* 授课教师ID
|
||||
*/
|
||||
private String teacherId;
|
||||
|
||||
/**
|
||||
* 封面图片URL
|
||||
*/
|
||||
private String coverImg;
|
||||
|
||||
/**
|
||||
* 价格
|
||||
*/
|
||||
private BigDecimal price;
|
||||
|
||||
/**
|
||||
* 授课教师id
|
||||
*/
|
||||
private String coursrTeacherId;
|
||||
|
||||
/**
|
||||
* 评分
|
||||
*/
|
||||
private BigDecimal rating;
|
||||
|
||||
/**
|
||||
* 评分人数
|
||||
*/
|
||||
private Integer ratingCount;
|
||||
|
||||
/**
|
||||
* 学习人数
|
||||
*/
|
||||
private Integer studentCount;
|
||||
|
||||
/**
|
||||
* 视频数量
|
||||
*/
|
||||
private Integer videoCount;
|
||||
|
||||
/**
|
||||
* 文档数量
|
||||
*/
|
||||
private Integer documentCount;
|
||||
|
||||
/**
|
||||
* 总时长
|
||||
*/
|
||||
private Integer totalDuration;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updatedAt;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package generator.mapper;
|
||||
|
||||
import generator.domain.Course;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【course(课程表)】的数据库操作Mapper
|
||||
* @createDate 2025-04-15 00:32:28
|
||||
* @Entity generator.domain.Course
|
||||
*/
|
||||
public interface CourseMapper extends BaseMapper<Course> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -1,13 +0,0 @@
|
|||
package generator.service;
|
||||
|
||||
import generator.domain.Course;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【course(课程表)】的数据库操作Service
|
||||
* @createDate 2025-04-15 00:32:28
|
||||
*/
|
||||
public interface CourseService extends IService<Course> {
|
||||
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package generator.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import generator.domain.Course;
|
||||
import generator.service.CourseService;
|
||||
import generator.mapper.CourseMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【course(课程表)】的数据库操作Service实现
|
||||
* @createDate 2025-04-15 00:32:28
|
||||
*/
|
||||
@Service
|
||||
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
||||
implements CourseService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.ChallengeParams;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【challenge_params】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 18:10:37
|
||||
* @Entity com.guwan.backend.pojo.entity.ChallengeParams
|
||||
*/
|
||||
public interface ChallengeParamsMapper extends BaseMapper<ChallengeParams> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Challenges;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【challenges】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 17:58:59
|
||||
* @Entity com.guwan.backend.pojo.entity.Challenges
|
||||
*/
|
||||
public interface ChallengesMapper extends BaseMapper<Challenges> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Chapter;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【chapter】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 14:39:30
|
||||
* @Entity com.guwan.backend.pojo.entity.Chapter
|
||||
*/
|
||||
public interface ChapterMapper extends BaseMapper<Chapter> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.RatingDistribution;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【rating_distribution(课程评分分布表)】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 14:32:23
|
||||
* @Entity com.guwan.backend.pojo.entity.RatingDistribution
|
||||
*/
|
||||
@Mapper
|
||||
public interface RatingDistributionMapper extends BaseMapper<RatingDistribution> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Review;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【review(课程评价表)】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 14:42:13
|
||||
* @Entity com.guwan.backend.pojo.entity.Review
|
||||
*/
|
||||
public interface ReviewMapper extends BaseMapper<Review> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Section;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【section】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 14:52:51
|
||||
* @Entity com.guwan.backend.pojo.entity.Section
|
||||
*/
|
||||
@Mapper
|
||||
public interface SectionMapper extends BaseMapper<Section> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Slide;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【slide(PPT幻灯片表)】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 15:51:55
|
||||
* @Entity com.guwan.backend.pojo.entity.Slide
|
||||
*/
|
||||
public interface SlideMapper extends BaseMapper<Slide> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.TestCaseParams;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【test_case_params】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 18:19:18
|
||||
* @Entity com.guwan.backend.pojo.entity.TestCaseParams
|
||||
*/
|
||||
public interface TestCaseParamsMapper extends BaseMapper<TestCaseParams> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.guwan.backend.mapper;
|
||||
|
||||
import com.guwan.backend.pojo.entity.TestCases;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【test_cases】的数据库操作Mapper
|
||||
* @createDate 2025-05-08 18:14:58
|
||||
* @Entity com.guwan.backend.pojo.entity.TestCases
|
||||
*/
|
||||
public interface TestCasesMapper extends BaseMapper<TestCases> {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.guwan.backend.pojo.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CaseResult {
|
||||
private Integer caseId;
|
||||
private String input;
|
||||
private String expected;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.guwan.backend.pojo.bo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CodeRunResult {
|
||||
private String status;
|
||||
private String message;
|
||||
private Integer passCount;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.pojo.bo;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class TestCaseBO {
|
||||
public String input;
|
||||
public String expectedOutput;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.guwan.backend.pojo.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SubmitCodeDTO {
|
||||
private Integer challengeId;
|
||||
private String code;
|
||||
private String language;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @TableName challenge_params
|
||||
*/
|
||||
@TableName(value ="challenge_params")
|
||||
@Data
|
||||
public class ChallengeParams implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Integer challengeId;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Integer paramOrder;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String paramName;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String paramType;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @TableName challenges
|
||||
*/
|
||||
@TableName(value ="challenges")
|
||||
@Data
|
||||
public class Challenges implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Object difficulty;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Integer memoryLimit;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Integer timeLimit;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Integer submitCount;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private BigDecimal acceptRate;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @TableName chapter
|
||||
*/
|
||||
@TableName(value ="chapter")
|
||||
@Data
|
||||
public class Chapter implements Serializable {
|
||||
/**
|
||||
* 章节id
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 关联课程ID
|
||||
*/
|
||||
private String courseId;
|
||||
|
||||
/**
|
||||
* 章节标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 章节排序序号
|
||||
*/
|
||||
private Integer orderNumber;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updatedAt;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 课程评分分布表
|
||||
* @TableName rating_distribution
|
||||
*/
|
||||
@TableName(value ="rating_distribution")
|
||||
@Data
|
||||
public class RatingDistribution implements Serializable {
|
||||
/**
|
||||
* 分布主键
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 关联课程ID(逻辑外键,由代码维护关系)
|
||||
*/
|
||||
private Integer courseId;
|
||||
|
||||
/**
|
||||
* 星级(1-5对应1星到5星)
|
||||
*/
|
||||
private Integer ratingLevel;
|
||||
|
||||
/**
|
||||
* 该星级评分数量
|
||||
*/
|
||||
private Integer count;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updatedAt;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 课程评价表
|
||||
* @TableName review
|
||||
*/
|
||||
@TableName(value ="review")
|
||||
@Data
|
||||
public class Review implements Serializable {
|
||||
/**
|
||||
* 评价主键
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 关联课程ID(逻辑外键,由代码维护关系)
|
||||
*/
|
||||
private Integer courseId;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String userId;
|
||||
|
||||
/**
|
||||
* 用户头像URL
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 评分(1-5)
|
||||
*/
|
||||
private Integer rating;
|
||||
|
||||
/**
|
||||
* 评价内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 评价日期
|
||||
*/
|
||||
private Date date;
|
||||
|
||||
/**
|
||||
* 教师回复
|
||||
*/
|
||||
private String reply;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updatedAt;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @TableName section
|
||||
*/
|
||||
@TableName(value ="section")
|
||||
@Data
|
||||
public class Section implements Serializable {
|
||||
/**
|
||||
* 主键
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 关联章节ID
|
||||
*/
|
||||
private String chapterId;
|
||||
|
||||
/**
|
||||
* 标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 类型
|
||||
*/
|
||||
private Object type;
|
||||
|
||||
/**
|
||||
* 视频时长
|
||||
*/
|
||||
private Integer duration;
|
||||
|
||||
/**
|
||||
* 资源URL
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 是否免费
|
||||
*/
|
||||
private Integer isFree;
|
||||
|
||||
/**
|
||||
* PDF是否允许下载
|
||||
*/
|
||||
private Integer downloadable;
|
||||
|
||||
/**
|
||||
* 小节排序序号
|
||||
*/
|
||||
private Integer orderNumber;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createdAt;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Date updatedAt;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* PPT幻灯片表
|
||||
* @TableName slide
|
||||
*/
|
||||
@TableName(value ="slide")
|
||||
@Data
|
||||
public class Slide implements Serializable {
|
||||
/**
|
||||
* 幻灯片主键
|
||||
*/
|
||||
@TableId
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 关联小节ID(逻辑外键,由代码维护关系)
|
||||
*/
|
||||
private Integer sectionId;
|
||||
|
||||
/**
|
||||
* 幻灯片图片URL
|
||||
*/
|
||||
private String url;
|
||||
|
||||
/**
|
||||
* 幻灯片标题
|
||||
*/
|
||||
private String title;
|
||||
|
||||
/**
|
||||
* 幻灯片排序
|
||||
*/
|
||||
private Integer orderNumber;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private Date createdAt;
|
||||
|
||||
/**
|
||||
* 更新时间
|
||||
*/
|
||||
private Date updatedAt;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @TableName test_case_params
|
||||
*/
|
||||
@TableName(value ="test_case_params")
|
||||
@Data
|
||||
public class TestCaseParams implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Integer testCaseId;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String paramName;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String paramValue;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
package com.guwan.backend.pojo.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import java.io.Serializable;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
*
|
||||
* @TableName test_cases
|
||||
*/
|
||||
@TableName(value ="test_cases")
|
||||
@Data
|
||||
public class TestCases implements Serializable {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private Integer challengeId;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String expectedOutput;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private String explanation;
|
||||
|
||||
@TableField(exist = false)
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package com.guwan.backend.pojo.response;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.guwan.backend.pojo.entity.Challenges;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ChallengesVO extends Challenges {
|
||||
@JsonProperty("testCases")
|
||||
List<TestCaseVO> testCaseVOS;
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
package com.guwan.backend.pojo.response;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class CourceHomeVO {
|
||||
/**
|
||||
* 类别名称
|
||||
*/
|
||||
private String categoryName;
|
||||
/**
|
||||
* 类别标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 学习人数
|
||||
*/
|
||||
private String studentCount;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private BigDecimal rating;
|
||||
|
||||
private String coverImg;
|
||||
}
|
|
@ -1,24 +0,0 @@
|
|||
package com.guwan.backend.pojo.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class CourseDetailVo {
|
||||
/**
|
||||
* 课程标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 课程描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
private String teacherAvatar;
|
||||
|
||||
private Double price;
|
||||
|
||||
private Double rating;
|
||||
|
||||
private Integer ratingCount;
|
||||
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package com.guwan.backend.pojo.response;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class TestCaseVO {
|
||||
private String input;
|
||||
private String output;
|
||||
private String explanation;
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package com.guwan.backend.pojo.response.courseDetail;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class BaseSectionVO {
|
||||
private String id;
|
||||
private String title;
|
||||
private String type; // video / pdf / ppt
|
||||
private boolean isFree;
|
||||
private boolean completed;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package com.guwan.backend.pojo.response.courseDetail;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.guwan.backend.pojo.response.courseDetail.BaseSectionVO;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class ChapterVO {
|
||||
|
||||
private String id;
|
||||
|
||||
private String title;
|
||||
@JsonProperty("sections")
|
||||
List<BaseSectionVO> sectionVOS;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
package com.guwan.backend.pojo.response.courseDetail;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class CourseDetailVO {
|
||||
/**
|
||||
* 课程标题
|
||||
*/
|
||||
private String title;
|
||||
/**
|
||||
* 课程描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
private String teacher;
|
||||
|
||||
private String teacherAvatar;
|
||||
|
||||
private Double price;
|
||||
|
||||
private Double rating;
|
||||
|
||||
private Integer ratingCount;
|
||||
|
||||
private Integer studentCount;
|
||||
|
||||
private Integer videoCount;
|
||||
|
||||
private Integer docCount;
|
||||
|
||||
private Integer totalDuration;
|
||||
|
||||
private Boolean enrolled;
|
||||
|
||||
private String coverImg;
|
||||
@JsonProperty("chapters")
|
||||
private List<ChapterVO> chapterVOS;
|
||||
@JsonProperty("reviews")
|
||||
private List<ReviewVO> reviewVOS;
|
||||
|
||||
private List<Integer> ratingDistribution;
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.guwan.backend.pojo.response.courseDetail;
|
||||
|
||||
import com.guwan.backend.pojo.response.courseDetail.BaseSectionVO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PdfSectionVO extends BaseSectionVO {
|
||||
private String url;
|
||||
private boolean downloadable;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package com.guwan.backend.pojo.response.courseDetail;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PptSectionVO extends BaseSectionVO {
|
||||
private List<SlideVO> slides;
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package com.guwan.backend.pojo.response.courseDetail;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@Data
|
||||
public class ReviewVO {
|
||||
|
||||
private String id;
|
||||
|
||||
@JsonProperty("username")
|
||||
private String userName;
|
||||
|
||||
/**
|
||||
* 用户头像URL
|
||||
*/
|
||||
private String avatar;
|
||||
|
||||
/**
|
||||
* 评分(1-5)
|
||||
*/
|
||||
private Integer rating;
|
||||
|
||||
/**
|
||||
* 评价内容
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 评价日期
|
||||
*/
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private Date date;
|
||||
|
||||
/**
|
||||
* 教师回复
|
||||
*/
|
||||
private String reply;
|
||||
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
package com.guwan.backend.pojo.response.courseDetail;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SlideVO {
|
||||
private String url;
|
||||
private String title;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
package com.guwan.backend.pojo.response.courseDetail;
|
||||
|
||||
import com.guwan.backend.pojo.response.courseDetail.BaseSectionVO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@ToString(callSuper = true)
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class VideoSectionVO extends BaseSectionVO {
|
||||
private String duration;
|
||||
private String url;
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.entity.ChallengeParams;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【challenge_params】的数据库操作Service
|
||||
* @createDate 2025-05-08 18:10:37
|
||||
*/
|
||||
public interface ChallengeParamsService extends IService<ChallengeParams> {
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.bo.CodeRunResult;
|
||||
import com.guwan.backend.pojo.dto.SubmitCodeDTO;
|
||||
import com.guwan.backend.pojo.entity.Challenges;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.guwan.backend.pojo.response.ChallengesVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【challenges】的数据库操作Service
|
||||
* @createDate 2025-05-08 17:58:59
|
||||
*/
|
||||
public interface ChallengesService extends IService<Challenges> {
|
||||
|
||||
List<ChallengesVO> getChallenge();
|
||||
|
||||
|
||||
CodeRunResult submitCode(SubmitCodeDTO submitCodeDTO);
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Chapter;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【chapter】的数据库操作Service
|
||||
* @createDate 2025-05-08 14:39:30
|
||||
*/
|
||||
public interface ChapterService extends IService<Chapter> {
|
||||
|
||||
}
|
|
@ -2,7 +2,9 @@ package com.guwan.backend.service;
|
|||
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import com.guwan.backend.pojo.entity.Course;
|
||||
import com.guwan.backend.pojo.response.CourseDetailVo;
|
||||
import com.guwan.backend.pojo.response.courseDetail.CourseDetailVO;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
|
@ -11,5 +13,11 @@ import com.guwan.backend.pojo.response.CourseDetailVo;
|
|||
*/
|
||||
public interface CourseService extends IService<Course> {
|
||||
|
||||
CourseDetailVo getCourseDetail(String courseId);
|
||||
CourseDetailVO getCourseDetail(String courseId);
|
||||
|
||||
int getStudentCount(String courseId);
|
||||
|
||||
void updateStudentCount(String courseId, int count);
|
||||
|
||||
Map<String, Integer> getAllCourseCounts();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.entity.RatingDistribution;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【rating_distribution(课程评分分布表)】的数据库操作Service
|
||||
* @createDate 2025-05-08 14:32:23
|
||||
*/
|
||||
public interface RatingDistributionService extends IService<RatingDistribution> {
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Review;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【review(课程评价表)】的数据库操作Service
|
||||
* @createDate 2025-05-08 14:42:13
|
||||
*/
|
||||
public interface ReviewService extends IService<Review> {
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Section;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【section】的数据库操作Service
|
||||
* @createDate 2025-05-08 14:52:51
|
||||
*/
|
||||
public interface SectionService extends IService<Section> {
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.entity.Slide;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【slide(PPT幻灯片表)】的数据库操作Service
|
||||
* @createDate 2025-05-08 15:51:55
|
||||
*/
|
||||
public interface SlideService extends IService<Slide> {
|
||||
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.guwan.backend.mapper.ChallengeParamsMapper;
|
||||
import com.guwan.backend.mapper.TestCaseParamsMapper;
|
||||
import com.guwan.backend.mapper.TestCasesMapper;
|
||||
import com.guwan.backend.pojo.bo.TestCaseBO;
|
||||
import com.guwan.backend.pojo.entity.ChallengeParams;
|
||||
import com.guwan.backend.pojo.entity.TestCaseParams;
|
||||
import com.guwan.backend.pojo.entity.TestCases;
|
||||
import org.apache.xmlbeans.impl.xb.ltgfmt.TestCase;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class TestCaseAssemblyService {
|
||||
|
||||
@Autowired
|
||||
private ChallengeParamsMapper challengeParamsMapper;
|
||||
@Autowired
|
||||
private TestCasesMapper testCasesMapper;
|
||||
@Autowired
|
||||
private TestCaseParamsMapper testCaseParamsMapper;
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
public List<TestCaseBO> buildTestCasesForChallenge(Integer challengeId) {
|
||||
List<TestCaseBO> result = new ArrayList<>();
|
||||
|
||||
// 查询题目参数并排序
|
||||
List<ChallengeParams> paramList = challengeParamsMapper.selectList(
|
||||
new LambdaQueryWrapper<ChallengeParams>().eq(ChallengeParams::getChallengeId, challengeId)
|
||||
);
|
||||
paramList.sort(Comparator.comparingInt(ChallengeParams::getParamOrder));
|
||||
|
||||
// 查询所有测试用例
|
||||
List<TestCases> testCases = testCasesMapper.selectList(
|
||||
new LambdaQueryWrapper<TestCases>().eq(TestCases::getChallengeId, challengeId)
|
||||
);
|
||||
|
||||
for (TestCases testCase : testCases) {
|
||||
// 获取该用例的参数值
|
||||
List<TestCaseParams> testCaseParams = testCaseParamsMapper.selectList(
|
||||
new LambdaQueryWrapper<TestCaseParams>().eq(TestCaseParams::getTestCaseId, testCase.getId())
|
||||
);
|
||||
Map<String, String> valueMap = testCaseParams.stream()
|
||||
.collect(Collectors.toMap(TestCaseParams::getParamName, TestCaseParams::getParamValue));
|
||||
|
||||
String input = buildCppInput(paramList, valueMap);
|
||||
String expected = testCase.getExpectedOutput();
|
||||
|
||||
result.add(new TestCaseBO(input, expected));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private String buildCppInput(List<ChallengeParams> paramList, Map<String, String> valueMap) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
for (ChallengeParams param : paramList) {
|
||||
String value = valueMap.get(param.getParamName());
|
||||
String type = param.getParamType();
|
||||
String cppValue = convertToCppInput(value, type);
|
||||
sb.append(cppValue).append("\n");
|
||||
}
|
||||
|
||||
return sb.toString().trim(); // 去掉最后一行的换行
|
||||
}
|
||||
|
||||
private String convertToCppInput(String value, String type) {
|
||||
try {
|
||||
switch (type) {
|
||||
case "int":
|
||||
case "string":
|
||||
return value.replaceAll("^\"|\"$", "");
|
||||
case "int[]":
|
||||
case "List<int>":
|
||||
return value.replaceAll("\\[|\\]", "").replaceAll(",", " ");
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("参数解析失败: value=" + value + ", type=" + type, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.entity.TestCaseParams;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【test_case_params】的数据库操作Service
|
||||
* @createDate 2025-05-08 18:19:18
|
||||
*/
|
||||
public interface TestCaseParamsService extends IService<TestCaseParams> {
|
||||
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.pojo.entity.TestCases;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【test_cases】的数据库操作Service
|
||||
* @createDate 2025-05-08 18:14:58
|
||||
*/
|
||||
public interface TestCasesService extends IService<TestCases> {
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package com.guwan.backend.service;
|
||||
|
||||
import com.guwan.backend.Handler.CoursesWebSocketHandler;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
public class WebSocketService {
|
||||
|
||||
@Autowired
|
||||
private CoursesWebSocketHandler coursesWebSocketHandler;
|
||||
|
||||
public void broadcastStudentCount(String courseId, int count) {
|
||||
String message = String.format(
|
||||
"{\"type\":\"STUDENT_COUNT_UPDATE\",\"courseId\":\"%s\",\"count\":%d}",
|
||||
courseId, count
|
||||
);
|
||||
coursesWebSocketHandler.broadcastMessage(message);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.mapper.ChallengeParamsMapper;
|
||||
import com.guwan.backend.pojo.entity.ChallengeParams;
|
||||
import com.guwan.backend.service.ChallengeParamsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【challenge_params】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 18:10:37
|
||||
*/
|
||||
@Service
|
||||
public class ChallengeParamsServiceImpl extends ServiceImpl<ChallengeParamsMapper, ChallengeParams>
|
||||
implements ChallengeParamsService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,253 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
|
||||
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 com.github.dockerjava.api.DockerClient;
|
||||
import com.github.dockerjava.api.command.CreateContainerResponse;
|
||||
import com.github.dockerjava.api.command.ExecCreateCmdResponse;
|
||||
import com.github.dockerjava.api.model.HostConfig;
|
||||
import com.github.dockerjava.core.command.ExecStartResultCallback;
|
||||
import com.guwan.backend.mapper.ChallengeParamsMapper;
|
||||
import com.guwan.backend.mapper.ChallengesMapper;
|
||||
import com.guwan.backend.mapper.TestCaseParamsMapper;
|
||||
import com.guwan.backend.mapper.TestCasesMapper;
|
||||
import com.guwan.backend.pojo.bo.CodeRunResult;
|
||||
import com.guwan.backend.pojo.bo.TestCaseBO;
|
||||
import com.guwan.backend.pojo.dto.SubmitCodeDTO;
|
||||
import com.guwan.backend.pojo.entity.*;
|
||||
import com.guwan.backend.pojo.response.ChallengesVO;
|
||||
import com.guwan.backend.pojo.response.TestCaseVO;
|
||||
import com.guwan.backend.service.ChallengesService;
|
||||
|
||||
import com.guwan.backend.service.TestCaseAssemblyService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.bson.types.Code;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.w3c.dom.stylesheets.LinkStyle;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【challenges】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 17:58:59
|
||||
*/
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ChallengesServiceImpl extends ServiceImpl<ChallengesMapper, Challenges>
|
||||
implements ChallengesService{
|
||||
|
||||
private final ChallengesMapper challengesMapper;
|
||||
private final ChallengeParamsMapper challengeParamsMapper;
|
||||
private final TestCasesMapper testCasesMapper;
|
||||
private final TestCaseParamsMapper testCaseParamsMapper;
|
||||
private final DockerClient dockerClient;
|
||||
private final TestCaseAssemblyService testCaseAssemblyService;
|
||||
@Override
|
||||
public List<ChallengesVO> getChallenge() {
|
||||
|
||||
ArrayList<ChallengesVO> challengesVOS = new ArrayList<>();
|
||||
Page<Challenges> page = new Page<>(1, 10);
|
||||
|
||||
LambdaQueryWrapper<Challenges> lambdaQueryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
List<Challenges> challengesList = challengesMapper.selectList(page, lambdaQueryWrapper);
|
||||
|
||||
for (Challenges challenges : challengesList) {
|
||||
ArrayList<TestCaseVO> testCaseVOS = new ArrayList<>();
|
||||
Integer challengesId = challenges.getId();
|
||||
List<ChallengeParams> challengeParams = challengeParamsMapper.selectList(new LambdaQueryWrapper<ChallengeParams>().eq(ChallengeParams::getChallengeId, challengesId));
|
||||
//获取题目的参数定义并按顺序排好
|
||||
challengeParams.sort(Comparator.comparingInt(ChallengeParams::getParamOrder));
|
||||
|
||||
List<TestCases> testCases = testCasesMapper.selectList(new LambdaQueryWrapper<TestCases>().eq(TestCases::getChallengeId, challengesId));
|
||||
|
||||
for (TestCases testCase : testCases) {
|
||||
Integer testCaseId = testCase.getId();
|
||||
|
||||
List<TestCaseParams> testCaseParams = testCaseParamsMapper.selectList(new LambdaQueryWrapper<TestCaseParams>().eq(TestCaseParams::getTestCaseId, testCaseId));
|
||||
|
||||
Map<String, String> paramValueMap = testCaseParams.stream()
|
||||
.collect(Collectors.toMap(TestCaseParams::getParamName, TestCaseParams::getParamValue));
|
||||
|
||||
|
||||
// 4. 根据 paramDefs 顺序拼接 input 字符串
|
||||
StringBuilder inputBuilder = new StringBuilder();
|
||||
for (int i = 0; i < challengeParams.size(); i++) {
|
||||
ChallengeParams paramDef = challengeParams.get(i);
|
||||
String paramName = paramDef.getParamName();
|
||||
String value = paramValueMap.get(paramName);
|
||||
inputBuilder.append(paramName).append(" = ").append(value);
|
||||
if (i < challengeParams.size() - 1) {
|
||||
inputBuilder.append(", ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
TestCaseVO testCaseVO = new TestCaseVO();
|
||||
testCaseVO.setInput(inputBuilder.toString());
|
||||
testCaseVO.setOutput(testCase.getExpectedOutput());
|
||||
testCaseVO.setExplanation(testCase.getExplanation() != null ? testCase.getExplanation() : "");
|
||||
testCaseVOS.add(testCaseVO);
|
||||
}
|
||||
|
||||
ChallengesVO challengesVO = new ChallengesVO();
|
||||
BeanUtils.copyProperties(challenges, challengesVO);
|
||||
challengesVO.setTestCaseVOS(testCaseVOS);
|
||||
challengesVOS.add(challengesVO);
|
||||
|
||||
}
|
||||
|
||||
for (ChallengesVO challengesVO : challengesVOS) {
|
||||
System.out.println("challengesVO = " + challengesVO);
|
||||
}
|
||||
|
||||
return challengesVOS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeRunResult submitCode(SubmitCodeDTO submitCodeDTO) {
|
||||
List<TestCaseBO> testCaseBOS = testCaseAssemblyService.buildTestCasesForChallenge(submitCodeDTO.getChallengeId());
|
||||
for (TestCaseBO testCaseBO : testCaseBOS) {
|
||||
System.out.println("testCaseBO = " + testCaseBO);
|
||||
}
|
||||
CodeRunResult codeRunResult = judgeCode(submitCodeDTO.getCode(), testCaseBOS);
|
||||
System.out.println("codeRunResult = " + codeRunResult);
|
||||
|
||||
return codeRunResult;
|
||||
}
|
||||
|
||||
|
||||
public CodeRunResult judgeCode(String code, List<TestCaseBO> testCases) {
|
||||
CodeRunResult codeRunResult = new CodeRunResult();
|
||||
|
||||
String containerId = null;
|
||||
try {
|
||||
// 创建容器(使用官方GCC镜像)
|
||||
CreateContainerResponse container = dockerClient.createContainerCmd("gcc:latest")
|
||||
.withTty(true)
|
||||
.withWorkingDir("/app")
|
||||
.withHostConfig(HostConfig.newHostConfig()
|
||||
.withMemory(100 * 1024 * 1024L) // 限制内存100MB
|
||||
.withCpuCount(1L)) // 限制1核CPU
|
||||
.exec();
|
||||
|
||||
containerId = container.getId();
|
||||
dockerClient.startContainerCmd(containerId).exec();
|
||||
|
||||
// 1. 写入代码文件
|
||||
execCommand(containerId, "mkdir -p /app", 10);
|
||||
execCommand(containerId,
|
||||
"bash -c 'cat > /app/main.cpp <<EOF\n" +
|
||||
code.replace("'", "'\"'\"'") + // 处理单引号
|
||||
"\nEOF'", 10);
|
||||
|
||||
// 2. 编译代码(带编译错误检查)
|
||||
String compileOutput = execCommand(containerId, "g++ main.cpp -o main -O2 -Wall", 10);
|
||||
if (!compileOutput.isEmpty()) {
|
||||
codeRunResult.setStatus("compile_error");
|
||||
codeRunResult.setMessage(compileOutput);
|
||||
return codeRunResult;
|
||||
}
|
||||
|
||||
// 3. 执行测试用例
|
||||
List<Map<String, Object>> caseResults = new ArrayList<>();
|
||||
for (int i = 0; i < testCases.size(); i++) {
|
||||
TestCaseBO testCase = testCases.get(i);
|
||||
Map<String, Object> caseResult = new HashMap<>();
|
||||
caseResult.put("case_id", i + 1);
|
||||
caseResult.put("input", testCase.input);
|
||||
caseResult.put("expected", testCase.expectedOutput);
|
||||
|
||||
try {
|
||||
// 写入输入文件
|
||||
execCommand(containerId,
|
||||
"bash -c 'cat > /app/input.txt <<EOF\n" +
|
||||
testCase.input.replace("'", "'\"'\"'") +
|
||||
"\nEOF'", 10);
|
||||
|
||||
// 执行程序(带超时控制)
|
||||
String actualOutput = execCommand(containerId,
|
||||
"timeout 2s ./main < /app/input.txt 2>&1", // 捕获标准错误
|
||||
3 // 超时3秒
|
||||
);
|
||||
|
||||
// 标准化输出处理
|
||||
actualOutput = actualOutput.trim()
|
||||
.replaceAll("\r\n", "\n")
|
||||
.replaceAll("[ \\t]+", " ");
|
||||
|
||||
// 结果对比
|
||||
boolean isPassed = actualOutput.equals(testCase.expectedOutput);
|
||||
caseResult.put("status", isPassed ? "passed" : "failed");
|
||||
caseResult.put("actual", actualOutput);
|
||||
|
||||
// 特殊错误类型检测
|
||||
if (actualOutput.contains("Timeout")) {
|
||||
caseResult.put("status", "time_limit_exceeded");
|
||||
} else if (actualOutput.contains("runtime error")) {
|
||||
caseResult.put("status", "runtime_error");
|
||||
} else if (actualOutput.isEmpty()) {
|
||||
caseResult.put("status", "no_output");
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
caseResult.put("status", "system_error");
|
||||
caseResult.put("message", e.getMessage());
|
||||
}
|
||||
|
||||
caseResults.add(caseResult);
|
||||
}
|
||||
|
||||
codeRunResult.setStatus("completed");
|
||||
//result.put("cases", caseResults);
|
||||
codeRunResult.setPassCount((int) caseResults.stream()
|
||||
.filter(c -> "passed".equals(c.get("status")))
|
||||
.count());
|
||||
|
||||
} catch (Exception e) {
|
||||
codeRunResult.setStatus("system_error");
|
||||
|
||||
codeRunResult.setMessage(e.getMessage());
|
||||
} finally {
|
||||
if (containerId != null) {
|
||||
dockerClient.removeContainerCmd(containerId)
|
||||
.withForce(true)
|
||||
.exec();
|
||||
}
|
||||
}
|
||||
|
||||
return codeRunResult;
|
||||
}
|
||||
|
||||
// 辅助方法:执行容器命令
|
||||
private String execCommand(String containerId, String command, int timeoutSeconds)
|
||||
throws Exception {
|
||||
|
||||
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
||||
ExecCreateCmdResponse exec = dockerClient.execCreateCmd(containerId)
|
||||
.withCmd("bash", "-c", command)
|
||||
.withAttachStdout(true)
|
||||
.withAttachStderr(true)
|
||||
.exec();
|
||||
|
||||
dockerClient.execStartCmd(exec.getId())
|
||||
.exec(new ExecStartResultCallback(output, output))
|
||||
.awaitCompletion(timeoutSeconds, TimeUnit.SECONDS);
|
||||
|
||||
return output.toString().trim();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.pojo.entity.Chapter;
|
||||
import com.guwan.backend.service.ChapterService;
|
||||
import com.guwan.backend.mapper.ChapterMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【chapter】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 14:39:30
|
||||
*/
|
||||
@Service
|
||||
public class ChapterServiceImpl extends ServiceImpl<ChapterMapper, Chapter>
|
||||
implements ChapterService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -2,19 +2,21 @@ package com.guwan.backend.service.impl;
|
|||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.mapper.CourseMapper;
|
||||
import com.guwan.backend.mapper.TeacherMapper;
|
||||
import com.guwan.backend.pojo.entity.Course;
|
||||
import com.guwan.backend.pojo.entity.Teacher;
|
||||
import com.guwan.backend.pojo.response.CourseDetailVo;
|
||||
import com.guwan.backend.factory.SectionVOFactory;
|
||||
import com.guwan.backend.mapper.*;
|
||||
import com.guwan.backend.pojo.entity.*;
|
||||
import com.guwan.backend.pojo.response.courseDetail.BaseSectionVO;
|
||||
import com.guwan.backend.pojo.response.courseDetail.ChapterVO;
|
||||
import com.guwan.backend.pojo.response.courseDetail.CourseDetailVO;
|
||||
import com.guwan.backend.pojo.response.courseDetail.ReviewVO;
|
||||
import com.guwan.backend.service.CourseService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
|
@ -30,31 +32,152 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
|
|||
|
||||
private final TeacherMapper teacherMapper;
|
||||
|
||||
@Override
|
||||
public CourseDetailVo getCourseDetail(String courseId) {
|
||||
private final RatingDistributionMapper ratingDistributionMapper;
|
||||
|
||||
private final ChapterMapper chapterMapper;
|
||||
|
||||
private final SectionMapper sectionMapper;
|
||||
|
||||
private final SectionVOFactory sectionVOFactory;
|
||||
|
||||
private final ReviewMapper reviewMapper;
|
||||
|
||||
private final UserMapper userMapper;
|
||||
|
||||
private static final Map<String, Integer> courseStudentCounts = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public CourseDetailVO getCourseDetail(String courseId) {
|
||||
|
||||
//首选查询course表
|
||||
Course course = courseMapper.selectOne(new LambdaQueryWrapper<Course>().eq(Course::getId, courseId));
|
||||
|
||||
if (course == null){
|
||||
if (course == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
System.out.println("course = " + course);
|
||||
|
||||
CourseDetailVO courseDetailVO = new CourseDetailVO();
|
||||
courseDetailVO.setTitle(course.getTitle());
|
||||
courseDetailVO.setDescription(course.getDescription());
|
||||
|
||||
// Course(id=1, title=黑马程序员匠心之作|C++教程从0到1入门编程, description=null, categoryId=2, categoryName=null, teacherId=1, coverImg=http://localhost:9000/photo/cover/c315f738-71aa-4329-8c7c-9092284c33c3.png, price=0.00, coursrTeacherId=null, rating=0.0, ratingCount=null, studentCount=0, videoCount=null, documentCount=null, totalDuration=null, createdAt=null, updatedAt=null)
|
||||
var teacherId = course.getTeacherId();
|
||||
Teacher teacher = null;
|
||||
if (teacherId != null) {
|
||||
teacher = teacherMapper.selectById(teacherId);
|
||||
}
|
||||
if (teacher != null) {
|
||||
courseDetailVO.setTeacher(teacher.getName());
|
||||
courseDetailVO.setTeacherAvatar(teacher.getAvatar());
|
||||
}
|
||||
|
||||
Teacher teacher = teacherMapper.selectById(teacherId);
|
||||
teacher.getName();
|
||||
teacher.getAvatar();
|
||||
courseDetailVO.setPrice(course.getPrice().doubleValue());
|
||||
|
||||
List<RatingDistribution> ratingDistributions = ratingDistributionMapper.selectList(new LambdaQueryWrapper<RatingDistribution>().eq(RatingDistribution::getCourseId, courseId));
|
||||
|
||||
ratingDistributions.sort(Comparator.comparingInt(RatingDistribution::getRatingLevel).reversed());
|
||||
|
||||
int ratingCount = 0;
|
||||
|
||||
int totalCount = 0;
|
||||
|
||||
for (RatingDistribution ratingDistribution : ratingDistributions) {
|
||||
ratingCount += ratingDistribution.getCount();
|
||||
totalCount += ratingDistribution.getCount() * ratingDistribution.getRatingLevel();
|
||||
}
|
||||
|
||||
courseDetailVO.setRating((double) totalCount / ratingCount);
|
||||
|
||||
courseDetailVO.setRatingCount(ratingCount);
|
||||
|
||||
courseDetailVO.setStudentCount(0);
|
||||
|
||||
List<Chapter> chapters = chapterMapper.selectList(new LambdaQueryWrapper<Chapter>().eq(Chapter::getCourseId, courseId));
|
||||
|
||||
List<String> chapterIds = chapters.stream().map(Chapter::getId).toList();
|
||||
List<Section> sections = sectionMapper.selectList(new LambdaQueryWrapper<Section>().in(Section::getChapterId, chapterIds));
|
||||
|
||||
int videoCount = 0;
|
||||
|
||||
int docCount = 0;
|
||||
|
||||
int totalTimeOfMinute = 0;
|
||||
|
||||
for (Section section : sections) {
|
||||
if (Objects.equals("video", section.getType())){
|
||||
videoCount ++;
|
||||
totalTimeOfMinute += section.getDuration();
|
||||
|
||||
}else {
|
||||
docCount ++;
|
||||
}
|
||||
}
|
||||
|
||||
courseDetailVO.setVideoCount(videoCount);
|
||||
|
||||
courseDetailVO.setDocCount(docCount);
|
||||
|
||||
courseDetailVO.setTotalDuration(totalTimeOfMinute / 60);
|
||||
|
||||
courseDetailVO.setEnrolled(false);
|
||||
|
||||
courseDetailVO.setCoverImg(course.getCoverImg());
|
||||
List<ChapterVO> chapterVOList = new ArrayList<>();
|
||||
//chapter 变 vo
|
||||
chapters.sort(Comparator.comparingInt(Chapter::getOrderNumber));
|
||||
for (Chapter chapter : chapters) {
|
||||
System.out.println("chapter = " + chapter);
|
||||
ChapterVO chapterVO = new ChapterVO();
|
||||
BeanUtils.copyProperties(chapter, chapterVO);
|
||||
String chapterId = chapter.getId();
|
||||
|
||||
List<Section> sectionList = sectionMapper.selectList(new LambdaQueryWrapper<Section>().eq(Section::getChapterId, chapterId));
|
||||
|
||||
sectionList.sort(Comparator.comparingInt(Section::getOrderNumber));
|
||||
|
||||
List<BaseSectionVO> BaseSectionVOs = sectionList.stream()
|
||||
.map(sectionVOFactory::fromSection) // 用实例方法引用
|
||||
.toList();
|
||||
|
||||
chapterVO.setSectionVOS(BaseSectionVOs);
|
||||
chapterVOList.add(chapterVO);
|
||||
}
|
||||
courseDetailVO.setChapterVOS(chapterVOList);
|
||||
|
||||
List<Review> reviews = reviewMapper.selectList(new LambdaQueryWrapper<Review>().eq(Review::getCourseId, courseId));
|
||||
|
||||
|
||||
List<String> words = new ArrayList<>(Arrays.asList("apple", "banana", "cherry"));
|
||||
Collections.sort(words, (s1, s2) -> s2.length() - s1.length()); // 按长度降序
|
||||
System.out.println(words); // 输出: [banana, cherry, apple]
|
||||
List<ReviewVO> reviewVOList = reviews.stream().map(review -> {
|
||||
ReviewVO reviewVO = new ReviewVO();
|
||||
BeanUtils.copyProperties(review, reviewVO);
|
||||
String userId = review.getUserId();
|
||||
User user = userMapper.selectById(userId);
|
||||
reviewVO.setUserName(user.getUsername());
|
||||
return reviewVO;
|
||||
}).toList();
|
||||
|
||||
return null;
|
||||
courseDetailVO.setReviewVOS(reviewVOList);
|
||||
|
||||
|
||||
courseDetailVO.setRatingDistribution(ratingDistributions.stream().map(RatingDistribution::getCount).collect(Collectors.toList()));
|
||||
System.out.println("courseDetailVO = " + courseDetailVO);
|
||||
return courseDetailVO;
|
||||
|
||||
|
||||
}
|
||||
|
||||
public int getStudentCount(String courseId) {
|
||||
return courseStudentCounts.getOrDefault(courseId, 0);
|
||||
}
|
||||
|
||||
public void updateStudentCount(String courseId, int count) {
|
||||
courseStudentCounts.put(courseId, count);
|
||||
}
|
||||
|
||||
public Map<String, Integer> getAllCourseCounts() {
|
||||
return new HashMap<>(courseStudentCounts);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.pojo.entity.RatingDistribution;
|
||||
import com.guwan.backend.service.RatingDistributionService;
|
||||
import com.guwan.backend.mapper.RatingDistributionMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【rating_distribution(课程评分分布表)】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 14:32:23
|
||||
*/
|
||||
@Service
|
||||
public class RatingDistributionServiceImpl extends ServiceImpl<RatingDistributionMapper, RatingDistribution>
|
||||
implements RatingDistributionService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.mapper.ReviewMapper;
|
||||
import com.guwan.backend.pojo.entity.Review;
|
||||
import com.guwan.backend.service.ReviewService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【review(课程评价表)】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 14:42:13
|
||||
*/
|
||||
@Service
|
||||
public class ReviewServiceImpl extends ServiceImpl<ReviewMapper, Review>
|
||||
implements ReviewService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.mapper.SectionMapper;
|
||||
import com.guwan.backend.pojo.entity.Section;
|
||||
import com.guwan.backend.service.SectionService;
|
||||
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【section】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 14:52:51
|
||||
*/
|
||||
@Service
|
||||
public class SectionServiceImpl extends ServiceImpl<SectionMapper, Section>
|
||||
implements SectionService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.mapper.SlideMapper;
|
||||
import com.guwan.backend.pojo.entity.Slide;
|
||||
import com.guwan.backend.service.SlideService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【slide(PPT幻灯片表)】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 15:51:55
|
||||
*/
|
||||
@Service
|
||||
public class SlideServiceImpl extends ServiceImpl<SlideMapper, Slide>
|
||||
implements SlideService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.pojo.entity.TestCaseParams;
|
||||
import com.guwan.backend.service.TestCaseParamsService;
|
||||
import com.guwan.backend.mapper.TestCaseParamsMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【test_case_params】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 18:19:18
|
||||
*/
|
||||
@Service
|
||||
public class TestCaseParamsServiceImpl extends ServiceImpl<TestCaseParamsMapper, TestCaseParams>
|
||||
implements TestCaseParamsService{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.guwan.backend.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import com.guwan.backend.mapper.TestCasesMapper;
|
||||
import com.guwan.backend.pojo.entity.TestCases;
|
||||
|
||||
import com.guwan.backend.service.TestCasesService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author 12455
|
||||
* @description 针对表【test_cases】的数据库操作Service实现
|
||||
* @createDate 2025-05-08 18:14:58
|
||||
*/
|
||||
@Service
|
||||
public class TestCasesServiceImpl extends ServiceImpl<TestCasesMapper, TestCases>
|
||||
implements TestCasesService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -5,6 +5,9 @@ spring:
|
|||
application:
|
||||
name: backend
|
||||
|
||||
jpa:
|
||||
open-in-view: false
|
||||
|
||||
kafka:
|
||||
bootstrap-servers: localhost:9092
|
||||
consumer:
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mapper.ChallengeParamsMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.ChallengeParams">
|
||||
<id property="id" column="id" jdbcType="INTEGER"/>
|
||||
<result property="challengeId" column="challenge_id" jdbcType="INTEGER"/>
|
||||
<result property="paramOrder" column="param_order" jdbcType="INTEGER"/>
|
||||
<result property="paramName" column="param_name" jdbcType="VARCHAR"/>
|
||||
<result property="paramType" column="param_type" jdbcType="VARCHAR"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,challenge_id,param_order,
|
||||
param_name,param_type
|
||||
</sql>
|
||||
</mapper>
|
|
@ -0,0 +1,23 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mapper.ChallengesMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Challenges">
|
||||
<id property="id" column="id" jdbcType="INTEGER"/>
|
||||
<result property="title" column="title" jdbcType="VARCHAR"/>
|
||||
<result property="difficulty" column="difficulty" jdbcType="OTHER"/>
|
||||
<result property="description" column="description" jdbcType="VARCHAR"/>
|
||||
<result property="memoryLimit" column="memory_limit" jdbcType="INTEGER"/>
|
||||
<result property="timeLimit" column="time_limit" jdbcType="INTEGER"/>
|
||||
<result property="submitCount" column="submit_count" jdbcType="INTEGER"/>
|
||||
<result property="acceptRate" column="accept_rate" jdbcType="DECIMAL"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,title,difficulty,
|
||||
description,memory_limit,time_limit,
|
||||
submit_count,accept_rate
|
||||
</sql>
|
||||
</mapper>
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.guwan.backend.mapper.ChapterMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Chapter">
|
||||
<id property="id" column="id" jdbcType="VARCHAR"/>
|
||||
<result property="courseId" column="course_id" jdbcType="VARCHAR"/>
|
||||
<result property="title" column="title" jdbcType="VARCHAR"/>
|
||||
<result property="orderNumber" column="order_number" jdbcType="INTEGER"/>
|
||||
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
|
||||
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,course_id,title,
|
||||
order_number,created_at,updated_at
|
||||
</sql>
|
||||
</mapper>
|
|
@ -1,35 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="generator.mapper.CourseMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Course">
|
||||
<id property="id" column="id" jdbcType="VARCHAR"/>
|
||||
<result property="title" column="title" jdbcType="VARCHAR"/>
|
||||
<result property="description" column="description" jdbcType="VARCHAR"/>
|
||||
<result property="categoryId" column="category_id" jdbcType="VARCHAR"/>
|
||||
<result property="categoryName" column="category_name" jdbcType="VARCHAR"/>
|
||||
<result property="teacherId" column="teacher_id" jdbcType="VARCHAR"/>
|
||||
<result property="coverImg" column="cover_img" jdbcType="VARCHAR"/>
|
||||
<result property="price" column="price" jdbcType="DECIMAL"/>
|
||||
<result property="coursrTeacherId" column="coursr_teacher_id" jdbcType="VARCHAR"/>
|
||||
<result property="rating" column="rating" jdbcType="DECIMAL"/>
|
||||
<result property="ratingCount" column="rating_count" jdbcType="INTEGER"/>
|
||||
<result property="studentCount" column="student_count" jdbcType="INTEGER"/>
|
||||
<result property="videoCount" column="video_count" jdbcType="INTEGER"/>
|
||||
<result property="documentCount" column="document_count" jdbcType="INTEGER"/>
|
||||
<result property="totalDuration" column="total_duration" jdbcType="INTEGER"/>
|
||||
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
|
||||
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,title,description,
|
||||
category_id,category_name,teacher_id,
|
||||
cover_img,price,coursr_teacher_id,
|
||||
rating,rating_count,student_count,
|
||||
video_count,document_count,total_duration,
|
||||
created_at,updated_at
|
||||
</sql>
|
||||
</mapper>
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="generator.mapper.RatingDistributionMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.RatingDistribution">
|
||||
<id property="id" column="id" jdbcType="VARCHAR"/>
|
||||
<result property="courseId" column="course_id" jdbcType="INTEGER"/>
|
||||
<result property="ratingLevel" column="rating_level" jdbcType="INTEGER"/>
|
||||
<result property="count" column="count" jdbcType="INTEGER"/>
|
||||
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
|
||||
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,course_id,rating_level,
|
||||
count,created_at,updated_at
|
||||
</sql>
|
||||
</mapper>
|
|
@ -0,0 +1,26 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mapper.ReviewMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Review">
|
||||
<id property="id" column="id" jdbcType="VARCHAR"/>
|
||||
<result property="courseId" column="course_id" jdbcType="INTEGER"/>
|
||||
<result property="userId" column="userId" jdbcType="VARCHAR"/>
|
||||
<result property="avatar" column="avatar" jdbcType="VARCHAR"/>
|
||||
<result property="rating" column="rating" jdbcType="INTEGER"/>
|
||||
<result property="content" column="content" jdbcType="VARCHAR"/>
|
||||
<result property="date" column="date" jdbcType="DATE"/>
|
||||
<result property="reply" column="reply" jdbcType="VARCHAR"/>
|
||||
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
|
||||
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,course_id,userId,
|
||||
avatar,rating,content,
|
||||
date,reply,created_at,
|
||||
updated_at
|
||||
</sql>
|
||||
</mapper>
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mapper.SectionMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Section">
|
||||
<id property="id" column="id" jdbcType="VARCHAR"/>
|
||||
<result property="chapterId" column="chapter_id" jdbcType="VARCHAR"/>
|
||||
<result property="title" column="title" jdbcType="VARCHAR"/>
|
||||
<result property="type" column="type" jdbcType="OTHER"/>
|
||||
<result property="duration" column="duration" jdbcType="INTEGER"/>
|
||||
<result property="url" column="url" jdbcType="VARCHAR"/>
|
||||
<result property="isFree" column="is_free" jdbcType="TINYINT"/>
|
||||
<result property="downloadable" column="downloadable" jdbcType="TINYINT"/>
|
||||
<result property="orderNumber" column="order_number" jdbcType="INTEGER"/>
|
||||
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
|
||||
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,chapter_id,title,
|
||||
type,duration,url,
|
||||
is_free,downloadable,order_number,
|
||||
created_at,updated_at
|
||||
</sql>
|
||||
</mapper>
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mapper.SlideMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Slide">
|
||||
<id property="id" column="id" jdbcType="VARCHAR"/>
|
||||
<result property="sectionId" column="section_id" jdbcType="INTEGER"/>
|
||||
<result property="url" column="url" jdbcType="VARCHAR"/>
|
||||
<result property="title" column="title" jdbcType="VARCHAR"/>
|
||||
<result property="orderNumber" column="order_number" jdbcType="INTEGER"/>
|
||||
<result property="createdAt" column="created_at" jdbcType="TIMESTAMP"/>
|
||||
<result property="updatedAt" column="updated_at" jdbcType="TIMESTAMP"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,section_id,url,
|
||||
title,order_number,created_at,
|
||||
updated_at
|
||||
</sql>
|
||||
</mapper>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.guwan.backend.mapper.TestCaseParamsMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.TestCaseParams">
|
||||
<id property="id" column="id" jdbcType="INTEGER"/>
|
||||
<result property="testCaseId" column="test_case_id" jdbcType="INTEGER"/>
|
||||
<result property="paramName" column="param_name" jdbcType="VARCHAR"/>
|
||||
<result property="paramValue" column="param_value" jdbcType="VARCHAR"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,test_case_id,param_name,
|
||||
param_value
|
||||
</sql>
|
||||
</mapper>
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="mapper.TestCasesMapper">
|
||||
|
||||
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.TestCases">
|
||||
<id property="id" column="id" jdbcType="INTEGER"/>
|
||||
<result property="challengeId" column="challenge_id" jdbcType="INTEGER"/>
|
||||
<result property="expectedOutput" column="expected_output" jdbcType="VARCHAR"/>
|
||||
<result property="explanation" column="explanation" jdbcType="VARCHAR"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,challenge_id,expected_output,
|
||||
explanation
|
||||
</sql>
|
||||
</mapper>
|
Loading…
Reference in New Issue