Bläddra i källkod

0615 redis string/list/hash

Qing 1 år sedan
förälder
incheckning
eb78269f96

+ 7 - 0
novel-demo/pom.xml

@@ -122,6 +122,13 @@
             <artifactId>spring-boot-starter-data-redis</artifactId>
         </dependency>
 
+        <!-- 谷歌提供的转化json的jar包 -->
+        <dependency>
+            <groupId>com.google.code.gson</groupId>
+            <artifactId>gson</artifactId>
+            <version>2.11.0</version>
+        </dependency>
+
     </dependencies>
 
     <build>

+ 44 - 0
novel-demo/src/main/java/com/sf/config/GsonConfig.java

@@ -0,0 +1,44 @@
+package com.sf.config;
+
+import com.google.gson.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 优化Gson对LocalDateTime的转换
+ *
+ * @Author i8023tp
+ **/
+@Configuration
+public class GsonConfig {
+    //序列化
+    final static JsonSerializer<LocalDateTime> jsonSerializerDateTime = (localDateTime, type, jsonSerializationContext)
+            -> new JsonPrimitive(localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    final static JsonSerializer<LocalDate> jsonSerializerDate = (localDate, type, jsonSerializationContext)
+            -> new JsonPrimitive(localDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    //反序列化
+    final static JsonDeserializer<LocalDateTime> jsonDeserializerDateTime = (jsonElement, type, jsonDeserializationContext)
+            -> LocalDateTime.parse(jsonElement.getAsJsonPrimitive().getAsString(),
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+    final static JsonDeserializer<LocalDate> jsonDeserializerDate = (jsonElement, type, jsonDeserializationContext)
+            -> LocalDate.parse(jsonElement.getAsJsonPrimitive().getAsString(),
+            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
+
+    @Bean
+    public Gson gson() {
+        return new GsonBuilder()
+                .setPrettyPrinting()
+                /* 更改先后顺序没有影响 */
+                .registerTypeAdapter(LocalDateTime.class, jsonSerializerDateTime)
+                .registerTypeAdapter(LocalDate.class, jsonSerializerDate)
+                .registerTypeAdapter(LocalDateTime.class, jsonDeserializerDateTime)
+                .registerTypeAdapter(LocalDate.class, jsonDeserializerDate)
+                .create();
+    }
+
+
+}

+ 32 - 0
novel-demo/src/main/java/com/sf/config/RedisConfig.java

@@ -0,0 +1,32 @@
+package com.sf.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+// 这是一个配置类
+@Configuration
+public class RedisConfig {
+
+    // 这是要注入spring容器中的一个对象
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
+        RedisTemplate<String, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(factory);
+
+        // 设置redis的序列化方式
+        // 设置key的序列化方式为StringRedisSerializer
+        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+        template.setKeySerializer(stringRedisSerializer);
+        template.setHashKeySerializer(stringRedisSerializer);
+
+        // 设置value的序列化方式GenericJackson2JsonRedisSerializer
+        GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
+        template.setValueSerializer(genericJackson2JsonRedisSerializer);
+        template.setHashValueSerializer(genericJackson2JsonRedisSerializer);
+        return template;
+    }
+}

+ 13 - 3
novel-demo/src/main/java/com/sf/config/TokenInterceptor.java

@@ -5,6 +5,7 @@ import com.sf.util.UserHolder;
 import jakarta.servlet.http.HttpServletRequest;
 import jakarta.servlet.http.HttpServletResponse;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 import org.springframework.web.servlet.HandlerInterceptor;
 
@@ -16,14 +17,23 @@ public class TokenInterceptor implements HandlerInterceptor {
     @Autowired
     private JwtUtils jwtUtils;
 
+    @Autowired
+    private RedisTemplate redisTemplate;
+
     // controller执行之前
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
         String token = request.getHeader("Authorization");
         if (token != null && !token.equals("null")) {
             Long uid = jwtUtils.parseToken(token, "front");
-            System.out.println("用拦截器解析uid: " + uid);
-            UserHolder.setUserId(uid);
+            String tokenKey = "token_" + uid;
+//            System.out.println("用拦截器解析uid: " + uid);
+            String str = (String)redisTemplate.opsForValue().get(tokenKey);
+            if(str != null) {
+                UserHolder.setUserId(uid);
+            }else {
+                // 用户登录失效
+            }
         }
         return HandlerInterceptor.super.preHandle(request, response, handler);
     }
@@ -31,7 +41,7 @@ public class TokenInterceptor implements HandlerInterceptor {
     // controller执行之后
     @Override
     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
-        System.out.println("controller执行完成");
+//        System.out.println("controller执行完成");
         UserHolder.clearUserId();
         HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
     }

+ 5 - 1
novel-demo/src/main/java/com/sf/controller/BookCommentController.java

@@ -35,7 +35,11 @@ public class BookCommentController {
     // http://127.0.0.1:8888/api/front/user/comment
     @PostMapping("/api/front/user/comment")
     public RestResp<Void> addComment(@RequestBody UserCommentReqDto userCommentReqDto) {
-        userCommentReqDto.setUserId(UserHolder.getUserId());
+        Long userId = UserHolder.getUserId();
+        if(userId == null){
+           return RestResp.fail("00005","用户登录失效了,请重新登录");
+        }
+        userCommentReqDto.setUserId(userId);
         bookCommentService.saveComment(userCommentReqDto);
         return RestResp.ok(null);
     }

+ 60 - 0
novel-demo/src/main/java/com/sf/service/impl/HomeBookServiceImpl.java

@@ -2,6 +2,7 @@ package com.sf.service.impl;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.google.gson.Gson;
 import com.sf.dto.resp.HomeBookRespDto;
 import com.sf.dto.resp.HomeFriendLinkRespDto;
 import com.sf.entity.BookInfo;
@@ -13,6 +14,9 @@ import com.sf.mapper.HomeFriendLinkMapper;
 import com.sf.service.IHomeBookService;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.ListOperations;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
 import java.util.ArrayList;
@@ -40,10 +44,23 @@ public class HomeBookServiceImpl extends ServiceImpl<HomeBookMapper, HomeBook> i
     @Autowired
     private HomeFriendLinkMapper homeFriendLinkMapper;
 
+    @Autowired
+    private RedisTemplate redisTemplate;
+
+    @Autowired
+    private Gson gson;
+
     // 去到home_book表中取数据
     // 再使用book_id去book_info表中找到关联数据
     @Override
     public List<HomeBookRespDto> allHomeBook() {
+        // 先尝试从redis中取数据
+        List<HomeBookRespDto> redisHomeBook = allHomeBookFromRedis();
+        if (redisHomeBook.size() != 0) {
+            System.out.println("从Redis中返回数据");
+            return redisHomeBook;
+        }
+        System.out.println("从Mysql中返回数据");
         List<HomeBookRespDto> list = new ArrayList<>();
 
         List<HomeBook> homeBookList = homeBookMapper.selectList(null);
@@ -82,6 +99,49 @@ public class HomeBookServiceImpl extends ServiceImpl<HomeBookMapper, HomeBook> i
         return list;
     }
 
+    public List<HomeBookRespDto> allHomeBookFromRedis() {
+        List<HomeBookRespDto> homeBookRespDtoList = new ArrayList<>();
+        ListOperations listOperations = redisTemplate.opsForList();
+        HashOperations hashOperations = redisTemplate.opsForHash();
+
+        String key0 = "homeBookList0";
+        String key1 = "homeBookList1";
+        String key2 = "homeBookList2";
+        String key3 = "homeBookList3";
+        String key4 = "homeBookList4";
+        String hashKey = "bookHash";
+        List<String> bookIdList0 = listOperations.range(key0, 0, -1);
+        List<String> bookIdList1 = listOperations.range(key1, 0, -1);
+        List<String> bookIdList2 = listOperations.range(key2, 0, -1);
+        List<String> bookIdList3 = listOperations.range(key3, 0, -1);
+        List<String> bookIdList4 = listOperations.range(key4, 0, -1);
+
+        List<String> current = bookIdList0;
+        for (int i = 0; i < 5; i++) {
+            if (i == 1) current = bookIdList1;
+            if (i == 2) current = bookIdList2;
+            if (i == 3) current = bookIdList3;
+            if (i == 4) current = bookIdList4;
+            for (String bookId : current) {
+                String json = (String) hashOperations.get(hashKey, bookId);
+                // 通过gson转化成对象
+                BookInfo bookInfo = gson.fromJson(json, BookInfo.class);
+                HomeBookRespDto homeBookRespDto = HomeBookRespDto.builder()
+                        .type(i)  // byte -> int
+                        .bookId(Long.parseLong(bookId))
+                        .picUrl(bookInfo.getPicUrl())
+                        .bookName(bookInfo.getBookName())
+                        .authorName(bookInfo.getAuthorName())
+                        .bookDesc(bookInfo.getBookDesc())
+                        .build();
+                homeBookRespDtoList.add(homeBookRespDto);
+            }
+        }
+
+        return homeBookRespDtoList;
+    }
+
+
     @Override
     public List<HomeFriendLinkRespDto> listHomeFriendLinks() {
         LambdaQueryWrapper<HomeFriendLink> queryWrapper = new LambdaQueryWrapper<>();

+ 16 - 5
novel-demo/src/main/java/com/sf/service/impl/UserInfoServiceImpl.java

@@ -14,6 +14,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.sf.util.CaptchaUtils;
 import com.sf.util.JwtUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.data.util.Pair;
 import org.springframework.stereotype.Service;
 import org.springframework.util.DigestUtils;
@@ -21,6 +22,7 @@ import org.springframework.util.DigestUtils;
 import java.nio.charset.StandardCharsets;
 import java.time.LocalDateTime;
 import java.util.HashMap;
+import java.util.concurrent.TimeUnit;
 
 /**
  * <p>
@@ -41,6 +43,10 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
     @Autowired
     private JwtUtils jwtUtils;
 
+    // https://docs.spring.io/spring-data/redis/docs/current/api/org/springframework/data/redis/core/RedisTemplate.html
+    @Autowired
+    private RedisTemplate redisTemplate;
+
 
     @Override
     public ImgVerifyCodeRespDto getImgVerifyCode() {
@@ -49,7 +55,8 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
         String sessionId = IdWorker.get32UUID();
         // 将这个唯一的sessionId和code码关联 存储在容器中
         // 将pair(成对的数据)中的第一个数据 和 sessionId存入map中
-        captcha.put(sessionId, pair.getFirst());
+//        captcha.put(sessionId, pair.getFirst());
+        redisTemplate.opsForValue().set(sessionId, pair.getFirst(),10,TimeUnit.MINUTES);
         ImgVerifyCodeRespDto verifyCodeRespDto = ImgVerifyCodeRespDto.builder()
                 .sessionId(sessionId)
                 .img(pair.getSecond())   // 将hutool生成的base数据设置进去
@@ -63,7 +70,8 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
         // 判断验证码是否正确
         String sessionId = reqDto.getSessionId();
         // 获取验证码图片的正确结果
-        String resultCode = captcha.get(sessionId);
+//        String resultCode = captcha.get(sessionId);
+        String resultCode = (String) redisTemplate.opsForValue().get(sessionId);
         // 如果用户传进来的验证码 不准确  返回验证码错误
         if (!reqDto.getVelCode().equals(resultCode)) {
             // 用类型1 代表验证码错误
@@ -82,6 +90,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
             return respDto;
         }
 
+        redisTemplate.delete(sessionId);
         // 存储数据
         byte[] bytes = reqDto.getPassword().getBytes(StandardCharsets.UTF_8);
         UserInfo userInfo = UserInfo.builder()
@@ -100,7 +109,7 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
         // 在存入数据库后 获取生成的id
         respDto.setUid(userInfo.getId());
 //        respDto.setToken("token_" + userInfo.getId());
-        respDto.setToken(jwtUtils.generateToken(userInfo.getId(),"front"));
+        respDto.setToken(jwtUtils.generateToken(userInfo.getId(), "front"));
         return respDto;
     }
 
@@ -130,8 +139,10 @@ public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper, UserInfo> i
         }
 
         // 登录成功
-//        String token = "token_" + userInfo.getId();
-        String token = jwtUtils.generateToken(userInfo.getId(),"front");
+        String tokenKey = "token_" + userInfo.getId();
+        String token = jwtUtils.generateToken(userInfo.getId(), "front");
+        redisTemplate.opsForValue().set(tokenKey, token, 10, TimeUnit.DAYS);
+        // token_1  -> 生成的token
         return UserLoginRespDto.builder().type(0)
                 .uid(userInfo.getId())
                 .nickName(userInfo.getNickName())

+ 1 - 0
novel-demo/src/main/resources/application.yml

@@ -28,3 +28,4 @@ spring:
       host: localhost
       port: 6379
       password:
+      database: 1

+ 112 - 2
novel-demo/src/test/java/com/sf/RedisTests.java

@@ -1,20 +1,130 @@
 package com.sf;
 
+import com.google.gson.Gson;
+import com.sf.entity.BookInfo;
+import com.sf.entity.HomeBook;
+import com.sf.mapper.BookInfoMapper;
+import com.sf.mapper.HomeBookMapper;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.ListOperations;
 import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+
+import java.util.*;
 
 @SpringBootTest
 public class RedisTests {
 
+    // RedisTemplate是redis整合spring过程中提供的模板工具
     @Autowired
     private RedisTemplate redisTemplate;
 
     @Test
     public void test() {
-        redisTemplate.opsForValue().set("k111", "v111");
-        Object object = redisTemplate.opsForValue().get("k111");
+        ValueOperations stringOperations = redisTemplate.opsForValue();
+        stringOperations.set("k111", "v111");
+        Object object = stringOperations.get("k111");
         System.out.println(object);
     }
+
+    @Test
+    public void testList() {
+        ListOperations forList = redisTemplate.opsForList();
+        String key = "mylist11";
+        forList.rightPushAll(key, "1", "2", "3", "4", "5");  //rightPush
+//        forList.leftPushAll(key, "10", "20", "30", "40", "50");
+        // 50 40 30 20 10 1 2 3 4 5
+        forList.leftPushAll(key, "50", "40", "30", "20", "10");
+        // llen
+        System.out.println(forList.size(key));
+        // lrange
+        System.out.println(forList.range(key, 0, -1));
+
+//        forList.rightPop(key);
+//        forList.trim(key, 0, 4);
+//        System.out.println(forList.range(key, 0, -1));
+    }
+
+    @Test
+    public void testHash() {
+        // 对hash的数据类型进行操作
+        HashOperations hashOperations = redisTemplate.opsForHash();
+        // hset myhash11 field11 value11
+        String key = "myhash11";
+//        hashOperations.put(key, "field11", "value11");
+//        // 批量设置key值
+//        Map<String, Object> map = new HashMap<>();
+//        map.put("field1", "value1");
+//        map.put("field2", "value2");
+//        hashOperations.putAll(key, map);
+
+        String object = (String) hashOperations.get(key, "field1");
+        System.out.println(object);
+        List<Object> mVals = hashOperations.multiGet(key, Arrays.asList("field1", "field2"));
+        System.out.println("根据指定的多个key获取value: " + mVals);
+
+        Boolean hasKey = hashOperations.hasKey(key, "field1");
+        System.out.println("判断key是否存在: " + hasKey);
+        Set<Object> keys = hashOperations.keys(key);
+        System.out.println("获取全部的key: " + keys);
+        List<Object> values = hashOperations.values(key);
+        System.out.println("获取全部的value: " + values);
+//        Long deletedFields = hashOperations.delete(key, "field1");
+//        Long incrementedValue = hashOperations.increment(key, "field1", 5);
+    }
+
+
+    @Autowired
+    private HomeBookMapper homeBookMapper;
+
+    @Autowired
+    private BookInfoMapper bookInfoMapper;
+
+    @Autowired
+    private Gson gson;
+
+    @Test
+    public void testBook() {
+        List<HomeBook> homeBookList = homeBookMapper.selectList(null);
+        ListOperations listOperations = redisTemplate.opsForList();
+        HashOperations hashOperations = redisTemplate.opsForHash();
+
+        List<String> bookIdList0 = new ArrayList<>();
+        List<String> bookIdList1 = new ArrayList<>();
+        List<String> bookIdList2 = new ArrayList<>();
+        List<String> bookIdList3 = new ArrayList<>();
+        List<String> bookIdList4 = new ArrayList<>();
+        Map<String, String> homeBookMap = new HashMap<>();
+        for (HomeBook homeBook : homeBookList) {
+            Long bookId = homeBook.getBookId();
+            switch (homeBook.getType().intValue()) {
+                case 0 -> bookIdList0.add(String.valueOf(bookId));
+                case 1 -> bookIdList1.add(String.valueOf(bookId));
+                case 2 -> bookIdList2.add(String.valueOf(bookId));
+                case 3 -> bookIdList3.add(String.valueOf(bookId));
+                case 4 -> bookIdList4.add(String.valueOf(bookId));
+            }
+
+            BookInfo bookInfo = bookInfoMapper.selectById(bookId);
+            String json = gson.toJson(bookInfo);
+            homeBookMap.put(bookId.toString(), json);
+        }
+        String key0 = "homeBookList0";
+        String key1 = "homeBookList1";
+        String key2 = "homeBookList2";
+        String key3 = "homeBookList3";
+        String key4 = "homeBookList4";
+        listOperations.rightPushAll(key0, bookIdList0);
+        listOperations.rightPushAll(key1, bookIdList1);
+        listOperations.rightPushAll(key2, bookIdList2);
+        listOperations.rightPushAll(key3, bookIdList3);
+        listOperations.rightPushAll(key4, bookIdList4);
+
+        String hashKey = "bookHash";
+        hashOperations.putAll(hashKey, homeBookMap);
+
+    }
 }