您好,登錄后才能下訂單哦!
這篇文章主要介紹“如何使用自定義注解+Redis的攔截器實現冪等性校驗”,在日常操作中,相信很多人在如何使用自定義注解+Redis的攔截器實現冪等性校驗問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”如何使用自定義注解+Redis的攔截器實現冪等性校驗”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
實現方法
編寫一個自定義注解和一個攔截器,本文中的自定義注解可以指定傳入超時時間(默認是60秒),攔截器對使用注解的方法進行攔截,獲取到傳入的參數和超時時間,將傳入的一個或多個參數拼接成一個json字符串,使用md5進行加密后把它作為key存入Redis緩存中,如果根據key在超時時間范圍內能找到相同的內容,則返回表單內容已提交提示,否則繼續執行方法。
自定義一個@Idempotent注解
/** * 自定義防重復提交注解 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Idempotent { /**可以傳入指定的重復提交限定時間,默認60秒*/ long value() default 60000; }
自定義一個IdempotentAspect攔截器
/** * 攔截器 * @author 豆芽 * @Date 2020-11-11 15:05 */ @Aspect @Component public class IdempotentAspect { private Logger logger = LoggerFactory.getLogger(IdempotentAspect.class); @Autowired private RedisService redisService; @Around("@annotation(idempotent)") public Object aroundMethod(ProceedingJoinPoint pjp,Idempotent idempotent)throws Throwable{ /**獲取執行方法的參數*/ Object[] args = pjp.getArgs(); /**獲取注解傳入的超時時間*/ long timeOut = idempotent.value(); /**使用MD5對傳入的參數進行加密*/ String encode = getMd5Value(args); try{ /** 校驗是否重復提交過,如果沒有,則按指定超時時間存入Redis緩存 */ boolean checkFormToken = redisService.checkForm(encode,timeOut); if (checkFormToken) { /**這是一個自定義的異常類,可以自己編寫*/ throw new CommonException(Code.RepeatSubmit,"表單內容已經提交"); } /**繼續執行方法*/ return pjp.proceed(); } catch (CommonException e) { logger.error("運行時錯誤:" + e.getMessage(), e); if (Code.RepeatSubmit.getCode() != e.getCode()) { /**調用方法可能會存在其他的CommonException自定義異常,需要刪除校驗的key,支持重復提交*/ redisService.delete(encode); } throw e; } catch (Exception e){ logger.error("冪等性校驗出錯:" + e.getMessage(), e); throw e; } } /** * 使用MD5對傳入的參數進行加密 * @param args * @return */ private String getMd5Value(Object[] args) { String md5 = "null"; if (args.length == 0) { return md5; } else { StringBuilder jsonString = new StringBuilder(JSON.toJSONString(args)); /**使用md5工具類對字符串進行加密*/ md5 = SecureUtil.md5Encode(jsonString.toString()); } return md5; } }
封裝的RedisService類
@Component public class RedisService { private Logger logger = LoggerFactory.getLogger(RedisService.class); @Autowired private StringRedisTemplate stringRedisTemplate; /** * 將對象存入緩存中 * @param key key * @param obj 對象數據 * @param timeout 超時時間 */ public void set(String key, Object obj, long timeout) { if (obj instanceof String) { stringRedisTemplate.opsForValue().set(key, (String) obj, timeout, TimeUnit.MILLISECONDS); return; } String json = JSON.toJSONString(obj); stringRedisTemplate.opsForValue().set(key, json, timeout, TimeUnit.MILLISECONDS); } /** * 根據Key查詢緩存中的數據 * @param key * @return */ public String get(final String key) { if (StringUtils.isEmpty(key)) { logger.warn("獲取Redis緩存,傳入的Key為空"); return null; } return stringRedisTemplate.opsForValue().get(key); } /** * 根據key刪除緩存數據 * @param key */ public void delete(String key) { stringRedisTemplate.delete(key); } /** * 查詢緩存是否存在 * @param checkCase * @return */ public boolean checkForm(String checkCase,long timeOut){ String cacheValue = get(checkCase); /**如果查詢緩存不為空,返回true*/ if (StringUtils.isNotEmpty(cacheValue)){ return true; } /**否則將對象存入緩存中,IdUtil.randomUUID()為hutool的UUID生成工具類,可到hutool官網加載相關依賴*/ set(checkCase, IdUtil.randomUUID(), timeOut); return false; } }
自定義的錯誤碼枚舉Code
public enum Code { ErrorSystem(500,"系統繁忙!"), RepeatSubmit(4,"重復提交") ; private int code; private String msg; Code(int code, String msg) { this.code = code; this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
自定義異常類CommonException
public class CommonException extends RuntimeException { /** 錯誤碼 */ private int code = Code.ErrorSystem.getCode(); /** 錯誤信息 */ private String msg = Code.ErrorSystem.getMsg(); public CommonException(Code code) { super("[" + code.getCode() + ":" + code.toString() +"]" + code.getMsg()); this.code = code.getCode(); this.msg = code.getMsg(); } public CommonException(String msg) { super("[" + Code.ErrorSystem.getCode() + ":" + Code.ErrorSystem.toString() +"]" + msg); this.code = Code.ErrorSystem.getCode(); this.msg = msg; } public CommonException(Code code, String msg) { super("[" + code.getCode() + ":" + code.toString() +"]" + msg); this.code = code.getCode(); this.msg = msg; } public int getCode() { return code; } public String getMsg() { return msg; } }
測試類RedisController,@Idempotent注解可以直接value參數,這個參數可以設置本次請求的參數在redis中的存活時間,不傳參默認存活60秒
/** * @author 豆芽 * @Date 2020-11-11 11:09 */ @RestController public class RedisController { private Logger logger = LoggerFactory.getLogger(RedisController.class); /** * 自定義注解+Redis+MD5加密的攔截器實現冪等性校驗 * @param name * @param age * @return */ @Idempotent @RequestMapping(value = "/auth/redis/idempotent",method = {RequestMethod.GET, RequestMethod.POST}) public String idempotentTest(String name,String age){ logger.info("name: "+name); logger.info("age: "+age); // TODO 執行保存或更新方法 return "執行成功"; } }
第一次發起請求返回執行成功
緊接著馬上再發起一次相同參數的請求,系統會拋出“表單內容已經提交”的異常
到此,關于“如何使用自定義注解+Redis的攔截器實現冪等性校驗”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。