SpringBoot AOP控制Redis自动缓存和更新的示例
程序员文章站
2024-03-02 20:11:22
导入redis的jar包
o...
导入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); } }
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。如果你想了解更多相关内容请查看下面相关链接