• SpringBoot AOP控制Redis自动缓存和更新


    导入redis的jar包

    
    <!-- redis -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
                <version>2.0.4.RELEASE</version>
            </dependency>
    
    

    编写自定义缓存注解

    
    /**
     * @Description: redis缓存注解 编写在需要缓存的类上
     **/
    @Documented
    @Target(ElementType.TYPE)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface RedisCache {
    }
    
    

    编写切面类

    
    package com.ys.edu.aop;
    
    import com.ys.edu.utils.ResultUtils;
    import org.apache.log4j.Logger;
    import org.aspectj.lang.ProceedingJoinPoint;
    import org.aspectj.lang.annotation.Around;
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.Pointcut;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.data.redis.core.ValueOperations;
    import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
    import org.springframework.data.redis.serializer.RedisSerializer;
    import org.springframework.data.redis.serializer.StringRedisSerializer;
    import org.springframework.stereotype.Service;
    import org.aspectj.lang.reflect.MethodSignature;
    import javax.annotation.Resource;
    import java.util.Arrays;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    
    /**
     * @ClassName RedisAOP
     * @description: redis 切面缓存
     **/
    @Aspect
    @Service
    public class RedisAOP {
    
        private static final Logger logger = Logger.getLogger(RedisAOP.class);
    
        private static final Integer TIME_OUT = 30 ; //redis 存活时长  分钟
    
        @Resource
        private RedisTemplate redisTemplate;
    
        /**
         * @Title: queryCachePointcut
         * @Description: 定义切点为缓存注解
         * @return void
         **/
        @Pointcut("@within(com.ys.edu.annotation.RedisCache)")
        public void queryCachePointcut(){
    
        }
    
        @Around("queryCachePointcut()")
        public Object Interceptor(ProceedingJoinPoint joinPoint) throws Throwable{
            long beginTime = System.currentTimeMillis();
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            //类路径名
            String classPathName = joinPoint.getTarget().getClass().getName();
            //类名
            String className = classPathName.substring(classPathName.lastIndexOf(".")+1,classPathName.length());
            //获取方法名
            String methodName = signature.getMethod().getName();
            String[] strings = signature.getParameterNames();
            String key = className+"_"+methodName+"_"+Arrays.toString(strings);
            if((methodName.indexOf("select") != -1 && methodName.substring(0,6).equalsIgnoreCase("select")) || (methodName.indexOf("query") != -1 && methodName.substring(0,5).equalsIgnoreCase("query")) || (methodName.indexOf("get") != -1 && methodName.substring(0,3).equalsIgnoreCase("get"))){
                Object data = getObject(beginTime,joinPoint,key);
                if(data != null){
                    return ResultUtils.success(data);
                }
                return joinPoint.proceed();
            }else if((methodName.indexOf("add") != -1 && methodName.substring(0,3).equalsIgnoreCase("add")) || (methodName.indexOf("insert") != -1 && methodName.substring(0,6).equalsIgnoreCase("insert")) || (methodName.indexOf("update") != -1 && methodName.substring(0,6).equalsIgnoreCase("update"))){
                Set<String> keys = redisTemplate.keys(className+"*");
                redisTemplate.delete(keys);
                logger.warn("执行方法 : [ "+methodName+" ] :  清除 key 包含 [ "+className+" ] 的缓存数据");
                logger.warn("AOP 缓存切面处理 >>>> end 耗时:" + (System.currentTimeMillis() - beginTime));
            }
            // 调用原始方法
            return joinPoint.proceed();
        }
    
    
        /**
         * @Title: getObject
         * @Description: 使用key获取数据  不存在则查询添加
         * @param beginTime : 切面开始时间
         * @param joinPoint : 切面对象
         * @param key : 获取redis数据的key值
         * @return java.lang.Object
         **/
        private Object getObject(long beginTime,ProceedingJoinPoint joinPoint,String key) throws Throwable {
            ValueOperations<String, Object> operations = redisTemplate.opsForValue();
            boolean hasKey = redisTemplate.hasKey(key);
            Object object = null;
            if(hasKey){
                // 缓存中获取到数据,直接返回。
                object = operations.get(key);
                logger.warn("从缓存中获取到 key 为 ["+key+" ] : 的数据 >>>> " + object.toString());
                logger.warn("AOP 缓存切面处理 >>>> end 耗时:" + (System.currentTimeMillis() - beginTime));
                return object;
            }
            if(object == null) {
                // 缓存中没有数据,调用原始方法查询数据库
                object = joinPoint.proceed();
                operations.set(key, object, TIME_OUT, TimeUnit.MINUTES); // 设置超时时间30分钟
                logger.warn("向 Redis 添加 key 为 ["+key+" ] , 存活时长为 "+TIME_OUT+" min 的数据 >>>> " + object.toString());
                logger.warn("AOP 缓存切面处理 >>>> end 耗时:" + (System.currentTimeMillis() - beginTime));
            }
            return object;
        }
    
    
        @Autowired(required = false)
        public void setRedisTemplate(RedisTemplate redisTemplate) {
            RedisSerializer stringSerializer = new StringRedisSerializer();//序列化为String
            Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);//序列化为Json
            redisTemplate.setKeySerializer(stringSerializer);
            redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
            redisTemplate.setHashKeySerializer(stringSerializer);
            redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
            this.redisTemplate = redisTemplate;
        }
    
    }
    
    
    

    在想要使用redis缓存的controller类上添加 @RedisCache 注解.

    切面方法则会切以select/get/query 开头的查询方法,获取方法名和参数拼接为key,存到redis.

    在执行add/insert/update 开头的方法时,则清空该类下的所有缓存.

    方法返回值格式统一实体类:

    
    package com.ys.edu.bean;
    
    import java.io.Serializable;
    
    /**
     * @ClassName ResultBody
     * @description:  RestFul API 方法返回值格式统一实体类
     **/
    public class ResultBody<T> implements Serializable {
    
        private static final long serialVersionUID = 694858559908048578L;
        private Integer code;
        private String msg;
        private Integer count = 0;
        private T data;
    
        public ResultBody(){}
    
        public ResultBody(Integer code, String msg,Integer count,T data) {
            this.code = code;
            this.msg = msg;
            this.count = count;
            this.data = data;
        }
    
        public ResultBody(Integer code, String msg,T data) {
            this.code = code;
            this.msg = msg;
            this.data = data;
        }
    
        
        /**
         * @Title: success
         * @Description: 成功  (无参)  默认 code : " 0 "  msg : "请求成功" , count : 0 , data: null
         * @date 2018/11/29 10:28
         **/
        public ResultBody success(){
            return success((T) null);
        }
    
        /**
         * @Title: success
         * @Description:   成功   默认 code : " 0 "  msg : "请求成功"
         * @param count : 数据条数
         * @param data :  数据
         * @date 2018/11/29 11:46
         **/
        public ResultBody success(Integer count,T data){
            return new ResultBody(0,"请求成功!",count,data);
        }
    
        /**
         * @Title: success
         * @Description:  成功   默认 code : " 0 "
         * @param msg :  提示信息
         * @param count :  数据条数
         * @param data :   数据
         **/
        public ResultBody success(String msg,Integer count,T data){
            return new ResultBody(0,msg,count,data);
        }
    
        /**
         * @Title: success
         * @Description:  成功   默认 code : " 0 " , msg : "请求成功"
         * @param data :  数据
         **/
        public ResultBody success(T data){
            return new ResultBody(0,"请求成功!",data);
        }
    
        /**
         * @Title: success
         * @Description:  成功   默认 code : " 0 "
         * @param msg :  提示信息
         * @param data :  数据
         * @date 2018/11/29 11:47
         **/
        public ResultBody success(String msg,T data){
            return new ResultBody(0,msg,data);
        }
    
        /**
         * @Title: success
         * @Description:  成功   默认 code : " 0 "
         * @param code :  枚举类代码
         * @param data :  数据
         **/
        public ResultBody success(Code code,T data){
            return new ResultBody(code.getCode(),code.getMsg(),data);
        }
    
        /**
         * @Title: success
         * @Description:  成功   默认 code : " 0 "
         * @param code :  枚举类代码
         **/
        public ResultBody success(Code code){
            return new ResultBody(code.getCode(),code.getMsg(),null);
        }
    
        
        /**
         * @Title: error
         * @Description:  错误   默认 data : null
         * @param code : 错误代码
         * @param msg : 错误信息
         **/
        public ResultBody error(Integer code,String msg){
            return new ResultBody(code,msg,null);
        }
    
        /**
         * @Title: error
         * @Description:  错误   默认 data : null
         * @param code :  枚举类错误代码
         **/
        public ResultBody error(Code code){
            return new ResultBody(code.getCode(),code.getMsg(),null);
        }
    
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public Integer getCount() {
            return count;
        }
    
        public void setCount(Integer count) {
            this.count = count;
        }
    
        public T getData() {
            return data;
        }
    
        public void setData(T data) {
            this.data = data;
        }
    }
    
    
    

    自定义提示枚举类:

    
    package com.ys.edu.bean;
    
    /**
     * @ClassName Code
     * @description: 自定义提示枚举类
     **/
    public enum Code {
    
       
        /**
         * @Description:  请求状态码
         **/
        SUCCESS(0,"请求成功"),
        ERROR(-1,"请求错误");
    
        private Integer code;
        private String msg;
    
        public Integer getCode() {
            return code;
        }
    
        public void setCode(Integer code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        Code(Integer code, String msg){
            this.code = code;
            this.msg = msg;
        }
    
    }
    
    
    

    返回结果工具类:

    
    package com.ys.edu.utils;
    
    import com.ys.edu.bean.Code;
    import com.ys.edu.bean.ResultBody;
    import com.ys.edu.entity.Page;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @ClassName ResultUtils
     * @description: 返回结果工具类
     **/
    public class ResultUtils {
    
        /**
         * @Title: success
         * @Description: 无参成功返回   默认值  code : "0" , msg : "请求成功" , count : 0 , data : null
         **/
        public static ResultBody success(){
            return success((Object)null);
        }
    
    
        public static ResultBody success(Object object){
            return success(0,object);
        }
    
    
        /**
         * @Title: success
         * @Description:  有参成功返回   默认值  code : "0" , msg : "请求成功"
         * @param count :  数据条数
         * @param object : 数据
         **/
        public static ResultBody success(Integer count,Object object){
            return new ResultBody().success(count,object);
        }
    
        /**
         * @Title: success
         * @Description:  有参成功返回   默认值  code : "0"
         * @param msg : 提示信息
         * @param count :  数据条数
         * @param object :  数据
         **/
        public static ResultBody success(String msg,Integer count,Object object){
            return new ResultBody().success(msg,count,object);
        }
    
        /**
         * @Title: error
         * @Description: 有参成功返回     默认值  code : "0"
         * @param code :
         * @param object : 数据
         **/
        public static ResultBody success(Code code,Object object){
            return new ResultBody().success(code,object);
        }
    
        /**
         * @Title: error
         * @Description: 有参成功返回     默认值  code : "0" data : null
         * @param code : 枚举类代码
         **/
        public static ResultBody success(Code code){
            return new ResultBody().success(code);
        }
    
        /**
         * @Title: error
         * @Description: 错误返回格式     默认值 data : null
         * @param code : 错误代码
         **/
        public static ResultBody error(Integer code,String msg){
            return new ResultBody().error(code,msg);
        }
        
        
        /**
         * @Title: error
         * @Description: 错误返回格式     默认值 data : null
         * @param code : 枚举类错误代码
         **/
        public static ResultBody error(Code code){
            return new ResultBody().error(code);
        }
    
        
        /**
         * @Title: successByLimit
         * @Description: 分页返回数据格式
         * @param page : 查询的页数
         * @param limit : 查询的条数
         * @param totalNum : 数据总条数
         * @param curCount : 当前页条数
         * @param object : 查询结果数据
         **/
        public static ResultBody successByLimit(Integer page,Integer limit,Integer totalNum,Integer curCount,Object object){
            Map<String,Object> map = new HashMap<>();
            Page pageInfo = new Page();
            pageInfo.setPage(page);
            pageInfo.setLimit(limit);
            pageInfo.setTotalNum(totalNum);
            pageInfo.setTotalPages((totalNum + limit - 1)/limit);
            map.put("page",pageInfo);
            map.put("data",object);
            return success(curCount,map);
        }
    
    }
    
    

    来源:https://blog.csdn.net/qq_36476972/article/details/85710225

  • 相关阅读:
    HRBUST 1377 金明的预算方案
    51Nod 2649 完全背包
    计蒜客 T2129 采药
    计蒜客 T1408 矩形嵌套
    OpenJudge 2711 合唱队形
    51Nod 2080 最长上升子序列
    2021NUAA暑假集训 Day5 部分题解
    2021NUAA暑假集训 Day4 部分题解
    C++ 11 move constructor 何时调用?
    老外这样说英文
  • 原文地址:https://www.cnblogs.com/qixidi/p/10229263.html
Copyright © 2020-2023  润新知