springboot整合Redis


一、新建项目,并添加所须要的jar包:javascript

分析:html

(1)在springboot中已经继承了Redis,就是说一旦咱们启动项目,它是能够根据properties配置文件中的配置信息自动建立Jedis对象的java

(2)咱们想要的是本身定义配置信息的名称,再根据本身定义的配置信息配置一个有关配置信息的类,最后根据这个类来建立一个咱们想要的Jedis对象。node

(3)springboot项目在加载的时候,因为springboot没法从配置文件中获取想要的信息,因此不会自动建立属于springboot的Jedis对象,而是根据咱们自定义mysql

的配置信息进行建立一个Jedis对象jquery

(4)在使用Jedis对象的时候,咱们给咱们的Jedis对象加上了@Bean注解,在要使用Jedis的类中使用@Autowired注解,因此spring中的BeanFactory工厂自动建立对象,web

,且是单例的;此处直接在@Autowire的注解下注入的是(3)中的对象,也就是根据咱们自定义信息建立的对象ajax

springboot-parent
spring-boot-web-start
mysql驱动包
druid(德鲁伊)链接池
springboot和mybatis的整合包
thymeleaf模板jar包
thymeleaf忽略语法的jar包

springboot和redis的整合包
jedis的包:
jedis就是经过Java实现对redis集群的增删改查,就是操做redis数据库
redis最终只支持5种数据格式:
String类型是最经常使用的
若是须要把User对象存入到redis中===>须要把User对象转换为json字符串===>再把字符串存入到redis中
json的jar包
configuration-processer包(为了使用其中的@ConfigurationProperties()注解,在下文中的RedisProperties类中所使用)


 1 <!-- springboot的jar -->
 2 <parent>
 3     <groupId>org.springframework.boot</groupId>
 4     <artifactId>spring-boot-starter-parent</artifactId>
 5     <version>1.5.10.RELEASE</version>
 6 </parent>
 7 
 8 <dependencies>
 9     <!--
10         springboot-starter-web 11     -->
12     <dependency>
13         <groupId>org.springframework.boot</groupId>
14         <artifactId>spring-boot-starter-web</artifactId>
15     </dependency>
16     <!--
17         springboot-mybatis整合包 18     -->
19     <dependency>
20         <groupId>org.mybatis.spring.boot</groupId>
21         <artifactId>mybatis-spring-boot-starter</artifactId>
22         <version>1.3.0</version>
23     </dependency>
24     <!--
25  mysql的驱动包 26     -->
27     <dependency>
28         <groupId>mysql</groupId>
29         <artifactId>mysql-connector-java</artifactId>
30         <version>5.1.38</version>
31     </dependency>
32     <!--
33  druid链接池 34     -->
35     <dependency>
36         <groupId>com.alibaba</groupId>
37         <artifactId>druid</artifactId>
38         <version>1.1.10</version>
39     </dependency>
40     <!--
41  html的thymeleaf模板 42     -->
43     <dependency>
44         <groupId>org.springframework.boot</groupId>
45         <artifactId>spring-boot-starter-thymeleaf</artifactId>
46     </dependency>
47     <!--
48  redis的jar包以及jedis的jar包 49     -->
50     <dependency>
51         <groupId>redis.clients</groupId>
52         <artifactId>jedis</artifactId>
53         <version>2.9.0</version>
54     </dependency>
55     <!--
56  redis和springboot的整合包 57     -->
58     <dependency>
59         <groupId>org.springframework.data</groupId>
60         <artifactId>spring-data-redis</artifactId>
61     </dependency>
62     <!--
63  fastjson包 64     -->
65     <dependency>
66         <groupId>com.fasterxml.jackson.core</groupId>
67         <artifactId>jackson-databind</artifactId>
68         <version>2.8.1</version>
69     </dependency>
70     <!--
71  添加springboot的进程jar包 72  里面包含了properties文件的读取(其实就是包含了@ConfigurationProperties()注解) 73     -->
74     <dependency>
75         <groupId>org.springframework.boot</groupId>
76         <artifactId>spring-boot-configuration-processor</artifactId>
77         <optional>true</optional>
78     </dependency>
79 
80     <dependency>
81         <groupId>net.sourceforge.nekohtml</groupId>
82         <artifactId>nekohtml</artifactId>
83         <version>1.9.21</version>
84     </dependency>
85 </dependencies>

 

二、在springboot框架中,已经整合了Redis,能够直接使用。
  此处根据springboot整合Redis的源码来实现本身的Redis,缘由:springboot自带的Redis已经很是完善,一旦出错,很难找到错误的地方
  例如:当服务器的IP变更,端口号的问题等,能够经过在本身的配置类中打断点等方法判断错误的地方

三、在config中配置application.properties配置信息:
 1 server.port=8081
 2 server.context-path=/
 3 
 4 spring.datasource.driver-class-name=com.mysql.jdbc.Driver  5 spring.datasource.url=jdbc:mysql://localhost:3306/mybatis?userSSL=false
 6 spring.datasource.username=root  7 spring.datasource.password=123456
 8 spring.datasource.type=com.alibaba.druid.pool.DruidDataSource  9 
10 mybatis.type-aliases-package=com.aaa.liu.redis.model 11 mybatis.mapper-locations=classpath:mapper/*Mapper.xml 12 
13 #开始自定义配置 14 # 配置redis集群的端口号和IP 15 spring.redis.nodes=192.168.134.130:6380,192.168.134.130:6381,192.168.134.130:6382,192.168.134.130:6383,192.168.134.130:6384,192.168.134.130:6385 16 # 配置了redistribution的最大链接数 17 spring.redis.maxAttempts=1000 18 # 配置了redis最大超时时间 19 spring.redis.commandTimeout=500000 20 # 配置了redis的失效时间 21 spring.redis.expire=1000 22 
23 # 定义图书的key值 24 book_key=bookKey1 25 
26 # 配置thymeleaf模板(不配置也能够,直接使用) 27 # 配置thymeleaf缓存:默认值true,须要手动修改成false 28 spring.thymeleaf.cache=false 29 # 配置不严谨的html 30 spring.thymeleaf.mode=LEGACYHTML5

 


四、在Java中新建一个config包,在包中新建RedisPro类,将刚刚application.properties的配置信息引入此类中:
 1 package com.aaa.liu.redis.config;  2 
 3 import org.springframework.boot.context.properties.ConfigurationProperties;  4 import org.springframework.stereotype.Component;  5 
 6 /**
 7  * @Author 刘其佳  8  * @DateTime 2019/8/28 19:49  9  * @Project_Name SpringBootRedis 10  * 11  * 一、@Component:把RedisProperties做为spring的一个组件 12  * 做用是 把Redis所须要配置和链接信息封装进RedisProperties类中 13  * 该组件可拆分 14  * 配置该组件类的做用是从application.properties文件中读取自定义的信息 15  * 二、@ConfigurationPrperties:做用是把application.properties中的属性读进RedisProperties类中 16  * 当使用该注解的时候必需要使用spring-boot-configuration-processor的jar包 17  * prefx="spring.redis";做用是选中在application.properties文件中的 属性名 进行对用(必须一致) 18  * 三、原本按理说在此类中定义属性事后,只有get方法,不该该有set方法,由于不能别其余类修改 19  * 但如果真的不放入set方法的话,在使用此类时,没法传递进来参数(属性是私有的) 20  * !!!因此最终仍是要有set方法,只要注意其余的类在调用RedisProperties类中的属性的时候, 21  * 必定不能修改!!! 22  * 23  */
24 
25 @Component 26 /**
27  * 全部以spring.redis开头的配置信息 28  */
29 @ConfigurationProperties(prefix = "spring.redis") 30 public class RedisProperties { 31 
32     /**
33  * 下列属性对应application.properties文件中的自定义的配置: 34  * redis集群的节点 35  * 最大链接数 36  * 最大超时时间 37  * 失效时间 38      */
39     private String nodes; 40     private String maxAttempts; 41     private String commandTimeout; 42     private String expire; 43 
44     public String getNodes() { 45         return nodes; 46  } 47 
48     public void setNodes(String nodes) { 49         this.nodes = nodes; 50  } 51 
52     public String getMaxAttempts() { 53         return maxAttempts; 54  } 55 
56     public void setMaxAttempts(String maxAttempts) { 57         this.maxAttempts = maxAttempts; 58  } 59 
60     public String getCommandTimeout() { 61         return commandTimeout; 62  } 63 
64     public void setCommandTimeout(String commandTimeout) { 65         this.commandTimeout = commandTimeout; 66  } 67 
68     public String getExpire() { 69         return expire; 70  } 71 
72     public void setExpire(String expire) { 73         this.expire = expire; 74  } 75 }

 


五、仍然在config包中新建类:RedisConfiguration,将RedisProperties类注入进来:
 1 package com.aaa.liu.redis.config;  2 
 3 import org.springframework.beans.factory.annotation.Autowired;  4 import org.springframework.boot.autoconfigure.SpringBootApplication;  5 import org.springframework.boot.context.properties.EnableConfigurationProperties;  6 import org.springframework.context.annotation.Bean;  7 import org.springframework.context.annotation.Configuration;  8 import redis.clients.jedis.HostAndPort;  9 import redis.clients.jedis.JedisCluster; 10 
11 import java.util.HashSet; 12 import java.util.Set; 13 
14 /**
15  * @Author 刘其佳 16  * @DateTime 2019/8/28 20:34 17  * @Project_Name SpringBootRedis 18  */
19 
20 /**
21  * 此处加上注解@Configuration或者@SpringBootApplication 22  * 23  * 由于在SpringBootApplication是一个组合注解 24  * 进入其中能够看到@SpringBootConfiguration @EnableAutoConfiguration @ComponentScan 25  * 再次进入@SpringBootConfiguration能够看到@Configuration 26  * 所以SpringBootConfiguration是EnableAutoConfiguration、ComponentScan和Configuration的组合注解 27  * 28  * 在较低版本的SpringBoot中: 29  * @Configuration是启用基于Java的配置 30  * @ComponentScan是启用组件扫描。 31  * @EnableAutoConfiguration是启用SpringBoot的自动配置功能 32  * 引用自:https://blog.csdn.net/qq_37939251/article/details/83058065
33  */
34 
35 /**
36  * 经过SpringBootApplication/Configuration注解将RedisConfiguration类标识为springboot的配置类 37  * 38  * 使用Jedis的jar包操做Redis集群数据库 39  * 一、Redis:标识了Redis是单节点模式(只有一台Redis) 40  * 源码中:protected static class RedisConfiguration {} 41  * 二、RedisCluster:标识了Redis的Redis集群模式 42  * 源码中:protected final RedisClusterConfiguration getClusterConfiguration() {} 43  * 本次只配置集群版的Redis 44  * 45  * @Bean: 至关于applicationContext.xml中的<bean id=""> class="JedisCluster.class"</bean> 46  * 47  * @EnableConfirgurationProperties({RedisProperties.class})是源码中使用的注解 48  * 在本类中咱们使用@Autowired来代替掉 49  */
50 @SpringBootApplication 51 public class RedisConfiguration { 52  @Autowired 53     private RedisProperties redisProperties; 54 
55  @Bean 56     public JedisCluster getJedisCluster(){ 57         //一、获取到application.properties文件中的Redis集群的节点信息
58         String nodes=redisProperties.getNodes(); 59         //二、使用split来将多个node进行拆分
60         String[] nodeArray = nodes.split(","); 61         //三、建立一个set集合,以HostAndPort对象做为泛型
62         Set<HostAndPort> hostAndPortSet=new HashSet<HostAndPort>(); 63         //四、遍历刚刚获得的节点数组
64         for (String node : nodeArray) { 65             //五、继续使用split将node拆分红IP和端口号(host、port)
66             String[] hostAndPortArray = node.split(":"); 67             //六、建立HostAndPort对象,并将获得的IP和端口号做为构造方法的参数传入
68             HostAndPort hostAndPort=new HostAndPort(hostAndPortArray[0],Integer.parseInt(hostAndPortArray[1])); 69             //七、把每个HostAndPort对象装进Set集合中
70  hostAndPortSet.add(hostAndPort); 71  } 72         //八、返回一个JedisCluster对象
73         return new JedisCluster(hostAndPortSet,Integer.parseInt(redisProperties.getCommandTimeout()),Integer.parseInt(redisProperties.getMaxAttempts())); 74  } 75 }

 


六、在Service层中新建RedisService
 1 package com.aaa.liu.redis.service;  2 
 3 import org.springframework.beans.factory.annotation.Autowired;  4 import org.springframework.stereotype.Service;  5 import redis.clients.jedis.JedisCluster;  6 
 7 /**
 8  * @Author 刘其佳  9  * @DateTime 2019/8/28 21:39 10  * @Project_Name SpringBootRedis 11  * 在之前的UserService中注入UserMapper,对数据库进行操做 12  * 如今的RedisService中注入JedisCluster,对Redis数据库进行操做 13  */
14 @Service 15 public class RedisService { 16 
17  @Autowired 18     private JedisCluster jedisCluster; 19 
20     /**
21  * 在Redis数据库中的增删查(没有修改)分别为: 22  * set del get 23  * 在下面分别定义 24      */
25 
26     /**
27  * @author 刘其佳 28  * @description 29  * 向Redis数据库中存入String类型的数据 30  * set的时候返回值是"ok" 31  * @param * param *:key 32  * @date 2019/8/28 33  * @return java.lang.String 34  * @throws
35     */
36     public String set(String key,String value){ 37         return jedisCluster.set(key,value); 38  } 39 
40     /**
41  * @author 刘其佳 42  * @description 43  * 从Redis数据库中经过key取出数据 44  * @param * param *:key 45  * @date 2019/8/28 46  * @return java.lang.String 47  * @throws
48     */
49     public String get(String key){ 50         return jedisCluster.get(key); 51  } 52 
53     /**
54  * @author 刘其佳 55  * @description 56  * 一、在此处的参数key是一个可变参 57  * 二、在Redis中删除的返回值是Integer类型 58  * 在Java中被转成了Long类型 59  * @param * param *:key 60  * @date 2019/8/28 61  * @return java.lang.Long 62  * @throws
63     */
64     public Long del(String key){ 65         return jedisCluster.del(key); 66  } 67 
68     /**
69  * @author 刘其佳 70  * @description 71  * 经过key设置失效时间(单位是秒) 72  * @param * param *:key 73  * param *:seconds 74  * @date 2019/8/28 75  * @return java.lang.Long 76  * @throws
77     */
78     public Long expire(String key,Integer seconds){ 79         return jedisCluster.expire(key,seconds); 80  } 81 }

 

查询图书信息的service:
 1 /**
 2  * @author 刘其佳  3  * @description  4  * 注意:service层不容许注入service  5  * 由于在applicationContext.xml中配置事务后,事务都是在service中的  6  * 当service注入另外一个事务时,会形成事务串线(若是线程是并行的没有问题)  7  * applicationContext.xml配置文件中进行注解扫描:  8  * controller:必需要在springmvc中进行扫描  9  * service:必需要在spring中进行扫描 10  * 11  * @param * param *:null 12  * @date 2019/8/28 13  * @return
14  * @throws
15     */
16     public Map<String ,Object> selectAllBooks(RedisService redisService){ 17         /**
18  * 一、从Redis中查询全部图书信息 19  * 二、判断从Redis中是否查询出数据 20  * 三、没有查询到的话再从数据库中查询数据 21  * 四、判断是否从数据库中查询到数据 22  * 五、若查询到数据,则返回结果,而且将数据放入Redis中 23  * 六、利用try...catch判断是否存入Redis中 24  * 七、若没有存入Redis中,要作出处理,此处为再次往Redis中存放一次 25          */
26         Map<String,Object> resultMap=new HashMap<String, Object>(); 27         //一、
28         String bookString=redisService.get(bookKey); 29         //二、
30         if(null==bookString||"".equals(bookString)){ 31             //三、
32             List<Book> bookList = bookMapper.selectAll(); 33             //四、
34             if(bookList.size()>0){ 35                 //六、
36                 try { 37                     //五、
38  redisService.set(bookKey, JSONUtil.toJsonString(bookList)); 39                     //将从数据库中查询到的数据存入resultMap中
40  resultMap.put(StatusEnum.SUCCESS.getCodeName(), StatusEnum.SUCCESS.getCode()); 41  resultMap.put(StatusEnum.SUCCESS.getResultName(),bookList); 42                 } catch (Exception e) { 43                     //七、
44  redisService.set(bookKey, JSONUtil.toJsonString(bookList)); 45                     //若是仍是没有将数据放入Redis中,此时咱们将resultMap里面的code换成404,可是用户仍是可以查询到数据
46  resultMap.put(StatusEnum.FAILED.getCodeName(),StatusEnum.FAILED.getCode()); 47  resultMap.put(StatusEnum.FAILED.getResultName(),bookList); 48  e.printStackTrace(); 49                     return resultMap; 50  } 51             }else { 52                 //说明数据库中没有数据,放入500
53  resultMap.put(StatusEnum.ERROR.getCodeName(),StatusEnum.ERROR.getCode()); 54  } 55         }else { 56             //!!!可能会存在Redis中的数据与数据库中的数据不一致的状况 57             //因此此处从Redis中获取到数据后与从数据库中查询到的数据作出一个判断(长度是否一致)
58             List<Book> bookList = JSONUtil.toList(bookString, Book.class); 59             List<Book> bookList1 = bookMapper.selectAll(); 60             if(bookList.size()==bookList1.size()){ 61                 //将查询从Redis中查询到的数据存入到resultMap 62                 //由于是从Redis中查询到的数据,此处给转回正常状态下的List集合类型的数据, 63                 //正好从数据库中查询到的数据也是List,保持一致
64  resultMap.put(StatusEnum.SUCCESS.getCodeName(), StatusEnum.SUCCESS.getCode()); 65                 resultMap.put(StatusEnum.SUCCESS.getResultName(),JSONUtil.toList(bookString,Book.class)); 66         }else { 67                 //发现数据不一致时,丢弃Redis中的数据,并将数据库中的数据存入Redis中
68  redisService.set(bookKey,JSONUtil.toJsonString(bookList)); 69  resultMap.put(StatusEnum.SUCCESS.getCodeName(), StatusEnum.SUCCESS.getCode()); 70  resultMap.put(StatusEnum.SUCCESS.getResultName(),bookList1); 71  } 72 
73  } 74         return resultMap; 75     }

 

七、控制层的BookController:
 1 /**
 2  * @Author 刘其佳  3  * @DateTime 2019/8/28 22:25  4  * @Project_Name SpringBootRedis  5  */
 6 @RestController  7 public class BookController {  8 
 9  @Autowired 10     private BookService bookService; 11  @Autowired 12     private RedisService redisService; 13 
14     @RequestMapping("/") 15     public List<Book> selectAllBooks(){ 16         Map<String, Object> resultMap = bookService.selectAllBooks(redisService); 17         List<Book> bookList=null; 18         //若是查询到的resultMap中的code值为200,说明直接从Redis中查到数据了
19         if(StatusEnum.SUCCESS.getCode().equals((resultMap.get(StatusEnum.SUCCESS.getCodeName())))){ 20             bookList= (List<Book>) resultMap.get(StatusEnum.SUCCESS.getResultName()); 21             System.out.println("everything is ok!"); 22         }else { 23             //若是code值不为200,则有两种状况:404即Redis错误; 500即mysql错误
24             if(StatusEnum.ERROR.getCode().equals((resultMap.get(StatusEnum.SUCCESS.getCodeName())))){ 25                 //一、result到最后也没存进去值,数据库都出现了问题
26                 System.out.println("数据库出现了问题"); 27             }else{ 28                 //二、result有值,Redis出现了问题,但从数据库查询了数据
29                 bookList= (List<Book>) resultMap.get(StatusEnum.SUCCESS.getResultName()); 30                 System.out.println("redis出现了问题"); 31  } 32  } 33         return bookList; 34     }

 

在本次项目中为了不魔法值问题,使用了枚举:
新建一个包statuscode ,在其中新建类:StatusEnum
 1 package com.aaa.liu.redis.statuscode;  2 
 3 /**
 4  * @Author 刘其佳  5  * @DateTime 2019/8/29 20:08  6  * @Project_Name SpringBootRedis  7  */
 8 public enum StatusEnum {  9     SUCCESS(200,"操做失败","code","result"), 10     FAILED(404,"操做成功","code","result"), 11     ERROR(500,"操做失败","code","result"); 12 
13     private Integer code; 14     private String msg; 15     private String codeName; 16     private String resultName; 17 
18     /**
19  * 给枚举赋值 20  * @param code 21  * @param msg 22  * @param codeName 23      */
24  StatusEnum(Integer code, String msg, String codeName,String resultName) { 25         this.code = code; 26         this.msg = msg; 27         this.codeName = codeName; 28         this.resultName=resultName; 29  } 30 
31     public Integer getCode() { 32         return code; 33  } 34 
35     public void setCode(Integer code) { 36         this.code = code; 37  } 38 
39     public String getMsg() { 40         return msg; 41  } 42 
43     public void setMsg(String msg) { 44         this.msg = msg; 45  } 46 
47     public String getCodeName() { 48         return codeName; 49  } 50 
51     public void setCodeName(String codeName) { 52         this.codeName = codeName; 53  } 54 
55     public String getResultName() { 56         return resultName; 57  } 58 
59     public void setResultName(String resultName) { 60         this.resultName = resultName; 61  } 62 }

 


mapper中的BookMapper查询全部图书:
 1 /**
 2  * @Author 刘其佳  3  * @DateTime 2019/8/27 20:19  4  * @Project_Name springbootshiro  5  */
 6 @Mapper  7 public interface BookMapper {  8     //查询全部书籍
 9     @Select("select id,book_name bookName,book_price bookPrice from book ") 10     List<Book> selectAll(); 11 }

 

其中的注意事项已在代码中写出!



此处插入一个关于ajax的用法:
 1 <!DOCTYPE html>
 2 <html xmlns="http://www.w3.org/1999/xhtml"
 3       xmlns:th="http://www.thymeleaf.org"
 4       xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
 5 <head>
 6     <meta charset="UTF-8">
 7     <title>Index</title>
 8     <script type="text/javascript" src="/jquery-3.2.1.min.js"></script>
 9 </head>
10 
11 <script>
12     /**
13  * 1.页面自动加载完成后,函数自动执行,查询出数据并拼接处table表单,将数据放入其中 14  * */
15  $(document).ready( selectBookTest()); 16 
17  function selectBookTest(){ 18  $.ajax({ 19             type:"POST", 20             url:"selectBooks", 21             dataType:"JSON", 22  success:function (msg) { 23                 var tr=""; 24                 for(var i=0;i<msg.length;i++){ 25                     tr+="<tr><td>"+msg[i].id+"</td>"; 26                     tr+="<td>"+msg[i].bookName+"</td>"; 27                     tr+="<td>"+msg[i].bookPrice+"</td></tr>"; 28                     //不能直接使用下面的方式,不然会只有一行数据;要使用+= 29                     // tr="<tr><td>"+msg[i].id+"</td><td>"+msg[i].bookName+"</td><td>"+msg[i].bookPrice+"</td></tr>"
30  } 31                 tr+="<tr><td onclick='testBookAdd()'>添加</td></tr>"; 32                 $("#test_Book").append("<table border='1px solid black'>" +
33                     "<thead>" +
34                     "<tr >" +
35                     "<th>图书编号</th>" +
36                     "<th>图书名称</th>" +
37                     "<th>图书价格</th>" +
38                     "</tr>" +
39                     tr +
40                     "</thead>" +
41                     "</table>") 42  } 43 
44  }) 45  } 46 
47     /**
48  * 2.点击添加按钮,将查询所得的数据清空,并拼接出新的form表单用以输入要添加的数据 49      */
50  function testBookAdd() { 51         $("#test_Book").empty(); 52         $("#test_Book").append("<form id='formBook'><table border='1px solid red'>" +
53             "<tr><td>图书名称:</td><td><input type='text' name='bookName'/></td></tr>" +
54             "<tr><td>图书价格:</td><td><input type='text' name='bookPrice'/></td></tr>"+
55             "<tr><td><input type='button' value='submit' onclick='bookAdd()'/></td></tr>"+
56             "</table></form>") 57  } 58 
59     /**
60  * 3.输入完数据,使用ajax调用添加方法添加 61      */
62  function bookAdd() { 63  $.ajax({ 64             type:"POST", 65             url:"testAddBook", 66             data:$("#formBook").serialize(), 67             dataType:"json", 68  success:function (msg) { 69                 if(null==msg){ 70                     alert("添加失败") 71                 }else{ 72                     $("#test_Book").empty(); 73  selectBookTest(); 74  } 75  } 76  }) 77  } 78 
79 </script>
80 <body>
81 
82 <div id="test_Book"></div>
83 </body>
84 
85 
86 </html>
相关文章
相关标签/搜索