国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

Spring MVC AOP通過(guò)注解方式攔截Controller等實(shí)現(xiàn)日志管理

2019-11-11 03:46:40
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

問(wèn)題介紹

       最近在做微信企業(yè)號(hào)的Saas套件開(kāi)發(fā),因而前端頁(yè)面都是使用H5做的。為了提高開(kāi)發(fā)效率,使得前后端基本能夠并行開(kāi)發(fā),我們后端開(kāi)發(fā)人員和前端開(kāi)發(fā)人員就約定使用前后端分離的開(kāi)發(fā)方式。

  

      一旦采用前后端分離的開(kāi)發(fā)方式,我們后端人員就只提供接口了。因?yàn)槲覀兪遣捎胹PRing + springmvc_mybatis的通用架構(gòu)。所以這種純接口的開(kāi)發(fā)非常方便。

 

      但是在開(kāi)發(fā)調(diào)試過(guò)程中遇到一個(gè)痛點(diǎn)就是在測(cè)試環(huán)境中一旦遇到錯(cuò)誤比較難定位問(wèn)題,因?yàn)槲⑿胖械恼{(diào)試器打開(kāi)比較麻煩,所以要看一個(gè)問(wèn)題需要耗費(fèi)比較長(zhǎng)的時(shí)間(相信使用微信工具調(diào)試的人深知此事)。所以一般情況下,后端開(kāi)發(fā)人員都在日志中打印前端傳給后端的請(qǐng)求參數(shù)以及返回給前端的結(jié)果。因而代碼中充斥著這樣的邏輯。

     

	/**	 * xxxx	 * 	 * @param queryVo	 * @return	 */	@RequestMapping(value = "/xxxx")	@ResponseBody	public Map<String, Object> xxxx(OrderStatisticsQueryParams queryParams)	{		logger.debug("請(qǐng)求參數(shù):" + JsonUtil.toJSONString(queryParams));		// PROCESS result		return result;	}

  

      如果只是一個(gè)兩個(gè)接口也就罷了,但是之后我們打算都采用前后端分離的方式來(lái)開(kāi)發(fā),因而代碼中必定到處都充斥著這樣的重復(fù)邏輯。

  

      因?yàn)槲蚁氲搅丝梢允褂肁OP來(lái)解決這個(gè)問(wèn)題。

      

問(wèn)題解決方案

       1.使用自定義注解來(lái)標(biāo)識(shí)哪些接口需要打印參數(shù)日志,而不是一刀切,所有的接口都需要打印日志

     2.考慮線(xiàn)上的情況。一般來(lái)講打印日志的需求只會(huì)在開(kāi)發(fā)測(cè)試階段才會(huì)有,而正常情況下線(xiàn)上不需要打印請(qǐng)求參數(shù)。而且打印參數(shù)也會(huì)浪費(fèi)線(xiàn)上的資源。

 

     二話(huà)不說(shuō),先上自定義日志注解的代碼

    

@Retention(RetentionPolicy.RUNTIME)@Target({	ElementType.METHOD})public @interface SystemLog{	String description() default "";  // 方法描述}

       再上切面的代碼

package com.zk.platform.aop;import java.lang.reflect.Method;import java.util.Map;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.annotation.AfterReturning;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Before;import org.aspectj.lang.annotation.Pointcut;import org.aspectj.lang.reflect.MethodSignature;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.stereotype.Component;import com.alibaba.fastjson.JSON;import com.google.common.collect.Maps;import com.zk.platform.annotation.SystemLog;import com.zk.platform.util.PropertiesUtil;@Aspect@Componentpublic class SystemLogAop{	private static final boolean ENABLE_METHOD_LOGGING = "true".equals(PropertiesUtil.getSysProp("method.args.logging",			"false"));	private static final Logger logger = LoggerFactory.getLogger(SystemLogAop.class);	@Pointcut("@annotation(com.zk.platform.annotation.SystemLog)")	public void systemLogPointCut()	{	}	@Before("systemLogPointCut()")	public void beforeExec(JoinPoint joinPoint)	{		// 不開(kāi)啟的話(huà)則不打印日志		if (!ENABLE_METHOD_LOGGING)		{			return;		}		try		{			String targetName = joinPoint.getTarget().getClass().getSimpleName();			String methodName = joinPoint.getSignature().getName();			MethodSignature ms = (MethodSignature) joinPoint.getSignature();			Object[] arguments = joinPoint.getArgs();			String[] parameterNames = ms.getParameterNames();			Method method = ms.getMethod();			SystemLog systemLog = method.getAnnotation(SystemLog.class);			if (arguments != null && parameterNames != null && arguments.length == parameterNames.length					&& arguments.length > 0)			{				Object argObj = null;				if (arguments.length == 1)				{					argObj = arguments[0];				}				else				{					Map<String, Object> map = Maps.newHashMapWithExpectedSize(arguments.length);					for (int i = 0; i < arguments.length; i++)					{						map.put(parameterNames[i], arguments[i]);					}					argObj = map;				}				logger.debug("{}.{}({}) args are:{}", targetName, methodName, systemLog.description(),						JSON.toJSONString(argObj));			}			else			{				logger.debug("{}.{}({}) invoked and no args", targetName, methodName, systemLog.description());			}		}		catch (Exception e)		{			logger.warn("打印日志異常:{}", e);		}	}	@AfterReturning(pointcut = "systemLogPointCut()", returning = "result")	public void afterReturning(JoinPoint joinPoint, Object result)	{		// 不開(kāi)啟的話(huà)則不打印日志		if (!ENABLE_METHOD_LOGGING)		{			return;		}		try		{			String targetName = joinPoint.getTarget().getClass().getSimpleName();			String methodName = joinPoint.getSignature().getName();			MethodSignature ms = (MethodSignature) joinPoint.getSignature();			Method method = ms.getMethod();			SystemLog systemLog = method.getAnnotation(SystemLog.class);			logger.debug("{}.{}({}) return value is:{}", targetName, methodName, systemLog.description(),					JSON.toJSONString(result));		}		catch (Exception e)		{			logger.warn("打印日志異常:{}", e);		}	}} 

      注意,日志功能是否生效由參數(shù)"method.args.logging來(lái)控制,保證線(xiàn)上不受影響。

       

問(wèn)題解決過(guò)程中遇到的問(wèn)題

     配置后,發(fā)現(xiàn)切面沒(méi)有生效。

    解決方案如下  

    <!-- 最重要:::如果放在spring-context.xml中,這里的aop設(shè)置將不會(huì)生效 -->    <aop:aspectj-autoproxy proxy-target-class="true"/>   

   在spring配置文件中加上這句

    <aop:aspectj-autoproxy proxy-target-class="true"/>

     

 

  

   

    

 

  

    


發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 衡水市| 荣成市| 婺源县| 沐川县| 招远市| 普兰店市| 恩施市| 牙克石市| 云阳县| 朔州市| 县级市| 沈阳市| 郯城县| 枞阳县| 鄢陵县| 监利县| 蓬溪县| 吉首市| 汶上县| 关岭| 岢岚县| 正定县| 莆田市| 额尔古纳市| 枣强县| 兴安县| 通州区| 南皮县| 汤原县| 黄石市| 冕宁县| 韶关市| 陆川县| 政和县| 浮梁县| 阿克苏市| 阳原县| 盱眙县| 甘泉县| 永春县| 留坝县|