controller Log Aspect Processing Based on Sprboot
Problem Requirements: In the project, we need to record the input value of the interface in the log, call ip of the interface, call time of the interface, and store it in the library.
Processing Method: Adding Cut Face Processing in controller Layer
1. Required packages, aop facets in spring boot, two tool classes, hutool and jackson
The pom is as follows (version can be replaced):
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-core</artifactId> <version>4.5.18</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.9.0</version> </dependency>
2. Coding:
/** * <dl> * <dt>ControllerAspect</dt> * <dd>Description:</dd> * <dd>Copyright: Copyright (C) 2019</dd> * <dd>Company:</dd> * <dd>CreateDate: 2019/7/26</dd> * </dl> * * @author hht */ @Component @Aspect public class ControllerAspect { private Logger logger = LoggerFactory.getLogger(ControllerAspect.class); // Define Pointcut @Pointcut( "execution(* com.test.test.controller..*(..))") public void executeController() { } @Before("executeController()") public void before(JoinPoint joinPoint) throws Exception{ RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; HttpServletRequest request = servletRequestAttributes.getRequest(); //The method obtained in this step may be either proxy method or real method. Method m = ((MethodSignature) joinPoint.getSignature()).getMethod(); //To determine whether the proxy object itself is the target object of the join point, if not, we need to retrieve the real method by reflection. if (joinPoint.getThis().getClass() != joinPoint.getTarget().getClass()) { m = ReflectUtil.getMethod(joinPoint.getTarget().getClass(), m.getName(), m.getParameterTypes()); } //Getting the parameter name of this method by real method LocalVariableTableParameterNameDiscoverer paramNames = new LocalVariableTableParameterNameDiscoverer(); String[] parameterNames = paramNames.getParameterNames(m); //Get the list of entry points for the join point method runtime Object[] args = joinPoint.getArgs(); //One-to-one correspondence between parameter names and input values Map<String, Object> params = new HashMap<>(); //A Method of Judging Empty Class Written by oneself if (!TextUtil.isEmpty(parameterNames)){ for (int i = 0; i < parameterNames.length; i++) { //If we use requestParam to accept parameters and require=false, there will be nonexistent phenomena. if (TextUtil.isEmpty(args[i])){ continue; } //Get values through all class transformations, including all kinds of encapsulated classes ObjectMapper objectMapper = new ObjectMapper(); objectMapper.convertValue(args[i],args[i].getClass()); params.put(parameterNames[i],JSON.toJSON(objectMapper.convertValue(args[i],args[i].getClass()))); } } logger.info("before start:-------------------------------"); logger.info("URL : " + request.getRequestURL().toString()); logger.info("HTTP_METHOD : " + request.getMethod()); logger.info("IP : " + request.getRemoteAddr()); logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName()+ "." + joinPoint.getSignature().getName()); //After processing, one-to-one correspondence between parameter name and value can be obtained. logger.info("ARGS-JSON : " + params); //This is simply to get the parameters, and the values need to match themselves. logger.info("ARGS : "+ Arrays.toString(joinPoint.getArgs())); logger.info("before end:-------------------------------"); } @AfterReturning(value = "executeController()",returning = "rtv") public void after(JoinPoint joinPoint, Object rtv){ logger.info("before return+++++++++++++++++++++++++++"); logger.info("responseBody:"+JSON.toJSONString(rtv,SerializerFeature.WriteMapNullValue)); logger.info("end return++++++++++++++++++++++++++++++++"); } }
As long as the cut-point modification can be used directly, you can see the log data more intuitively, by the way, there is no exception processing cut.
Using aop surround to process section call data into database
Code directly
public class ControllerAspect { @Autowired AsyncTask asyncTask; private Logger logger = LoggerFactory.getLogger(ControllerAspect.class); // Define Pointcut @Pointcut( "execution(* com.test.web..*.*(..))") public void executeController() { } @Before("executeController()") public void before(JoinPoint joinPoint) throws Exception{ RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; HttpServletRequest request = servletRequestAttributes.getRequest(); logger.info("before start:-------------------------------"); logger.info("URL : " + request.getRequestURL().toString()); logger.info("HTTP_METHOD : " + request.getMethod()); logger.info("IP : " + request.getRemoteAddr()); logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName()+ "." + joinPoint.getSignature().getName()); logger.info("ARGS-JSON : " + CommonAop.getAopParam(joinPoint)); logger.info("ARGS : "+ Arrays.toString(joinPoint.getArgs())); logger.info("before end:-------------------------------"); } /** * Surrounding section data into database */ @Around("executeController()") public Object around(ProceedingJoinPoint pjp) throws Throwable { //Be careful!!!!! Here, the method pjp.proceed() gets the return value. It can not be called many times. Calling the whole interface many times will run, similar to hasnext() and next(). Object object = pjp.proceed(); try { //Circumferential Notification Processing Method RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes; HttpServletRequest request = servletRequestAttributes.getRequest(); //Asynchronous library entry, where an asynchronous class method is called for data storage //Common Aop. getAopParam (pjp) is a method that refers to the above method to get parameters ProceedingJoinPoint and JoinPoint are similar. asyncTask.doInsertLog(request.getRequestURL().toString(),request.getRemoteAddr(), JSON.toJSONString(CommonAop.getAopParam(pjp),SerializerFeature.WriteMapNullValue),request.getMethod(),JSON.toJSONString(object,SerializerFeature.WriteMapNullValue)); }catch (Exception e){ e.printStackTrace(); } return object; } @AfterReturning(value = "executeController()",returning = "rtv") public void after(JoinPoint joinPoint, Object rtv){ logger.info("before return+++++++++++++++++++++++++++"); logger.info("responseBody:"+JSON.toJSONString(rtv,SerializerFeature.WriteMapNullValue)); logger.info("end return++++++++++++++++++++++++++++++++"); } }
CommonAop
public class CommonAop { public static Map<String,Object> getAopParam(JoinPoint joinPoint){ //The method obtained in this step may be either proxy method or real method. Method m = ((MethodSignature) joinPoint.getSignature()).getMethod(); //To determine whether the proxy object itself is the target object of the join point, if not, we need to retrieve the real method by reflection. if (joinPoint.getThis().getClass() != joinPoint.getTarget().getClass()) { m = ReflectUtil.getMethod(joinPoint.getTarget().getClass(), m.getName(), m.getParameterTypes()); } //Get the list of entry points for the join point method runtime Object[] args = joinPoint.getArgs(); return CommonAop.getParam(m,args); } public static Map<String,Object> getParam(Method m,Object[] args){ //Getting the parameter name of this method by real method LocalVariableTableParameterNameDiscoverer paramNames = new LocalVariableTableParameterNameDiscoverer(); String[] parameterNames = paramNames.getParameterNames(m); //One-to-one correspondence between parameter names and input values Map<String, Object> params = new HashMap<>(); if (!TextUtil.isEmpty(parameterNames)){ for (int i = 0; i < parameterNames.length; i++) { if (TextUtil.isEmpty(args[i])){ continue; } //Get values through all class transformations, including all kinds of encapsulated classes ObjectMapper objectMapper = new ObjectMapper(); objectMapper.convertValue(args[i],args[i].getClass()); params.put(parameterNames[i], JSON.toJSON(objectMapper.convertValue(args[i],args[i].getClass()))); } } return params; } }