From efb3a69498c3a3dddf302e1008fd1ee8d6141005 Mon Sep 17 00:00:00 2001 From: none Date: Mon, 20 Mar 2023 17:52:24 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AF=BE=E6=97=B6=E8=A7=82?= =?UTF-8?q?=E7=9C=8B=E8=BF=9B=E5=BA=A6=E8=AE=B0=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/frontend/HourController.java | 32 ++++++-- .../event/UserCourseHourFinishedEvent.java | 28 +++++++ .../UserCourseHourFinishedListener.java | 36 ++++++++ .../frontend/CourseHourRecordRequest.java | 14 ++++ .../service/UserCourseHourRecordService.java | 12 ++- .../api/service/UserCourseRecordService.java | 11 ++- .../impl/UserCourseHourRecordServiceImpl.java | 82 +++++++++++++++++-- .../impl/UserCourseRecordServiceImpl.java | 59 +++++++++++-- 8 files changed, 248 insertions(+), 26 deletions(-) create mode 100644 src/main/java/xyz/playedu/api/event/UserCourseHourFinishedEvent.java create mode 100644 src/main/java/xyz/playedu/api/listener/UserCourseHourFinishedListener.java create mode 100644 src/main/java/xyz/playedu/api/request/frontend/CourseHourRecordRequest.java diff --git a/src/main/java/xyz/playedu/api/controller/frontend/HourController.java b/src/main/java/xyz/playedu/api/controller/frontend/HourController.java index 1bd7abb..e83335d 100644 --- a/src/main/java/xyz/playedu/api/controller/frontend/HourController.java +++ b/src/main/java/xyz/playedu/api/controller/frontend/HourController.java @@ -1,17 +1,18 @@ package xyz.playedu.api.controller.frontend; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import xyz.playedu.api.PlayEduFCtx; import xyz.playedu.api.caches.UserCanSeeCourseCache; -import xyz.playedu.api.domain.Course; -import xyz.playedu.api.domain.CourseHour; -import xyz.playedu.api.domain.Resource; +import xyz.playedu.api.domain.*; import xyz.playedu.api.exception.NotFoundException; import xyz.playedu.api.exception.ServiceException; +import xyz.playedu.api.request.frontend.CourseHourRecordRequest; import xyz.playedu.api.service.CourseHourService; import xyz.playedu.api.service.CourseService; import xyz.playedu.api.service.ResourceService; +import xyz.playedu.api.service.UserCourseHourRecordService; import xyz.playedu.api.types.JsonResponse; import java.util.HashMap; @@ -36,6 +37,9 @@ public class HourController { @Autowired private ResourceService resourceService; + @Autowired + private UserCourseHourRecordService userCourseHourRecordService; + @GetMapping("/{id}/play") public JsonResponse play(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException, ServiceException { Course course = courseService.findOrFail(courseId); @@ -52,10 +56,28 @@ public class HourController { } @PostMapping("/{id}/record") - public JsonResponse record(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException, ServiceException { + public JsonResponse record(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id, @RequestBody @Validated CourseHourRecordRequest req) throws NotFoundException, ServiceException { + Integer duration = req.getDuration(); + if (duration <= 0) { + return JsonResponse.error("duration参数错误"); + } + User user = PlayEduFCtx.getUser(); + // 线上课检测 + Course course = courseService.findOrFail(courseId); + // 权限校验 + userCanSeeCourseCache.check(user, course, true); + // 课时检测 + CourseHour hour = hourService.findOrFail(id, courseId); + + userCourseHourRecordService.storeOrUpdate(user.getId(), course.getId(), hour.getId(), duration, hour.getDuration()); + + return JsonResponse.success(); + } + + @PostMapping("/{id}/ping") + public JsonResponse ping(@PathVariable(name = "courseId") Integer courseId, @PathVariable(name = "id") Integer id) throws NotFoundException, ServiceException { Course course = courseService.findOrFail(courseId); userCanSeeCourseCache.check(PlayEduFCtx.getUser(), course, true); - CourseHour hour = hourService.findOrFail(id, courseId); return JsonResponse.success(); } diff --git a/src/main/java/xyz/playedu/api/event/UserCourseHourFinishedEvent.java b/src/main/java/xyz/playedu/api/event/UserCourseHourFinishedEvent.java new file mode 100644 index 0000000..6ba3cc7 --- /dev/null +++ b/src/main/java/xyz/playedu/api/event/UserCourseHourFinishedEvent.java @@ -0,0 +1,28 @@ +package xyz.playedu.api.event; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.context.ApplicationEvent; + +import java.util.Date; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/3/20 17:32 + */ +@Getter +@Setter +public class UserCourseHourFinishedEvent extends ApplicationEvent { + private Integer userId; + private Integer courseId; + private Integer hourId; + private Date createdAt; + + public UserCourseHourFinishedEvent(Object source, Integer userId, Integer courseId, Integer hourId) { + super(source); + this.userId = userId; + this.courseId = courseId; + this.hourId = hourId; + this.createdAt = new Date(); + } +} diff --git a/src/main/java/xyz/playedu/api/listener/UserCourseHourFinishedListener.java b/src/main/java/xyz/playedu/api/listener/UserCourseHourFinishedListener.java new file mode 100644 index 0000000..a8e7f03 --- /dev/null +++ b/src/main/java/xyz/playedu/api/listener/UserCourseHourFinishedListener.java @@ -0,0 +1,36 @@ +package xyz.playedu.api.listener; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; +import xyz.playedu.api.event.UserCourseHourFinishedEvent; +import xyz.playedu.api.service.CourseHourService; +import xyz.playedu.api.service.UserCourseHourRecordService; +import xyz.playedu.api.service.UserCourseRecordService; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/3/20 17:41 + */ +@Component +public class UserCourseHourFinishedListener { + + @Autowired + private UserCourseRecordService userCourseRecordService; + + @Autowired + private UserCourseHourRecordService userCourseHourRecordService; + + @Autowired + private CourseHourService hourService; + + @EventListener + @Async + public void userCourseProgressUpdate(UserCourseHourFinishedEvent evt) { + Integer hourCount = hourService.getCountByCourseId(evt.getCourseId()); + Integer finishedCount = userCourseHourRecordService.getFinishedHourCount(evt.getUserId(), evt.getCourseId()); + userCourseRecordService.storeOrUpdate(evt.getUserId(), evt.getCourseId(), hourCount, finishedCount); + } + +} diff --git a/src/main/java/xyz/playedu/api/request/frontend/CourseHourRecordRequest.java b/src/main/java/xyz/playedu/api/request/frontend/CourseHourRecordRequest.java new file mode 100644 index 0000000..1d00a1c --- /dev/null +++ b/src/main/java/xyz/playedu/api/request/frontend/CourseHourRecordRequest.java @@ -0,0 +1,14 @@ +package xyz.playedu.api.request.frontend; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; + +/** + * @Author 杭州白书科技有限公司 + * @create 2023/3/20 17:12 + */ +@Data +public class CourseHourRecordRequest { + @NotNull(message = "duration参数不存在") + private Integer duration; +} diff --git a/src/main/java/xyz/playedu/api/service/UserCourseHourRecordService.java b/src/main/java/xyz/playedu/api/service/UserCourseHourRecordService.java index a14c72b..6203315 100644 --- a/src/main/java/xyz/playedu/api/service/UserCourseHourRecordService.java +++ b/src/main/java/xyz/playedu/api/service/UserCourseHourRecordService.java @@ -4,10 +4,14 @@ import xyz.playedu.api.domain.UserCourseHourRecord; import com.baomidou.mybatisplus.extension.service.IService; /** -* @author tengteng -* @description 针对表【user_course_hour_records】的数据库操作Service -* @createDate 2023-03-20 16:41:08 -*/ + * @author tengteng + * @description 针对表【user_course_hour_records】的数据库操作Service + * @createDate 2023-03-20 16:41:08 + */ public interface UserCourseHourRecordService extends IService { + UserCourseHourRecord find(Integer userId, Integer courseId, Integer hourId); + UserCourseHourRecord storeOrUpdate(Integer userId, Integer courseId, Integer hourId, Integer duration, Integer totalDuration); + + Integer getFinishedHourCount(Integer userId, Integer courseId); } diff --git a/src/main/java/xyz/playedu/api/service/UserCourseRecordService.java b/src/main/java/xyz/playedu/api/service/UserCourseRecordService.java index 3a09655..484bcce 100644 --- a/src/main/java/xyz/playedu/api/service/UserCourseRecordService.java +++ b/src/main/java/xyz/playedu/api/service/UserCourseRecordService.java @@ -4,10 +4,13 @@ import xyz.playedu.api.domain.UserCourseRecord; import com.baomidou.mybatisplus.extension.service.IService; /** -* @author tengteng -* @description 针对表【user_course_records】的数据库操作Service -* @createDate 2023-03-20 16:41:04 -*/ + * @author tengteng + * @description 针对表【user_course_records】的数据库操作Service + * @createDate 2023-03-20 16:41:04 + */ public interface UserCourseRecordService extends IService { + UserCourseRecord find(Integer userId, Integer courseId); + + void storeOrUpdate(Integer userId, Integer courseId, Integer hourCount, Integer finishedCount); } diff --git a/src/main/java/xyz/playedu/api/service/impl/UserCourseHourRecordServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/UserCourseHourRecordServiceImpl.java index 0ad5879..be51a20 100644 --- a/src/main/java/xyz/playedu/api/service/impl/UserCourseHourRecordServiceImpl.java +++ b/src/main/java/xyz/playedu/api/service/impl/UserCourseHourRecordServiceImpl.java @@ -1,20 +1,86 @@ package xyz.playedu.api.service.impl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import xyz.playedu.api.domain.UserCourseHourRecord; +import xyz.playedu.api.event.UserCourseHourFinishedEvent; import xyz.playedu.api.service.UserCourseHourRecordService; import xyz.playedu.api.mapper.UserCourseHourRecordMapper; import org.springframework.stereotype.Service; -/** -* @author tengteng -* @description 针对表【user_course_hour_records】的数据库操作Service实现 -* @createDate 2023-03-20 16:41:08 -*/ -@Service -public class UserCourseHourRecordServiceImpl extends ServiceImpl - implements UserCourseHourRecordService{ +import java.util.Date; +/** + * @author tengteng + * @description 针对表【user_course_hour_records】的数据库操作Service实现 + * @createDate 2023-03-20 16:41:08 + */ +@Service +public class UserCourseHourRecordServiceImpl extends ServiceImpl implements UserCourseHourRecordService { + + @Autowired + private ApplicationContext ctx; + + @Override + public UserCourseHourRecord find(Integer userId, Integer courseId, Integer hourId) { + return getOne(query().getWrapper().eq("user_id", userId).eq("course_id", courseId).eq("hour_id", hourId)); + } + + @Override + public UserCourseHourRecord storeOrUpdate(Integer userId, Integer courseId, Integer hourId, Integer duration, Integer totalDuration) { + UserCourseHourRecord record = find(userId, courseId, hourId); + + // 已看完 + if (record != null && record.getIsFinished() == 1) { + return record; + } + + // 是否看完 + boolean isFinished = duration >= totalDuration; + Date finishedAt = isFinished ? new Date() : null; + + if (record == null) { + UserCourseHourRecord insertRecord = new UserCourseHourRecord(); + insertRecord.setUserId(userId); + insertRecord.setCourseId(courseId); + insertRecord.setHourId(hourId); + insertRecord.setTotalDuration(totalDuration); + insertRecord.setFinishedDuration(duration); + insertRecord.setIsFinished(isFinished ? 1 : 0); + insertRecord.setFinishedAt(finishedAt); + insertRecord.setCreatedAt(new Date()); + insertRecord.setUpdatedAt(new Date()); + + save(insertRecord); + + record = insertRecord; + } else { + // 未看完 && 大于存在的观看记录时长 + if (record.getFinishedDuration() < duration) { + UserCourseHourRecord updateRecord = new UserCourseHourRecord(); + updateRecord.setId(record.getId()); + updateRecord.setTotalDuration(totalDuration); + updateRecord.setFinishedDuration(duration); + updateRecord.setIsFinished(isFinished ? 1 : 0); + updateRecord.setFinishedAt(finishedAt); + + updateById(updateRecord); + record = updateRecord; + } + } + + if (isFinished) { + ctx.publishEvent(new UserCourseHourFinishedEvent(this, record.getUserId(), record.getCourseId(), record.getHourId())); + } + + return record; + } + + @Override + public Integer getFinishedHourCount(Integer userId, Integer courseId) { + return Math.toIntExact(count(query().getWrapper().eq("user_id", userId).eq("course_id", courseId).eq("is_finished", 1))); + } } diff --git a/src/main/java/xyz/playedu/api/service/impl/UserCourseRecordServiceImpl.java b/src/main/java/xyz/playedu/api/service/impl/UserCourseRecordServiceImpl.java index 94b72e7..7ce143c 100644 --- a/src/main/java/xyz/playedu/api/service/impl/UserCourseRecordServiceImpl.java +++ b/src/main/java/xyz/playedu/api/service/impl/UserCourseRecordServiceImpl.java @@ -6,15 +6,64 @@ import xyz.playedu.api.service.UserCourseRecordService; import xyz.playedu.api.mapper.UserCourseRecordMapper; import org.springframework.stereotype.Service; +import java.util.Date; + /** -* @author tengteng -* @description 针对表【user_course_records】的数据库操作Service实现 -* @createDate 2023-03-20 16:41:04 -*/ + * @author tengteng + * @description 针对表【user_course_records】的数据库操作Service实现 + * @createDate 2023-03-20 16:41:04 + */ @Service public class UserCourseRecordServiceImpl extends ServiceImpl - implements UserCourseRecordService{ + implements UserCourseRecordService { + @Override + public UserCourseRecord find(Integer userId, Integer courseId) { + return getOne(query().getWrapper().eq("user_id", userId).eq("course_id", courseId)); + } + + @Override + public void storeOrUpdate(Integer userId, Integer courseId, Integer hourCount, Integer finishedCount) { + if (hourCount == 0) { + return; + } + + UserCourseRecord record = find(userId, courseId); + + // 已看完 + if (record != null && record.getIsFinished() == 1) { + return; + } + + boolean isFinished = finishedCount >= hourCount; + Date finishedAt = isFinished ? new Date() : null; + Integer progress = finishedCount * 100 / hourCount * 100; + + if (record == null) { + UserCourseRecord insertRecord = new UserCourseRecord(); + insertRecord.setUserId(userId); + insertRecord.setCourseId(courseId); + insertRecord.setHourCount(hourCount); + insertRecord.setFinishedCount(finishedCount); + insertRecord.setFinishedAt(finishedAt); + insertRecord.setIsFinished(isFinished ? 1 : 0); + insertRecord.setProgress(progress); + insertRecord.setCreatedAt(new Date()); + insertRecord.setUpdatedAt(new Date()); + + save(insertRecord); + } else { + UserCourseRecord updateRecord = new UserCourseRecord(); + updateRecord.setId(record.getId()); + updateRecord.setHourCount(hourCount); + updateRecord.setFinishedCount(finishedCount); + updateRecord.setFinishedAt(finishedAt); + updateRecord.setIsFinished(isFinished ? 1 : 0); + updateRecord.setProgress(progress); + + updateById(updateRecord); + } + } }