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

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

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

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

問(wèn)題介紹

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

  

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

 

      但是在開發(fā)調(diào)試過(guò)程中遇到一個(gè)痛點(diǎn)就是在測(cè)試環(huán)境中一旦遇到錯(cuò)誤比較難定位問(wèn)題,因?yàn)槲⑿胖械恼{(diào)試器打開比較麻煩,所以要看一個(gè)問(wèn)題需要耗費(fèi)比較長(zhǎng)的時(shí)間(相信使用微信工具調(diào)試的人深知此事)。所以一般情況下,后端開發(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)開發(fā),因而代碼中必定到處都充斥著這樣的重復(fù)邏輯。

  

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

      

問(wèn)題解決方案

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

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

 

     二話不說(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)	{		// 不開啟的話則不打印日志		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)	{		// 不開啟的話則不打印日志		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)控制,保證線上不受影響。

       

問(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)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 广东省| 榆中县| 东光县| 扬州市| 万盛区| 池州市| 周至县| 阿巴嘎旗| 西安市| 西畴县| 法库县| 蒙阴县| 唐河县| 长汀县| 大丰市| 武邑县| 绥江县| 武冈市| 保靖县| 定州市| 汕尾市| 玉龙| 鄂州市| 南江县| 峨眉山市| 广丰县| 泗洪县| 南川市| 竹溪县| 宁海县| 收藏| 乌拉特前旗| 信丰县| 辛集市| 云安县| 西吉县| 集安市| 佳木斯市| 罗平县| 奎屯市| 榆中县|