您好,登錄后才能下訂單哦!
這篇文章主要介紹springMVC如何自定義注解并使用AOP來(lái)實(shí)現(xiàn)日志記錄,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
需求背景
最近的一個(gè)項(xiàng)目,在項(xiàng)目基本完工的階段,客戶提出要將所有業(yè)務(wù)操作的日志記錄到數(shù)據(jù)庫(kù)中,并且要提取一些業(yè)務(wù)的關(guān)鍵信息(比如交易單號(hào))體現(xiàn)在日志中。
為了保證工期,在查閱了資料以后,決定用AOP+自定義注解的方式來(lái)完成這個(gè)需求。
準(zhǔn)備工作
自定義注解需要依賴的jar包有 aspectjrt-XXX.jar ,aspectjweaver-XXX.jar,XXX代表版本號(hào)。
自定義注解
在項(xiàng)目下單獨(dú)建立了一個(gè)log包,來(lái)存放日志相關(guān)的內(nèi)容
**.common.log.annotation //自定義注解存放位置 **.common.log.aop //aop工具類存放位置
在annotation包下面新建自定義注解類:
package **.common.log.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) public @interface XXXOperateLog { /** * 操作類型描述 * @return */ String operateTypeDesc() default ""; /** * 操作類型 * @return */ long operateType() default -1; /** * 模塊編碼 * @return */ String moudleCode() default "M30"; /** * 模塊名稱 * @return */ String moudleName() default "XX模塊"; /** * 業(yè)務(wù)類型 * @return */ String bussType() default ""; /** * 業(yè)務(wù)類型描述 * @return */ String bussTypeDesc() default ""; }
在aop包下新建XXXOperateLogAop
package **.common.log.aop; import ** ;//省略 @Aspect @Component public class XXXOperateLogAop{ @Autowired SystemLogService systemLogService; HttpServletRequest request = null; Logger logger = LoggerFactory.getLogger(XXXOperateLogAop.class); ThreadLocal<Long> time = new ThreadLocal<Long>(); //用于生成操作日志的唯一標(biāo)識(shí),用于業(yè)務(wù)流程審計(jì)日志調(diào)用 public static ThreadLocal<String> tag = new ThreadLocal<String>(); //聲明AOP切入點(diǎn),凡是使用了XXXOperateLog的方法均被攔截 @Pointcut("@annotation(**.common.log.annotation.XXXOperateLog)") public void log() { System.out.println("我是一個(gè)切入點(diǎn)"); } /** * 在所有標(biāo)注@Log的地方切入 * @param joinPoint */ @Before("log()") public void beforeExec(JoinPoint joinPoint) { time.set(System.currentTimeMillis()); info(joinPoint); //設(shè)置日志記錄的唯一標(biāo)識(shí)號(hào) tag.set(UUID.randomUUID().toString()); request= ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); } @After("log()") public void afterExec(JoinPoint joinPoint) { MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method method = ms.getMethod(); logger.debug("標(biāo)記為" + tag.get() + "的方法" + method.getName() + "運(yùn)行消耗" + (System.currentTimeMillis() - time.get()) + "ms"); } //在執(zhí)行目標(biāo)方法的過(guò)程中,會(huì)執(zhí)行這個(gè)方法,可以在這里實(shí)現(xiàn)日志的記錄 @Around("log()") public Object aroundExec(ProceedingJoinPoint pjp) throws Throwable { Object ret = pjp.proceed(); try { Object[] orgs = pjp.getArgs(); SystemLog valueReturn = null; for (int i = 0; i < orgs.length; i++) { if(orgs[i] instanceof SystemLog){ valueReturn = (SystemLog) orgs[i]; } } if(valueReturn==null){ valueReturn = new SystemLog(); } if(valueReturn!=null&&request!=null){ MethodSignature ms = (MethodSignature) pjp.getSignature(); Method method = ms.getMethod(); //獲取注解的操作日志信息 XXXOperateLog log = method.getAnnotation(XXXOperateLog.class); String businessType = log.bussType(); String businessDesc = log.bussTypeDesc(); HashMap requestMap = ServletUtils.getParametersToHashMap(request) ; //從參數(shù)中尋找業(yè)務(wù)類型 if(businessType.equals("")) { Object objBusinessType = requestMap.get("business_type"); businessType = objBusinessType == null ? "" : objBusinessType.toString(); } //從執(zhí)行結(jié)果的申請(qǐng)單中找業(yè)務(wù)類型 Object apply = request.getAttribute("apply") ; if(apply != null){ JSONObject obj = JSONFactory.toJSONAbstractEntity(apply); if(obj != null) { valueReturn.setOtherDesc("申請(qǐng)單號(hào):"+obj.getString("apply_no")); if(businessType.equals("")) { businessType = obj.getString("business_type"); } } } //從方法的執(zhí)行過(guò)程參數(shù)中找業(yè)務(wù)類型(一般是手動(dòng)設(shè)置) if(businessType.equals("")) { businessType = (String) request.getAttribute("business_type"); businessType = businessType == null ? "" : businessType; } if(!businessType.equals("") && businessDesc.equals("")) { businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType); } valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType)); valueReturn.setBussTypeDesc(businessDesc); valueReturn.setMoudleCode(log.moudleCode()); valueReturn.setMoudleName(log.moudleName()); valueReturn.setOperateResult(XXXSysConstant.YesOrNo.YES); valueReturn.setOperateType(log.operateType()); valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId()); valueReturn.setOperateTypeDesc(log.operateTypeDesc()); valueReturn.setRequestIp(getRemoteHost(request)); valueReturn.setRequestUrl(request.getRequestURI()); valueReturn.setServerIp(request.getLocalAddr()); valueReturn.setUids(tag.get()); //保存操作日志 systemLogService.saveSystemLog(valueReturn); }else{ logger.info("不記錄日志信息"); } //保存操作結(jié)果 } catch (Exception e) { e.printStackTrace(); } return ret; } //記錄異常日志 @AfterThrowing(pointcut = "log()",throwing="e") public void doAfterThrowing(JoinPoint joinPoint, Throwable e) { try { info(joinPoint); Object[] orgs = joinPoint.getArgs(); SystemLog valueReturn = null; for (int i = 0; i < orgs.length; i++) { if(orgs[i] instanceof SystemLog){ valueReturn = (SystemLog) orgs[i]; } } if(valueReturn==null){ valueReturn = new SystemLog(); } if(valueReturn!=null&&request!=null){ MethodSignature ms = (MethodSignature) joinPoint.getSignature(); Method method = ms.getMethod(); XXXOperateLog log = method.getAnnotation(XXXOperateLog.class); String businessType = log.bussType(); String businessDesc = log.bussTypeDesc(); if(businessType.equals("")) { Object objBusinessType = ServletUtils.getParametersToHashMap(request).get("business_type"); businessType = objBusinessType == null ? "" : objBusinessType.toString(); businessDesc = XXXSysConstant.BUSINESS_TYPE.getName(businessType); } valueReturn.setBussType(XXXSysConstant.BUSINESS_TYPE.getNumber(businessType)); valueReturn.setBussTypeDesc(businessDesc); valueReturn.setMoudleCode(log.moudleCode()); valueReturn.setMoudleName(log.moudleName()); valueReturn.setOperateType(log.operateType()); valueReturn.setOperateTypeDesc(log.operateTypeDesc()); valueReturn.setInputUserId(((UserContext)WebUtils.getSessionAttribute(request, "XXXuserContext")).getSysUser().getId()); valueReturn.setOperateResult(XXXSysConstant.YesOrNo.NO); String errMes = e.getMessage(); if(errMes!=null && errMes.length()>800){ errMes = errMes.substring(0, 800); } valueReturn.setErrorMessage(errMes); valueReturn.setRequestIp(getRemoteHost(request)); valueReturn.setRequestUrl(request.getRequestURI()); valueReturn.setServerIp(request.getLocalAddr()); valueReturn.setUids(tag.get()); systemLogService.saveSystemLog(valueReturn); }else{ logger.info("不記錄日志信息"); } } catch (Exception e1) { e1.printStackTrace(); } } private void info(JoinPoint joinPoint) { logger.debug("--------------------------------------------------"); logger.debug("King:\t" + joinPoint.getKind()); logger.debug("Target:\t" + joinPoint.getTarget().toString()); Object[] os = joinPoint.getArgs(); logger.debug("Args:"); for (int i = 0; i < os.length; i++) { logger.debug("\t==>參數(shù)[" + i + "]:\t" + os[i].toString()); } logger.debug("Signature:\t" + joinPoint.getSignature()); logger.debug("SourceLocation:\t" + joinPoint.getSourceLocation()); logger.debug("StaticPart:\t" + joinPoint.getStaticPart()); logger.debug("--------------------------------------------------"); } /** * 獲取遠(yuǎn)程客戶端Ip * @param request * @return */ private String getRemoteHost(javax.servlet.http.HttpServletRequest request){ String ip = request.getHeader("x-forwarded-for"); if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){ ip = request.getHeader("Proxy-Client-IP"); } if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){ ip = request.getHeader("WL-Proxy-Client-IP"); } if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)){ ip = request.getRemoteAddr(); } return ip.equals("0:0:0:0:0:0:0:1")?"127.0.0.1":ip; } }
修改配置文件spring-mvc.xml,添加如下配置
<!-- 開(kāi)啟AOP攔截 --> <aop:aspectj-autoproxy proxy-target-class="true" /> <mvc:annotation-driven /> <!-- 定義Spring描述Bean的范圍 --> <context:component-scan base-package="**.common.log" > <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> </context:component-scan>
需要注意的是,上述配置必須放在同一個(gè)xml文件里面,要么spring-mvc.xml,要么spring-context.xml,否則可能不生效,暫時(shí)還未查明是為什么。
注解的使用
@XXXOperateLog( bussType=XXXSysConstant.BUSINESS_TYPE.YYYY ,bussTypeDesc="業(yè)務(wù)類型描述" ,operateType = XXXSysConstant.LogOperateType.QUERY ,operateTypeDesc = "操作描述" ) @RequestMapping(value = "/**/**/queryXXXXX4DataGrid.json", method = RequestMethod.POST) public void queryXXXXX4DataGrid(HttpServletRequest request, HttpServletResponse arg1, Model model, Writer writer) { logger.info("==========驗(yàn)票查詢(出庫(kù))交易信息 開(kāi)始====================="); try { //do something for business } catch (SystemException se) { throw se; } catch (BusinessException be) { throw be; } catch (Exception e) { throw new SystemException(e); } }
以上是“springMVC如何自定義注解并使用AOP來(lái)實(shí)現(xiàn)日志記錄”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。