jsp文件通常用common_springboot还能这样用redis
作者:xfk
https://www.cnblogs.com/xfk1999/p/11347793.html
一直想在springboot上集成帶緩存的redis,終于成功了。網(wǎng)上有1000種寫法,想找到一篇合適的還真不容易?。走下流程,加深下印象。
?環(huán)境:
springboot版本:2.1.7
orm框架:mybatis
實(shí)現(xiàn)?:
在serviceImpl層方法上加注解@Cacheable和@CachEvict。
@Cacheable把數(shù)據(jù)放進(jìn)redis,下一次需要數(shù)據(jù)直接在緩存中取;@CacheEvict使redis中的緩存失效。
關(guān)于注解的更多詳細(xì)可以參考https://www.cnblogs.com/fashflying/p/6908028.html寫得很詳細(xì)。
準(zhǔn)備工作:
pom.xml?:
org.springframework.bootspring-boot-starter-parent2.1.7.RELEASEorg.springframework.bootspring-boot-starter-weborg.springframework.bootspring-boot-starter-testtestjavax.servletjavax.servlet-apijavax.servletjstlorg.apache.tomcat.embedtomcat-embed-jasperorg.springframework.bootspring-boot-devtoolstruemysqlmysql-connector-java5.1.21org.mybatis.spring.bootmybatis-spring-boot-starter1.1.1org.mybatis.generatormybatis-generator-core1.3.7com.fasterxml.jackson.datatypejackson-datatype-jsr310org.springframework.bootspring-boot-starter-data-redisapplication.properties文件?:
#mvcspring.mvc.view.prefix=/WEB-INF/jsp/spring.mvc.view.suffix=.jsp#mysqlspring.datasource.url=jdbc:mysql://localhost:3306/common?characterEncoding=utf-8spring.datasource.username=xfkspring.datasource.password=123456spring.datasource.driver-class-name=com.mysql.jdbc.Driver#mybatismybatis.mapper-locations=classpath:/mapper/*.xmlmybatis.type-aliases-package=com.xfk.sb.pojo#redisspring.redis.database=0spring.redis.host=127.0.0.1spring.redis.port=6379spring.redis.password=spring.redis.timeout=5000書寫:
一,允許使用緩存:
?在springboot的主啟動(dòng)類上添加注解@EnableCaching
SbApplication.java
package com.xfk.sb;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cache.annotation.EnableCaching;@SpringBootApplication@EnableCachingpublic class SbApplication {public static void main(String[] args) { SpringApplication.run(SbApplication.class, args); }}?二,redis配置類:
?這里一個(gè)重要的點(diǎn)就是Serializer。RedisCache默認(rèn)使用的是JdkSerializationRedisSerializer,我們要實(shí)現(xiàn)json格式的數(shù)據(jù)在redis上的存儲(chǔ)。利用Jackson2JsonRedisSerializer或GenericJackson2JsonRedisSerializer,其優(yōu)點(diǎn)是存儲(chǔ)的長(zhǎng)度小。在這里我們用GenericJackson2JsonRedisSerializer。成功之后可以換Jackson2JsonRedisSerializer試試,看一看存儲(chǔ)的數(shù)據(jù)有什么不同。
?cacheManager方法是用作注解@Cacheable和@CacheEvict執(zhí)行service實(shí)現(xiàn)層方法緩存數(shù)據(jù)的,另外就是定義一個(gè)redisTemplate,哪個(gè)controller需要就在哪個(gè)controller中注入,靈活使用。
RedisConfig.java
package com.xfk.sb.config;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.RedisCacheConfiguration;import org.springframework.data.redis.cache.RedisCacheManager;import org.springframework.data.redis.connection.RedisConnectionFactory;import org.springframework.data.redis.core.RedisTemplate;import org.springframework.data.redis.serializer.*;import java.time.Duration;@Configuration@EnableCachingpublic class RedisConfig extends CachingConfigurerSupport {// 過(guò)期時(shí)間private Duration timeToLive = Duration.ofHours(12);@Beanpublic RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) { RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig() .entryTtl(this.timeToLive) .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(keySerializer())) .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(valueSerializer())) .disableCachingNullValues();return RedisCacheManager.builder(connectionFactory) .cacheDefaults(config) .transactionAware() .build(); } @Bean(name = "redisTemplate")public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); redisTemplate.setKeySerializer(keySerializer()); redisTemplate.setHashKeySerializer(keySerializer()); redisTemplate.setValueSerializer(valueSerializer()); redisTemplate.setHashValueSerializer(valueSerializer());return redisTemplate; }private RedisSerializer keySerializer() {return new StringRedisSerializer(); }private RedisSerializer valueSerializer() {return new GenericJackson2JsonRedisSerializer(); }}三,增刪改查Demo:
簡(jiǎn)單的pojo類,Student.java
package com.xfk.sb.pojo;public class Student {private int id;private String name;private int age;public Student() { }public int getId() {return id; }public void setId(int id) {this.id = id; }public String getName() {return name; }public void setName(String name) {this.name = name; }public int getAge() {return age; }public void setAge(int age) {this.age = age; }@Overridepublic String toString() {return "Student{" +"id=" + id +", name='" + name + '\'' +", age=" + age +'}'; }}?我使用的是mybatis的注解方式,簡(jiǎn)單的幾個(gè)增刪改查方法。
xml文件,studentMapper.xml
<?xml version="1.0" encoding="UTF-8"?>/span> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> select * from student delete from student where id = #{id} insert into student(id, name, age) values(null, #{student.name}, #{student.age}) update student set name=#{student.name}, age=#{student.age} where id = #{student.id} select * from student where id = #{id} limit 1mapper接口,StudentMapper.java
package com.xfk.sb.mapper;import com.xfk.sb.pojo.Student;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import org.springframework.stereotype.Component;import java.util.List;@Mapper@Componentpublic interface StudentMapper {List selectStudent();int deleteStudent(@Param("id")int id);int createStudent(@Param("student")Student student);int updateStudent(@Param("student")Student student);Student selectStudentByPrimaryKey(@Param("id")int id);}service層接口,StudentService.java
package com.xfk.sb.service;import com.xfk.sb.pojo.Student;import java.util.List;public interface StudentService {List selectStudent();int deleteStudent(int id);int createStudent(Student student);int updateStudent(Student student);Student selectStudentByPrimaryKey(int id);}service實(shí)現(xiàn)層,StudentServiceImpl.java
package com.xfk.sb.service.implement;import com.xfk.sb.mapper.StudentMapper;import com.xfk.sb.pojo.Student;import com.xfk.sb.service.StudentService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cache.annotation.CacheConfig;import org.springframework.cache.annotation.CacheEvict;import org.springframework.cache.annotation.Cacheable;import org.springframework.cache.annotation.Caching;import org.springframework.stereotype.Service;import java.util.List;@Service@CacheConfig(cacheNames="students")public class StudentServiceImpl implements StudentService {private final StudentMapper studentMapper;@Autowiredpublic StudentServiceImpl(StudentMapper studentMapper) {this.studentMapper = studentMapper; }@Cacheable(key="'students'")@Overridepublic List selectStudent() { System.out.println("從數(shù)據(jù)庫(kù)中取selectStudent");return studentMapper.selectStudent(); }@Override@Caching(evict={ @CacheEvict(key="'singleStudent'+#id"),@CacheEvict(key="'students'"), })public int deleteStudent(int id) { System.out.println("從數(shù)據(jù)庫(kù)中刪除deleteStudent");return studentMapper.deleteStudent(id); }@Override@Caching(evict={ @CacheEvict(key="'singleStudent'+#student.id"),@CacheEvict(key="'students'"), })public int createStudent(Student student) { System.out.println("從數(shù)據(jù)庫(kù)中創(chuàng)建createStudent");return studentMapper.createStudent(student); }@Caching(evict={ @CacheEvict(key="'singleStudent'+#student.id"),@CacheEvict(key="'students'"), })@Overridepublic int updateStudent(Student student) { System.out.println("從數(shù)據(jù)庫(kù)中更新updateStudent");return studentMapper.updateStudent(student); }@Cacheable(key="'singleStudent'+#p0")@Overridepublic Student selectStudentByPrimaryKey(int id) { System.out.println("從數(shù)據(jù)庫(kù)中取一個(gè)selectStudentByPrimaryKey");return studentMapper.selectStudentByPrimaryKey(id); }}?使用@CacheConfig注解,相當(dāng)于在redis數(shù)據(jù)庫(kù)下建一個(gè)文件夾,以cacheNames作為文件夾的名字,統(tǒng)一管理這個(gè)實(shí)現(xiàn)層緩存的數(shù)據(jù)。正如在Redis Desktop Manager下看到的目錄結(jié)構(gòu),db0下有一個(gè)students文件夾。
?使用@Cacheable注解使緩存生效,以實(shí)現(xiàn)層的selectStudentByPrimaryKey()方法為例,從數(shù)據(jù)庫(kù)中根據(jù)id查詢一個(gè)Student對(duì)象。
使用@Cacheable(key="'singleStudent'+#p0"),#p0就是形參parameter0,多個(gè)參數(shù)就是#p1,#p2,,,也可以寫成#id,注意singleStudent字符串一定要用單引號(hào)擴(kuò)上,然后使用字符串的拼接模式,這個(gè)變量的規(guī)則是spring的EL表達(dá)式,一定要用加上#符號(hào),如果是一個(gè)對(duì)象則可以直接用"."引用屬性,參考createStudent()方法中的#student.id 。
屬性key相當(dāng)于在students文件夾下的文件夾創(chuàng)建一條以singleStudent+#p0為名字的一條緩存數(shù)據(jù),在Redis Desktop Manager可以看到,由于students文件夾下的文件夾沒(méi)有名字,所以成功緩存數(shù)據(jù)的命名是students::singleStudent1,兩個(gè)引號(hào)之間為空。這就相當(dāng)以這個(gè)命名空間下的唯一key,可以根據(jù)唯一key準(zhǔn)確的失效緩存數(shù)據(jù)。
?@CacheEvict注解使緩存失效,根據(jù)需求要保證數(shù)據(jù)庫(kù)與緩存的一致性,所以操作數(shù)據(jù)庫(kù)之后要同步緩存。
在更新,刪除和增加后要使緩存失效,不能返回過(guò)時(shí)的信息。在這里使用@Caching的目的是使多條緩存失效,它集合了@Cacheable,@CacheEvict,@CachePut,可以很直觀的管理生效與失效。還可以直接使用@CacheEvict(allEntries=true)使這個(gè)命名空間下的所有緩存失效。
到這里核心工作完成得差不多了,就還差controller返回視圖層了。
controller層,StudentController.java
package com.xfk.sb.web;import com.xfk.sb.pojo.Student;import com.xfk.sb.service.StudentService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.redis.core.StringRedisTemplate;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.*;import java.util.List;@Controllerpublic class StudentController {private final StudentService studentService;private final StringRedisTemplate redis;@Autowiredpublic StudentController(StudentService studentService, StringRedisTemplate redis) {this.studentService = studentService;this.redis = redis; }@GetMapping("/students")public String listStudent(Model model){ List students = studentService.selectStudent(); model.addAttribute("students", students);return "listStudent"; }@DeleteMapping("/students/{id}")public String deleteStudent(@PathVariable("id")int id) throws Exception{ studentService.deleteStudent(id);return "redirect:/students"; }@PutMapping("/students")public String updateStudent(Student student){ studentService.updateStudent(student);return "redirect:/students"; }@PostMapping("/students")public String createStudent(Student student){ studentService.createStudent(student);return "redirect:/students"; }@GetMapping("/students/{id}")public String editStudent(@PathVariable("id")int id, Model model){ Student s = studentService.selectStudentByPrimaryKey(id); model.addAttribute("student", s);return "editStudent"; }@RequestMapping("/test")public String test(Model model){ List students = studentService.selectStudent(); model.addAttribute("students", students);return "test"; }@RequestMapping("/getOne")public String getOne(Model model){ // 獲取id為1的Student對(duì)象到test.jsp Student student = studentService.selectStudentByPrimaryKey(1); model.addAttribute("student", student);return "test"; }}?使用的restful風(fēng)格,返回的jsp頁(yè)面,/test和/getOne用來(lái)驗(yàn)證緩存是否生效。
小貼一下jsp:
listStudent.jsp
students 增加: name:?idnameage編輯刪除${each.id}${each.name}${each.age}修改刪除驗(yàn)證你的jquer是否生效 $(function(){ $(".deleteStudent").click(function(){var href = $(this).attr("value"); alert(href); $("#deleteType").attr("action", href).submit(); }) $(".hhh").click(function(){ alert("你的jquer已生效"); }) })editStudent.jsp
editStudent name: age :返回主頁(yè)test.jsp
test${each.id}, ${each.name}, ${each.age}得到一個(gè)Student${student.id}, ${student.name}, ${student.age}?
四,驗(yàn)證測(cè)試:
?步驟:
1,/getOne
由于StudentServiceImpl.java中的System.out.println("從數(shù)據(jù)庫(kù)中取一個(gè)selectStudentByPrimaryKey");?查看后臺(tái)控制臺(tái),可以知道這條數(shù)據(jù)是從數(shù)據(jù)庫(kù)中獲取的。
/getOne獲取的Student的id為1,所以會(huì)在Redis Desktop Manager中看到一條singleStudent1的緩存記錄。
http://localhost:8080/getOne
2,更改Redis Desktop Manager中的記錄
?比如redis庫(kù)中原來(lái)的數(shù)據(jù)是
?更改數(shù)據(jù),因?yàn)檫@里改的數(shù)據(jù)是redis的,mysql里的數(shù)據(jù)還是沒(méi)變,這樣就知道了是從緩存中讀取的數(shù)據(jù)
?點(diǎn)擊save之后,刷新http://localhost:8080/getOne
?成功!????? 然后@CacheEvict是一樣的邏輯,指定失效的key就好了
在看不好意思,那就點(diǎn)個(gè)贊吧
總結(jié)
以上是生活随笔為你收集整理的jsp文件通常用common_springboot还能这样用redis的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: ORACLE 树形遍历查询根节点、父节点
- 下一篇: 关于梦想--------听说标题够长才有