引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--处理Java8 日期类型-->
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
</dependency>
- @Cacheable : 用于查询
- @CacheEvict : allEntries 这个注解的特有属性。如果触发该注解解,会清空该类型(value) 下的所有缓存。默认为false, 若要使用需要设为true。不能与key共存。
- @CachePut:用来接收方法的返回值,并将其添加到缓存。(不常用)
属性:
- value:指明缓存的类型。
- key:用于标记某次缓存,一般通过id标记,查询条件标记。删除缓存时,通过标记去删除。
- conditon:是否缓存的判断条件,可以用来指明查询结果为null时不缓存。
- unless:与condition相反。
注意:主类上添加 @EnableCaching 注解,开启缓存
配置类
用于处理返回前端的数据,序列化和反序列化的格式
public class JacksonObjectMapper extends ObjectMapper {
@Serial
private static final long serialVersionUID = 2220067913562288238L;
public static final String DATE_TIME_FORMATTER= "yyyy-MM-dd HH:mm:ss";
public static final String TIME_FORMATTER= "HH:mm:ss";
public static final String DATE_FORMATTER= "yyyy-MM-dd";
public JacksonObjectMapper() {
this.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
this.setSerializationInclusion(JsonInclude.Include.ALWAYS);
this.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT,true);
this.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,false);
this.configure(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS,false);
this.configure(DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES,false);
this.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false);
this.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false);
SimpleModule simpleModule = new SimpleModule()
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMATTER)))
.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMATTER)))
.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(TIME_FORMATTER)))
//防止Long类型在前端精度缺失
.addSerializer(Long.class, new ToStringSerializer())
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMATTER)))
.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMATTER)))
.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(TIME_FORMATTER)));
this.registerModule(simpleModule);
}
}
配置类
扩展转换器
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setObjectMapper(new JacksonObjectMapper());
converters.add(0,converter);
}
}
配置类
利用redis进行缓存时,对数据进行序列化,解决乱码。
@EnableCaching
@Configuration
public class RedisConfig {
@Bean
public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() {
String DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
ObjectMapper objectMapper = new ObjectMapper();
// 处理Date类型
objectMapper.setDateFormat(new SimpleDateFormat(DATE_TIME_FORMAT));
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
objectMapper.registerModule(new JavaTimeModule()
// 处理LocalDateTime类型
.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT)))
.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_TIME_FORMAT))));
// 序列化java对象时,将类的信息写入redis
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
return new GenericJackson2JsonRedisSerializer(objectMapper);
}
@Bean
public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
redisTemplate.setDefaultSerializer(genericJackson2JsonRedisSerializer());
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofMinutes(30)) // 配置缓存时长
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer()));
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
接口类
注意:key的书写格式,双引号内部的是变量,再加个单引号才能表示字符串。
通过#,可以获得参数的信息。
@RestController
@RequestMapping("/wuxia")
public class UserController {
@Resource
private WuXiaService wuXiaService;
/**
* 缓存整个列表的数据
* @return
*/
@Cacheable(value = "wuxia",key = "'wuxiaList'")
@GetMapping
public Result list(){
return Result.ok(wuXiaService.list());
}
/**
* 缓存该id对应的数据到redis
* @param id
* @return
*/
@Cacheable(value = "wuxia",key = "'wuxia'+'_'+#id")
@GetMapping("/{id}")
public Result getWuxiaById(@PathVariable("id") Integer id){
return Result.ok(wuXiaService.getById(id));
}
/**
* 有数据修改时,就会删除这个分组的所有缓存,防止list出现假数据
* @param wuXia
* @return
*/
@CacheEvict(value = "wuxia",allEntries = true)
@PutMapping
public Result updateById(@RequestBody WuXia wuXia){
wuXiaService.updateById(wuXia);
return Result.ok("更新成功");
}
/**
* 有数据删除时,就会删除这个分组的所有缓存,防止list出现假数据
* @param id
* @return
*/
@CacheEvict(value = "wuxia",allEntries = true)
@DeleteMapping("/{id}")
public Result deleteById(@PathVariable("id") Integer id){
wuXiaService.removeById(id);
return Result.ok("删除成功");
}
}
测试类
- 使用RestTemplate需要注册Bean。
- 对于RestTemplate的返回类型,最好使用Object类来接收,否则会出现类转换异常。
@SpringBootTest
public class CacheAppTest {
@Resource
private WuXiaService wuXiaService;
@Test
public void testSelect(){
wuXiaService.list().forEach(System.out::println);
}
@Resource
private RedisTemplate redisTemplate;
@Test
public void testRedis(){
redisTemplate.opsForValue().set("age","23");
System.out.println(redisTemplate.opsForValue().get("age"));
}
@Resource
RestTemplate restTemplate;
@Test
public void testList(){
Object object = restTemplate.getForObject("http://localhost:8080/wuxia", Object.class);
System.out.println(object);
}
@Test
public void testSelectById(){
ResponseEntity<Object> forEntity = restTemplate.getForEntity("http://localhost:8080/wuxia/3", Object.class);
System.out.println(forEntity.getBody());
}
@Test
public void testUpdateById(){
HashMap<String, Object> map = new HashMap<>();
map.put("id",1);
map.put("name","lisi");
map.put("age",14);
map.put("inSchoolTime",LocalDate.now().plusDays(1));
restTemplate.put("http://localhost:8080/wuxia",map);
}
@Test
public void testDeleteById(){
restTemplate.delete("http://localhost:8080/wuxia/2");
}
}