springboot + AOP 日志

一. 简介
            记录日志方便排错,记录操作记录。通常有俩层需要加日志:controller层和service层。

            controller层的日志使用Log打印信息,service层的日志使用数据库记录操作日志。

Controller层    
通过添加一个AOP切面,监控controller层的所有方法:

调用之前打印请求信息,包含URL,HTTP_METHOD,IP,CLASS_METHOD,ARGS;

在方法完成后,打印返回的请求结果,包含code, msg。

ServiceImpl层    
创建一张日志表sys_log, 创建一个SysLogService接口和一个SysLogServiceImpl实现类。里面包含一个saveSysLog(...)方法,该方法加@Transactional注解,内置的传播行为为PROPAGATION_REQUIRES_NEW。

在每个其他的service层中注入SysLogService,在每个方法最后加一个插入日志表的操作。

此处不展示。

二. 代码
2.1 切面类
package com.yss.shopping.aspect;
 
import com.alibaba.fastjson.JSONObject;
import com.yss.shopping.vo.ResultVO;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
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.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
 
import javax.servlet.http.HttpServletRequest;
 
/**
 * 日志切面类
 */
@Aspect
@Component
@Slf4j
public class LogAspect {
 
    /**
     * ..表示包及子包 该方法代表controller层的所有方法  TODO 路径需要根据自己项目定义
     */
    @Pointcut("execution(public * com.yss.shopping.controller..*.*(..))")
    public void controllerMethod() {
    }
 
 
    /**
     * 方法执行前
     *
     * @param joinPoint
     * @throws Exception
     */
    @Before("controllerMethod()")
    public void LogRequestInfo(JoinPoint joinPoint) throws Exception {
 
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
 
        StringBuilder requestLog = new StringBuilder();
        Signature signature = joinPoint.getSignature();
        requestLog.append(((MethodSignature) signature).getMethod().getAnnotation(ApiOperation.class).value()).append("\t")
                .append("请求信息:").append("URL = {").append(request.getRequestURI()).append("},\t")
                .append("请求方式 = {").append(request.getMethod()).append("},\t")
                .append("请求IP = {").append(request.getRemoteAddr()).append("},\t")
                .append("类方法 = {").append(signature.getDeclaringTypeName()).append(".")
                .append(signature.getName()).append("},\t");
 
        // 处理请求参数
        String[] paramNames = ((MethodSignature) signature).getParameterNames();
        Object[] paramValues = joinPoint.getArgs();
        int paramLength = null == paramNames ? 0 : paramNames.length;
        if (paramLength == 0) {
            requestLog.append("请求参数 = {} ");
        } else {
            requestLog.append("请求参数 = [");
            for (int i = 0; i < paramLength - 1; i++) {
                requestLog.append(paramNames[i]).append("=").append(JSONObject.toJSONString(paramValues[i])).append(",");
            }
            requestLog.append(paramNames[paramLength - 1]).append("=").append(JSONObject.toJSONString(paramValues[paramLength - 1])).append("]");
        }
 
        log.info(requestLog.toString());
    }
 
 
    /**
     * 方法执行后
     *
     * @param resultVO
     * @throws Exception
     */
    @AfterReturning(returning = "resultVO", pointcut = "controllerMethod()")
    public void logResultVOInfo(ResultVO resultVO) throws Exception {
        log.info("请求结果:" + resultVO.getCode() + "\t" + resultVO.getMsg());
    }
 
 
}
注意:

        如果有BaseController的话,不需要被日志扫描,可以通过添加不扫描路径即可。如下:

   

2.2 ResultVO类
package com.yzx.codedemo.vo;
 
import io.swagger.annotations.ApiModelProperty;
 
/**
 * 返回结果类
 *
 * @param <T> 类型
 */
 
public class ResultVO<T> {
 
    @ApiModelProperty("状态码 0失败 1成功 ")
    private Integer code;
    @ApiModelProperty("返回信息")
    private String msg;
    @ApiModelProperty("返回数据")
    private T data;
 
    public ResultVO(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
 
    public ResultVO(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
 
    /**
     * 请求成功  状态码 1
     *
     * @param msg 返回信息
     * @param <T> 类型
     * @return ResultVO
     */
    public static <T> ResultVO getSuccess(String msg) {
        return new ResultVO(1, msg);
    }
 
    /**
     * 请求成功  状态码 1
     *
     * @param msg  返回信息
     * @param data 返回对象
     * @param <T>  类型
     * @return ResultVO
     */
    public static <T> ResultVO getSuccess(String msg, T data) {
        return new ResultVO(1, msg, data);
    }
 
    /**
     * 请求失败   状态码 0
     *
     * @param msg 返回信息
     * @param <T> 类型
     * @return ResultVO
     */
    public static <T> ResultVO getFailed(String msg) {
        return new ResultVO(0, msg);
    }
 
    /**
     * 请求失败  状态 0
     *
     * @param msg  返回信息
     * @param data 返回数据
     * @param <T>  类型
     * @return ResultVO
     */
    public static <T> ResultVO getFailed(String msg, T data) {
        return new ResultVO(0, msg, data);
    }
 
 
    public Integer getCode() {
        return code;
    }
 
    public void setCode(Integer code) {
        this.code = code;
    }
 
    public String getMsg() {
        return msg;
    }
 
    public void setMsg(String msg) {
        this.msg = msg;
    }
 
    public T getData() {
        return data;
    }
 
    public void setData(T data) {
        this.data = data;
    }
 
}
2.3 Controller类
package com.yzx.codedemo.controller.user;
 
import com.yzx.codedemo.entity.user.SysUser;
import com.yzx.codedemo.service.user.SysUserService;
import com.yzx.codedemo.vo.PageVO;
import com.yzx.codedemo.vo.ResultVO;
import com.yzx.codedemo.vo.user.SysUserVO;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
 
import java.util.List;
 
@Api(tags = {"SysUserController"}, description = "用户Controller")
@RestController
@RequestMapping(value = "/sysuser")
public class SysUserController {
 
    @Autowired
    private SysUserService sysUserService;
 
 
    @ApiOperation("查询用户分页列表")
    @ApiImplicitParams({
            @ApiImplicitParam(paramType = "query", dataType = "Long", name = "currentPage", value = "当前页码", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "Long", name = "pageSize", value = "每页记录数", required = true),
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "userName", value = "用户名称", required = false),
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "phone", value = "手机号", required = false),
            @ApiImplicitParam(paramType = "query", dataType = "Long", name = "userState", value = "用户状态: 0删除 1正常", required = false),
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "starttime", value = "开始时间 格式:yyyy-MM-dd HH:mm:ss", required = false),
            @ApiImplicitParam(paramType = "query", dataType = "String", name = "endtime", value = "结束时间 格式:yyyy-MM-dd HH:mm:ss", required = false)
    })
    @GetMapping(value = "/page")
    public ResultVO<PageVO<SysUserVO>> selectSysUserPage(@ApiIgnore SysUserVO sysUserVO) {
        try {
            return this.sysUserService.selectSysUserPage(sysUserVO);
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVO.getSuccess("查询用户分页列表失败");
        }
    }
 
 
}
2.3 测试
每次调用controller层的代码的方法,都会打印日志信息:

2018-08-22 16:17:12.251  INFO 12200 --- [nio-8080-exec-1] com.yzx.codedemo.aspect.LogAspect        : 请求信息:URL = {/sysuser/page},    HTTP_METHOD = {GET},    IP = {0:0:0:0:0:0:0:1},    CLASS_METHOD = {com.yzx.codedemo.controller.user.SysUserController.selectSysUserPage},    ARGS = {"currentPage":1,"pageSize":10}
2018-08-22 16:17:12.319 DEBUG 12200 --- [nio-8080-exec-1] c.y.c.m.u.S.selectSysUserPage_COUNT      : ==>  Preparing: SELECT count(0) FROM sys_user WHERE 1 = 1 
2018-08-22 16:17:12.336 DEBUG 12200 --- [nio-8080-exec-1] c.y.c.m.u.S.selectSysUserPage_COUNT      : ==> Parameters: 
2018-08-22 16:17:12.351 DEBUG 12200 --- [nio-8080-exec-1] c.y.c.m.u.S.selectSysUserPage_COUNT      : <==      Total: 1
2018-08-22 16:17:12.356 DEBUG 12200 --- [nio-8080-exec-1] c.y.c.m.u.S.selectSysUserPage            : ==>  Preparing: SELECT id AS user_id, user_name, password, phone, createtime FROM sys_user WHERE 1=1 ORDER BY createtime DESC LIMIT ? 
2018-08-22 16:17:12.357 DEBUG 12200 --- [nio-8080-exec-1] c.y.c.m.u.S.selectSysUserPage            : ==> Parameters: 10(Integer)
2018-08-22 16:17:12.363 DEBUG 12200 --- [nio-8080-exec-1] c.y.c.m.u.S.selectSysUserPage            : <==      Total: 10
2018-08-22 16:17:12.365  INFO 12200 --- [nio-8080-exec-1] com.yzx.codedemo.aspect.LogAspect        : 请求结果:1    查询分页列表成功
 
————————————————
版权声明:本文为CSDN博主「请叫我猿叔叔」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35206261/article/details/81945618

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值