diff --git a/pom.xml b/pom.xml
index b9fd511..a1e84e0 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,6 +21,10 @@
org.springframework.boot
spring-boot-starter-data-jpa
+
+ org.springframework.boot
+ spring-boot-starter-data-redis
+
org.springframework.boot
spring-boot-starter-web
diff --git a/src/main/java/com/codemagician/onlinelibrary/domain/entity/RoleDO.java b/src/main/java/com/codemagician/onlinelibrary/domain/entity/RoleDO.java
index beab1b1..d5d4622 100644
--- a/src/main/java/com/codemagician/onlinelibrary/domain/entity/RoleDO.java
+++ b/src/main/java/com/codemagician/onlinelibrary/domain/entity/RoleDO.java
@@ -5,6 +5,8 @@
import lombok.Data;
import lombok.NoArgsConstructor;
+import java.io.Serializable;
+
/**
* @author Siuyun Yip
* @version 1.0
@@ -14,7 +16,7 @@
@NoArgsConstructor
@Entity
@Table(name = "roles")
-public class RoleDO {
+public class RoleDO implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
diff --git a/src/main/java/com/codemagician/onlinelibrary/domain/entity/UserDO.java b/src/main/java/com/codemagician/onlinelibrary/domain/entity/UserDO.java
index ab6dc1d..a3e1ebf 100644
--- a/src/main/java/com/codemagician/onlinelibrary/domain/entity/UserDO.java
+++ b/src/main/java/com/codemagician/onlinelibrary/domain/entity/UserDO.java
@@ -6,6 +6,7 @@
import lombok.Data;
import lombok.NoArgsConstructor;
+import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@@ -15,6 +16,7 @@
* @date 2023/8/31 15:39
*/
+
@Data
@NoArgsConstructor
@Entity
@@ -23,7 +25,7 @@
@UniqueConstraint(columnNames = "username"),
@UniqueConstraint(columnNames = "email")
})
-public class UserDO {
+public class UserDO implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
diff --git a/src/main/java/com/codemagician/onlinelibrary/security/jwt/AuthTokenFilter.java b/src/main/java/com/codemagician/onlinelibrary/security/jwt/AuthTokenFilter.java
index 76866f6..15324c0 100644
--- a/src/main/java/com/codemagician/onlinelibrary/security/jwt/AuthTokenFilter.java
+++ b/src/main/java/com/codemagician/onlinelibrary/security/jwt/AuthTokenFilter.java
@@ -43,7 +43,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
String jwt = parseJwt(request);
if (jwt != null && jwtUtils.validateJwtToken(jwt)) {
String username = jwtUtils.getUserNameFromJwtToken(jwt);
- // TODO fetch user data from Redis
UserDetails user = userDetailsService.loadUserByUsername(username);
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
diff --git a/src/main/java/com/codemagician/onlinelibrary/security/services/UserDetailsServiceImpl.java b/src/main/java/com/codemagician/onlinelibrary/security/services/UserDetailsServiceImpl.java
index 933cb48..5c45f48 100644
--- a/src/main/java/com/codemagician/onlinelibrary/security/services/UserDetailsServiceImpl.java
+++ b/src/main/java/com/codemagician/onlinelibrary/security/services/UserDetailsServiceImpl.java
@@ -3,7 +3,10 @@
import com.codemagician.onlinelibrary.domain.entity.UserDO;
import com.codemagician.onlinelibrary.dao.repo.UserRepository;
import com.codemagician.onlinelibrary.common.exception.AccessException;
+import com.codemagician.onlinelibrary.util.RedisUtil;
+import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;
@@ -23,10 +26,17 @@ public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
UserRepository userRepository;
+ @Resource
+ private RedisUtil redisUtil;
+
@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws AccessException {
- UserDO user = userRepository.findByUsernameWithRoles(username).orElseThrow(() -> new AccessException("User Not Found with username: " + username));
+ UserDO user;
+ if ((user = (UserDO)redisUtil.get(username)) == null) {
+ user = userRepository.findByUsernameWithRoles(username).orElseThrow(() -> new AccessException("User Not Found with username: " + username));
+ redisUtil.set(username, user);
+ }
return UserDetailsImpl.build(user);
}
diff --git a/src/main/java/com/codemagician/onlinelibrary/util/RedisUtil.java b/src/main/java/com/codemagician/onlinelibrary/util/RedisUtil.java
new file mode 100644
index 0000000..aa0f8c1
--- /dev/null
+++ b/src/main/java/com/codemagician/onlinelibrary/util/RedisUtil.java
@@ -0,0 +1,620 @@
+package com.codemagician.onlinelibrary.util;
+
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.BoundListOperations;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * @author Siuyun Yip
+ * @version 1.0
+ * @date 2023/10/1 16:55
+ */
+
+@Component
+public class RedisUtil {
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ /**
+ * set cache valid time
+ *
+ * @param key
+ * @param time
+ * @return
+ */
+ public boolean expire(String key, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.expire(key, time, TimeUnit.SECONDS);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ public long getExpire(String key) {
+ return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+ }
+
+ public boolean hasKey(String key) {
+ try {
+ return redisTemplate.hasKey(key);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * delete cache
+ *
+ * @param key
+ */
+ public void del(String... key) {
+ if (key != null && key.length > 0) {
+ if (key.length == 1) {
+ redisTemplate.delete(key[0]);
+ } else {
+ redisTemplate.delete((Collection) CollectionUtils.arrayToList(key));
+ }
+ }
+ }
+
+ public Object get(String key) {
+ return key == null ? null : redisTemplate.opsForValue().get(key);
+ }
+
+ public boolean set(String key, Object value) {
+ try {
+ redisTemplate.opsForValue().set(key, value);
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * set cache with timeout
+ *
+ * @param key
+ * @param value
+ * @param time
+ * @return
+ */
+ public boolean set(String key, Object value, long time) {
+ try {
+ if (time > 0) {
+ redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+ } else {
+ set(key, value);
+ }
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ }
+
+ /**
+ * distributed lock
+ *
+ * @param key locked key
+ * @param lockExpireMils expire time without unlock
+ * @return
+ */
+ public boolean setNx(String key, Long lockExpireMils) {
+ return (boolean) redisTemplate.execute((RedisCallback) connection -> {
+ return connection.setNX(key.getBytes(), String.valueOf(System.currentTimeMillis() + lockExpireMils + 1).getBytes());
+ });
+ }
+
+ /**
+ * increase value for key
+ *
+ * @param key
+ * @param delta value to increase
+ * @return
+ */
+ public long incr(String key, long delta) {
+ if (delta < 0) {
+ throw new RuntimeException("increment element has to be greater than 0");
+ }
+
+ return redisTemplate.opsForValue().increment(key, delta);
+ }
+
+ public long decr(String key, long delta) {
+ if (delta < 0) {
+ throw new RuntimeException("decrement element has to be greater than 0");
+ }
+ return redisTemplate.opsForValue().increment(key, -delta);
+ }
+
+ /**
+ * HashGet
+ *
+ * @param key 键 不能为null
+ * @param item 项 不能为null
+ * @return 值
+ */
+ public Object hget(String key, String item) {
+ return redisTemplate.opsForHash().get(key, item);
+ }
+
+ /**
+ * 获取hashKey对应的所有键值
+ *
+ * @param key 键
+ * @return 对应的多个键值
+ */
+ public Map