1.记录日志

使用aop来记录controller中的请求返回日志

pom.xml引入:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>

在完成了引入AOP依赖包后,一般来说并不需要去做其他配置。也许在Spring中使用过注解配置方式的人会问是否需要在程序主类中增加@EnableAspectJAutoProxy来启用,实际并不需要。

可以看下面关于AOP的默认配置属性,其中spring.aop.auto属性默认是开启的,也就是说只要引入了AOP依赖后,默认已经增加了@EnableAspectJAutoProxy。

# AOP
spring.aop.auto=true # Add @EnableAspectJAutoProxy.
spring.aop.proxy-target-class=false # Whether subclass-based (CGLIB) proxies are to be created (true) as opposed to standard Java interface-based proxies (false).

1.使用Around

@Aspect
@Component
public class ControllerAspect {
private Logger logger = LoggerFactory.getLogger(getClass()); /**
* Controller aspect.
*/
@Pointcut("execution(* com.shitou.huishi.service..*.*(..))")
public void controllerAspect() {
} /**
* Around 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
* <p>
* 注意:当核心业务抛异常后,立即退出,转向AfterAdvice 执行完AfterAdvice,再转到ThrowingAdvice
*
* @param pjp
* the pjp
* @return object
* @throws Throwable
* the throwable
*/
@Around(value = "controllerAspect()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
HttpServletRequest request = sra.getRequest(); logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName());
logger.info("REQUEST ARGS : " + JSON.toJSONString(pjp.getArgs())); long startTime = System.currentTimeMillis();
try {
Object response = pjp.proceed();
// 2.打印出参,返回结果
long endTime = System.currentTimeMillis();
// 3.出参打印
logger.info("RESPONSE:{}", response != null ? JSON.toJSONString(response) : "");
logger.info("SPEND TIME : {}ms", (endTime - startTime));
return response;
} catch (AuthException e) {
logger.info("RESPONSE ERROR:{}", e.getMsg());
throw e;
} catch (HuishiApiException e) {
logger.info("RESPONSE ERROR:{}", e.getMsg());
throw e;
} catch (MethodArgumentNotValidException e) {
logger.info("RESPONSE ERROR:{}", e.getMessage());
throw e;
} catch (Throwable e) {
logger.error("RESPONSE ERROR:{}", Arrays.toString(e.getStackTrace()));
throw e;
} finally {
long endTime = System.currentTimeMillis();
logger.error("SPEND TIME : {}ms", (endTime - startTime));
}
}
}

2.使用Before,AfterReturning处理:

import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; /**
* Created by qhong on 2018/5/28 14:25
**/
@Aspect
@Component
public class LogAspect {
private Logger logger = LoggerFactory.getLogger(getClass()); ThreadLocal<Long> startTime = new ThreadLocal<>(); @Pointcut("execution(public * com.shitou.huishi.service.*.*(..))")
public void logAspect(){} @Before("logAspect()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
startTime.set(System.currentTimeMillis()); // 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest(); // 记录下请求内容
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 : " + Arrays.toString(joinPoint.getArgs())); } @AfterReturning(returning = "ret", pointcut = "logAspect()")
public void doAfterReturning(Object ret) throws Throwable {
// 处理完请求,返回内容
logger.info("RESPONSE : " + ret);
logger.info("SPEND TIME : " + (System.currentTimeMillis() - startTime.get()));
}
}

两种方式计算出来的时间,参数,返回体是一样的。

完善版本:

import com.alibaba.fastjson.JSON;
import com.shitou.huishi.contract.datacontract.exception.AuthException;
import com.shitou.huishi.contract.datacontract.exception.HuishiApiException;
import java.util.Arrays;
import javax.servlet.http.HttpServletRequest;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; /**
* 类描述: 日志拦截器,打印controller层的入参和出参<br> 创建时间: 2016/7/29 0029 <br>
*
* @author 李恒
*/
@Aspect
@Component
public class ControllerAspect { private Logger logger = LoggerFactory.getLogger(getClass()); /**
* Controller aspect.
*/
@Pointcut("execution(* com.shitou.huishi.service..*.*(..))")
public void controllerAspect() {
} /**
* Around 手动控制调用核心业务逻辑,以及调用前和调用后的处理,
* <p>
* 注意:当核心业务抛异常后,立即退出,转向AfterAdvice 执行完AfterAdvice,再转到ThrowingAdvice
*
* @param pjp the pjp
* @return object
* @throws Throwable the throwable
*/
@Around(value = "controllerAspect()")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
//防止不是http请求的方法,例如:scheduled
if (ra == null || sra == null) {
return pjp.proceed();
}
HttpServletRequest request = sra.getRequest(); logger.info("URL : " + request.getRequestURL().toString());
logger.info("HTTP_METHOD : " + request.getMethod());
logger.info("IP : " + request.getRemoteAddr());
logger.info("CLASS_METHOD : " + pjp.getSignature().getDeclaringTypeName() + "." + pjp.getSignature().getName());
logger.info("REQUEST ARGS : " + JSON.toJSONString(pjp.getArgs())); long startTime = System.currentTimeMillis();
try {
Object response = pjp.proceed();
// 3.出参打印
logger.info("RESPONSE:{}", response != null ? JSON.toJSONString(response) : "");
return response;
} catch (Throwable e) {
if (e instanceof AuthException) {
logger.info("RESPONSE ERROR:{}", ((AuthException) e).getMsg());
} else if (e instanceof HuishiApiException) {
logger.info("RESPONSE ERROR:{}", ((HuishiApiException) e).getMsg());
} else if (e instanceof MethodArgumentNotValidException) {
logger.info("RESPONSE ERROR:{}", e.getMessage());
} else {
logger.error("RESPONSE ERROR:{}", Arrays.toString(e.getStackTrace()));
}
throw e;
} finally {
long endTime = System.currentTimeMillis();
logger.info("SPEND TIME : {}ms", (endTime - startTime));
}
}
}

http://blog.didispace.com/springbootaoplog/

http://blog.didispace.com/springbootexception/

SpringBoot 全局统一记录日志的更多相关文章

  1. SpringBoot开发二十三-统一记录日志

    统一记录日志 AlphaAspect package com.nowcoder.community.aspect; import org.aspectj.lang.ProceedingJoinPoin ...

  2. SpringBoot异常处理统一封装我来做-使用篇

    SpringBoot异常处理统一封装我来做-使用篇 简介 重复功能我来写.在 SpringBoot 项目里都有全局异常处理以及返回包装等,返回前端是带上succ.code.msg.data等字段.单个 ...

  3. spring boot 2 全局统一返回RESTful风格数据、统一异常处理

    全局统一返回RESTful风格数据,主要是实现ResponseBodyAdvice接口的方法,对返回值在输出之前进行修改.使用注解@RestControllerAdvice拦截异常并统一处理. 开发环 ...

  4. Springboot项目统一异常处理

    Springboot项目统一异常处理 一.接口返回值封装 1. 定义Result对象,作为通用返回结果封装 2. 定义CodeMsg对象,作为通用状态码和消息封装 二.定义全局异常类 三.定义异常处理 ...

  5. SpringBoot全局异常拦截

    SpringBoot全局异常捕获 使用到的技能 @RestControllerAdvice或(@ControllerAdvice+@ResponseBody) @ExceptionHandler 代码 ...

  6. SpringBoot全局时间转换器

    SpringBoot全局时间转换器 日常开发中,接收时间类型参数处处可见,但是针对不同的接口.往往需要的时间类型不一致 @DateTimeFormat(pattern = "yyyy-MM- ...

  7. SpringBoot 如何统一后端返回格式?老鸟们都是这样玩的!

    大家好,我是飘渺. 今天我们来聊一聊在基于SpringBoot前后端分离开发模式下,如何友好的返回统一的标准格式以及如何优雅的处理全局异常. 首先我们来看看为什么要返回统一的标准格式? 为什么要对Sp ...

  8. SpringBoot 如何统一后端返回格式

    在前后端分离的项目中后端返回的格式一定要友好,不然会对前端的开发人员带来很多的工作量.那么SpringBoot如何做到统一的后端返回格式呢?今天我们一起来看看. 为什么要对SpringBoot返回统一 ...

  9. GUID 全局统一标识符的介绍

    GUID(全局统一标识符)是指在一台机器上生成的数字,它保证对在同一时空中的所有机器都是唯一的.通常平台会提供生成GUID的API.生成算法很有意思,用到了以太网卡地址.纳秒级时间.芯片ID码和许多可 ...

随机推荐

  1. strlen实现

    1.strlen函数. 普通版实现方法, int strlen( char *s) { int length = 0; while(*s++) length++; return length; } 优 ...

  2. 向SQL Server中导入Excel的数据

    1.  手动界面导入Excel数据 同 https://jingyan.baidu.com/article/ce09321b9a0e252bff858ff9.html 首先打开并登陆sql serve ...

  3. Memento Mori (二维前缀和 + 枚举剪枝)

    枚举指的是枚举矩阵的上下界,然后根据p0, p1, p2的关系去找出另外的中间2个点.然后需要记忆化一些地方防止重复减少时间复杂度.这应该是最关键的一步优化时间,指的就是代码中to数组.然后就是子矩阵 ...

  4. 【Hbase学习之二】Hbase 搭建

    环境 虚拟机:VMware 10 Linux版本:CentOS-6.5-x86_64 客户端:Xshell4 FTP:Xftp4 jdk8 hadoop-3.1.1 hbase-2.1.3 一.单机模 ...

  5. 1.python虚拟环境的安装-用以同时使用py2,py3

    第一步:安装环境支持[linux下在前加sudo] http://www.lfd.uci.edu/~gohlke/pythonlibs/#pycurl pip install virtualenv 第 ...

  6. File §1

    The Class of File, it can be seen as one document, also can be seen as list of documents. File  f = ...

  7. DNN模型训练词向量原理

    转自:https://blog.csdn.net/fendouaini/article/details/79821852 1 词向量 在NLP里,最细的粒度是词语,由词语再组成句子,段落,文章.所以处 ...

  8. flask上下文全局变量,程序上下文、请求上下文、上下文钩子

    Flask上下文 Flask中有两种上下文,程序上下文(application context)和请求上下文(request context) 当客户端发来请求时,请求上下文就登场了.请求上下文里包含 ...

  9. TensorFlow 1.2.0新版本完美支持Python3.6,windows在cmd中输入pip install tensorflow就能下载应用最新tensorflow

    TensorFlow 1.2.0新版本完美支持Python3.6,windows在cmd中输入pip install tensorflow就能下载应用最新tensorflow 只需在cmd中输入pip ...

  10. 新做了块avr开发板--tft屏研究用

    2010-05-04 14:03:00 测试效果不错,使用也方便.