背景:项目从头开始,需结合Springboot和Redis

需求:用注解管理缓存

方法:

      一、用Redis取代Springboot原有缓存

      1、pom引入依赖   

        

        2、application.yml配置

        

      3、启动类开启注解

        

        4、RedisConfig配置

        

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.*;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.cache.RedisCacheManager; import javax.annotation.Resource; @Configuration
public class RedisConfig extends CachingConfigurerSupport { @Resource
private RedisConnectionFactory factory; /**
* 自定义生成redis-key
*
* @return
*/
@Override
@Bean
public KeyGenerator keyGenerator() {
return (o, method, objects) -> {
StringBuilder sb = new StringBuilder();
sb.append(o.getClass().getName()).append(".");
sb.replace(0,21,"");
sb.append(method.getName()).append(".");
for (Object obj : objects) {
if (null!=obj){
sb.append(obj.toString());
}
}
System.out.println("keyGenerator=" + sb.toString());
return sb.toString();
};
} /*
* 要启用spring缓存支持,需创建一个 CacheManager的 bean,CacheManager 接口有很多实现,这里Redis 的集成,用
* RedisCacheManager这个实现类 Redis 不是应用的共享内存,它只是一个内存服务器,就像 MySql 似的,
* 我们需要将应用连接到它并使用某种“语言”进行交互,因此我们还需要一个连接工厂以及一个 Spring 和 Redis 对话要用的
* RedisTemplate, 这些都是 Redis 缓存所必需的配置,把它们都放在自定义的 CachingConfigurerSupport 中
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheManager rm = RedisCacheManager.create(connectionFactory);
/*rm.setDefaultExpiration(30L);// 设置缓存时间*/
return rm;
} /*@Bean
@Override
public CacheResolver cacheResolver() {
return new SimpleCacheResolver(cacheManager());
}*/ @Bean
@Override
public CacheErrorHandler errorHandler() {
// 用于捕获从Cache中进行CRUD时的异常的回调处理器。
return new SimpleCacheErrorHandler();
} // 1.项目启动时此方法先被注册成bean被spring管理,如果没有这个bean,则redis可视化工具中的中文内容(key或者value)都会以二进制存储,不易检查。
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}

     二、用注解管理缓存(注意实体类序列化)

package com.hztech.framework.dict.ctl;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.hztech.framework.cache.DictCache;
import com.hztech.framework.core.BaseController;
import com.hztech.framework.dict.entity.Dict;
import com.hztech.framework.dict.entity.DictItem;
import com.hztech.framework.dict.service.DictItemService;
import com.hztech.framework.dict.service.DictService;
import com.hztech.framework.dict.vo.ItemListResp;
import com.hztech.framework.dict.vo.ItemResp;
import com.hztech.framework.util.CommonConst;
import com.hztech.framework.util.RedisUtil;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*; import javax.validation.Valid;
import java.util.ArrayList;
import java.util.List;
import java.util.Set; /**
* 字典及字典项管理接口
*/
@RestController
@RequestMapping(path = "接口路径")
@Api(tags = "字典及字典项管理")
public class DictItemCtl extends BaseController { public DictItemCtl() {
setLog(DictItemCtl.class); cols.put("code", "c_code");
cols.put("name", "c_name");
cols.put("seq","n_seq");
} @Autowired
private DictService dictService; @Autowired
private DictItemService itemService; @Autowired
private RedisUtil redisUtil; @ApiOperation("添加字典")
@ApiImplicitParam(name = "dict",value = "字典",dataType = "Dict",paramType = "body",required = true)
@PostMapping(name = "添加字典")
@Transactional
@Caching(evict = {@CacheEvict(value = "dict:list",allEntries = true)},put = {@CachePut(value = "dict",key = "#result")} )
public String add(@RequestBody @Valid Dict dict) { log.info("添加字典【{}】", dict.getName());
dictService.insert(dict);
/*if (!redisUtil.set("dict:"+dict.getCode(),dict)){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}*/
return dict.getId();
} @ApiOperation("删除字典")
@ApiImplicitParam(name = "id",value = "字典id",dataType = "String",paramType = "path",required = true)
@DeleteMapping(path = "{id}", name = "删除字典")
@Transactional
@Caching(
evict = {@CacheEvict(value = "dict",key = "#id"),@CacheEvict(value = "dict:list",allEntries = true)}
)
public void delete(@PathVariable(name = "id") String id) { Dict dict = dictService.selectById(id);
if (dict == null) {
return;
}
log.info("删除字典【{}】", dict.getName());
dictService.deleteById(id); EntityWrapper<DictItem> ew = new EntityWrapper<>();
ew.eq("c_dict_id", id);
//需要同时删除下面包含的字典项
itemService.delete(ew); /*//采用事件通知方式更新缓存
redisUtil.delete("dict:"+dict.getCode());
redisUtil.deleteStart("item:"+dict.getId()+"#");*/
} @ApiOperation("更新字典")
@ApiImplicitParams({
@ApiImplicitParam(name = "id",value = "字典id",dataType = "String",paramType = "path",required = true),
@ApiImplicitParam(name = "dict",value = "字典",dataType = "Dict",paramType = "body",required = true)
})
@Transactional
@PutMapping(path = "{id}", name = "更新字典")
@CachePut(value = "dict",key = "#id")
@Caching(
evict = {@CacheEvict(value = "dict:list",allEntries = true)},
put = {@CachePut(value = "dict",key = "#id")}
)
public void update(@PathVariable String id, @RequestBody @Valid Dict dict) { Dict old = dictService.selectById(id);
if (old == null) {
return;
}
log.info("更新字典【{}】", old.getName());
dictService.updateById(dict); /*//采用事件通知方式更新缓存
if(!redisUtil.set("dict:"+dict.getCode(),dict)){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}*/ } @ApiOperation("查询字典列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "pageNo",value = "当前页(默认第一页)",dataType = "Integer",paramType = "header",required = true),
@ApiImplicitParam(name = "pageSize",value = "每页显示条数(默认15条)",dataType = "Integer",paramType = "header",required = true),
@ApiImplicitParam(name = "codeOrName",value = "编号或者名称",dataType = "String",paramType = "query"),
@ApiImplicitParam(name = "sort",value = "排序方式",dataType = "String",paramType = "query"),
@ApiImplicitParam(name = "asc",value = "升序(默认升序)",dataType = "boolean",paramType = "query"),
})
@GetMapping(name = "查询字典列表")
@Cacheable(value = "dict:list")
public List<Dict> query(@RequestHeader(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestHeader(name = "pageSize", defaultValue = "15") Integer pageSize,
@RequestParam(name = "codeOrName", required = false) String codeOrName,
@RequestParam(name = "sort", defaultValue = "code", required = false) String sort,
@RequestParam(name = "asc", defaultValue = "true", required = false) boolean asc) { log.info("查询字典列表"); EntityWrapper<Dict> ew = new EntityWrapper<>();
if (!StringUtils.isEmpty(codeOrName)) {
ew.like("c_code", codeOrName);
ew.or();
ew.like("c_name", codeOrName);
}
ew.orderBy(cols.get(sort), asc); Page<Dict> page = new Page<>(pageNo, pageSize);
page = dictService.selectPage(page, ew); log.info("总数:{}", page.getTotal());
response.setIntHeader(CommonConst.RECORD_TOTAL, (int) page.getTotal());
return page.getRecords();
} @ApiOperation("添加字典项")
@ApiImplicitParam(name = "item",value = "字典项",dataType = "DictItem",paramType = "body",required = true)
@PostMapping(path = "items", name = "添加字典项")
@Transactional
@Caching(
evict = {@CacheEvict(value = "item:list",allEntries = true)},
put = {@CachePut(value = "item",key = "#result")}
)
public String addItem(@RequestBody @Valid DictItem item) { itemService.insert(item); //采用事件通知方式更新缓存
/*if(!redisUtil.set("item:"+item.getDictId()+"#"+item.getCode(),item)){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}*/ return item.getId();
} @ApiOperation("删除字典项")
@ApiImplicitParam(name = "itemId",value = "删除字典项",dataType = "String",paramType = "path",required = true)
@DeleteMapping(path = "items/{itemId}", name = "删除字典项")
@Transactional
@Caching(
evict = {@CacheEvict(value = "item",key = "#itemId"),@CacheEvict(value = "item:list",allEntries = true)}
)
public void deleteItem(@PathVariable(name = "itemId") String itemId) { DictItem dictItem=itemService.selectById(itemId);
itemService.deleteById(itemId); //采用事件通知方式更新缓存
/*redisUtil.delete("item:"+dictItem.getDictId()+"#"+dictItem.getCode());*/ } @ApiOperation("更新字典项")
@ApiImplicitParams({
@ApiImplicitParam(name = "id",value = "字典项id",dataType = "String",paramType = "path",required = true),
@ApiImplicitParam(name = "item",value = "字典项",dataType = "DictItem",paramType = "body",required = true)
})
@PutMapping(path = "items/{id}", name = "更新字典项")
@Transactional
@Caching(
evict = {@CacheEvict(value = "item:list",allEntries = true)},
put = {@CachePut(value = "item",key = "#id")}
)
public String updateItem(@PathVariable(name = "id") String id,@RequestBody @Valid DictItem item) { item.setId(id); DictItem dictItem=itemService.selectById(id);
itemService.updateById(item); //采用事件通知方式更新缓存 /*if(!redisUtil.set("item:"+dictItem.getDictId()+"#"+dictItem.getCode(),item)){
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}*/ return item.getId();
} @ApiOperation("查询字典项")
@ApiImplicitParams({
@ApiImplicitParam(name = "pageNo",value = "当前页(默认第一页)",dataType = "Integer",paramType = "header",required = true),
@ApiImplicitParam(name = "pageSize",value = "每页显示条数(默认15条)",dataType = "Integer",paramType = "header",required = true),
@ApiImplicitParam(name = "dictId",value = "字典项id",dataType = "String",paramType = "query",required = true),
@ApiImplicitParam(name = "codeOrName",value = "编号或名称",dataType = "String",paramType = "query"),
@ApiImplicitParam(name = "sort",value = "排序方式(默认seq)",dataType = "String",paramType = "query"),
@ApiImplicitParam(name = "asc",value = "(默认升序)",dataType = "boolean",paramType = "query") })
@GetMapping(path = "items", name = "查询字典项")
@Cacheable(value = "item:list")
public List<DictItem> queryItem(@RequestHeader(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestHeader(name = "pageSize", defaultValue = "15") Integer pageSize,
@RequestParam(name = "dictId") String dictId,
@RequestParam(name = "codeOrName", required = false) String codeOrName,
@RequestParam(name = "sort", defaultValue = "seq", required = false) String sort,
@RequestParam(name = "asc", defaultValue = "true", required = false) boolean asc) { log.info("查询字典项列表"); EntityWrapper<DictItem> ew = new EntityWrapper<>(); ew.eq("c_dict_id",dictId); if (!StringUtils.isEmpty(codeOrName)) {
ew.like("c_code", codeOrName);
ew.or();
ew.like("c_name", codeOrName);
}
ew.orderBy(cols.get(sort), asc); Page<DictItem> page = new Page<>(pageNo, pageSize);
page = itemService.selectPage(page, ew); log.info("总数:{}", page.getTotal());
response.setIntHeader(CommonConst.RECORD_TOTAL, (int) page.getTotal());
return page.getRecords(); } /**
* 此方法用于页面填充字典项,其内容从缓存中提取。
*
* @param dictCode
* @return
*/
@ApiOperation("下拉列表获取字典项")
@ApiImplicitParam(name = "dictCode",value = "字典项名称",dataType = "String",paramType = "path",required = true)
@GetMapping(path = "common/items/{dictCode}",name = "下拉列表获取字典项")
@Cacheable(value = "item:list")
public ItemListResp getDictItems(@PathVariable String dictCode){ ItemListResp resp=new ItemListResp(); //List<DictItem> items=DictCache.getItems(dictCode); Set<String> set = redisUtil.keysStart("item:"+((Dict)redisUtil.get("dict:"+dictCode)).getId()+"#"); if(set.isEmpty()){
return resp;
} for (String k:set){
DictItem item = (DictItem) redisUtil.get(k); ItemResp ir=new ItemResp();
ir.setCode(item.getCode());
ir.setName(item.getName()); resp.getItems().add(ir); if (item.getSelected() == 1 &&
StringUtils.isEmpty(resp.getDefaultValue())) {
// 设置默认选中项
resp.setDefaultValue(item.getCode());
}
} /*for(DictItem item : items){ ItemResp ir=new ItemResp();
ir.setCode(item.getCode());
ir.setName(item.getName()); resp.getItems().add(ir); if (item.getSelected() == 1 &&
StringUtils.isEmpty(resp.getDefaultValue())) {
// 设置默认选中项
resp.setDefaultValue(item.getCode());
}
}*/ return resp;
} }

Spingboot整合Redis,用注解(@Cacheable、@CacheEvict、@CachePut、@Caching)管理缓存的更多相关文章

  1. spring整合redis缓存,以注解(@Cacheable、@CachePut、@CacheEvict)形式使用

    maven项目中在pom.xml中依赖2个jar包,其他的spring的jar包省略: <dependency> <groupId>redis.clients</grou ...

  2. 八、springboot整合redis

    整合Redis 一. 注解方式实现添加缓存 1.在pom.xml加入依赖 <!-- 配置使用redis启动器 --> <dependency> <groupId>o ...

  3. 002-spring cache 基于声明式注解的缓存-02-CachePut、CacheEvict、Caching、CacheConfig、EnableCaching、自定义

    1.2.CachePut annotation 在支持Spring Cache的环境下,对于使用@Cacheable标注的方法,Spring在每次执行前都会检查Cache中是否存在相同key的缓存元素 ...

  4. SpringBoot进阶教程(二十五)整合Redis之@Cacheable、@CachePut、@CacheEvict的应用

    在上一篇文章(<SpringBoot(二十四)整合Redis>)中,已经实现了Spring Boot对Redis的整合,既然已经讲到Cache了,今天就介绍介绍缓存注解.各家互联网产品现在 ...

  5. Spring-Cache 注解 @Cacheable,@CachePut , @CacheEvict

    1.自动生成key @Bean public KeyGenerator keyGenerator() { return new KeyGenerator() { @Override public Ob ...

  6. Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用(转)

    原文地址:https://www.cnblogs.com/fashflying/p/6908028.html 从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对 ...

  7. Spring缓存注解@Cacheable、@CacheEvict、@CachePut使用

    从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...

  8. 详解Spring缓存注解@Cacheable,@CachePut , @CacheEvict使用

    https://blog.csdn.net/u012240455/article/details/80844361 注释介绍 @Cacheable @Cacheable 的作用 主要针对方法配置,能够 ...

  9. 缓存注解@Cacheable、@CacheEvict、@CachePut使用及注解失效时间

    从3.1开始,Spring引入了对Cache的支持.其使用方法和原理都类似于Spring对事务管理的支持.Spring Cache是作用在方法上的,其核心思想是这样的:当我们在调用一个缓存方法时会把该 ...

随机推荐

  1. shell cp拷贝的用法

    个人觉得这个记录的比较全 自己查阅: cp [options] <source file or directory> <target file or directory> 或 ...

  2. VMware Workstation Pro 无法在Windows 上运行 检查可在Windows上运行的此应用的更新版

    1.问题描述 2.排查原因 国庆节后微软推送了一个新的更新补丁,更新之后发现VMware无法打开(未更新前正常). 3.解决方案 3.1卸载微软更新补丁 Windows 10的安全更新难以被彻底规避, ...

  3. mybatis关联查询之一对一查询

    一对一也就是 A 表的一条记录对应 B 表的一条记录,下面的测试数据中,从employee 表来看,一个员工对应一个部门,是一对一关系,如果从部门角度来看,则是一对多的关系,一个部门对应多个员工,本节 ...

  4. mysqldump 多实例备份

    通过/var/lib/mysql/mysql4406.sock   登录到某一个实例,备份 mysqldump -uroot -p --all-databases --add-drop-databas ...

  5. docker--linux network namespace

    docker container的namespace使用 的是一种虚拟网络设备 veth-pair.顾名思义,veth-pair 就是一对的虚拟设备接口,和 tap/tun 设备不同的是,它都是成对出 ...

  6. box2d——1.tiles瓦片积木

    [调试渲染]   将TestCpp里Box2DTestBed的GLES-Render.h/cpp加入到项目中.声明绘制变量:GLESDebugDrawmDebugDraw. [创建世界]   // 依 ...

  7. 60.Median of Two Sorted Arrays(两个排序数组的中位数)

    Level:   Hard 题目描述: There are two sorted arrays nums1 and nums2 of size m and n respectively. Find t ...

  8. go语言从例子开始之Example23.通道缓冲

    默认通道是 无缓冲 的,这意味着只有在对应的接收(<- chan)通道准备好接收时,才允许进行发送(chan <-).可缓存通道允许在没有对应接收方的情况下,缓存限定数量的值. 不支持缓冲 ...

  9. 函数传递是如何让HTTP服务器工作的

    var http = require("http"); http.createServer(function(request, response) { response.write ...

  10. 说一说Vuex有哪几种状态和属性

    vuex的流程 页面通过mapAction异步提交事件到action.action通过commit把对应参数同步提交到mutation mutation会修改state中对应的值.最后通过getter ...