SpringBoot AOP控制Redis自動(dòng)緩存和更新的示例
導(dǎ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 存活時(shí)長 分鐘
@Resource
private RedisTemplate redisTemplate;
/**
* @Title: queryCachePointcut
* @Description: 定義切點(diǎn)為緩存注解
* @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("執(zhí)行方法 : [ "+methodName+" ] : 清除 key 包含 [ "+className+" ] 的緩存數(shù)據(jù)");
logger.warn("AOP 緩存切面處理 >>>> end 耗時(shí):" + (System.currentTimeMillis() - beginTime));
}
// 調(diào)用原始方法
return joinPoint.proceed();
}
/**
* @Title: getObject
* @Description: 使用key獲取數(shù)據(jù) 不存在則查詢添加
* @param beginTime : 切面開始時(shí)間
* @param joinPoint : 切面對象
* @param key : 獲取redis數(shù)據(jù)的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){
// 緩存中獲取到數(shù)據(jù),直接返回。
object = operations.get(key);
logger.warn("從緩存中獲取到 key 為 ["+key+" ] : 的數(shù)據(jù) >>>> " + object.toString());
logger.warn("AOP 緩存切面處理 >>>> end 耗時(shí):" + (System.currentTimeMillis() - beginTime));
return object;
}
if(object == null) {
// 緩存中沒有數(shù)據(jù),調(diào)用原始方法查詢數(shù)據(jù)庫
object = joinPoint.proceed();
operations.set(key, object, TIME_OUT, TimeUnit.MINUTES); // 設(shè)置超時(shí)時(shí)間30分鐘
logger.warn("向 Redis 添加 key 為 ["+key+" ] , 存活時(shí)長為 "+TIME_OUT+" min 的數(shù)據(jù) >>>> " + object.toString());
logger.warn("AOP 緩存切面處理 >>>> end 耗時(shí):" + (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 注解.
切面方法則會(huì)切以select/get/query 開頭的查詢方法,獲取方法名和參數(shù)拼接為key,存到redis.
在執(zhí)行add/insert/update 開頭的方法時(shí),則清空該類下的所有緩存.
方法返回值格式統(tǒng)一實(shí)體類:
package com.ys.edu.bean;
import java.io.Serializable;
/**
* @ClassName ResultBody
* @description: RestFul API 方法返回值格式統(tǒng)一實(shí)體類
**/
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: 成功 (無參) 默認(rèn) code : " 0 " msg : "請求成功" , count : 0 , data: null
* @date 2018/11/29 10:28
**/
public ResultBody success(){
return success((T) null);
}
/**
* @Title: success
* @Description: 成功 默認(rèn) code : " 0 " msg : "請求成功"
* @param count : 數(shù)據(jù)條數(shù)
* @param data : 數(shù)據(jù)
* @date 2018/11/29 11:46
**/
public ResultBody success(Integer count,T data){
return new ResultBody(0,"請求成功!",count,data);
}
/**
* @Title: success
* @Description: 成功 默認(rèn) code : " 0 "
* @param msg : 提示信息
* @param count : 數(shù)據(jù)條數(shù)
* @param data : 數(shù)據(jù)
**/
public ResultBody success(String msg,Integer count,T data){
return new ResultBody(0,msg,count,data);
}
/**
* @Title: success
* @Description: 成功 默認(rèn) code : " 0 " , msg : "請求成功"
* @param data : 數(shù)據(jù)
**/
public ResultBody success(T data){
return new ResultBody(0,"請求成功!",data);
}
/**
* @Title: success
* @Description: 成功 默認(rèn) code : " 0 "
* @param msg : 提示信息
* @param data : 數(shù)據(jù)
* @date 2018/11/29 11:47
**/
public ResultBody success(String msg,T data){
return new ResultBody(0,msg,data);
}
/**
* @Title: success
* @Description: 成功 默認(rèn) code : " 0 "
* @param code : 枚舉類代碼
* @param data : 數(shù)據(jù)
**/
public ResultBody success(Code code,T data){
return new ResultBody(code.getCode(),code.getMsg(),data);
}
/**
* @Title: success
* @Description: 成功 默認(rèn) code : " 0 "
* @param code : 枚舉類代碼
**/
public ResultBody success(Code code){
return new ResultBody(code.getCode(),code.getMsg(),null);
}
/**
* @Title: error
* @Description: 錯(cuò)誤 默認(rèn) data : null
* @param code : 錯(cuò)誤代碼
* @param msg : 錯(cuò)誤信息
**/
public ResultBody error(Integer code,String msg){
return new ResultBody(code,msg,null);
}
/**
* @Title: error
* @Description: 錯(cuò)誤 默認(rèn) data : null
* @param code : 枚舉類錯(cuò)誤代碼
**/
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: 請求狀態(tài)碼
**/
SUCCESS(0,"請求成功"),
ERROR(-1,"請求錯(cuò)誤");
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;
}
}
返回結(jié)果工具類:
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: 返回結(jié)果工具類
**/
public class ResultUtils {
/**
* @Title: success
* @Description: 無參成功返回 默認(rèn)值 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: 有參成功返回 默認(rèn)值 code : "0" , msg : "請求成功"
* @param count : 數(shù)據(jù)條數(shù)
* @param object : 數(shù)據(jù)
**/
public static ResultBody success(Integer count,Object object){
return new ResultBody().success(count,object);
}
/**
* @Title: success
* @Description: 有參成功返回 默認(rèn)值 code : "0"
* @param msg : 提示信息
* @param count : 數(shù)據(jù)條數(shù)
* @param object : 數(shù)據(jù)
**/
public static ResultBody success(String msg,Integer count,Object object){
return new ResultBody().success(msg,count,object);
}
/**
* @Title: error
* @Description: 有參成功返回 默認(rèn)值 code : "0"
* @param code :
* @param object : 數(shù)據(jù)
**/
public static ResultBody success(Code code,Object object){
return new ResultBody().success(code,object);
}
/**
* @Title: error
* @Description: 有參成功返回 默認(rèn)值 code : "0" data : null
* @param code : 枚舉類代碼
**/
public static ResultBody success(Code code){
return new ResultBody().success(code);
}
/**
* @Title: error
* @Description: 錯(cuò)誤返回格式 默認(rèn)值 data : null
* @param code : 錯(cuò)誤代碼
**/
public static ResultBody error(Integer code,String msg){
return new ResultBody().error(code,msg);
}
/**
* @Title: error
* @Description: 錯(cuò)誤返回格式 默認(rèn)值 data : null
* @param code : 枚舉類錯(cuò)誤代碼
**/
public static ResultBody error(Code code){
return new ResultBody().error(code);
}
/**
* @Title: successByLimit
* @Description: 分頁返回?cái)?shù)據(jù)格式
* @param page : 查詢的頁數(shù)
* @param limit : 查詢的條數(shù)
* @param totalNum : 數(shù)據(jù)總條數(shù)
* @param curCount : 當(dāng)前頁條數(shù)
* @param object : 查詢結(jié)果數(shù)據(jù)
**/
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);
}
}
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對腳本之家的支持。如果你想了解更多相關(guān)內(nèi)容請查看下面相關(guān)鏈接
- Springboot中使用Redisson+AOP+自定義注解實(shí)現(xiàn)訪問限流與黑名單攔截
- SpringBoot整合redis+Aop防止重復(fù)提交的實(shí)現(xiàn)
- SpringBoot+Redis使用AOP防止重復(fù)提交的實(shí)現(xiàn)
- SpringBoot?使用AOP?+?Redis?防止表單重復(fù)提交的方法
- SpringBoot使用自定義注解+AOP+Redis實(shí)現(xiàn)接口限流的實(shí)例代碼
- SpringBoot?AOP?Redis實(shí)現(xiàn)延時(shí)雙刪功能實(shí)戰(zhàn)
- 淺談SpringBoot集成Redis實(shí)現(xiàn)緩存處理(Spring AOP實(shí)現(xiàn))
- Springboot整合AOP和redis的示例詳解
相關(guān)文章
Springboot實(shí)現(xiàn)全局自定義異常的方法詳解
這篇文章主要介紹了Springboot實(shí)現(xiàn)全局自定義異常的方法詳解,SpringBoot的項(xiàng)目已經(jīng)對有一定的異常處理了,但是對于我們開發(fā)者而言可能就不太合適了,因此我們需要對這些異常進(jìn)行統(tǒng)一的捕獲并處理,需要的朋友可以參考下2023-11-11
一文帶你看懂Android動(dòng)畫的實(shí)現(xiàn)原理
動(dòng)畫是 Android 應(yīng)用程序中重要的交互特性,ndroid 提供了多種動(dòng)畫效果,包括平移、縮放、旋轉(zhuǎn)和透明度等,它們可以通過代碼或 XML 來實(shí)現(xiàn),本文將介紹 Android 動(dòng)畫的原理和實(shí)現(xiàn)方法,并提供一些示例,需要的朋友可以參考下2023-07-07
MyBatis通用Mapper實(shí)現(xiàn)原理及相關(guān)內(nèi)容
今天小編就為大家分享一篇關(guān)于MyBatis通用Mapper實(shí)現(xiàn)原理及相關(guān)內(nèi)容,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12

