From 50bdc39ce8fc5ecd760592092bc4d978d320f5bb Mon Sep 17 00:00:00 2001 From: 670788339 <670788339@qq.com> Date: Mon, 14 Apr 2025 14:08:01 +0800 Subject: [PATCH] =?UTF-8?q?appendtime=20=E4=BA=8E=20study-video-time=20?= =?UTF-8?q?=E5=90=88=E5=B9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../xboe/school/study/api/StudyCourseApi.java | 58 ++++++++++++++- .../school/study/api/StudyCourseTask.java | 68 ++++++++++++++++-- .../school/study/service/IStudyService.java | 4 ++ .../study/service/impl/StudyServiceImpl.java | 70 ++++++++++++++----- .../java/com/xboe/school/vo/StudyTimeVo.java | 19 +++++ 5 files changed, 196 insertions(+), 23 deletions(-) create mode 100644 servers/boe-server-all/src/main/java/com/xboe/school/vo/StudyTimeVo.java diff --git a/servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseApi.java b/servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseApi.java index 9f041064..1a5a1080 100644 --- a/servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseApi.java +++ b/servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseApi.java @@ -15,6 +15,7 @@ import com.xboe.constants.CacheName; import com.xboe.module.course.vo.TeacherVo; import com.xboe.module.usergroup.service.IUserGroupService; import com.xboe.school.study.dao.StudyCourseDao; +import com.xboe.school.vo.StudyTimeVo; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -625,7 +626,7 @@ public class StudyCourseApi extends ApiBaseController{ @Deprecated @RequestMapping(value="/appendtime",method = {RequestMethod.GET,RequestMethod.POST}) public JsonResponse appendTime(StudyTime studyTime, HttpServletRequest request){ - + if(StringUtils.isBlank(studyTime.getStudyId())){ return error("参数错误"); } @@ -655,6 +656,61 @@ public class StudyCourseApi extends ApiBaseController{ return error("记录学习时长错误",e.getMessage()); } } + + /** + * appendtime 于 study-video-time 合并 + * */ + @RequestMapping(value="/updateStudyVideoTime",method = {RequestMethod.GET,RequestMethod.POST}) + public JsonResponse updateStudyVideoTime(StudyTimeVo studyTime, HttpServletRequest request){ + + // 0 study-video-time , 1 appendtime + if (studyTime.getType() == 0){ + if(StringUtils.isBlank(studyTime.getItemId())){ + return error("参数错误"); + } + if(studyTime.getVideoTime()==null){ + return error("无时间点"); + } + //检查是否已存在 + try { + studyService.updateLastTime(studyTime.getItemId(),studyTime.getVideoTime(), getCurrent().getAccountId()); + if (studyTime.getContentId() != null && studyTime.getCourseId() != null && studyTime.getProgressVideo() != null){ + contentService.updateProcessVideo(studyTime.getContentId(), studyTime.getCourseId(), studyTime.getProgressVideo()); + } + return success("true"); + }catch(Exception e) { + log.error("updateStudyVideoTime type =0 记录最后学习时间错误",e); + return error("updateStudyVideoTime type =0 记录最后学习时间失败 ",e.getMessage()); + } + }else if(studyTime.getType() == 1){ + if(StringUtils.isBlank(studyTime.getStudyId())){ + return error("参数错误"); + } + if(StringUtils.isBlank(studyTime.getCourseId())){ + return error("未指定课程"); + } + if(StringUtils.isBlank(studyTime.getContentId())){ + return error("未指定资源内容"); + } + + String token = request.getHeader("Xboe-Access-Token"); + if (StringUtils.isEmpty(token)) { + token = request.getHeader("token"); + } + try { + studyService.updateStudyDuration(studyTime.getStudyId(),null,studyTime.getContentId(),studyTime.getDuration(),studyTime.getCourseId()); + List allUserList = thirdApi.getStudyCourseList(studyTime.getStudyId() ,studyTime.getCourseId(), token); + log.info("updateStudyVideoTime type =1 在线课学习记录 = " + allUserList); + return success(studyTime.getId()); + }catch(Exception e) { + log.error("updateStudyVideoTime type =1 记录学习时长错误",e); + return error("updateStudyVideoTime type =1 记录学习时长错误 ",e.getMessage()); + } + }else{ + return error("type不能为空"); + } + } + /**获取最后一次的学习内容*/ @GetMapping("/last-study") diff --git a/servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseTask.java b/servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseTask.java index 9236c855..a5b8d8c0 100644 --- a/servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseTask.java +++ b/servers/boe-server-all/src/main/java/com/xboe/school/study/api/StudyCourseTask.java @@ -1,5 +1,7 @@ package com.xboe.school.study.api; +import com.xboe.api.ThirdApi; +import com.xboe.school.study.entity.StudyCourse; import com.xboe.school.study.service.IStudyService; import com.xxl.job.core.handler.annotation.XxlJob; import lombok.RequiredArgsConstructor; @@ -10,8 +12,10 @@ import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.stereotype.Component; +import javax.annotation.Resource; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; +import java.util.List; import java.util.Objects; import java.util.concurrent.TimeUnit; @@ -26,6 +30,8 @@ public class StudyCourseTask { private final IStudyService studyService; private final StringRedisTemplate redisTemplate; + @Resource + private ThirdApi thirdApi; /** * 定时任务 @@ -59,7 +65,6 @@ public class StudyCourseTask { String[] parts = redisKey.split(":"); if (parts.length < 2) continue; String studyContentId = parts[1]; - // 7. 获取存储的时间点(示例逻辑) String redisValue = redisTemplate.opsForValue().get(redisKey); if (redisValue == null) continue; @@ -69,19 +74,15 @@ public class StudyCourseTask { if (partValues.length >= 2){ timestamp = LocalDateTime.parse(partValues[1], formatter); } - // 8. 更新数据库(调用已有服务方法) studyService.updateStudyCourseItemLastTime(studyContentId, lastStudyTime, timestamp); - // 9. 删除Redis键(原子操作) redisTemplate.delete(redisKey); - log.info("处理成功 key: {}, lastStudyTime: {}", redisKey, lastStudyTime); } catch (Exception e) { log.error("处理失败 key: {}", redisKey, e); } } - } cursor.close(); } catch (Exception e) { @@ -101,6 +102,63 @@ public class StudyCourseTask { } + public void saveStudyCourseItemLastTime1() { + // 1. 定义匹配模式(匹配所有目标key) + final String KEY_PATTERN = "studyId:*:courseId:*:courseContentId:*"; + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + // 2. 使用SCAN安全遍历(避免阻塞) + ScanOptions options = ScanOptions.scanOptions() + .match(KEY_PATTERN) + .count(100) // 分页大小 + .build(); + try (RedisConnection connection = Objects.requireNonNull(redisTemplate.getConnectionFactory()).getConnection()) { + Cursor cursor = connection.scan(options); + // 3. 遍历处理符合条件的key + while (cursor.hasNext()) { + String redisKey = new String(cursor.next()); + // 4. 获取剩余TTL(秒) + Long ttl = redisTemplate.getExpire(redisKey, TimeUnit.SECONDS); + + // 5. 过滤条件:剩余时间 >= 29天23小时30分钟(转换为秒) + // 总需时间 = (30天 - 30分钟) = 29天23小时30分钟 = 2590200秒 + // 5分钟 300秒 || 2592000 - 300 = 2591700 + if (ttl <= 2590200) { + try { + // 6. 提取studyContentId + String[] parts = redisKey.split(":"); + if (parts.length < 6) continue; + String studyId = parts[1]; + String courseId = parts[3]; + String courseContentId = parts[5]; + // 7. 获取存储的时间点(示例逻辑) + String redisValue = redisTemplate.opsForValue().get(redisKey); + if (redisValue == null) continue; + String[] partValues = redisValue.split("&"); + int duration = Integer.parseInt(partValues[0]); + LocalDateTime timestamp = null; + if (partValues.length >= 2){ + timestamp = LocalDateTime.parse(partValues[1], formatter); + } + // 8. 更新数据库(调用已有服务方法) + studyService.newAppendStudyDuration(studyId,null,courseContentId,duration,timestamp); + + List allUserList = thirdApi.getStudyCourseList(studyId , courseId, null); + log.info("处理成功 allUserList: {}", allUserList); + // 9. 删除Redis键(原子操作) + redisTemplate.delete(redisKey); + log.info("处理成功 key: {}, lastStudyTime: {}", redisKey, duration); + } catch (Exception e) { + log.error("处理失败 key: {}", redisKey, e); + } + } + } + cursor.close(); + } catch (Exception e) { + log.error("定时任务执行异常", e); + } + + + } } diff --git a/servers/boe-server-all/src/main/java/com/xboe/school/study/service/IStudyService.java b/servers/boe-server-all/src/main/java/com/xboe/school/study/service/IStudyService.java index cc4a66e4..340865e0 100644 --- a/servers/boe-server-all/src/main/java/com/xboe/school/study/service/IStudyService.java +++ b/servers/boe-server-all/src/main/java/com/xboe/school/study/service/IStudyService.java @@ -101,4 +101,8 @@ public interface IStudyService { List getList(String courseId, String contentId, String name, Integer status); void updateStudyCourseItemLastTime(String studyContentId, int lastStudyTime, LocalDateTime timestamp); + + void updateStudyDuration(String studyId,String studyItemId, String contentId, Integer duration,String courseId); + + void newAppendStudyDuration(String studyId, String studyItemId, String courseContentId, int duration, LocalDateTime timestamp); } diff --git a/servers/boe-server-all/src/main/java/com/xboe/school/study/service/impl/StudyServiceImpl.java b/servers/boe-server-all/src/main/java/com/xboe/school/study/service/impl/StudyServiceImpl.java index 589547d3..797b31a2 100644 --- a/servers/boe-server-all/src/main/java/com/xboe/school/study/service/impl/StudyServiceImpl.java +++ b/servers/boe-server-all/src/main/java/com/xboe/school/study/service/impl/StudyServiceImpl.java @@ -116,34 +116,69 @@ public class StudyServiceImpl implements IStudyService{ //增加内容的学习时长 if(StringUtils.isNotBlank(studyItemId)) { //直接根据id更新 -// String hql="Update StudyCourseItem set studyDuration=studyDuration+"+duration+",status=(case when status<2 then 2 else status end) where id=?1"; -// scItemDao.update(hql,studyItemId); String sql="Update boe_study_course_item set study_duration=study_duration+"+duration+",status=(case when status<2 then 2 else status end) where id=?1"; scItemDao.sqlUpdate(sql,studyItemId); - //scItemDao.updateMultiFieldById(studyItemId, UpdateBuilder.create("studyDuration", "studyDuration+"+duration,FieldUpdateType.EXPRESSION)); - + }else { - //根据学习id和课程内容id更新 -// scItemDao.update(UpdateBuilder.from(StudyCourseItem.class) -// .addUpdateField("studyDuration", "studyDuration+"+duration,FieldUpdateType.EXPRESSION) -// .addFilter(FieldFilters.eq("studyId", studyId)) -// .addFilter(FieldFilters.eq("contentId", courseContentId)) -// .builder()); -// -// String hql="Update StudyCourseItem set studyDuration=studyDuration+"+duration+",status=(case when status<2 then 2 else status end) where studyId=?1 and contentId=?2"; -// scItemDao.update(hql,studyId,courseContentId); String sql="Update boe_study_course_item set study_duration=study_duration+"+duration+",status=(case when status<2 then 2 else status end) where study_id=?1 and content_id=?2"; scItemDao.sqlUpdate(sql,studyId,courseContentId); } - //追加课程的学习时长 - //scDao.updateMultiFieldById(studyId, UpdateBuilder.create("totalDuration", "totalDuration+"+duration,FieldUpdateType.EXPRESSION)); - String sql="Update boe_study_course set total_duration=total_duration+"+duration+",status=(case when status<2 then 2 else status end),progress=(case when progress=0 then 1 else progress end),last_time = '"+LocalDateTime.now()+"' where id=?1"; scDao.sqlUpdate(sql,studyId); - } + @Override + @Transactional + public void newAppendStudyDuration(String studyId,String studyItemId,String courseContentId, int duration,LocalDateTime timestamp) { + + //增加内容的学习时长 + if(StringUtils.isNotBlank(studyItemId)) { + //直接根据id更新 + String sql="Update boe_study_course_item set study_duration=study_duration+"+duration+",status=(case when status<2 then 2 else status end) where id=?1"; + scItemDao.sqlUpdate(sql,studyItemId); + + }else { + String sql="Update boe_study_course_item set study_duration=study_duration+"+duration+",status=(case when status<2 then 2 else status end) where study_id=?1 and content_id=?2"; + scItemDao.sqlUpdate(sql,studyId,courseContentId); + } + + String sql="Update boe_study_course set total_duration=total_duration+"+duration+",status=(case when status<2 then 2 else status end),progress=(case when progress=0 then 1 else progress end),last_time = '"+timestamp+"' where id=?1"; + scDao.sqlUpdate(sql,studyId); + } + + // 更新 前端传输已学习时长 + @Override + public void updateStudyDuration(String studyId,String studyItemId,String courseContentId, Integer duration,String courseId) { + + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"); + + String key = "studyId:" + studyId + ":courseId:" + courseId + ":courseContentId:" + courseContentId; + String currentValue = redisTemplate.opsForValue().get(key); + int lastDuration = 0; + int sum = duration; + if (currentValue != null) { + String[] partValues = currentValue.split("&"); + lastDuration = Integer.parseInt(partValues[0]); + sum += lastDuration; + }; + + String value = sum + "&" + now.format(formatter); // 使用ISO8601时间格式 + log.info("-study-video-time-----value = " + value); + + // 20250303 优化 多次更新改一次更新 + // 更新Redis中的最后活跃时间(带30秒过期) + redisTemplate.opsForValue().set( + key, + value, + Duration.ofSeconds(2592000) + ); + log.info("- 合并 updateStudyDuration -redis保存---value = " + value); +// Duration.ofDays(30) 也就是 2592000秒 + } + + @Override @Transactional public void appendStudyDuration(StudyTime st) { @@ -357,6 +392,7 @@ public class StudyServiceImpl implements IStudyService{ log.info("-study-video-time-mysql保存---studyContentId = " + studyContentId); } + @Override public Map getLast(String aid) { //按lastTime排序,第一条,只是课件内容 diff --git a/servers/boe-server-all/src/main/java/com/xboe/school/vo/StudyTimeVo.java b/servers/boe-server-all/src/main/java/com/xboe/school/vo/StudyTimeVo.java new file mode 100644 index 00000000..388c10d7 --- /dev/null +++ b/servers/boe-server-all/src/main/java/com/xboe/school/vo/StudyTimeVo.java @@ -0,0 +1,19 @@ +package com.xboe.school.vo; + +import com.xboe.school.study.entity.StudyTime; +import lombok.Data; + +/** appendtime 于 study-video-time 合并 + * appendtime 参数 StudyTime + * study-video-time 参数 是 StudyTimeVo + */ +@Data +public class StudyTimeVo extends StudyTime { + + private String itemId; + private Integer videoTime; +// private String contentId; // 已继承 +// private String courseId; // 已继承 + private Float progressVideo; + private Integer type; // 0 study-video-time , 1 appendtime +}