From 3f7cdb4c5096214765f935e9e8616730bcac1344 Mon Sep 17 00:00:00 2001 From: fuliqi <fuliqi@qq.com> Date: 星期四, 04 七月 2024 11:04:44 +0800 Subject: [PATCH] 学习记录,引入caffeine --- src/main/java/com/ycl/jxkg/domain/query/WebSocketQuery.java | 9 + src/main/java/com/ycl/jxkg/service/StudyRecordService.java | 20 ++++ src/main/java/com/ycl/jxkg/service/impl/StudyRecordServiceImpl.java | 20 ++++ src/main/java/com/ycl/jxkg/enums/WebsocketCommendEnum.java | 1 src/main/java/com/ycl/jxkg/job/StudyRecordJob.java | 67 +++++++++++++ src/main/java/com/ycl/jxkg/server/WebsocketServer.java | 16 +++ src/main/java/com/ycl/jxkg/service/EducationResourceService.java | 2 pom.xml | 6 + src/main/java/com/ycl/jxkg/service/impl/EducationResourceServiceImpl.java | 30 +++++ src/main/resources/mapper/StudyRecordMapper.xml | 21 ++++ src/main/java/com/ycl/jxkg/domain/entity/StudyRecord.java | 24 ++++ src/main/java/com/ycl/jxkg/mapper/StudyRecordMapper.java | 28 +++++ src/main/java/com/ycl/jxkg/config/CaffeineConfig.java | 24 ++++ 13 files changed, 266 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 4bf0f97..e34a11a 100644 --- a/pom.xml +++ b/pom.xml @@ -42,6 +42,12 @@ <dependencies> + <!-- caffeine --> + <dependency> + <groupId>com.github.ben-manes.caffeine</groupId> + <artifactId>caffeine</artifactId> + <version>3.0.5</version> + </dependency> <!-- rabbitmq --> <dependency> diff --git a/src/main/java/com/ycl/jxkg/config/CaffeineConfig.java b/src/main/java/com/ycl/jxkg/config/CaffeineConfig.java new file mode 100644 index 0000000..80f585e --- /dev/null +++ b/src/main/java/com/ycl/jxkg/config/CaffeineConfig.java @@ -0,0 +1,24 @@ +package com.ycl.jxkg.config; + +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.concurrent.TimeUnit; + +@Configuration +public class CaffeineConfig { + + @Bean + public Cache<String, Object> caffeineCache() { + return Caffeine.newBuilder() + // 璁剧疆鏈�鍚庝竴娆″啓鍏ユ垨璁块棶鍚庣粡杩囧浐瀹氭椂闂磋繃鏈� + .expireAfterWrite(600, TimeUnit.SECONDS) + // 鍒濆鐨勭紦瀛樼┖闂村ぇ灏� + .initialCapacity(100) + // 缂撳瓨鐨勬渶澶ф潯鏁� + .maximumSize(1000) + .build(); + } +} diff --git a/src/main/java/com/ycl/jxkg/domain/entity/StudyRecord.java b/src/main/java/com/ycl/jxkg/domain/entity/StudyRecord.java new file mode 100644 index 0000000..4c51e07 --- /dev/null +++ b/src/main/java/com/ycl/jxkg/domain/entity/StudyRecord.java @@ -0,0 +1,24 @@ +package com.ycl.jxkg.domain.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 lombok.Data; + +import java.util.Date; + +@Data +@TableName("t_study_record") +public class StudyRecord { + @TableId(value = "id", type = IdType.AUTO) + private Integer id; + @TableField("student_id") + private Integer studentId; + @TableField("study_time") + private Long studyTime; + //涓婁竴娆¤褰曟椂闂� + @TableField("last_time") + private Date lastTime; + +} diff --git a/src/main/java/com/ycl/jxkg/domain/query/WebSocketQuery.java b/src/main/java/com/ycl/jxkg/domain/query/WebSocketQuery.java new file mode 100644 index 0000000..d6ff159 --- /dev/null +++ b/src/main/java/com/ycl/jxkg/domain/query/WebSocketQuery.java @@ -0,0 +1,9 @@ +package com.ycl.jxkg.domain.query; + +import lombok.Data; + +@Data +public class WebSocketQuery { + private String commend; + private Integer id; +} diff --git a/src/main/java/com/ycl/jxkg/enums/WebsocketCommendEnum.java b/src/main/java/com/ycl/jxkg/enums/WebsocketCommendEnum.java index c0e3564..c4849d5 100644 --- a/src/main/java/com/ycl/jxkg/enums/WebsocketCommendEnum.java +++ b/src/main/java/com/ycl/jxkg/enums/WebsocketCommendEnum.java @@ -14,6 +14,7 @@ DELAYED("delayed", "寤堕暱鑰冭瘯鏃堕棿"), FORCE_SUBMIT("forceSubmit", "寮哄埗鎻愪氦"), + RECORD_STUDY_TIME("recordStudyTime", "璁板綍瀛︿範鏃堕棿"), ; private final String commend; diff --git a/src/main/java/com/ycl/jxkg/job/StudyRecordJob.java b/src/main/java/com/ycl/jxkg/job/StudyRecordJob.java new file mode 100644 index 0000000..0167d8d --- /dev/null +++ b/src/main/java/com/ycl/jxkg/job/StudyRecordJob.java @@ -0,0 +1,67 @@ +package com.ycl.jxkg.job; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; +import com.github.benmanes.caffeine.cache.Cache; +import com.ycl.jxkg.domain.entity.StudyRecord; +import com.ycl.jxkg.mapper.StudyRecordMapper; +import com.ycl.jxkg.service.StudyRecordService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; +import org.springframework.util.CollectionUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentMap; +import java.util.stream.Collectors; + +/** + * @author锛歺p + * @date锛�2024/7/1 11:06 + */ +@Component +@RequiredArgsConstructor +@Slf4j +public class StudyRecordJob { + + @Autowired + private Cache<String, Object> caffeineCache; + private final StudyRecordMapper studyRecordMapper; + private final StudyRecordService studyRecordService; + + @Scheduled(fixedRate = 1200000) // 20鍒嗛挓鎵ц涓�娆� + private void updateStudyRecord() { + log.info("寮�濮嬪瓨瀛︿範鏃堕暱"); + List<StudyRecord> cacheList = new ArrayList<>(); + // 鍙栧嚭鎵�鏈夌紦瀛橀」 + ConcurrentMap<String, Object> map = caffeineCache.asMap(); + for (Map.Entry<String, Object> entry : map.entrySet()) { + String key = entry.getKey(); + if (key.startsWith("STUDENT_")) { + StudyRecord studyRecord = (StudyRecord) entry.getValue(); + cacheList.add(studyRecord); + } + } + List<Integer> studentIds = cacheList.stream().map(StudyRecord::getStudentId).collect(Collectors.toList()); + if (!CollectionUtils.isEmpty(studentIds)) { + //鏁版嵁搴撲腑宸茬粡瀛樺湪鐨勫鐢熸暟鎹� + QueryWrapper<StudyRecord> wrapper = new QueryWrapper<>(); + wrapper.in("student_id", studentIds); + List<StudyRecord> studyRecords = studyRecordMapper.selectList(wrapper); + for (StudyRecord record : studyRecords) { + for (StudyRecord cacheRecord : cacheList) { + if (record.getStudentId().equals(cacheRecord.getStudentId())) { + cacheRecord.setId(record.getId()); + cacheRecord.setStudyTime(record.getStudyTime() + cacheRecord.getStudyTime()); + } + } + } + studyRecordService.saveOrUpdateBatch(cacheList); + } + caffeineCache.invalidateAll(map.keySet()); + log.info("缁撴潫瀛樺涔犳椂闀�"); + } +} diff --git a/src/main/java/com/ycl/jxkg/mapper/StudyRecordMapper.java b/src/main/java/com/ycl/jxkg/mapper/StudyRecordMapper.java new file mode 100644 index 0000000..45e14a7 --- /dev/null +++ b/src/main/java/com/ycl/jxkg/mapper/StudyRecordMapper.java @@ -0,0 +1,28 @@ +package com.ycl.jxkg.mapper; + +import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.ycl.jxkg.domain.entity.StudyRecord; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * 浼氳琛� Mapper 鎺ュ彛 + * + * @author flq + * @since 2024-06-17 + */ +@Mapper +public interface StudyRecordMapper extends BaseMapper<StudyRecord> { + + /** + * id鏌ユ壘 + * @param + * @return + */ + StudyRecord getByStudentId(Integer studentId); + + + void updateBatch(List<StudyRecord> list); + +} diff --git a/src/main/java/com/ycl/jxkg/server/WebsocketServer.java b/src/main/java/com/ycl/jxkg/server/WebsocketServer.java index 3e27189..9886607 100644 --- a/src/main/java/com/ycl/jxkg/server/WebsocketServer.java +++ b/src/main/java/com/ycl/jxkg/server/WebsocketServer.java @@ -1,8 +1,16 @@ package com.ycl.jxkg.server; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.JsonObject; +import com.ycl.jxkg.domain.entity.Message; +import com.ycl.jxkg.domain.query.WebSocketQuery; +import com.ycl.jxkg.enums.WebsocketCommendEnum; +import com.ycl.jxkg.service.EducationResourceService; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import javax.servlet.http.HttpSession; import javax.websocket.OnClose; import javax.websocket.OnMessage; import javax.websocket.OnOpen; @@ -23,6 +31,8 @@ @ServerEndpoint("/websocket/{userId}") public class WebsocketServer { + @Autowired + private EducationResourceService educationResourceService; /** * 绾跨▼瀹夊叏鐨勬棤搴忕殑闆嗗悎 */ @@ -56,6 +66,12 @@ @OnMessage public void onMessage(String message) { + WebSocketQuery webSocketQuery = JSONObject.parseObject(message, WebSocketQuery.class); + String commend = webSocketQuery.getCommend(); + Integer userId = webSocketQuery.getId(); + if(WebsocketCommendEnum.RECORD_STUDY_TIME.getCommend().equals(commend)){ + educationResourceService.recordTime(userId); + } log.info("銆怶ebSocket娑堟伅銆戞敹鍒板鎴风娑堟伅锛�" + message); } diff --git a/src/main/java/com/ycl/jxkg/service/EducationResourceService.java b/src/main/java/com/ycl/jxkg/service/EducationResourceService.java index 304f10c..8864d9c 100644 --- a/src/main/java/com/ycl/jxkg/service/EducationResourceService.java +++ b/src/main/java/com/ycl/jxkg/service/EducationResourceService.java @@ -37,4 +37,6 @@ * @return */ Result typeList(); + + Result recordTime(Integer userId); } diff --git a/src/main/java/com/ycl/jxkg/service/StudyRecordService.java b/src/main/java/com/ycl/jxkg/service/StudyRecordService.java new file mode 100644 index 0000000..9c24875 --- /dev/null +++ b/src/main/java/com/ycl/jxkg/service/StudyRecordService.java @@ -0,0 +1,20 @@ +package com.ycl.jxkg.service; + +import com.baomidou.mybatisplus.extension.service.IService; +import com.ycl.jxkg.base.Result; +import com.ycl.jxkg.domain.entity.Meet; +import com.ycl.jxkg.domain.entity.StudyRecord; +import com.ycl.jxkg.domain.form.MeetForm; +import com.ycl.jxkg.domain.query.MeetQuery; + +import java.util.List; + +/** + * 瀛︿範璁板綍 鏈嶅姟绫� + * + * @author flq + * @since 2024-06-17 + */ +public interface StudyRecordService extends IService<StudyRecord> { + +} diff --git a/src/main/java/com/ycl/jxkg/service/impl/EducationResourceServiceImpl.java b/src/main/java/com/ycl/jxkg/service/impl/EducationResourceServiceImpl.java index 374f718..c29ac89 100644 --- a/src/main/java/com/ycl/jxkg/service/impl/EducationResourceServiceImpl.java +++ b/src/main/java/com/ycl/jxkg/service/impl/EducationResourceServiceImpl.java @@ -1,20 +1,22 @@ package com.ycl.jxkg.service.impl; import com.alibaba.fastjson.JSON; +import com.github.benmanes.caffeine.cache.Cache; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.ycl.jxkg.base.Result; import com.ycl.jxkg.context.WebContext; import com.ycl.jxkg.domain.entity.EducationResource; import com.ycl.jxkg.domain.entity.Subject; +import com.ycl.jxkg.domain.entity.StudyRecord; import com.ycl.jxkg.domain.vo.admin.education.EducationResourceVO; -import com.ycl.jxkg.domain.vo.student.education.StudentOnlineVO; import com.ycl.jxkg.mapper.ClassesUserMapper; import com.ycl.jxkg.mapper.EducationResourceMapper; import com.ycl.jxkg.mapper.SubjectMapper; import com.ycl.jxkg.service.EducationResourceService; import lombok.RequiredArgsConstructor; import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; @@ -35,7 +37,8 @@ private final SubjectMapper subjectMapper; private final WebContext webContext; private final ClassesUserMapper classesUserMapper; - + @Autowired + private Cache<String, Object> caffeineCache; @Override public Result add(EducationResourceVO form) { EducationResource educationResource = new EducationResource(); @@ -109,4 +112,27 @@ List<Subject> subjects = subjectMapper.allSubject(); return Result.ok(subjects); } + //璁板綍瑙嗛鏃堕暱 + @Override + public Result recordTime(Integer userId) { + if (userId ==null){ + throw new RuntimeException("鐢ㄦ埛id涓虹┖"); + } + StudyRecord studyRecord = (StudyRecord) caffeineCache.getIfPresent("STUDENT_"+userId); + if (studyRecord != null) { + //瀛樺湪缂撳瓨 + Date lastTime = studyRecord.getLastTime(); + Date now = new Date(); + studyRecord.setStudyTime(studyRecord.getStudyTime()+(now.getTime()-lastTime.getTime())/1000); + studyRecord.setLastTime(now); + }else { + //涓嶅瓨鍦ㄧ紦瀛� + studyRecord = new StudyRecord(); + studyRecord.setStudentId(userId); + studyRecord.setStudyTime(0L); + studyRecord.setLastTime(new Date()); + } + caffeineCache.put("STUDENT_" + userId, studyRecord); + return Result.ok(); + } } diff --git a/src/main/java/com/ycl/jxkg/service/impl/StudyRecordServiceImpl.java b/src/main/java/com/ycl/jxkg/service/impl/StudyRecordServiceImpl.java new file mode 100644 index 0000000..56602cd --- /dev/null +++ b/src/main/java/com/ycl/jxkg/service/impl/StudyRecordServiceImpl.java @@ -0,0 +1,20 @@ +package com.ycl.jxkg.service.impl; + +import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import com.ycl.jxkg.domain.entity.StudyRecord; +import com.ycl.jxkg.mapper.StudyRecordMapper; +import com.ycl.jxkg.service.StudyRecordService; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; + +/** + * 瀛︿範璁板綍 鏈嶅姟瀹炵幇绫� + * + * @author flq + * @since 2024-06-17 + */ +@Service +@RequiredArgsConstructor +public class StudyRecordServiceImpl extends ServiceImpl<StudyRecordMapper, StudyRecord> implements StudyRecordService { + +} diff --git a/src/main/resources/mapper/StudyRecordMapper.xml b/src/main/resources/mapper/StudyRecordMapper.xml new file mode 100644 index 0000000..3b371cb --- /dev/null +++ b/src/main/resources/mapper/StudyRecordMapper.xml @@ -0,0 +1,21 @@ +<?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.ycl.jxkg.mapper.StudyRecordMapper"> + + <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 --> + <resultMap id="BaseResultMap" type="com.ycl.jxkg.domain.entity.StudyRecord"> + <result column="id" property="id"/> + <result column="student_id" property="studentId"/> + <result column="study_time" property="studyTime"/> + <result column="last_time" property="lastTime"/> + </resultMap> + + + <select id="getByStudentId" resultMap="BaseResultMap"> + SELECT * + from t_study_record + WHERE student_id = #{studentId} + </select> + + +</mapper> -- Gitblit v1.8.0