feature: [定时任务统计评分和评论功能实现]

This commit is contained in:
ovo 2025-05-08 23:48:32 +08:00
parent 46adeb5622
commit 1b4f330af6
22 changed files with 171 additions and 48 deletions

View File

@ -9,7 +9,7 @@ import org.springframework.web.filter.CorsFilter;
@Configuration
public class CorsConfig {
//get请求变成了options 后端预检过不了怎么改
//get请求变成options 后端预检无法通过怎么办 详见 securityFilterChain
@Bean
public CorsFilter corsFilter() {

View File

@ -20,7 +20,7 @@ import org.springframework.beans.factory.annotation.Autowired;
* @since 2025-04-19 22:54:02
*/
@RestController
@RequestMapping("baseExam")
@RequestMapping("/baseExam")
public class BaseExamController {
/**
* 服务对象

View File

@ -1,27 +0,0 @@
package com.guwan.backend.controller;
class CompileResult {
boolean success;
String message;
// constructor...
}
class CaseResult {
boolean passed;
String input;
String expected;
String actual;
String message;
// 成功构造器
public CaseResult(boolean passed, String input,
String expected, String actual) {
// ...
}
// 失败构造器
public CaseResult(boolean passed, String message) {
// ...
}
}

View File

@ -38,7 +38,6 @@ public class DockerController {
public String getDockerInfo() {
Info info = dockerClient.infoCmd().exec(); // 获取 Docker 守护进程的信息
System.out.println("info = " + info);
return info.toString(); // Docker 信息返回到 HTTP 响应

View File

@ -28,7 +28,7 @@ public class GPTController {
private final QwenStreamingChatModel qwenStreamingChatModel;
private final Aiconfig.Assistant assistant;
@GetMapping("/testQwen")
@GetMapping("/chatWithQwen")
public Result chatWithQwen(@RequestParam(value = "message", required = false) String message) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

View File

@ -18,7 +18,7 @@ import org.springframework.beans.factory.annotation.Autowired;
* @since 2025-01-11 18:02:34
*/
@RestController
@RequestMapping("api/common/questions")
@RequestMapping("/api/common/questions")
public class QuestionsController {
/**
* 服务对象

View File

@ -0,0 +1,26 @@
package com.guwan.backend.controller;
import com.guwan.backend.common.Result;
import com.guwan.backend.pojo.dto.SubmitReviewDTO;
import com.guwan.backend.service.ReviewService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/review")
@RequiredArgsConstructor
public class ReviewController {
private final ReviewService reviewService;
@PostMapping("/submitReview")
public Result submitReview(@RequestBody SubmitReviewDTO submitReviewDTO){
System.out.println("submitReviewDTO = " + submitReviewDTO);
reviewService.submitReview(submitReviewDTO);
return Result.success();
}
}

View File

@ -0,0 +1,11 @@
package com.guwan.backend.pojo.dto;
import lombok.Data;
@Data
public class SubmitReviewDTO {
private Integer courseId;
private String content;
private Integer rating;
private Integer userId;
}

View File

@ -1,5 +1,6 @@
package com.guwan.backend.service;
import com.guwan.backend.pojo.dto.SubmitReviewDTO;
import com.guwan.backend.pojo.entity.Review;
import com.baomidou.mybatisplus.extension.service.IService;
@ -10,4 +11,5 @@ import com.baomidou.mybatisplus.extension.service.IService;
*/
public interface ReviewService extends IService<Review> {
void submitReview(SubmitReviewDTO submitReviewDTO);
}

View File

@ -155,6 +155,7 @@ public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course>
String userId = review.getUserId();
User user = userMapper.selectById(userId);
reviewVO.setUserName(user.getUsername());
reviewVO.setAvatar(user.getAvatar());
return reviewVO;
}).toList();

View File

@ -1,10 +1,19 @@
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.RatingDistributionMapper;
import com.guwan.backend.mapper.ReviewMapper;
import com.guwan.backend.pojo.dto.SubmitReviewDTO;
import com.guwan.backend.pojo.entity.RatingDistribution;
import com.guwan.backend.pojo.entity.Review;
import com.guwan.backend.service.ReviewService;
import com.guwan.backend.util.UUIDUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* @author 12455
@ -12,9 +21,48 @@ import org.springframework.stereotype.Service;
* @createDate 2025-05-08 14:42:13
*/
@Service
@RequiredArgsConstructor
public class ReviewServiceImpl extends ServiceImpl<ReviewMapper, Review>
implements ReviewService {
private final ReviewMapper reviewMapper;
private final RatingDistributionMapper ratingDistributionMapper;
@Transactional
@Override
public void submitReview(SubmitReviewDTO submitReviewDTO) {
Review review = new Review();
review.setId(UUIDUtil.uuid());
Integer courseId = submitReviewDTO.getCourseId();
review.setCourseId(courseId);
//TODO 统一整个项目的用户id类型
review.setUserId(String.valueOf(submitReviewDTO.getUserId()));
Integer rating = submitReviewDTO.getRating();
review.setRating(rating);
review.setContent(submitReviewDTO.getContent());
review.setDate(new Date());
review.setCreatedAt(new Date());
review.setUpdatedAt(new Date());
reviewMapper.insert(review);
RatingDistribution ratingDistribution = ratingDistributionMapper.selectOne(new LambdaQueryWrapper<RatingDistribution>()
.eq(RatingDistribution::getCourseId, courseId)
.eq(RatingDistribution::getRatingLevel, rating));
if (ratingDistribution != null){
ratingDistribution.setCount(ratingDistribution.getCount() + 1);
ratingDistributionMapper.updateById(ratingDistribution);
}else {
RatingDistribution newRatingDistribution = new RatingDistribution();
newRatingDistribution.setId(UUIDUtil.uuid());
newRatingDistribution.setCourseId(courseId);
newRatingDistribution.setRatingLevel(rating);
newRatingDistribution.setCount(1);
ratingDistributionMapper.insert(newRatingDistribution);
}
}
}

View File

@ -6,8 +6,5 @@ public class UUIDUtil {
public static String uuid(){
return UUID.randomUUID().toString().replace("-","");
}
public static void main(String args[]){
String uuid = UUIDUtil.uuid();
System.out.println(uuid);
}
}

View File

@ -0,0 +1,67 @@
package com.guwan.backend.xxljob.job;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import com.guwan.backend.common.BusinessException;
import com.guwan.backend.constant.CacheConstants;
import com.guwan.backend.mapper.CourseMapper;
import com.guwan.backend.mapper.RatingDistributionMapper;
import com.guwan.backend.pojo.entity.Course;
import com.guwan.backend.pojo.entity.RatingDistribution;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Slf4j
@Component
@RequiredArgsConstructor
public class CourseXxlJob {
private final CourseMapper courseMapper;
private final RatingDistributionMapper ratingDistributionMapper;
@XxlJob("courseRatingCount")
public void courseRatingCount() {
log.debug("开始执行统计评分的定时任务");
List<Course> courseList = courseMapper.selectList(new LambdaQueryWrapper<>());
for (Course course : courseList) {
String courseId = course.getId();
List<RatingDistribution> ratingDistributionList = ratingDistributionMapper.selectList(new LambdaQueryWrapper<RatingDistribution>().eq(RatingDistribution::getCourseId, courseId));
if (!ratingDistributionList.isEmpty()){
int ratingCount = 0;
int totalCount = 0;
for (RatingDistribution ratingDistribution : ratingDistributionList) {
ratingCount += ratingDistribution.getCount();
totalCount += ratingDistribution.getCount() * ratingDistribution.getRatingLevel();
}
course.setRating(BigDecimal.valueOf((double) totalCount / ratingCount));
course.setRatingCount(ratingCount);
courseMapper.update(course, new LambdaUpdateWrapper<Course>().eq(Course::getId, courseId));
}
}
log.debug("执行统计评分的定时任务结束");
}
}

View File

@ -5,6 +5,8 @@ import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.stats.CacheStats;
import com.guwan.backend.common.BusinessException;
import com.guwan.backend.constant.CacheConstants;
import com.guwan.backend.mapper.CourseMapper;
import com.guwan.backend.mapper.RatingDistributionMapper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@ -22,7 +24,6 @@ import java.util.Map;
@RequiredArgsConstructor
public class SimpleXxlJob {
private final CacheManager cacheManager;
@XxlJob("demoGuwanJobHandler")
@ -30,7 +31,6 @@ public class SimpleXxlJob {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.out.println("执行定时任务,执行时间:"+sdf.format(new Date()));
for (String cache : CacheConstants.CACHE_LIST) {
@ -43,7 +43,6 @@ public class SimpleXxlJob {
}
}
public Map<String, Object> getStats(String cacheName) {
CaffeineCacheManager caffeineCacheManager = (CaffeineCacheManager) cacheManager;
Cache<Object, Object> nativeCache = null;

View File

@ -212,9 +212,9 @@ logging:
xxl:
job:
enabled: false # 控制是否启用xxl-job
enabled: true # 控制是否启用xxl-job
admin:
addresses: http://192.168.0.122:9001/xxl-job-admin
addresses: http://10.129.41.185:9001/xxl-job-admin
accessToken: GuwanTest
executor:
appname: xxl-job-executor-guwan

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.ChallengeParamsMapper">
<mapper namespace="com.guwan.backend.mapper.ChallengeParamsMapper">
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.ChallengeParams">
<id property="id" column="id" jdbcType="INTEGER"/>

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.ChallengesMapper">
<mapper namespace="com.guwan.backend.mapper.ChallengesMapper">
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Challenges">
<id property="id" column="id" jdbcType="INTEGER"/>

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="generator.mapper.RatingDistributionMapper">
<mapper namespace="com.guwan.backend.mapper.RatingDistributionMapper">
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.RatingDistribution">
<id property="id" column="id" jdbcType="VARCHAR"/>

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.ReviewMapper">
<mapper namespace="com.guwan.backend.mapper.ReviewMapper">
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Review">
<id property="id" column="id" jdbcType="VARCHAR"/>

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.SectionMapper">
<mapper namespace="com.guwan.backend.mapper.SectionMapper">
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Section">
<id property="id" column="id" jdbcType="VARCHAR"/>

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.SlideMapper">
<mapper namespace="com.guwan.backend.mapper.SlideMapper">
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.Slide">
<id property="id" column="id" jdbcType="VARCHAR"/>

View File

@ -2,7 +2,7 @@
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper.TestCasesMapper">
<mapper namespace="com.guwan.backend.mapper.TestCasesMapper">
<resultMap id="BaseResultMap" type="com.guwan.backend.pojo.entity.TestCases">
<id property="id" column="id" jdbcType="INTEGER"/>