springboot的切面應(yīng)用方式(注解Aspect)
spring boot 攔截的方式
1.過(guò)濾器filter
可以獲取http、http請(qǐng)求和響應(yīng),但無(wú)法獲取與spring框架相關(guān)的信息,如哪個(gè)control處理,哪個(gè)方法處理,有哪些參數(shù),這些都是無(wú)法獲取的。
主要用于內(nèi)容上的過(guò)濾,敏感字替換成*等,也可用于非登入狀態(tài)的非法請(qǐng)求過(guò)濾。
2.攔截器interceptor
除了獲取http、http請(qǐng)求和響應(yīng)對(duì)象,還可以獲取請(qǐng)求的類(lèi)名、方法名,但攔截器無(wú)法獲取請(qǐng)求參數(shù)的值,從DispatcherServlet類(lèi)源碼分析。
主要用于對(duì)公共的一些攔截獲取,例如請(qǐng)求的IP 地址,IP黑白名單里的過(guò)過(guò)濾,非登入狀態(tài)的接口請(qǐng)求攔截。
3.切面攔截Aspect
能獲取到方法請(qǐng)求的參數(shù),方法名,以及方法返回的json數(shù)據(jù),更多的是用于數(shù)據(jù)的處理,比如對(duì)操作進(jìn)行記錄,修改,新建,查詢(xún),審批等操作記錄進(jìn)行處理統(tǒng)計(jì)。
對(duì)返回的json中的一些特殊數(shù)據(jù),比如字典值替換成對(duì)應(yīng)的數(shù)據(jù),避免前端轉(zhuǎn)化,等等。
執(zhí)行順序
- 正常情況:過(guò)濾器、攔截器、切片,
- 異常報(bào)錯(cuò):切片、ControllerAdvice注解類(lèi)、攔截器、過(guò)濾器
切片的使用
相關(guān)注解
(1)@Pointcut 注解:
指定一個(gè)切點(diǎn),定義需要攔截的東西,這里介紹兩個(gè)常 用的表達(dá)式:一個(gè)是使用 execution(),另一個(gè)是使用 annotation()。
- execution表達(dá)式:
以 execution(* com.mutest.controller..*.*(..))) 表達(dá)式為例:
- 第一個(gè) * 號(hào)的位置:表示返回值類(lèi)型,* 表示所有類(lèi)型。包名:表示需要攔截的包名,后面的兩個(gè)句*斜體樣式*點(diǎn)表示當(dāng)前包和當(dāng)前包的所有子包,在本例中指 com.mutest.controller包、子包下所有類(lèi)的方法。
- 第二個(gè) * *號(hào)的位置:表示類(lèi)名,** 表示所有類(lèi)。
- (..):*這個(gè)星號(hào)表示方法名*,* 表示所有的方法,后面括弧里面表示方法的參數(shù),兩個(gè)句點(diǎn)表示任何參數(shù)。
annotation() 表達(dá)式:
annotation() 方式是針對(duì)某個(gè)注解來(lái)定義切點(diǎn),其中注解包括GetMapping等
(2)@Around注解:
用于修飾Around增強(qiáng)處理,Around增強(qiáng)處理非常強(qiáng)大,表現(xiàn)在:
@Around可以自由選擇增強(qiáng)動(dòng)作與目標(biāo)方法的執(zhí)行順序,也就是說(shuō)可以在增強(qiáng)動(dòng)作前后,甚至過(guò)程中執(zhí)行目標(biāo)方法。這個(gè)特性的實(shí)現(xiàn)在于,調(diào)用 ProceedingJoinPoint參數(shù)的procedd()方法才會(huì)執(zhí)行目標(biāo)方法。
@Around可以改變執(zhí)行目標(biāo)方法的參數(shù)值,也可以改變執(zhí)行目標(biāo)方法之后的返回值。
(3)@Before 注解:
指定的方法在切面切入目標(biāo)方法之前執(zhí)行,可以做一些 Log 處理,也可以做一些信息的統(tǒng)計(jì),可以通過(guò)參數(shù)JointPoint 來(lái)獲取一些有用的信息,可以用它來(lái)獲取一個(gè)簽名,利用簽名可以獲取請(qǐng)求的包名、方法名,包括參數(shù)(通過(guò)joinPoint. getArgs() 獲取)等。
(4)@After注解:
和before注解相對(duì)應(yīng)的注解,同樣可以進(jìn)行一些日志處理等
(5)@AfterReturning 注解:
和@After 有些類(lèi)似,區(qū)別在于 @AfterReturning 注解可以用來(lái)捕獲切入方法執(zhí)行完之后的返回值,對(duì)返回值進(jìn)行業(yè)務(wù)邏輯上的增強(qiáng)處理。
對(duì)返回的json字符串進(jìn)行處理。
(6)@@AfterThrowing注解:
當(dāng)被切方法執(zhí)行過(guò)程中拋出異常時(shí),會(huì)進(jìn)入 @AfterThrowing 注解的方法中執(zhí)行,在該方法中可以做一些異常的處理邏輯。
示例
import com.alibaba.fastjson.JSONObject; import com.cmhit.crm.constants.FunctionEnum; import com.cmhit.crm.service.OperateLogService; import com.cmhit.crm.utils.JsonUtil; import com.cmhit.crm.vo.operlog.OperateLogCreateReqVO; import lombok.extern.slf4j.Slf4j; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Objects; @Slf4j @Aspect @Component public class OperateLogAspect { //操作日志service @Autowired private OperateLogService operateLogService; //操作日志實(shí)體 private OperateLogCreateReqVO operateLog = new OperateLogCreateReqVO(); // 定義一個(gè)切入點(diǎn) @Pointcut("execution(* com.cmhit.crm.controller.*.*(..))") public void operlog(){ //這里面不要寫(xiě)代碼,不會(huì)執(zhí)行的 } // 前置通知 @Before(value = "operlog()") public void before(JoinPoint jp) { //方法名獲取 String name = jp.getSignature().getName(); //方法參數(shù)獲取 Object[] args = jp.getArgs(); //設(shè)置操作日志 setOperateLogType(name,args); log.debug("{}方法開(kāi)始執(zhí)行...開(kāi)始設(shè)置設(shè)置操作日志的操作類(lèi)型",name); } // 后置通知 @After(value = "operlog()") public void after(JoinPoint jp) { String name = jp.getSignature().getName(); log.debug("{}方法執(zhí)行結(jié)束...",name); } // 返回通知 @AfterReturning(value = "operlog()") public void afterReturning(JoinPoint jp) { String name = jp.getSignature().getName(); if (Objects.nonNull(operateLog.getSourceId())) { operateLog.setOperationResult("操作成功!"); operateLogService.insertOperateLog(operateLog); } log.debug("{}方法執(zhí)行成功",name); } // 異常通知 @AfterThrowing(value = "operlog()", throwing = "e") public void afterThrowing(JoinPoint jp, Exception e) { String name = jp.getSignature().getName(); if (Objects.nonNull(operateLog.getSourceId())){ operateLog.setOperationResult(e.getMessage()); operateLogService.insertOperateLog(operateLog); } log.debug("{}方法拋異常,異常是{}",name , e.getMessage()); } // 環(huán)繞通知 @Around("operlog()") public Object around(ProceedingJoinPoint pjp) throws Throwable { String name = pjp.getSignature().getName(); // 統(tǒng)計(jì)方法執(zhí)行時(shí)間 long start = System.currentTimeMillis(); Object result = pjp.proceed(); long end = System.currentTimeMillis(); System.out.println(name + "方法執(zhí)行時(shí)間為:" + (end - start) + " ms"); return result; } private void setOperateLogType(String name,Object[] args){ //公司的業(yè)務(wù)邏輯,這里建立使用自己的 } } //參數(shù)處理方法 private void dealGetinfoArgs(Object[] args){ //自己寫(xiě)邏輯吧 } }
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java二叉查找樹(shù)的實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了java二叉查找樹(shù)的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-08-08idea創(chuàng)建SpringBoot項(xiàng)目時(shí)Type選maven?project和maven?pom有何區(qū)別
Maven是一個(gè)Java工程的管理工具,跟其相同功能的工具如Gradle,下面這篇文章主要給大家介紹了關(guān)于idea創(chuàng)建SpringBoot項(xiàng)目時(shí)Type選maven?project和maven?pom有何區(qū)別的相關(guān)資料,需要的朋友可以參考下2023-02-02hibernate 中 fetch=FetchType.LAZY 懶加載失敗處理方法
這篇文章主要介紹了hibernate 中 fetch=FetchType.LAZY 懶加載失敗處理方法,需要的朋友可以參考下2017-09-09通過(guò)weblogic API解析如何獲取weblogic中服務(wù)的IP和端口操作
這篇文章主要介紹了通過(guò)weblogic API解析如何獲取weblogic中服務(wù)的IP和端口操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06redis setIfAbsent和setnx的區(qū)別與使用說(shuō)明
這篇文章主要介紹了redis setIfAbsent和setnx的區(qū)別與使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-08-08Python實(shí)現(xiàn)filter函數(shù)實(shí)現(xiàn)字符串切分
這篇文章主要介紹了Python實(shí)現(xiàn)filter函數(shù)實(shí)現(xiàn)字符串切分,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03SpringBoot整合Mybatis-Plus實(shí)現(xiàn)關(guān)聯(lián)查詢(xún)
Mybatis-Plus(簡(jiǎn)稱(chēng)MP)是一個(gè)Mybatis的增強(qiáng)工具,只是在Mybatis的基礎(chǔ)上做了增強(qiáng)卻不做改變,MyBatis-Plus支持所有Mybatis原生的特性,本文給大家介紹了SpringBoot整合Mybatis-Plus實(shí)現(xiàn)關(guān)聯(lián)查詢(xún),需要的朋友可以參考下2024-08-08Java?C++算法題解leetcode801使序列遞增的最小交換次數(shù)
這篇文章主要為大家介紹了Java?C++題解leetcode801使序列遞增的最小交換次數(shù)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10