采用AOP机制,通过接口配置形式统一记录写入日志库

设置注解配置类

注解类代码如下:

import com.pub.enums.LogOperationTypeEnum;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;


/**
 *
 */
@Documented
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LogAnnotation {

    /**
     * 菜单,多级用'/'分隔,最多三级
     */
    String classMenu();

    /**
     * 功能名称
     *
     * @return
     */
    String funcName();

    /**
     * 操作类型
     *
     * @see LogOperationTypeEnum
     */
    LogOperationTypeEnum operType();

}

增加AOP切面类

Aspect切面类代码如下:

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.pub.config.mvc.AuthContext;
import com.pub.enums.LogOperationTypeEnum;
import com.pub.param.base.CommonResponse;
import com.pub.param.req.IdStatusParam;
import com.pub.param.resp.SysLogBO;
import com.pub.param.resp.UserEditVo;
import com.pub.param.resp.UserVo;
import com.pub.service.impl.RedisService;
import com.pub.service.interfacetask.SysLogService;
import com.pub.util.DateUtil;
import com.pub.util.IpUtil;
import com.pub.util.JsonUtils;
import com.pub.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.annotation.Annotation;
import java.util.Date;
import java.util.Map;
import java.util.Objects;


/**
 *
 */
@Slf4j
@Aspect
@Component
public class LogAopAspect {

    @Autowired
    private SysLogService sysLogService;

    @Autowired
    private RedisService redisService;


    @Pointcut(value = "@annotation(com.pub.aop.LogAnnotation)")
    public void logPointCut() {
    }


    @AfterReturning(value = "logPointCut()&& @annotation(logAnnotation)", returning = "result")
    public void afterReturn(JoinPoint joinPoint, LogAnnotation logAnnotation, Object result) {
        log.info("AfterReturning 开始记录日志.");
        SysLogBO sysOperLogBo = new SysLogBO();
        CommonResponse responseVo = getResponseVo(result);
        sysOperLogBo.setOperationDetail(responseVo.getCode() + "-" + responseVo.getMessage());
        processLog(joinPoint, sysOperLogBo, logAnnotation);
    }


    /**
     * 判断返回对象类型并处理,此处根据项目统一封装返回对象Bean进行调整即可
     */
    private CommonResponse getResponseVo(Object result) {
        CommonResponse responseVo = new CommonResponse<>();
        if (result instanceof CommonResponse) {
            responseVo = (CommonResponse) result;
        } else if (result instanceof ResponseEntity) {
            ResponseEntity responseEntity = (ResponseEntity) result;
            int code = responseEntity.getStatusCode().is2xxSuccessful() ? 0 : responseEntity.getStatusCode().value();
            responseVo.setCode(code + "");
            if (!responseEntity.getStatusCode().is2xxSuccessful()) {
                String body = JSON.toJSONString(responseEntity.getBody());
                //长度限制,以免超长记录入库失败
                responseVo.setMessage(body.length() >= 200 ? body.substring(0, 200) : body);
            }
            responseVo.setResult(responseEntity.getBody());
        } else {
            log.warn("aop getResponseVo result: {}", result);
        }
        return responseVo;
    }


    /**
     * 操作失败,记录异常处理
     *
     * @param joinPoint
     * @param logAnnotation
     * @param e
     */
    @AfterThrowing(value = "logPointCut() && @annotation(logAnnotation)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, LogAnnotation logAnnotation, Throwable e) {
        log.info("doAfterThrowing 开始记录日志.");
        SysLogBO sysOperLogBo = new SysLogBO();
        String comments = e.getMessage();
        if (StringUtils.isNotBlank(comments) && comments.length() > 256) {
            comments = comments.substring(0, 255);
        }
        sysOperLogBo.setOperationDetail(comments);
        processLog(joinPoint, sysOperLogBo, logAnnotation);
    }

    /**
     * 日志记录入库
     *
     * @param joinPoint
     * @param sysOperLogBo
     * @param logAnnotation
     */
    private void processLog(JoinPoint joinPoint, SysLogBO sysOperLogBo, LogAnnotation logAnnotation) {
        try {
            //记录用户信息
            UserVo sysUserDO = AuthContext.getUser();
            sysOperLogBo.setUserName(sysUserDO.getLoginNo());
            // 记录菜单
            String[] menus = logAnnotation.classMenu().split("/");
            if (menus.length >= 1) {
                sysOperLogBo.setFirstClassMenu(menus[0]);
            }
            if (menus.length >= 2) {
                sysOperLogBo.setSecondClassMenu(menus[1]);
            }
            if (menus.length >= 3) {
                sysOperLogBo.setThirdClassMenu(menus[2]);
            }
//            sysOperLogBo.setFuncName(logAnnotation.funcName());
            // 解析请求参数
            Object[] args = joinPoint.getArgs();
            HttpServletRequest httpServletRequest = null;
            for (Object object : args) {
                if (object instanceof HttpServletRequest) {
                    httpServletRequest = (HttpServletRequest) object;
                }
            }
            if (null == httpServletRequest) {
                httpServletRequest = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            }
            String requestURI = httpServletRequest.getRequestURI();
            if (requestURI.indexOf("hdp") > -1) {
                requestURI = requestURI.substring(requestURI.indexOf("hdp") + 3);
            }
            sysOperLogBo.setVisitUrl(requestURI);
            sysOperLogBo.setVisitIp(IpUtil.getRequestIp());
            //
            String sessionId = System.currentTimeMillis() + StringUtil.getUuid();
            HttpSession session = httpServletRequest.getSession();
            if (session != null) {
                sessionId = session.getId();
            }
            sysOperLogBo.setSessionId(sessionId);
            sysOperLogBo.setOperationTime(DateUtil.getYYYYMMDDHHMMSS(new Date()));
            sysOperLogBo.setOperationType(logAnnotation.operType().getDesc());
            // 获取请求方式, 获取请求内容类型,请求参数
            String requestMethod = httpServletRequest.getMethod();
            String contentType = httpServletRequest.getContentType();
            Object reqParamJson = getReqParamJson(joinPoint, httpServletRequest, requestMethod, contentType);
            log.info("reqParamJson: {}", reqParamJson);
            dealParamsLog(sysOperLogBo, reqParamJson, logAnnotation);

            // 持久化
            log.info(JSONObject.toJSONString(sysOperLogBo));
            sysLogService.saveSysLog(sysOperLogBo);
        } catch (Exception e) {
            log.error("aop deal insert log error: {}", e);
        }
    }

    /**
     * 根据参数处理业务日志类型
     *
     * @param sysOperLogBo
     * @param reqParamJson
     * @param logAnnotation
     */
    private void dealParamsLog(SysLogBO sysOperLogBo, Object reqParamJson, LogAnnotation logAnnotation) {
        if (Objects.isNull(reqParamJson)) {
            return;
        }
        // 用户启停
        if (logAnnotation.operType() == LogOperationTypeEnum.LOG_USER_DISABLE) {
            IdStatusParam statusParam = JsonUtils.toObject(JsonUtils.toJson(reqParamJson), IdStatusParam.class);
            // 用户帐号状态, 1正常 0加锁-未授权
            if (1 == statusParam.getStatus()) {
                sysOperLogBo.setOperationType(LogOperationTypeEnum.LOG_USER_ENABLE.getDesc());
            }
        }
        // 用户启用新增-编辑
        else if (logAnnotation.operType() == LogOperationTypeEnum.LOG_USER_EDIT) {
            UserEditVo editVo = JsonUtils.toObject(JsonUtils.toJson(reqParamJson), UserEditVo.class);
            // 新增/编辑标识,1编辑,0新增
            if (0 == editVo.getEdit()) {
                sysOperLogBo.setOperationType(LogOperationTypeEnum.LOG_USER_ENABLE.getDesc());
            }
            sysOperLogBo.setRemarks(editVo.getRemarks());
        }
    }

    /**
     * 获取请求参数JSON字符串
     *
     * @param joinPoint
     * @param request
     * @param requestMethod
     * @param contentType
     */
    private Object getReqParamJson(JoinPoint joinPoint, HttpServletRequest request, String requestMethod, String contentType) {
        // 判断控制器方法参数中,是否有RequestBody注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Annotation[][] annotations = signature.getMethod().getParameterAnnotations();
        boolean isRequestBody = false;
        for (Annotation[] annotationArray : annotations) {
            for (Annotation annotation : annotationArray) {
                if (annotation instanceof RequestBody) {
                    isRequestBody = true;
                    break;
                }
            }
        }
        /**
         * 判断请求内容类型
         * 通常有3中请求内容类型
         * 1.发送get请求时,contentType为null
         * 2.发送post请求时,contentType为application/x-www-form-urlencoded
         * 3.发送post json请求,contentType为application/json
         * 4.发送post json请求并有RequestBody注解,contentType为application/json
         */
        Object paramObject = null;
        int requestType = 0;
        if ("GET".equals(requestMethod)) {
            requestType = 1;
        } else if ("POST".equals(requestMethod)) {
            if (contentType == null) {
                requestType = 5;
            } else if (contentType.startsWith("application/x-www-form-urlencoded")) {
                requestType = 2;
            } else if (contentType.startsWith("application/json")) {
                if (isRequestBody) {
                    requestType = 4;
                } else {
                    requestType = 3;
                }
            }
        }
        // 1,2,3中类型时, 获取getParameterMap中所有的值, 处理后序列化成JSON字符串
        if (requestType == 1 || requestType == 2 || requestType == 3 || requestType == 5) {
            Map<String, String[]> paramsMap = request.getParameterMap();
            paramObject = paramsMap;
        } else if (requestType == 4) { // POST,application/json,RequestBody的类型,简单判断,然后序列化成JSON字符串
            Object[] args = joinPoint.getArgs();
            if (args == null) {
                paramObject = null;
            } else if (args.length == 1) {
                paramObject = args[0];
            } else {
                paramObject = args;
//                paramObject = args[0];
            }
        }
        return paramObject;
    }


}

其余代码举例

代码示例:

package com.pub.enums;

/**
 * 日志记录。 操作类型:1、系统登录,2、系统登出
 */
public enum LogOperationTypeEnum {


    LOG_TYPE_1(1, "系统登录"),
    LOG_TYPE_2(2, "系统登出"),

    // 新增账号 = 启用账号
    LOG_USER_ENABLE(12, "新增账号"),
    LOG_USER_DISABLE(13, "停用账号"),
    LOG_USER_EDIT(14, "编辑账号"),
    LOG_USER_BATCH_EDIT(15, "批量授权"),

    ;
    private final int code;
    private final String desc;


    LogOperationTypeEnum(int code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public int getCode() {
        return code;
    }

    public String getDesc() {
        return desc;
    }

    public static LogOperationTypeEnum getEnum(int code) {
        for (LogOperationTypeEnum logType : values()) {
            if (logType.getCode() == code) {
                return logType;
            }
        }
        return null;
    }

}

使用示例:

    /**
     * @param userVo
     * @return
     */
    @LogAnnotation(classMenu = "系统管理/用户管理", funcName = "用户编辑", operType = LogOperationTypeEnum.LOG_USER_EDIT)
    @PostMapping("/editUser")
    @Operation(summary = "编辑用户信息,修改角色")
    public CommonResponse<Boolean> editUser(@RequestBody @Valid UserEditVo userVo) {
	}
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;

import javax.validation.constraints.NotNull;
import java.io.Serializable;

/**
 * IdStatusParam
 */
@Data
@Schema(title = "主键状态参数")
public class IdStatusParam implements Serializable {

    private static final long serialVersionUID = 8159404372669135796L;
    @NotNull(message = "id不能为空")
    @Schema(title = "主键ID")
    private Integer id;

    // 若是:用户帐号状态, 1正常 0加锁-未授权
    @Schema(title = "状态")
    @NotNull(message = "状态不能为空")
    private Integer status;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值