zoukankan      html  css  js  c++  java
  • Spingboot整合Redis,用注解(@Cacheable、@CacheEvict、@CachePut、@Caching)管理缓存

    背景:项目从头开始,需结合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;
        }
    
    }

      

  • 相关阅读:
    .NET的SqlHelper应用代码
    .NET获取客户端的操作系统、IP地址、浏览器版本
    Codevs 3981 动态最大子段和
    洛谷 P3373 【模板】线段树 2
    一些笔记【杂】
    洛谷 P1432 倒水问题
    洛谷 P2324 [SCOI2005]骑士精神
    Codevs 1010 过河卒
    POJ 3278 Catch That Cow
    洛谷P2184 贪婪大陆
  • 原文地址:https://www.cnblogs.com/java-bhp/p/11778269.html
Copyright © 2011-2022 走看看