diff --git a/README.md b/README.md
index df9d7bb..78d595b 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@
2. 运行镜像
```shell
- sudo docker run -p 80:8080 -e MYSQL_URL=192.168.66.1:3306 -e MYSQL_USERNAME=root -e MYSQL_PASSWORD=root -it registry.cn-beijing.aliyuncs.com/itning/shw_server:latest
+ sudo docker run -p 80:8080 -e MYSQL_URL=192.168.66.1:3306 -e MYSQL_USERNAME=root -e MYSQL_PASSWORD=root -e REDIS_HOST=192.168.66.1 -e REDIS_PORT=6379 -it registry.cn-beijing.aliyuncs.com/itning/shw_server:latest
```
**其中MYSQL_URL参数值为MySql数据库服务器地址(带端口号)**
diff --git a/pom.xml b/pom.xml
index 49fa57c..ffcc518 100644
--- a/pom.xml
+++ b/pom.xml
@@ -10,7 +10,7 @@
top.yunshu
shw_server
- 1.6.6-RELEASE
+ 1.7.0-RELEASE
shw_server
Student HomeWork Management System
@@ -50,6 +50,14 @@
org.springframework.boot
spring-boot-starter-websocket
+
+ org.springframework.boot
+ spring-boot-starter-cache
+
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
mysql
mysql-connector-java
diff --git a/src/main/java/org/springframework/data/redis/cache/RedisCache.java b/src/main/java/org/springframework/data/redis/cache/RedisCache.java
new file mode 100644
index 0000000..457cbfe
--- /dev/null
+++ b/src/main/java/org/springframework/data/redis/cache/RedisCache.java
@@ -0,0 +1,338 @@
+/*
+ * Copyright 2017-2019 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.data.redis.cache;
+
+import org.springframework.cache.support.AbstractValueAdaptingCache;
+import org.springframework.cache.support.NullValue;
+import org.springframework.cache.support.SimpleValueWrapper;
+import org.springframework.core.convert.ConversionService;
+import org.springframework.core.convert.TypeDescriptor;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.data.redis.util.ByteUtils;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.ObjectUtils;
+import org.springframework.util.ReflectionUtils;
+import top.yunshu.shw.server.config.SpringContextHelper;
+
+import java.lang.reflect.Method;
+import java.nio.ByteBuffer;
+import java.util.Set;
+import java.util.concurrent.Callable;
+
+/**
+ * {@link org.springframework.cache.Cache} implementation using for Redis as underlying store.
+ *
+ * Use {@link RedisCacheManager} to create {@link RedisCache} instances.
+ *
+ * @author Christoph Strobl
+ * @author Mark Paluch
+ * @see RedisCacheConfiguration
+ * @see RedisCacheWriter
+ * @since 2.0
+ */
+@SuppressWarnings("all")
+public class RedisCache extends AbstractValueAdaptingCache {
+ private static final byte[] BINARY_NULL_VALUE = RedisSerializer.java().serialize(NullValue.INSTANCE);
+
+ private final String name;
+ private final RedisCacheWriter cacheWriter;
+ private final RedisCacheConfiguration cacheConfig;
+ private final ConversionService conversionService;
+ private final RedisTemplate redisTemplate;
+
+ {
+ redisTemplate = SpringContextHelper.getBean("redisTemplate", RedisTemplate.class);
+ redisTemplate.setKeySerializer(new StringRedisSerializer());
+ }
+
+ /**
+ * Create new {@link RedisCache}.
+ *
+ * @param name must not be {@literal null}.
+ * @param cacheWriter must not be {@literal null}.
+ * @param cacheConfig must not be {@literal null}.
+ */
+ protected RedisCache(String name, RedisCacheWriter cacheWriter, RedisCacheConfiguration cacheConfig) {
+
+ super(cacheConfig.getAllowCacheNullValues());
+
+ Assert.notNull(name, "Name must not be null!");
+ Assert.notNull(cacheWriter, "CacheWriter must not be null!");
+ Assert.notNull(cacheConfig, "CacheConfig must not be null!");
+
+ this.name = name;
+ this.cacheWriter = cacheWriter;
+ this.cacheConfig = cacheConfig;
+ this.conversionService = cacheConfig.getConversionService();
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.cache.support.AbstractValueAdaptingCache#lookup(java.lang.Object)
+ */
+ @Override
+ protected Object lookup(Object key) {
+
+ byte[] value = cacheWriter.get(name, createAndConvertCacheKey(key));
+
+ if (value == null) {
+ return null;
+ }
+
+ return deserializeCacheValue(value);
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.cache.Cache#getName()
+ */
+ @Override
+ public String getName() {
+ return name;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.cache.Cache#getNativeCache()
+ */
+ @Override
+ public RedisCacheWriter getNativeCache() {
+ return this.cacheWriter;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.cache.Cache#get(java.lang.Object, java.util.concurrent.Callable)
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public synchronized T get(Object key, Callable valueLoader) {
+
+ ValueWrapper result = get(key);
+
+ if (result != null) {
+ return (T) result.get();
+ }
+
+ T value = valueFromLoader(key, valueLoader);
+ put(key, value);
+ return value;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.cache.Cache#put(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public void put(Object key, @Nullable Object value) {
+
+ Object cacheValue = preProcessCacheValue(value);
+
+ if (!isAllowNullValues() && cacheValue == null) {
+
+ throw new IllegalArgumentException(String.format(
+ "Cache '%s' does not allow 'null' values. Avoid storing null via '@Cacheable(unless=\"#result == null\")' or configure RedisCache to allow 'null' via RedisCacheConfiguration.",
+ name));
+ }
+
+ cacheWriter.put(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue), cacheConfig.getTtl());
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.cache.Cache#putIfAbsent(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public ValueWrapper putIfAbsent(Object key, @Nullable Object value) {
+
+ Object cacheValue = preProcessCacheValue(value);
+
+ if (!isAllowNullValues() && cacheValue == null) {
+ return get(key);
+ }
+
+ byte[] result = cacheWriter.putIfAbsent(name, createAndConvertCacheKey(key), serializeCacheValue(cacheValue),
+ cacheConfig.getTtl());
+
+ if (result == null) {
+ return null;
+ }
+
+ return new SimpleValueWrapper(fromStoreValue(deserializeCacheValue(result)));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.cache.Cache#evict(java.lang.Object)
+ */
+ @Override
+ public void evict(Object key) {
+ if (key instanceof String) {
+ String keyStr = (String) key;
+ if (keyStr.startsWith("regex:")) {
+ String regex = keyStr.substring(6);
+ if ("".equals(regex)) {
+ throw new RuntimeException("must write regex");
+ }
+ Set keys = redisTemplate.keys(name + "::" + regex);
+ redisTemplate.delete(keys);
+ return;
+ }
+ }
+
+ cacheWriter.remove(name, createAndConvertCacheKey(key));
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.springframework.cache.Cache#clear()
+ */
+ @Override
+ public void clear() {
+ byte[] pattern = conversionService.convert(createCacheKey("*"), byte[].class);
+ cacheWriter.clean(name, pattern);
+ }
+
+ /**
+ * Get {@link RedisCacheConfiguration} used.
+ *
+ * @return immutable {@link RedisCacheConfiguration}. Never {@literal null}.
+ */
+ public RedisCacheConfiguration getCacheConfiguration() {
+ return cacheConfig;
+ }
+
+ /**
+ * Customization hook called before passing object to
+ * {@link org.springframework.data.redis.serializer.RedisSerializer}.
+ *
+ * @param value can be {@literal null}.
+ * @return preprocessed value. Can be {@literal null}.
+ */
+ @Nullable
+ protected Object preProcessCacheValue(@Nullable Object value) {
+
+ if (value != null) {
+ return value;
+ }
+
+ return isAllowNullValues() ? NullValue.INSTANCE : null;
+ }
+
+ /**
+ * Serialize the key.
+ *
+ * @param cacheKey must not be {@literal null}.
+ * @return never {@literal null}.
+ */
+ protected byte[] serializeCacheKey(String cacheKey) {
+ return ByteUtils.getBytes(cacheConfig.getKeySerializationPair().write(cacheKey));
+ }
+
+ /**
+ * Serialize the value to cache.
+ *
+ * @param value must not be {@literal null}.
+ * @return never {@literal null}.
+ */
+ protected byte[] serializeCacheValue(Object value) {
+
+ if (isAllowNullValues() && value instanceof NullValue) {
+ return BINARY_NULL_VALUE;
+ }
+
+ return ByteUtils.getBytes(cacheConfig.getValueSerializationPair().write(value));
+ }
+
+ /**
+ * Deserialize the given value to the actual cache value.
+ *
+ * @param value must not be {@literal null}.
+ * @return can be {@literal null}.
+ */
+ @Nullable
+ protected Object deserializeCacheValue(byte[] value) {
+
+ if (isAllowNullValues() && ObjectUtils.nullSafeEquals(value, BINARY_NULL_VALUE)) {
+ return NullValue.INSTANCE;
+ }
+
+ return cacheConfig.getValueSerializationPair().read(ByteBuffer.wrap(value));
+ }
+
+ /**
+ * Customization hook for creating cache key before it gets serialized.
+ *
+ * @param key will never be {@literal null}.
+ * @return never {@literal null}.
+ */
+ protected String createCacheKey(Object key) {
+
+ String convertedKey = convertKey(key);
+
+ if (!cacheConfig.usePrefix()) {
+ return convertedKey;
+ }
+
+ return prefixCacheKey(convertedKey);
+ }
+
+ /**
+ * Convert {@code key} to a {@link String} representation used for cache key creation.
+ *
+ * @param key will never be {@literal null}.
+ * @return never {@literal null}.
+ * @throws IllegalStateException if {@code key} cannot be converted to {@link String}.
+ */
+ protected String convertKey(Object key) {
+
+ TypeDescriptor source = TypeDescriptor.forObject(key);
+ if (conversionService.canConvert(source, TypeDescriptor.valueOf(String.class))) {
+ return conversionService.convert(key, String.class);
+ }
+
+ Method toString = ReflectionUtils.findMethod(key.getClass(), "toString");
+
+ if (toString != null && !Object.class.equals(toString.getDeclaringClass())) {
+ return key.toString();
+ }
+
+ throw new IllegalStateException(
+ String.format("Cannot convert %s to String. Register a Converter or override toString().", source));
+ }
+
+ private byte[] createAndConvertCacheKey(Object key) {
+ return serializeCacheKey(createCacheKey(key));
+ }
+
+ private String prefixCacheKey(String key) {
+
+ // allow contextual cache names by computing the key prefix on every call.
+ return cacheConfig.getKeyPrefixFor(name) + key;
+ }
+
+ private static T valueFromLoader(Object key, Callable valueLoader) {
+
+ try {
+ return valueLoader.call();
+ } catch (Exception e) {
+ throw new ValueRetrievalException(key, valueLoader, e);
+ }
+ }
+}
diff --git a/src/main/java/top/yunshu/shw/server/ShwServerApplication.java b/src/main/java/top/yunshu/shw/server/ShwServerApplication.java
index 7158054..00ad4c2 100644
--- a/src/main/java/top/yunshu/shw/server/ShwServerApplication.java
+++ b/src/main/java/top/yunshu/shw/server/ShwServerApplication.java
@@ -4,6 +4,7 @@
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.cache.annotation.EnableCaching;
import org.springframework.scheduling.annotation.EnableScheduling;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@@ -16,6 +17,7 @@
@SpringBootApplication
@EnableSwagger2
@EnableScheduling
+@EnableCaching
public class ShwServerApplication {
private static final Logger logger = LoggerFactory.getLogger(ShwServerApplication.class);
diff --git a/src/main/java/top/yunshu/shw/server/service/config/impl/ConfigServiceImpl.java b/src/main/java/top/yunshu/shw/server/service/config/impl/ConfigServiceImpl.java
index 8d3e8f7..9885a67 100644
--- a/src/main/java/top/yunshu/shw/server/service/config/impl/ConfigServiceImpl.java
+++ b/src/main/java/top/yunshu/shw/server/service/config/impl/ConfigServiceImpl.java
@@ -1,6 +1,9 @@
package top.yunshu.shw.server.service.config.impl;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.annotation.Caching;
import org.springframework.stereotype.Service;
import top.itning.cas.CasProperties;
import top.yunshu.shw.server.dao.ConfigDao;
@@ -78,16 +81,22 @@ private void init() {
}
}
+ @Cacheable(cacheNames = "allConfigs")
@Override
public List getAllConfigs() {
return configDao.findAll();
}
+ @Cacheable(cacheNames = "config", key = "#configKey.key")
@Override
public Optional getConfig(Config.ConfigKey configKey) {
return configDao.findById(configKey.getKey()).map(Config::getValue);
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "allConfigs", allEntries = true),
+ @CacheEvict(cacheNames = "config", key = "#configKey.key")
+ })
@Override
public void saveConfig(Config.ConfigKey configKey, String value) {
Config config = new Config();
diff --git a/src/main/java/top/yunshu/shw/server/service/group/impl/GroupServiceImpl.java b/src/main/java/top/yunshu/shw/server/service/group/impl/GroupServiceImpl.java
index 3a66ed9..a3b87d3 100644
--- a/src/main/java/top/yunshu/shw/server/service/group/impl/GroupServiceImpl.java
+++ b/src/main/java/top/yunshu/shw/server/service/group/impl/GroupServiceImpl.java
@@ -3,12 +3,18 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.annotation.Caching;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
-import top.yunshu.shw.server.dao.*;
+import top.yunshu.shw.server.dao.GroupDao;
+import top.yunshu.shw.server.dao.StudentGroupDao;
+import top.yunshu.shw.server.dao.UploadDao;
+import top.yunshu.shw.server.dao.WorkDao;
import top.yunshu.shw.server.entity.Group;
import top.yunshu.shw.server.entity.StudentGroup;
import top.yunshu.shw.server.entity.Upload;
@@ -47,6 +53,7 @@ public GroupServiceImpl(GroupDao groupDao, StudentGroupDao studentGroupDao, Work
this.uploadDao = uploadDao;
}
+ @Cacheable(cacheNames = "groupOfStudent", key = "#studentNumber+#pageable")
@Override
public Page findStudentAllGroups(String studentNumber, Pageable pageable) {
List groupList = studentGroupDao.findAllByStudentNumber(studentNumber, pageable)
@@ -65,21 +72,31 @@ public Page findStudentAllGroups(String studentNumber, Pageable pageable)
return new PageImpl<>(groupList, pageable, studentGroupDao.countAllByStudentNumber(studentNumber));
}
+ @Cacheable(cacheNames = "groupOfTeacher", key = "#teacherNumber+#pageable")
@Override
public Page findTeacherAllGroups(String teacherNumber, Pageable pageable) {
return groupDao.findByTeacherNumber(teacherNumber, pageable);
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "groupOfTeacher", key = "'regex:'+#teacherId+'*'"),
+ @CacheEvict(cacheNames = "isHaveAnyGroup", key = "#teacherId")
+ })
@Override
public Group createGroup(String groupName, String teacherName, String teacherId) {
String id = UUID.randomUUID().toString().replace("-", "");
return groupDao.save(new Group(id, groupName, teacherName, teacherId, id));
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "groupOfStudent", key = "'regex:'+#studentId+'*'"),
+ //学生加入群组,教师作业详情缓存清空
+ @CacheEvict(cacheNames = "workDetail", allEntries = true)
+ })
@Override
public Group joinGroup(String code, String studentId) {
if (!groupDao.existsAllByCode(code)) {
- throw new NoSuchFiledValueException("群ID不存在", HttpStatus.NOT_FOUND);
+ throw new NoSuchFiledValueException("邀请码过期或不存在", HttpStatus.NOT_FOUND);
}
if (studentGroupDao.findByStudentNumberAndGroupID(studentId, code) != null) {
throw new NoSuchFiledValueException("已加入过该群", HttpStatus.CONFLICT);
@@ -90,6 +107,11 @@ public Group joinGroup(String code, String studentId) {
return group;
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "groupOfStudent", key = "'regex:'+#studentId+'*'"),
+ //学生退出群组,教师作业详情缓存清空
+ @CacheEvict(cacheNames = "workDetail", allEntries = true)
+ })
@Override
public void dropOutGroup(String groupId, String studentId) {
if (!groupDao.existsById(groupId)) {
@@ -110,7 +132,13 @@ public void dropOutGroup(String groupId, String studentId) {
uploadDao.deleteAll(willDeleteUploadList);
}
-
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "groupOfStudent", allEntries = true),
+ @CacheEvict(cacheNames = "groupOfTeacher", key = "'regex:'+#teacherNumber+'*'"),
+ @CacheEvict(cacheNames = "isHaveAnyGroup", key = "#teacherNumber"),
+ @CacheEvict(cacheNames = "findGroupNameByGroupId", key = "#id"),
+ @CacheEvict(cacheNames = "findTeacherNameById", key = "#id")
+ })
@Override
public void deleteGroup(String id, String teacherNumber) {
Group group = groupDao.findById(id).orElseThrow(() -> new NoSuchFiledValueException("id: " + id + " not found", HttpStatus.NOT_FOUND));
@@ -127,6 +155,11 @@ public void deleteGroup(String id, String teacherNumber) {
groupDao.delete(group);
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "groupOfStudent", allEntries = true),
+ @CacheEvict(cacheNames = "groupOfTeacher", key = "'regex:'+#teacherNumber+'*'"),
+ @CacheEvict(cacheNames = "findGroupNameByGroupId", key = "#id")
+ })
@Override
public Group updateGroup(String id, String name, String teacherNumber) {
Group group = groupDao.findById(id).orElseThrow(() -> new NoSuchFiledValueException("id: " + id + " not found ", HttpStatus.NOT_FOUND));
@@ -137,6 +170,7 @@ public Group updateGroup(String id, String name, String teacherNumber) {
return groupDao.save(group);
}
+ @Cacheable(cacheNames = "findGroupNameByGroupId", key = "#groupId")
@Override
public String findGroupNameByGroupId(String groupId) {
if (!groupDao.existsById(groupId)) {
@@ -145,6 +179,7 @@ public String findGroupNameByGroupId(String groupId) {
return groupDao.findNameById(groupId);
}
+ @Cacheable(cacheNames = "findTeacherNameById", key = "#groupId")
@Override
public String findTeacherNameById(String groupId) {
if (!groupDao.existsById(groupId)) {
@@ -153,6 +188,7 @@ public String findTeacherNameById(String groupId) {
return groupDao.findTeacherNameById(groupId);
}
+ @Cacheable(cacheNames = "isHaveAnyGroup", key = "#teacherNumber")
@Override
public boolean isHaveAnyGroup(String teacherNumber) {
return !groupDao.findByTeacherNumber(teacherNumber).isEmpty();
diff --git a/src/main/java/top/yunshu/shw/server/service/upload/impl/UploadServiceImpl.java b/src/main/java/top/yunshu/shw/server/service/upload/impl/UploadServiceImpl.java
index 13c7980..ef89b43 100644
--- a/src/main/java/top/yunshu/shw/server/service/upload/impl/UploadServiceImpl.java
+++ b/src/main/java/top/yunshu/shw/server/service/upload/impl/UploadServiceImpl.java
@@ -1,6 +1,8 @@
package top.yunshu.shw.server.service.upload.impl;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Caching;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
@@ -51,6 +53,11 @@ public Upload getUploadInfoByWorkId(String studentId, String workId) {
return uploadDao.findUploadByStudentIdAndWorkId(studentId, workId);
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "studentDoneWork", allEntries = true),
+ @CacheEvict(cacheNames = "studentUndoneWork", allEntries = true),
+ @CacheEvict(cacheNames = "workDetail", allEntries = true)
+ })
@Override
public void delUploadInfoByWorkId(String studentId, String workId) {
if (!uploadDao.existsByStudentIdAndWorkId(studentId, workId)) {
@@ -71,6 +78,11 @@ public void delUploadInfoByWorkId(String studentId, String workId) {
uploadDao.delete(upload);
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "studentDoneWork", allEntries = true),
+ @CacheEvict(cacheNames = "studentUndoneWork", allEntries = true),
+ @CacheEvict(cacheNames = "workDetail", allEntries = true)
+ })
@Override
public void uploadFile(MultipartFile file, String studentNumber, String workId) {
String[] format = FileNameSpecificationUtils.safeGetStudentNameAndFileNameFormat(studentDao, workDao, studentNumber, workId);
diff --git a/src/main/java/top/yunshu/shw/server/service/work/impl/WorkServiceImpl.java b/src/main/java/top/yunshu/shw/server/service/work/impl/WorkServiceImpl.java
index 69adee3..37c51a6 100644
--- a/src/main/java/top/yunshu/shw/server/service/work/impl/WorkServiceImpl.java
+++ b/src/main/java/top/yunshu/shw/server/service/work/impl/WorkServiceImpl.java
@@ -5,6 +5,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.cache.annotation.Caching;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
@@ -57,6 +60,7 @@ public WorkServiceImpl(WorkDao workDao, StudentGroupDao studentGroupDao, UploadD
this.modelMapper = modelMapper;
}
+ @Cacheable(cacheNames = "studentUndoneWork", key = "#studentId+#pageable")
@Override
public Page getStudentUnDoneWork(String studentId, Pageable pageable) {
List workList = studentGroupDao.findGroupIdByStudentNumber(studentId)
@@ -69,6 +73,7 @@ public Page getStudentUnDoneWork(String studentId, Pageable pageable)
return getWorkModels(pageable, workList);
}
+ @Cacheable(cacheNames = "studentDoneWork", key = "#studentId+#pageable")
@Override
public Page getStudentDoneWork(String studentId, Pageable pageable) {
List workList = studentGroupDao.findGroupIdByStudentNumber(studentId)
@@ -85,6 +90,7 @@ public Page getStudentDoneWork(String studentId, Pageable pageable) {
return getWorkModels(pageable, workList);
}
+ @Cacheable(cacheNames = "work", key = "#teacherNumber+#pageable")
@Override
public Page getTeacherAllWork(String teacherNumber, Pageable pageable) {
List workList = groupDao.findByTeacherNumber(teacherNumber)
@@ -96,6 +102,7 @@ public Page getTeacherAllWork(String teacherNumber, Pageable pageable
return getWorkModels(pageable, workList);
}
+ @Cacheable(cacheNames = "work", key = "#teacherNumber+#groupId+#pageable")
@Override
public Page getTeacherWork(String teacherNumber, String groupId, Pageable pageable) {
Group group = groupDao.findById(groupId).orElseThrow(() -> new NoSuchFiledValueException("群ID: " + groupId + "不存在", HttpStatus.NOT_FOUND));
@@ -105,6 +112,10 @@ public Page getTeacherWork(String teacherNumber, String groupId, Page
}.getType()), pageable, workPage.getTotalElements());
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "studentUndoneWork", allEntries = true),
+ @CacheEvict(cacheNames = "work", allEntries = true)
+ })
@Override
public Work createWork(String workName, String groupId, String format, boolean enabled) {
if (!groupDao.existsById(groupId)) {
@@ -119,6 +130,10 @@ public Work createWork(String workName, String groupId, String format, boolean e
return workDao.save(work);
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "studentUndoneWork", allEntries = true),
+ @CacheEvict(cacheNames = "work", allEntries = true)
+ })
@Override
public void changeEnabledWord(String workId, boolean enabled) {
Work work = workDao.findById(workId).orElseThrow(() -> new NoSuchFiledValueException("作业ID: " + workId + "不存在", HttpStatus.NOT_FOUND));
@@ -126,6 +141,12 @@ public void changeEnabledWord(String workId, boolean enabled) {
workDao.save(work);
}
+ @Caching(evict = {
+ @CacheEvict(cacheNames = "studentDoneWork", allEntries = true),
+ @CacheEvict(cacheNames = "studentUndoneWork", allEntries = true),
+ @CacheEvict(cacheNames = "work", key = "'regex:'+#teacherNumber+'*'"),
+ @CacheEvict(cacheNames = "workDetail", key = "'regex:'+#workId+'*'")
+ })
@Override
public void delWork(String workId, String teacherNumber) {
Work work = workDao.findById(workId).orElseThrow(() -> new NoSuchFiledValueException("作业ID: " + workId + "不存在", HttpStatus.NOT_FOUND));
@@ -134,8 +155,10 @@ public void delWork(String workId, String teacherNumber) {
throw new NoSuchFiledValueException("Forbidden", HttpStatus.FORBIDDEN);
}
workDao.delete(work);
+ uploadDao.deleteAll(uploadDao.findAllByWorkId(workId));
}
+ @Cacheable(cacheNames = "workDetail", key = "#workId+#teacherNumber+#pageable")
@Override
public Page getWorkDetailByWorkId(String teacherNumber, String workId, Pageable pageable) {
Work work = workDao.findById(workId).orElseThrow(() -> new NoSuchFiledValueException("作业ID: " + workId + "不存在", HttpStatus.NOT_FOUND));
@@ -175,7 +198,6 @@ public Optional getOneWorkById(String workId) {
* @return WorkModel
*/
private Page getWorkModels(Pageable pageable, List workList) {
- //TODO 直接查所有分页意义不大,解决:Cache List
//页数*每页条数
int to = (pageable.getPageNumber() + 1) * pageable.getPageSize();
int toIndex = to > workList.size() ? workList.size() : to;
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
index 470c1ac..e7589c8 100644
--- a/src/main/resources/application-dev.yml
+++ b/src/main/resources/application-dev.yml
@@ -8,6 +8,9 @@ spring:
password: kingston
jpa:
show-sql: true
+ redis:
+ host: locahost
+ port: 6379
logging:
level: debug
level.top: debug
diff --git a/src/main/resources/application-docker.yml b/src/main/resources/application-docker.yml
index f4322f8..7b1a5f3 100644
--- a/src/main/resources/application-docker.yml
+++ b/src/main/resources/application-docker.yml
@@ -8,6 +8,9 @@ spring:
password: ${MYSQL_PASSWORD}
jpa:
show-sql: false
+ redis:
+ host: ${REDIS_HOST}
+ port: ${REDIS_PORT}
logging:
level: warn
level.top: warn
diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml
index cb97e0e..b38580e 100644
--- a/src/main/resources/application-prod.yml
+++ b/src/main/resources/application-prod.yml
@@ -5,6 +5,9 @@ spring:
url: jdbc:mysql://localhost:3306/shw2${datasource_url_end_str}
username: root
password: root
+ redis:
+ host: locahost
+ port: 6379
logging:
level: error
level.top: warn
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 9e1b4d4..b602988 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -17,6 +17,20 @@ spring:
multipart:
max-file-size: 1024MB
max-request-size: 1024MB
+ cache:
+ type: redis
+ redis:
+ jedis:
+ pool:
+ max-idle: 8
+ min-idle: 0
+ max-active: 8
+ max-wait: -1
+ database: 0
+ data:
+ redis:
+ repositories:
+ enabled: false
cas:
server-url: http://login.greathiit.com
login-url: http://login.greathiit.com/login
diff --git a/src/test/java/top/yunshu/shw/server/test/CommonTest.java b/src/test/java/top/yunshu/shw/server/test/CommonTest.java
new file mode 100644
index 0000000..f908c19
--- /dev/null
+++ b/src/test/java/top/yunshu/shw/server/test/CommonTest.java
@@ -0,0 +1,27 @@
+package top.yunshu.shw.server.test;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import org.springframework.test.context.junit4.SpringRunner;
+import top.yunshu.shw.server.ShwServerApplication;
+
+import java.util.Set;
+
+@RunWith(SpringRunner.class)
+@SpringBootTest(classes = ShwServerApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+public class CommonTest {
+ @Autowired
+ private RedisTemplate redisTemplate;
+
+ @Test
+ public void test1() {
+ redisTemplate.setDefaultSerializer(new StringRedisSerializer());
+ redisTemplate.setKeySerializer(new StringRedisSerializer());
+ Set keys = redisTemplate.keys("work::00027*");
+ redisTemplate.delete(keys);
+ }
+}