19.SPRINGBOOT JPA REDIS 整合在一起做一套带分页的 增删改查 CRUD


pom.xml

增加对 Redis 支持的包
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<? xml  version = "1.0"  encoding = "UTF-8" ?>
< project  xmlns = "http://maven.apache.org/POM/4.0.0"  xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" >
     < modelVersion >4.0.0</ modelVersion >
 
   < groupId >com.how2java</ groupId >
   < artifactId >springboot</ artifactId >
   < version >0.0.1-SNAPSHOT</ version >
   < name >springboot</ name >
   < description >springboot</ description >
   < packaging >war</ packaging >
   
     < parent >
         < groupId >org.springframework.boot</ groupId >
         < artifactId >spring-boot-starter-parent</ artifactId >
         < version >1.5.9.RELEASE</ version >
     </ parent >
     < dependencies >
         < dependency >
             < groupId >org.springframework.boot</ groupId >
             < artifactId >spring-boot-starter-web</ artifactId >
         </ dependency >
         < dependency >
             < groupId >org.springframework.boot</ groupId >
             < artifactId >spring-boot-starter-tomcat</ artifactId >
             
         </ dependency >
         < dependency >
               < groupId >junit</ groupId >
               < artifactId >junit</ artifactId >
               < version >3.8.1</ version >
               < scope >test</ scope >
         </ dependency >
         <!-- servlet依赖. -->
         < dependency >
               < groupId >javax.servlet</ groupId >
               < artifactId >javax.servlet-api</ artifactId >
               
         </ dependency >
               < dependency >
                      < groupId >javax.servlet</ groupId >
                      < artifactId >jstl</ artifactId >
               </ dependency >
         <!-- tomcat的支持.-->
         < dependency >
                < groupId >org.apache.tomcat.embed</ groupId >
                < artifactId >tomcat-embed-jasper</ artifactId >
                
         </ dependency >    
         < dependency >
             < groupId >org.springframework.boot</ groupId >
             < artifactId >spring-boot-devtools</ artifactId >
             < optional >true</ optional <!-- 这个需要为 true 热部署才有效 -->
         </ dependency >
         
         <!-- mysql-->
         < dependency >
             < groupId >mysql</ groupId >
             < artifactId >mysql-connector-java</ artifactId >
             < version >5.1.21</ version >
         </ dependency >
 
         <!-- jpa-->
         < dependency >
             < groupId >org.springframework.boot</ groupId >
             < artifactId >spring-boot-starter-data-jpa</ artifactId >
         </ dependency >
         <!-- redis -->       
         < dependency >
             < groupId >org.springframework.boot</ groupId >
             < artifactId >spring-boot-starter-data-redis</ artifactId >
         </ dependency >       
         < dependency >
             < groupId >org.springframework.boot</ groupId >
             < artifactId >spring-boot-starter-test</ artifactId >
             < scope >test</ scope >
         </ dependency >       
         < dependency >
           < groupId >junit</ groupId >
           < artifactId >junit</ artifactId >
           < version > 4.12</ version >
         </ dependency >       
     </ dependencies >
 
     < properties >
         < java.version >1.8</ java.version >
     </ properties >
 
     < build >
         < plugins >
             < plugin >
                 < groupId >org.springframework.boot</ groupId >
                 < artifactId >spring-boot-maven-plugin</ artifactId >
             </ plugin >
         </ plugins >
     </ build >
 
</ project >
 步骤 8 : 

application.properties

增加redis相关配置
同时让hibernate的sql语句显示出来,这样才知道到底是通过 Redis 取到的数据,还是依然是从数据库取到的数据
 
spring.jpa.show-sql=true
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
spring.mvc.view.prefix=/WEB-INF/jsp/
spring.mvc.view.suffix=.jsp
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/how2java?characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=admin
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.properties.hibernate.hbm2ddl.auto=update
 
###########################redis#########################
#Redis数据库索引(默认为0)
spring.redis.database=0
#Redis服务器地址
spring.redis.host=127.0.0.1
#Redis服务器连接端口
spring.redis.port=6379
#Redis服务器连接密码(默认为空)
spring.redis.password=
#连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=10
#连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
#连接池中的最大空闲连接
spring.redis.pool.max-idle=8
#连接池中的最小空闲连接
spring.redis.pool.min-idle=0
#连接超时时间(毫秒)
spring.redis.timeout=0
 
spring.jpa.show-sql=true
 步骤 9 : 

Application

增加注解,以开启缓存
 
@EnableCaching
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package  com.how2java.springboot;
  
import  org.springframework.boot.SpringApplication;
import  org.springframework.boot.autoconfigure.SpringBootApplication;
import  org.springframework.cache.annotation.EnableCaching;
  
@SpringBootApplication
@EnableCaching
public  class  Application {
  
     public  static  void  main(String[] args) {
         SpringApplication.run(Application. class , args);
     }
  
}
 步骤 10 : 

RedisConfig.java

Redis 缓存配置类。
这个配置,一个作用: 让保存到 Redis 里的 key 和 value 都转换为可读的 json 格式。 否则会是二进制格式,通过 RedisClient 工具也无法识别。
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package  com.how2java.springboot.config;
import  org.springframework.cache.CacheManager;
import  org.springframework.cache.annotation.CachingConfigurerSupport;
import  org.springframework.cache.annotation.EnableCaching;
import  org.springframework.context.annotation.Bean;
import  org.springframework.context.annotation.Configuration;
import  org.springframework.data.redis.cache.RedisCacheManager;
import  org.springframework.data.redis.core.RedisTemplate;
import  org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import  org.springframework.data.redis.serializer.RedisSerializer;
import  org.springframework.data.redis.serializer.StringRedisSerializer;
 
import  com.fasterxml.jackson.annotation.JsonAutoDetect;
import  com.fasterxml.jackson.annotation.PropertyAccessor;
import  com.fasterxml.jackson.databind.ObjectMapper;
 
@Configuration
@EnableCaching
//Redis 缓存配置类
public  class  RedisConfig  extends  CachingConfigurerSupport {
 
     @Bean
     public  CacheManager cacheManager(RedisTemplate<?,?> redisTemplate) {
         RedisSerializer stringSerializer =  new  StringRedisSerializer();
         Jackson2JsonRedisSerializer jackson2JsonRedisSerializer =  new  Jackson2JsonRedisSerializer(Object. class );
         ObjectMapper om =  new  ObjectMapper();
         om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.PUBLIC_ONLY);
         om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
         jackson2JsonRedisSerializer.setObjectMapper(om);
         redisTemplate.setKeySerializer(stringSerializer);
         redisTemplate.setHashKeySerializer(stringSerializer);  
         
         redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);         
         redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
         CacheManager cacheManager =  new  RedisCacheManager(redisTemplate);
         return  cacheManager;
  
     }
}
 步骤 11 : 

Page4Navigator

创建一个工具类 Page4Navigator 用以替换 原本分页查询要返回的 org.springframework.data.domain.Page 类。 原因是 Page 类对json 还原不支持,在放如 Redis 之后,再拿出来,就会报错失败。
使用 Page4Navigator 对其包裹,就解决了这个问题了。
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
package  com.how2java.springboot.util;
 
import  java.util.List;
 
import  org.springframework.data.domain.Page;
 
public  class  Page4Navigator<T> {
     Page<T> page4jpa;
     int  navigatePages;
     
     int  totalPages;
 
     int  number;
     
     long  totalElements;
     
     int  size;
 
     int  numberOfElements;
 
     List<T> content;
 
     boolean  isHasContent;
 
     boolean  first;
 
     boolean  last;
     
     boolean  isHasNext;
 
     boolean  isHasPrevious;
     
     int [] navigatepageNums;
     
     public  Page4Navigator() {
         //这个空的分页是为了 Redis 从 json格式转换为 Page4Navigator 对象而专门提供的
     }
     
     public  Page4Navigator(Page<T> page4jpa, int  navigatePages) {
         this .page4jpa = page4jpa;
         this .navigatePages = navigatePages;
         
         totalPages = page4jpa.getTotalPages();
         
         number  = page4jpa.getNumber() ;
         
         totalElements = page4jpa.getTotalElements();
         
         size = page4jpa.getSize();
         
         numberOfElements = page4jpa.getNumberOfElements();
         
         content = page4jpa.getContent();
         
         isHasContent = page4jpa.hasContent();
                 
         first = page4jpa.isFirst();
         
         last = page4jpa.isLast();
         
         isHasNext = page4jpa.hasNext();
         
         isHasPrevious  = page4jpa.hasPrevious();       
         
         calcNavigatepageNums();
         
     }
 
     private  void  calcNavigatepageNums() {
         int  navigatepageNums[];
         int  totalPages = getTotalPages();
         int  num = getNumber();
         //当总页数小于或等于导航页码数时
         if  (totalPages <= navigatePages) {
             navigatepageNums =  new  int [totalPages];
             for  ( int  i =  0 ; i < totalPages; i++) {
                 navigatepageNums[i] = i +  1 ;
             }
         else  //当总页数大于导航页码数时
             navigatepageNums =  new  int [navigatePages];
             int  startNum = num - navigatePages /  2 ;
             int  endNum = num + navigatePages /  2 ;
 
             if  (startNum <  1 ) {
                 startNum =  1 ;
                 //(最前navigatePages页
                 for  ( int  i =  0 ; i < navigatePages; i++) {
                     navigatepageNums[i] = startNum++;
                 }
             else  if  (endNum > totalPages) {
                 endNum = totalPages;
                 //最后navigatePages页
                 for  ( int  i = navigatePages -  1 ; i >=  0 ; i--) {
                     navigatepageNums[i] = endNum--;
                 }
             else  {
                 //所有中间页
                 for  ( int  i =  0 ; i < navigatePages; i++) {
                     navigatepageNums[i] = startNum++;
                 }
             }
         }  
         this .navigatepageNums = navigatepageNums;
     }
 
     public  int  getNavigatePages() {
         return  navigatePages;
     }
 
     public  void  setNavigatePages( int  navigatePages) {
         this .navigatePages = navigatePages;
     }
 
     public  int  getTotalPages() {
         return  totalPages;
     }
 
     public  void  setTotalPages( int  totalPages) {
         this .totalPages = totalPages;
     }
 
     public  int  getNumber() {
         return  number;
     }
 
     public  void  setNumber( int  number) {
         this .number = number;
     }
 
     public  long  getTotalElements() {
         return  totalElements;
     }
 
     public  void  setTotalElements( long  totalElements) {
         this .totalElements = totalElements;
     }
 
     public  int  getSize() {
         return  size;
     }
 
     public  void  setSize( int  size) {
         this .size = size;
     }
 
     public  int  getNumberOfElements() {
         return  numberOfElements;
     }
 
     public  void  setNumberOfElements( int  numberOfElements) {
         this .numberOfElements = numberOfElements;
     }
 
     public  List<T> getContent() {
         return  content;
     }
 
     public  void  setContent(List<T> content) {
         this .content = content;
     }
 
     public  boolean  isHasContent() {
         return  isHasContent;
     }
 
     public  void  setHasContent( boolean  isHasContent) {
         this .isHasContent = isHasContent;
     }
 
     public  boolean  isFirst() {
         return  first;
     }
 
     public  void  setFirst( boolean  first) {
         this .first = first;
     }
 
     public  boolean  isLast() {
         return  last;
     }
 
     public  void  setLast( boolean  last) {
         this .last = last;
     }
 
     public  boolean  isHasNext() {
         return  isHasNext;
     }
 
     public  void  setHasNext( boolean  isHasNext) {
         this .isHasNext = isHasNext;
     }
 
     public  boolean  isHasPrevious() {
         return  isHasPrevious;
     }
 
     public  void  setHasPrevious( boolean  isHasPrevious) {
         this .isHasPrevious = isHasPrevious;
     }
 
     public  int [] getNavigatepageNums() {
         return  navigatepageNums;
     }
 
     public  void  setNavigatepageNums( int [] navigatepageNums) {
         this .navigatepageNums = navigatepageNums;
     }
 
}
 步骤 12 : 

CategoryService

增加 Service接口。 注意: list 返回的是 Page4Navigator 而不是 Page 类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package  com.how2java.springboot.service;
 
import  org.springframework.data.domain.Pageable;
 
import  com.how2java.springboot.pojo.Category;
import  com.how2java.springboot.util.Page4Navigator;
 
public  interface  CategoryService {
 
     public  Page4Navigator<Category> list(Pageable pageable);
     
     public  void  save(Category category);
     
     public  void  delete( int  id);
     
     public  Category get( int  id);
}
 步骤 13 : 

CategoryServiceImpl

实现类CategoryServiceImp 做了一下工作:
1. 实现 CategoryService 接口,提供 crud

2. 在相应方法实现的时候,都是通过调用 dao 实现的

3. CacheConfig,表示 分类数据在 redis 中都放在 category 这个分组里。
 
@CacheConfig(cacheNames="category")
 


4. list方法讲解:
先说注解
 
@Cacheable(key="'category '+#p0.offset + '-' + #p0.pageSize ")
 

假如是第一页,即offset=0,pageSize=0,那么会创建一个 key: "category 0-5"
首先根据这个key 到 redis中查询数据。 第一次是不会有数据的,那么就会从数据库中取到这5条数据,然后以这个 key: "category 0-5" 保存到 redis 数据库中。
下一次再次访问的时候,根据这个key,就可以从 redis 里取到数据了。

5. get 方法讲解
先说注解:
 
@Cacheable(key="'category '+ #p0")
 

假如是获取id=71的数据,那么
就会以 key= "category 71" 到reids中去获取,如果没有就会从数据库中拿到,然后再以 key= "category 71" 这个值存放到 redis 当中。
下一次再次访问的时候,根据这个key,就可以从 redis 里取到数据了。

6. add 方法讲解
先说注解:
 
@CacheEvict(allEntries=true)
// @CachePut(key="'category '+ #p0")
 

可以看到,本来有个 CachePut,但是被注释掉了。 按理说,本来是应该用这个的。 这样会到在,在增加数据之后,就会在Redis 中以 key= "category 71" 缓存一条数据。 但是为什么被注释掉不用呢? 
因为加入这样做了,那么 list 对应的数据,在缓存在对应的数据,并没有发生变化呀? 因为 list 对应的数据是这样的 key: "category 0-5"。 如果用这种方式,就会导致数据不同步,即,虽然增加了,并且也增加到缓存中了,但是因为 key 不一样,通过查询拿到的数据,是不会包含新的这一条的。 
所以,才会使用CacheEvict 这个注解,这个注解就表示清除掉缓存。 allEntries= true 是表示清除掉 category 分组 下所有的keys. 注意看截图,里面有一个 category~keys ,里面就表明了都有哪些 keys,都会被清除掉。 
假如这个时候,还有一个分组 cacheNames="product", 那么它下面对应的缓存,都是不会被影响到的。 这样就保证了,只清楚当前分组下的缓存,而不是清除 redis 所有的数据了。

7. delete 方法讲解
先说注解:
 
@CacheEvict(allEntries=true)
// @CacheEvict(key="'category '+ #p0")
 

这个道理和 add 是一样的,仅仅删除 key= "category 71" ,没有什么意义, key: "category 0-5" 里面的数据没有影响呀。 所以还是通过 CacheEvict删除掉所有的缓存就好了。
CategoryServiceImpl
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package  com.how2java.springboot.service.impl;
 
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springframework.cache.annotation.CacheConfig;
import  org.springframework.cache.annotation.CacheEvict;
import  org.springframework.cache.annotation.CachePut;
import  org.springframework.cache.annotation.Cacheable;
import  org.springframework.data.domain.Page;
import  org.springframework.data.domain.Pageable;
import  org.springframework.stereotype.Service;
 
import  com.how2java.springboot.dao.CategoryDAO;
import  com.how2java.springboot.pojo.Category;
import  com.how2java.springboot.service.CategoryService;
import  com.how2java.springboot.util.Page4Navigator;
 
@Service
@CacheConfig (cacheNames= "category" )
public  class  CategoryServiceImpl  implements  CategoryService{
 
     @Autowired  CategoryDAO categoryDAO;
     
     @Override
     @Cacheable (key= "'category '+#p0.offset + '-' + #p0.pageSize " )
     public  Page4Navigator<Category> list(Pageable pageable) {
         Page<Category> pageFromJPA=  categoryDAO.findAll(pageable);
         Page4Navigator<Category> page =  new  Page4Navigator<>(pageFromJPA, 5 );
         return  page;
     }
 
     @Override
     @Cacheable (key= "'category '+ #p0" )
     public  Category get( int  id) {
         Category c =categoryDAO.findOne(id);
         return  c;
     }  
     
     @Override
     @CacheEvict (allEntries= true )
//  @CachePut(key="'category '+ #p0")
     public  void  save(Category category) {
         // TODO Auto-generated method stub
         categoryDAO.save(category);
     }
     
     @Override
     @CacheEvict (allEntries= true )
//  @CacheEvict(key="'category '+ #p0")
     public  void  delete( int  id) {
         // TODO Auto-generated method stub
         categoryDAO.delete(id);
     }
 
}
 步骤 14 : 

CategoryController

 
由原来直接从 dao 获取,变为从 Service 获取了
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package  com.how2java.springboot.web;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springframework.data.domain.PageRequest;
import  org.springframework.data.domain.Pageable;
import  org.springframework.data.domain.Sort;
import  org.springframework.stereotype.Controller;
import  org.springframework.ui.Model;
import  org.springframework.web.bind.annotation.RequestMapping;
import  org.springframework.web.bind.annotation.RequestParam;
 
import  com.how2java.springboot.pojo.Category;
import  com.how2java.springboot.service.CategoryService;
import  com.how2java.springboot.util.Page4Navigator;
  
@Controller
public  class  CategoryController {
     @Autowired  CategoryService categoryService;
     
     @RequestMapping ( "/listCategory" )
     
     public  String listCategory(Model m, @RequestParam (value =  "start" , defaultValue =  "0" int start, @RequestParam (value =  "size" , defaultValue =  "5" int  size)  throws  Exception {
         start = start< 0 ? 0 :start;
         Sort sort =  new  Sort(Sort.Direction.DESC,  "id" );
         Pageable pageable =  new  PageRequest(start, size, sort);
         Page4Navigator<Category> page =categoryService.list(pageable);
         m.addAttribute( "page" , page);
         return  "listCategory" ;
     }
 
     @RequestMapping ( "/addCategory" )
     public  String addCategory(Category c)  throws  Exception {
         categoryService.save(c);
         return  "redirect:listCategory" ;
     }
     @RequestMapping ( "/deleteCategory" )
     public  String deleteCategory(Category c)  throws  Exception {
         categoryService.delete(c.getId());
         return  "redirect:listCategory" ;
     }
     @RequestMapping ( "/updateCategory" )
     public  String updateCategory(Category c)  throws  Exception {
         categoryService.save(c);
         return  "redirect:listCategory" ;
     }
     @RequestMapping ( "/editCategory" )
     public  String ediitCategory( int  id,Model m)  throws  Exception {
         Category c= categoryService.get(id);
         m.addAttribute( "c" , c);
         return  "editCategory" ;
     }
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM