【功能】自定义记录日志注解

目录

  • 1、 引入依赖
  • 2、 添加数据库表
  • 3、 创建实体
  • 4、 创建枚举
  • 5、 创建Mapper(可忽略)
  • 6、 创建Service
  • 7、 创建注解切面配置类
  • 8、 使用方式

--------------------------------------------------------------------------------------------------------

1、 引入依赖

注意: 缺失依赖可能导致切面注解不生效。

        <dependency>
            <groupId>mysqlgroupId>
            <artifactId>mysql-connector-javaartifactId>
            <scope>8.0.12scope>
        dependency>
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjrtartifactId>
            <version>1.9.4version>
        dependency>
        <dependency>
            <groupId>org.aspectjgroupId>
            <artifactId>aspectjweaverartifactId>
            <version>1.9.2version>
        dependency>

2、 添加数据库表

CREATE TABLE `sys_log`  (
  `oper_id` varchar(50) NOT NULL AUTO_INCREMENT COMMENT '日志主键',
  `title` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '模块标题',
  `business_type` int(11) NULL DEFAULT 0 COMMENT '业务类型(0其它 1新增 2修改 3删除)',
  `method` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '方法名称',
  `request_method` varchar(10) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求方式',
  `operator_type` int(11) NULL DEFAULT 0 COMMENT '操作类别( 0、用户端   1、平台管理端)',
  `oper_name` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作人员',
  `oper_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求URL',
  `oper_ip` varchar(128) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '主机地址',
  `oper_location` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '操作地点',
  `oper_param` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '请求参数',
  `json_result` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '返回参数',
  `status` int(11) NULL DEFAULT 0 COMMENT '操作状态(1正常 0异常)',
  `error_msg` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '错误消息',
  `oper_time` datetime(0) NULL DEFAULT NULL COMMENT '操作时间',
  PRIMARY KEY (`oper_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3166 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '操作日志记录' ROW_FORMAT = COMPACT;

3、 创建实体

package com.xiaobai.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.Date;

/**
 * @Author 小白
 * @Date 2023/3/9 11:22
 * @description: 操作日志记录
 * @Title: Log
 * @Package com.xiaobai.entity
 */
@Data
@TableName("sys_log")
@ApiModel(value="Log对象", description="操作日志记录")
public class Log {

    private static final long serialVersionUID = 1L;

    @TableId(type = IdType.AUTO)
    @ApiModelProperty(value = "日志主键")
    private String operId;

    @ApiModelProperty(value = "模块标题")
    private String title;

    @ApiModelProperty(value = "业务类型(0其它 1新增 2修改 3删除 4查询)")
    private Integer businessType;

    @ApiModelProperty(value = "方法名称")
    private String method;

    @ApiModelProperty(value = "请求方式")
    private String requestMethod;

    @ApiModelProperty(value = "操作人员")
    private String operName;

    @ApiModelProperty(value = "请求URL")
    private String operUrl;

    @ApiModelProperty(value = "主机地址")
    private String operIp;

    @ApiModelProperty(value = "请求参数")
    private String operParam;

    @ApiModelProperty(value = "返回参数")
    private String jsonResult;

    @ApiModelProperty(value = "操作状态(0正常 1异常)")
    private String status;

    @ApiModelProperty(value = "错误消息")
    private String errorMsg;

    @ApiModelProperty(value = "操作时间")
    private Date operTime;


}

4、 创建枚举

package com.xiaobai.enumerations;

/**
 * @Author 小白
 * @Date 2023/3/9 13:02
 * @description: 日志类型枚举
 * @Title: LogTypeEnum
 * @Package com.xiaobai.enumerations
 */
public enum LogTypeEnum {
    /**
     * 其它
     */
    OTHER,

    /**
     * 新增
     */
    INSERT,

    /**
     * 修改
     */
    UPDATE,

    /**
     * 删除
     */
    DELETE,

    /**
     * 查询
     */
    SEARCH,

    /**
     * 授权
     */
    GRANT,

    /**
     * 导出
     */
    EXPORT,

    /**
     * 导入
     */
    IMPORT,
}

5、 创建Mapper(可忽略)

package com.xiaobai.mapper;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xiaobai.entity.Log;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Param;

/**
 * @Author 小白
 * @Date 2023/3/9 13:13
 * @description:
 * @Title: LogMapper
 * @Package com.xiaobai.mapper
 */
public interface AutoLogMapper extends BaseMapper<Log> {
    @Insert("INSERT INTO sys_log (oper_id,title,business_type,method,request_method,oper_name,oper_ip,oper_param,json_result,status,error_msg,oper_url,oper_time)" +
            "values(" +
            "#{log.operId},#{log.title},#{log.businessType},#{log.method},#{log.requestMethod}," +
            "#{log.operName},#{log.operIp}," +
            "#{log.operParam},#{log.jsonResult}," +
            "#{log.status},#{log.errorMsg},#{log.operUrl},#{log.operTime})")
    boolean add(@Param("log") Log log);
}

6、 创建Service

package com.xiaobai.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.xiaobai.entity.Log;

/**
 * @Author 小白
 * @Date 2023/3/9 13:12
 * @description:
 * @Title: LogService
 * @Package com.xiaobai.service
 */
public interface AutoLogService extends IService<Log> {
    boolean save(Log log);
}

package com.xiaobai.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xiaobai.entity.Log;
import com.xiaobai.mapper.AutoLogMapper;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

/**
 * @Author 小白
 * @Date 2023/3/9 13:12
 * @description:
 * @Title: LogServiceImpl
 * @Package com.xiaobai.service
 */
@Service
public class AutoLogServiceImpl extends ServiceImpl<AutoLogMapper, Log> implements AutoLogService {
    @Resource
    private AutoLogMapper autoLogMapper;
    public boolean save(Log log){
        return autoLogMapper.add(log);
    }
}

7、 创建注解切面配置类

重点来了,友友们~

package com.xiaobai.config;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.xiaobai.annotation.AutoLog;
import com.xiaobai.entity.Log;
import com.xiaobai.service.AutoLogService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
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.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.UUID;

/**
 * @Author 小白
 * @Date 2023/3/9 13:03
 * @description: 日志配置
 * @Title: LogConfig
 * @Package com.xiaobai.config
 */
@Slf4j
@Aspect
@Component
public class AutoLogConfig {
        @Autowired
        private AutoLogService uxmLogService;

        /**
         * 后置通过,⽬标⽅法正常执⾏完毕时执⾏
         *
         */
        @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
        public void doAfterReturning(JoinPoint joinPoint, AutoLog controllerLog, Object jsonResult) {
                handleLog(joinPoint, controllerLog, null, jsonResult);
        }

        /**
         * 异常通知,⽬标⽅法发⽣异常的时候执⾏
         *
         */
        @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
        public void doAfterThrowing(JoinPoint joinPoint, AutoLog controllerLog, Exception e) {
                handleLog(joinPoint, controllerLog, e, null);
        }

        protected void handleLog(final JoinPoint joinPoint, AutoLog controllerLog, final Exception e, Object jsonResult) {
                try {
                        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
                        ApiOperation operation = methodSignature.getMethod().getAnnotation(ApiOperation.class);
                        String title = null;
                        if (ObjectUtils.isNotNull(operation)){
                                title = operation.value();
                        }
                        // 获取当前的用户
                        String userName = "";

                        // *========数据库日志=========*//
                        Log uxmLog = new Log();
                        uxmLog.setOperId(UUID.randomUUID() + "".replace("-",""));
                        uxmLog.setStatus("0");
                        // 请求的地址
                        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
                        assert requestAttributes != null;
                        HttpServletRequest request = requestAttributes.getRequest();
                        String ip = getIpAddr(request);
                        // 设置标题
                        uxmLog.setTitle(title);
                        // 设置ip
                        uxmLog.setOperIp(ip);
                        // 设置请求路径
                        uxmLog.setOperUrl(request.getRequestURI());
                        // 操作人
                        uxmLog.setOperName(userName);

                        if (e != null) {
                                uxmLog.setStatus("1");
                                uxmLog.setErrorMsg(e.getMessage());
                        }
                        // 设置方法名称
                        String className = joinPoint.getTarget().getClass().getName();
                        String methodName = joinPoint.getSignature().getName();
                        uxmLog.setMethod(className + "." + methodName + "()");
                        // 设置请求方式
                        uxmLog.setRequestMethod(request.getMethod());
                        // 处理设置注解上的参数
                        getControllerMethodDescription(joinPoint, controllerLog, uxmLog, jsonResult, request);
                        // 保存数据库
                        uxmLog.setOperTime(new Date());
                        uxmLogService.save(uxmLog);
                } catch (Exception exp) {
                        // 记录本地异常日志
                        log.error("==前置通知异常==");
                        log.error("异常信息:{}", exp.getMessage());
                        exp.printStackTrace();
                }
        }

        public static String getIpAddr(HttpServletRequest request) {
                if (request == null) {
                        return "unknown";
                }
                String ip = request.getHeader("x-forwarded-for");
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                        ip = request.getHeader("Proxy-Client-IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                        ip = request.getHeader("X-Forwarded-For");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                        ip = request.getHeader("WL-Proxy-Client-IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                        ip = request.getHeader("X-Real-IP");
                }
                if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
                        try {
                                ip = InetAddress.getLocalHost().getHostAddress();
                        } catch (UnknownHostException e) {
                                throw new RuntimeException(e);
                        }
                }
                return ip;
        }

        public void getControllerMethodDescription(JoinPoint joinPoint, AutoLog autoLog, Log uxmLog, Object jsonResult, HttpServletRequest request) throws Exception {
                // 设置action动作
                uxmLog.setBusinessType(autoLog.value().ordinal());
                // 是否需要保存request,参数和值
                if (autoLog.isSaveRequestData()) {
                        // 获取参数的信息,传入到数据库中。
                        setRequestValue(joinPoint, uxmLog, request);
                }
                // 是否需要保存response,参数和值
                if (autoLog.isSaveResponseData()) {
                        uxmLog.setJsonResult(JSON.toJSONString(jsonResult));
                }
        }

        private void setRequestValue(JoinPoint joinPoint, Log uxmLog, HttpServletRequest request) throws Exception {
                String requestMethod = uxmLog.getRequestMethod();
                if (RequestMethod.PUT.name().equals(requestMethod) || RequestMethod.POST.name().equals(requestMethod)) {
                        String params = argsArrayToString(joinPoint.getArgs());
                        uxmLog.setOperParam(params);
                } else {
                        Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
                        uxmLog.setOperParam(paramsMap.toString());
                }
        }

        private String argsArrayToString(Object[] paramsArray) {
                StringBuilder params = new StringBuilder();
                if (paramsArray != null && paramsArray.length > 0) {
                        for (Object o : paramsArray) {
                                if (ObjectUtils.isNotNull(o) && !isFilterObject(o)) {
                                        try {
                                                Object jsonObj = JSON.toJSON(o);
                                                params.append(jsonObj.toString()).append(" ");
                                        } catch (Exception e) {
                                                log.error(e.getMessage());
                                        }
                                }
                        }
                }
                return params.toString().trim();
        }

        @SuppressWarnings("rawtypes")
        public boolean isFilterObject(final Object o) {
                Class<?> clazz = o.getClass();
                if (clazz.isArray()) {
                        return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
                } else if (Collection.class.isAssignableFrom(clazz)) {
                        Collection collection = (Collection) o;
                        for (Object value : collection) {
                                return value instanceof MultipartFile;
                        }
                } else if (Map.class.isAssignableFrom(clazz)) {
                        Map map = (Map) o;
                        for (Object value : map.entrySet()) {
                                Map.Entry entry = (Map.Entry) value;
                                return entry.getValue() instanceof MultipartFile;
                        }
                }
                return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
                        || o instanceof BindingResult;
        } 
}

8、 使用方式

    @ApiOperation("测试方法")
    @AutoLog(LogTypeEnum.OTHER)
    @GetMapping("/test")
    public String test(){
       return "hello";
    }

【功能】自定义记录日志注解_第1张图片
成功~~~

--------------------------------------------------------------------------------------------------------
本文部分借鉴自:JAVA 使用自定义注解实现插入日志操作功能

你可能感兴趣的:(java,数据库,java,mysql,spring,boot)