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