Spring Boot AOP 记录系统操作日志和异常日志到数据库

登录存redis中保存50分钟

    @Autowired
    private RedisTemplate<String, Object> template;
    
    ValueOperations<String, Object> redisString = template.opsForValue();
    redisString.set("token:" + uuids, JSON.toJSONString(sysUser), 60 * 50, TimeUnit.SECONDS);//token有效期50分钟

拦截器

package com.xiaoq.store.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

/**
 * @author locken
 * @date 2022-08-23 20:51
 * @Description: -TOOD
 */
@Component
public class WebConfig extends WebMvcConfigurationSupport {

    @Autowired
    private MyInterceptorConfig myInterceptorConfig;

    /**
     * 添加接口请求拦截器  排除用户接口不用验证
     * @param registry
     */
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptorConfig)
                .addPathPatterns("/**")
//                .excludePathPatterns("/user/login");
                .excludePathPatterns("/sys/login","/captchaImage")
                .excludePathPatterns("/doc.html") //不需要拦截的地
                .excludePathPatterns("/swagger-resources/**")
                .excludePathPatterns("/webjars/**")
                .excludePathPatterns("/v2/**")
                .excludePathPatterns("/favicon.ico")
                .excludePathPatterns("/swagger-ui.html/**");
    }

    /*
     * @param registry
     * @return void
     * @introduction: 跨域支持
     * @date 2021/5/19 21:44
     */

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("*")
                .allowCredentials(true)
                .allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH", "OPTIONS", "HEAD")
                .maxAge(3600 * 24);
    }
    /**
     * 发现如果继承了WebMvcConfigurationSupport,则在yml中配置的相关内容会失效。 需要重新指定静态资源
     *
     * @param registry
     */
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations(
                "classpath:/static/");
        registry.addResourceHandler("swagger-ui.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations(
                "classpath:/META-INF/resources/webjars/");

        registry.addResourceHandler("doc.html").addResourceLocations(
                "classpath:/META-INF/resources/");
        super.addResourceHandlers(registry);
    }


}
package com.xiaoq.store.config;

import io.swagger.models.HttpMethod;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;

/**
 * @author locken
 * @date 2022-08-23 20:38
 * @Description: -TOOD
 */
@Configuration
@Component
@Slf4j
public class MyInterceptorConfig implements HandlerInterceptor {
    /**
     * 添加接口请求拦截器
     * @param request
     * @param resp
     * @param handler
     * @return
     * @throws Exception
     */
    public boolean preHandle(HttpServletRequest request, HttpServletResponse resp, Object handler) throws Exception {
        //打印请求内容
        log.info("==============preHandle======start====================");
        log.info("IP   :" + request.getRemoteAddr());
        log.info("URL  :" + request.getRequestURL().toString());
        log.info("HTTP Method   :" + request.getMethod());
        log.info("===============preHandle======End=====================");

        if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
            log.info("OPTIONS请求,放行");
            return true;
        }
        log.info("------------ MyInterceptorConfig...................");
        String token = request.getHeader("token");
        log.info("=============== MyInterceptorConfig token : {}", token);
        if (StringUtils.isBlank(token) ) {
            log.info("=============== 请求拦截 : {}", token);
            return false;
        }
        return true;
    }
}

登录

import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
    @Autowired
    private RedisTemplate<String, Object> template;

    @ApiOperation("登录")
    @PostMapping(value = "/login")
    @OperLog(operModul = "后台系统-登录", operDesc = "登录")
    public Result loginAdminUser(@RequestParam String username, @RequestParam String password, @RequestParam(required = false) String code, @RequestParam(required = false) String uuid) {
        validateCaptcha(code, uuid);
        Result<JSONObject> result = new Result<JSONObject>();
        SysUser sysUser = sysUserService.getBaseMapper().selectOne(new QueryWrapper<SysUser>().eq("username", username));
        if (ObjectUtil.isNotNull(sysUser)) {
            String decrypt = PasswordUtil.decrypt(sysUser.getPassword(), sysUser.getUsername(), sysUser.getSalt());
            if (decrypt.equals(password)) { 
                JSONObject obj = new JSONObject(); 
                //获取验证码并将之放入到redis中,一分钟后失效
                String uuids = IdUtils.getUUID();
                ValueOperations<String, Object> redisString = template.opsForValue();
                redisString.set("token:" + uuids, JSON.toJSONString(sysUser), 60 * 50, TimeUnit.SECONDS);//token有效期50分钟
                obj.put("token", uuids);
                obj.put("userInfo", sysUser);
                result.setData(obj);
                result.setCode(200);
                result.setMsg("登录成功");
                return result;
            } else {
                return result.setMsg("用户密码错误").setCode(400);
            }
        } else {
            return result.setMsg("当前用户不存在").setCode(400);
        }
    }

实体类UserToken

package com.xiaoq.store.entity;

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

@Data
@ApiModel(value = "用户token")
public class UserToken {

    @ApiModelProperty(value = "名称")
    private String username;
    @ApiModelProperty(value = "密码")
    private String password;

}

退出登录

    @Autowired
    private RedisTemplate<String, Object> template;
    /**
     * 退出登录
     *
     * @param request
     * @param response
     * @return
     */
    @ApiOperation("退出登录")
    @OperLog(operModul = "后台系统-退出登录", operDesc = "退出登录")
    @PostMapping(value = "/logout")
    public Result<Object> logout(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //用户退出逻辑
        String token = request.getHeader("token");
        if (oConvertUtils.isEmpty(token)) {
            return Result.fail("退出登录失败!");
        }
        UserToken userToken = TokenFactory.validateToken(request);
        log.info(" 用户名:  " + userToken.getUsername() + ",退出成功! ");
        //清空用户登录Token缓存
        template.delete("token:" + token);
        return Result.succeed("退出登录成功!");
    }

每一个请求都要加上@OperLog注解

    @ApiImplicitParams({@ApiImplicitParam(name = "email",value = "邮箱")})
    @ApiOperation("欢迎语  邀请二维码")
    @PostMapping(value = "welcome")
    @OperLog(operModul = "后台系统-欢迎语",operDesc = "欢迎语")
    public Result<Users> welcome(@RequestParam String email) {
    }

启动类上加入 @MapperScan("com.xiaoq.store.mapper") 更换成自己的mapper路径

pom

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>
         <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.4</version>
        </dependency>
          <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.54</version>
        </dependency>
        <dependency>
    		<groupId>org.apache.commons</groupId>
    		<artifactId>commons-lang3</artifactId>
    		<version>3.5</version>
		</dependency>
		 <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
        </dependency>

数据库

DROP TABLE IF EXISTS `exception_log`;
CREATE TABLE `exception_log`  (
  `exc_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `exc_requ_param` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '请求参数',
  `exc_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '异常名称',
  `exc_message` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '异常信息',
  `oper_user_id` int(11) NULL DEFAULT NULL COMMENT '操作员ID',
  `oper_user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作员姓名',
  `oper_method` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求方法',
  `base_path` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '根路径',
  `oper_url` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求URL',
  `oper_ip` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求IP',
  `oper_ver` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求版本号',
  `oper_create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
  PRIMARY KEY (`exc_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 17 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci COMMENT = '异常日志表' ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;
DROP TABLE IF EXISTS `operation_log`;
CREATE TABLE `operation_log`  (
  `oper_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
  `oper_modul` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '功能模块',
  `oper_type` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作类型',
  `oper_desc` varchar(500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作描述',
  `oper_requ_param` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '请求参数',
  `oper_resp_param` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL COMMENT '返回参数',
  `oper_user_id` int(11) NULL DEFAULT NULL COMMENT '操作员ID',
  `oper_user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作员名称',
  `oper_method` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作方法',
  `base_path` varchar(255) CHARACTER SET latin1 COLLATE latin1_swedish_ci NULL DEFAULT NULL COMMENT '根路径',
  `oper_url` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求Url',
  `oper_ip` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '请求IP',
  `oper_ver` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '操作版本号',
  `oper_create_time` datetime NULL DEFAULT CURRENT_TIMESTAMP COMMENT '操作时间',
  PRIMARY KEY (`oper_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 24 CHARACTER SET = latin1 COLLATE = latin1_swedish_ci COMMENT = '操作日志表' ROW_FORMAT = DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;

ExceptionLog

package com.xiaoq.galaxy.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

@Data
@EqualsAndHashCode(callSuper = true)
@TableName("exception_log")
public class ExceptionLog extends Model<ExceptionLog> {

    @TableId(value = "exc_id", type = IdType.AUTO)
    private Integer excId;

    @ApiModelProperty("请求参数")
    private String excRequParam;

    @ApiModelProperty("异常名称")
    private String excName;

    @ApiModelProperty("异常信息")
    private String excMessage;

    @ApiModelProperty("操作员ID")
    private Integer operUserId;

    @ApiModelProperty("操作员姓名")
    private String operUserName;

    @ApiModelProperty("请求方法")
    private String operMethod;

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

    @ApiModelProperty("请求IP")
    private String operIp;

    @ApiModelProperty("请求版本号")
    private String operVer;

    @ApiModelProperty("创建时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date operCreateTime;
    /**
     * 根路径
     */
    @ApiModelProperty("根路径")
    private String basePath;

}

OperationLog

package com.xiaoq.galaxy.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.format.annotation.DateTimeFormat;

import java.util.Date;

/**
 * 正常操作日志
 */
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("operation_log")
public class OperationLog extends Model<OperationLog> {

    @TableId(value = "oper_id", type = IdType.AUTO)
    private Integer operId;

    //功能模块
    @ApiModelProperty("功能模块")
    private String operModul;

    //操作类型
    @ApiModelProperty("操作类型")
    private String operType;

    //操作描述
    @ApiModelProperty("操作描述")
    private String operDesc;

    //请求参数
    @ApiModelProperty("请求参数")
    private String operRequParam;

    //返回参数
    @ApiModelProperty("返回参数")
    private String operRespParam;

    //操作员ID
    @ApiModelProperty("操作员ID")
    private Integer operUserId;

    //操作员名称
    @ApiModelProperty("操作员名称")
    private String operUserName;

    //操作方法
    @ApiModelProperty("操作方法")
    private String operMethod;

    //根路径
    @ApiModelProperty("根路径")
    private String basePath;

    //请求Url
    @ApiModelProperty("请求Url")
    private String operUrl;

    //请求Url
    @ApiModelProperty("请求Url")
    private String operIp;

    //操作版本号
    @ApiModelProperty("操作版本号")
    private String operVer;

    @ApiModelProperty("操作时间")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone = "GMT+8")
    private Date operCreateTime;

}

HttpUtils

package com.luck.backstage.tests;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;

public class HttpUtils {
/**
 * 获取用户真实IP地址,不使用request.getRemoteAddr();的原因是有可能用户使用了代理软件方式避免真实IP地址,
 *
 * 可是,如果通过了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP值,究竟哪个才是真正的用户端的真实IP呢?
 * 答案是取X-Forwarded-For中第一个非unknown的有效IP字符串。
 *
 * 如:X-Forwarded-For:192.168.1.110, 192.168.1.120, 192.168.1.130,
 * 192.168.1.100
 *
 * 用户真实IP为: 192.168.1.110
 *
 * @param request
 * @return
 */
 public static String getIpAddress(HttpServletRequest request) {
         String Xip = request.getHeader("X-Real-IP");
         String XFor = request.getHeader("X-Forwarded-For");

         //多次反向代理后会有多个ip值,第一个ip才是真实ip
         if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor)) {
             int index = XFor.indexOf(",");
             if (index != -1) {
                 return "0:0:0:0:0:0:0:1".equals(XFor.substring(0, index)) ? "127.0.0.1" : XFor.substring(0, index);
             } else {
                 return "0:0:0:0:0:0:0:1".equals(XFor) ? "127.0.0.1" : XFor;
             }
         }
         XFor = Xip;
         if (StringUtils.isNotEmpty(XFor) && !"unKnown".equalsIgnoreCase(XFor))
             return "0:0:0:0:0:0:0:1".equals(XFor) ? "127.0.0.1" : XFor;

         if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
             XFor = request.getHeader("Proxy-Client-IP");

         if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
             XFor = request.getHeader("WL-Proxy-Client-IP");

         if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
             XFor = request.getHeader("HTTP_CLIENT_IP");

         if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
             XFor = request.getHeader("HTTP_X_FORWARDED_FOR");

         if (StringUtils.isBlank(XFor) || "unknown".equalsIgnoreCase(XFor))
             XFor = request.getRemoteAddr();

         return "0:0:0:0:0:0:0:1".equals(XFor) ? "127.0.0.1" : XFor;
     }
}

OperLog

package com.luck.backstage.tests;

import java.lang.annotation.*;

/**
 * AOP日志切入
 */
@Target(ElementType.METHOD) //注解放置的目标位置,METHOD是可注解在方法级别上
@Retention(RetentionPolicy.RUNTIME) //注解在哪个阶段执行
@Documented
public @interface  OperLog {
    String operModul() default ""; // 操作模块
    String operType() default "";  // 操作类型
    String operDesc() default "";  // 操作说明
}

ExceptionLogDao

package com.luck.backstage.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.luck.backstage.entity.Days;
import com.luck.backstage.tests.ExceptionLog;

public interface ExceptionLogDao extends BaseMapper<ExceptionLog> {
}

OperationLogDao

package com.luck.backstage.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.luck.backstage.entity.SysUser;
import com.luck.backstage.tests.OperationLog;

public interface OperationLogDao extends BaseMapper<OperationLog> {
}

ExceptionLogService

package com.luck.backstage.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.luck.backstage.test.SysLog;
import com.luck.backstage.tests.ExceptionLog;

public interface ExceptionLogService  extends IService<ExceptionLog> {
}

OperationLogService

package com.luck.backstage.service;

import com.baomidou.mybatisplus.extension.service.IService;
import com.luck.backstage.entity.SysUser;
import com.luck.backstage.tests.OperationLog;
import org.springframework.stereotype.Service;

@Service
public interface OperationLogService  extends IService<OperationLog> {
}

ExceptionLogServiceImpl

package com.luck.backstage.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luck.backstage.dao.ExceptionLogDao;
import com.luck.backstage.dao.LogRepository;
import com.luck.backstage.service.ExceptionLogService;
import com.luck.backstage.service.LogService;
import com.luck.backstage.test.SysLog;
import com.luck.backstage.tests.ExceptionLog;
import org.springframework.stereotype.Service;

@Service
public class ExceptionLogServiceImpl extends ServiceImpl<ExceptionLogDao, ExceptionLog> implements ExceptionLogService {
}

OperationLogServiceImpl

package com.luck.backstage.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.luck.backstage.dao.OperationLogDao;
import com.luck.backstage.dao.SysUserDao;
import com.luck.backstage.entity.SysUser;
import com.luck.backstage.service.OperationLogService;
import com.luck.backstage.service.SysUserService;
import com.luck.backstage.tests.OperationLog;
import org.springframework.stereotype.Service;

@Service
public class OperationLogServiceImpl extends ServiceImpl<OperationLogDao, OperationLog> implements OperationLogService {
}

OperLogAspect
更换 @Pointcut("@annotation(com.qhzx.mad.backstage.config.OperLog)")
@Pointcut("execution(* com.qhzx.mad.backstage.controller..*.*(..))")

package com.xiaoq.store.config;


import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter;
import com.xiaoq.store.entity.ExceptionLog;
import com.xiaoq.store.entity.OperationLog;
import com.xiaoq.store.entity.UserToken;
import com.xiaoq.store.service.ExceptionLogService;
import com.xiaoq.store.service.OperationLogService;
import com.xiaoq.store.util.HttpUtils;
import com.xiaoq.store.util.OperLog;
import com.xiaoq.store.util.TokenFactory;
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.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.multipart.MultipartFile;


/**
 * 登录自定义表单其他参数
 */
@Aspect
@Component
public class OperLogAspect {

    @Autowired
    private Environment env;

    @Autowired
    private ExceptionLogService exceptionLogService;
    @Autowired
    private OperationLogService operationLogService;

    /**
     * 设置操作日志切入点 记录操作日志 在注解的位置切入代码
     */
    @Pointcut("@annotation(com.xiaoq.store.util.OperLog)")
    public void operLogPoinCut() {
    }

    /**
    * 设置操作异常切入点记录异常日志 扫描所有controller包下操作
    */
    @Pointcut("execution(* com.xiaoq.store.web.controller..*.*(..))")
    public void operExceptionLogPoinCut() {
    }

    /**
     * 正常返回通知,拦截用户操作日志,连接点正常执行完成后执行, 如果连接点抛出异常,则不会执行
     *
     * @param joinPoint 切入点
     * @param keys      返回结果
     */
    @AfterReturning(value = "operLogPoinCut()", returning = "keys")
    public void saveOperLog(JoinPoint joinPoint, Object keys) throws Exception {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = (HttpServletRequest) requestAttributes
                           .resolveReference(RequestAttributes.REFERENCE_REQUEST);
        OperationLog operlog = new OperationLog();
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();// 获取切入点所在的方法
            OperLog opLog = method.getAnnotation(OperLog.class);//获取操作
            String operDesc = null;
            if (opLog !=null){
                String operModul = opLog.operModul();
                String operType = opLog.operType();
                operDesc = opLog.operDesc();
                operlog.setOperModul(operModul); // 操作模块
                operlog.setOperType(operType); // 操作类型
                operlog.setOperDesc(operDesc); // 操作描述
            }
            String urlStr = request.getRequestURL().toString();
            // 获取请求的类名
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = method.getName();// 获取请求的方法名
            methodName = className + "." + methodName;
            operlog.setOperMethod(methodName); // 请求方法
            operlog.setOperRequParam(getReqestParams(request,joinPoint));
            operlog.setOperRespParam(JSON.toJSONString(keys));
//            operlog.setOperUserId(user.getSysId());
            if (!Objects.equals(operDesc, "登录") && !Objects.equals(operDesc, "退出登录")){
                UserToken userToken = TokenFactory.validateToken(request);
                operlog.setOperUserName(userToken.getUsername());
            }
            operlog.setOperIp(HttpUtils.getIpAddress(request));
            operlog.setOperUrl(request.getRequestURI());
            operlog.setOperVer(env.getProperty("platform.operVer"));
            operlog.setBasePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath()));
            operationLogService.save(operlog);
    }
    /**
     * 异常返回通知,用于拦截异常日志信息 连接点抛出异常后执行
     *
     * @param joinPoint 切入点
     * @param e         异常信息
     */
    @AfterThrowing(pointcut = "operExceptionLogPoinCut()", throwing = "e")
    public void saveExceptionLog(JoinPoint joinPoint, Throwable e) {
        // 获取RequestAttributes
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        // 从获取RequestAttributes中获取HttpServletRequest的信息
        HttpServletRequest request = (HttpServletRequest) requestAttributes
                .resolveReference(RequestAttributes.REFERENCE_REQUEST);

        ExceptionLog excepLog = new ExceptionLog();
        try {
            // 从切面织入点处通过反射机制获取织入点处的方法
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            // 获取切入点所在的方法
            Method method = signature.getMethod();
            String urlStr = request.getRequestURL().toString();
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = method.getName();
            methodName = className + "." + methodName;
//            Map rtnMap = converMap(request.getParameterMap());
//            String params = JSON.toJSONString(rtnMap);
            excepLog.setExcRequParam(getReqestParams(request,joinPoint));
//            excepLog.setExcRequParam(params);
            excepLog.setOperMethod(methodName);
            excepLog.setExcName(e.getClass().getName());
            excepLog.setExcMessage(stackTraceToString(e.getClass().getName(), e.getMessage(), e.getStackTrace()));
//            SystemUser user = SesionUtils.getSysUserSession();
//            excepLog.setOperUserId(user.getSysId());
//            excepLog.setOperUserName(user.getUsername());
            excepLog.setOperUrl(request.getRequestURI());
            excepLog.setOperIp(HttpUtils.getIpAddress(request));
            excepLog.setOperVer(env.getProperty("platform.operVer"));
            excepLog.setBasePath(StrUtil.removeSuffix(urlStr, URLUtil.url(urlStr).getPath()));
            exceptionLogService.save(excepLog);
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }


    /**
     * @Description: 获取请求参数
     * @author: scott
     * @date: 2020/4/16 0:10
     * @param request:  request
     * @param joinPoint:  joinPoint
     * @Return: java.lang.String
     */
    private String getReqestParams(HttpServletRequest request, JoinPoint joinPoint) {
        String httpMethod = request.getMethod();
        String params = "";
        if ("POST".equals(httpMethod) || "PUT".equals(httpMethod) || "PATCH".equals(httpMethod)) {
            Object[] paramsArray = joinPoint.getArgs();
            // java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
            //  https://my.oschina.net/mengzhang6/blog/2395893
            Object[] arguments  = new Object[paramsArray.length];
            for (int i = 0; i < paramsArray.length; i++) {
                if (paramsArray[i] instanceof BindingResult || paramsArray[i] instanceof ServletRequest || paramsArray[i] instanceof ServletResponse || paramsArray[i] instanceof MultipartFile) {
                    //ServletRequest不能序列化,从入参里排除,否则报异常:java.lang.IllegalStateException: It is illegal to call this method if the current request is not in asynchronous mode (i.e. isAsyncStarted() returns false)
                    //ServletResponse不能序列化 从入参里排除,否则报异常:java.lang.IllegalStateException: getOutputStream() has already been called for this response
                    continue;
                }
                arguments[i] = paramsArray[i];
            }
            //update-begin-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
            PropertyFilter profilter = new PropertyFilter() {
                @Override
                public boolean apply(Object o, String name, Object value) {
                    if(value!=null && value.toString().length()>500){
                        return false;
                    }
                    return true;
                }
            };
            params = JSONObject.toJSONString(arguments, profilter);
            //update-end-author:taoyan date:20200724 for:日志数据太长的直接过滤掉
        } else {
            MethodSignature signature = (MethodSignature) joinPoint.getSignature();
            Method method = signature.getMethod();
            // 请求的方法参数值
            Object[] args = joinPoint.getArgs();
            // 请求的方法参数名称
            LocalVariableTableParameterNameDiscoverer u = new LocalVariableTableParameterNameDiscoverer();
            String[] paramNames = u.getParameterNames(method);
            if (args != null && paramNames != null) {
                for (int i = 0; i < args.length; i++) {
                    params += "  " + paramNames[i] + ": " + args[i];
                }
            }
        }
        return params;
    }



    /**
     * 转换request 请求参数
     *
     * @param paramMap request获取的参数数组
     */
     public Map<String, String> converMap(Map<String, String[]> paramMap) {
        Map<String, String> rtnMap = new HashMap<String, String>();
        for(String key : paramMap.keySet()) {
                 rtnMap.put(key, paramMap.get(key)[0]);
            }
        return rtnMap;
     }

    /**
     * 转换异常信息为字符串
     *
     * @param exceptionName    异常名称
     * @param exceptionMessage 异常信息
     * @param elements         堆栈信息
     */
     public String stackTraceToString(String exceptionName, String exceptionMessage, StackTraceElement[] elements) {
        StringBuffer strbuff = new StringBuffer();
        for (StackTraceElement stet : elements) {
            strbuff.append(stet + "\n");
            }
        String message = exceptionName + ":" + exceptionMessage + "\n\t" + strbuff.toString();
        return message;
     }
}

ExceptionLogController

package com.xiaoq.store.web.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoq.store.entity.ExceptionLog;
import com.xiaoq.store.mapper.ExceptionLogDao;
import com.xiaoq.store.service.ExceptionLogService;
import com.xiaoq.store.util.OperLog;
import com.xiaoq.store.util.Result;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * 异常日志
 */
@RestController
@RequestMapping("/ExceptionLog")
@CrossOrigin
@Slf4j
public class ExceptionLogController {

    @Resource
    private ExceptionLogDao exceptionLogDao;

    //异常日志分页查询所有数据
    @ApiOperation("异常日志分页查询所有数据")
    @GetMapping(value = "/selectPage")
    @OperLog(operModul = "后台系统-异常日志分页查询所有数据",operDesc = "异常日志分页查询所有数据")
    public Result<IPage<ExceptionLog>> selectPage(
            @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
        return Result.succeed(exceptionLogDao.selectPage(new Page<>(pageNum, pageSize), new QueryWrapper<>()));
    }
    //新增异常日志
    @ApiOperation("新增异常日志")
    @PostMapping(value = "addSave")
    @OperLog(operModul = "后台系统-新增异常日志",operDesc = "新增异常日志")
    public Result<Integer> addSave(@RequestBody ExceptionLog exceptionLog) {
        return Result.succeed(exceptionLogDao.insert(exceptionLog));
    }
    //修改异常日志
    @ApiOperation("修改异常日志")
    @PostMapping(value = "update")
    @OperLog(operModul = "后台系统-修改异常日志",operDesc = "修改异常日志")
    public Result<Integer> update(@RequestBody ExceptionLog exceptionLog) {
        return Result.succeed(exceptionLogDao.updateById(exceptionLog));
    }
    //删除异常日志
    @ApiOperation("删除异常日志")
    @PostMapping(value = "delete")
    @OperLog(operModul = "后台系统-删除异常日志",operDesc = "删除异常日志")
    public Result<Integer> delete(@RequestParam String id) {
        return Result.succeed(exceptionLogDao.deleteById(id));
    }
}

OperationLogController

package com.xiaoq.store.web.controller;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xiaoq.store.entity.OperationLog;
import com.xiaoq.store.mapper.OperationLogDao;
import com.xiaoq.store.util.OperLog;
import com.xiaoq.store.util.Result;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;

/**
 * 正常日志
 */
@RestController
@RequestMapping("/OperationLog")
@CrossOrigin
@Slf4j
public class OperationLogController {
    @Resource
    private OperationLogDao operationLogDao;

    //操作日志查询所有数据
    @ApiOperation("操作日志查询所有数据")
    @GetMapping(value = "/selectPage")
    @OperLog(operModul = "后台系统-操作日志查询所有数据",operDesc = "操作日志查询所有数据")
    public Result<IPage<OperationLog>> selectPage(
            @RequestParam(value = "pageNum", required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(value = "pageSize", required = false, defaultValue = "10") Integer pageSize) {
        return Result.succeed(operationLogDao.selectPage(new Page<>(pageNum, pageSize), new QueryWrapper<>()));
    }
    //新增操作日志
    @ApiOperation("新增操作日志")
    @PostMapping(value = "addSave")
    @OperLog(operModul = "后台系统-新增操作日志",operDesc = "新增操作日志")
    public Result<Integer> addSave(@RequestBody OperationLog operationLog) {
        return Result.succeed(operationLogDao.insert(operationLog));
    }
    //修改操作日志
    @ApiOperation("修改操作日志")
    @PostMapping(value = "update")
    @OperLog(operModul = "后台系统-修改操作日志",operDesc = "修改操作日志")
    public Result<Integer> update(@RequestBody OperationLog operationLog) {
        return Result.succeed(operationLogDao.updateById(operationLog));
    }
    //删除操作日志
    @ApiOperation("删除操作日志")
    @PostMapping(value = "delete")
    @OperLog(operModul = "后台系统-删除操作日志",operDesc = "删除操作日志")
    public Result<Integer> delete(@RequestParam String id) {
        return Result.succeed(operationLogDao.deleteById(id));
    }
}

TokenFactory

package com.xiaoq.store.util;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.xiaoq.store.entity.UserToken;
import com.xiaoq.store.exception.ComFoundException;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

import static com.xiaoq.store.constant.enums.CommonEnum.FAILED_RESPONSE;
import static com.xiaoq.store.constant.enums.CommonEnum.SUCCESS_RESPONSE;

@Component
public class TokenFactory {


    private static RedisTemplate redisTemplate;  //存储对象

    @Autowired
    public void setRedisTemplate(RedisTemplate redisTemplate) {
        TokenFactory.redisTemplate = redisTemplate;
    }

    private static UserToken get(String key) {
        Object token = redisTemplate.opsForValue().get("token:"+key);
        return token == null ? null : JSON.parseObject(token.toString(), UserToken.class);
    }

    private static List<UserToken> gets(String key) {
        Object token = redisTemplate.opsForValue().get("token:"+key);
        return token == null ? null :  JSONArray.parseArray(token.toString(), UserToken.class);
    }
    public static UserToken validateToken(HttpServletRequest request) throws Exception {
        String token = request.getHeader("token");
        UserToken userToken = get(token);
        Assert.notEmpty(token, "token不能为空!");
        Assert.notNull(userToken, "token无效!");
        return userToken;
    }
    //测试
    public static List<UserToken> validateTokens(HttpServletRequest request) {
        String token = request.getHeader("token");
        Assert.notEmpty(token, "token不能为空!");
        List<UserToken> userToken = gets(token);

        Assert.notNull(userToken, "token无效!");
        return userToken;
    }
}

全局异常处理DefaultExceptionAdvice

package com.xiaoq.store.exception;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.xiaoq.store.StarcraftApplication;
import com.xiaoq.store.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.sql.SQLException;
import java.util.List;

@ControllerAdvice
@ResponseBody
public class DefaultExceptionAdvice {
    private static final Logger LOGGER = LoggerFactory.getLogger(DefaultExceptionAdvice.class);

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler({HttpMessageNotReadableException.class,})
    public ResponseEntity handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
        LOGGER.error("参数解析失败", e);
        Response response = Response.failure(DefaultError.INVALID_PARAMETER);
        response.setResult(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
    }

    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public ResponseEntity handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        LOGGER.error("不支持当前请求方法", e);
        Response response = Response.failure(DefaultError.METHOD_NOT_SUPPORTED);
        response.setResult(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.METHOD_NOT_ALLOWED);
    }

    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
    @ExceptionHandler({HttpMediaTypeNotSupportedException.class})
    public ResponseEntity handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
        LOGGER.error("不支持当前媒体类型", e);
        Response response = Response.failure(DefaultError.CONTENT_TYPE_NOT_SUPPORT);
        response.setResult(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.UNSUPPORTED_MEDIA_TYPE);
    }

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler({SQLException.class})
    public ResponseEntity handleSQLException(SQLException e) {
        LOGGER.error("服务运行SQLException异常", e);
        Response response = Response.failure(DefaultError.SQL_EXCEPTION);
        response.setResult(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * 所有异常统一处理
     *
     * @return ResponseEntity
     */
    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(Exception.class)
    public ResponseEntity handleException(Exception ex) {
        LOGGER.error("未知异常", ex);
        IError error;
        String extMessage = null;
        if (ex instanceof BindException) {
            error = DefaultError.INVALID_PARAMETER;
            List<ObjectError> errors = ((BindException) ex).getAllErrors();
            if (errors.size() != 0) {
                StringBuilder msg = new StringBuilder();
                for (ObjectError objectError : errors) {
                    msg.append("Field error in object '").append(objectError.getObjectName()).append(" ");
                    if (objectError instanceof FieldError) {
                        msg.append("on field ").append(((FieldError) objectError).getField()).append(" ");
                    }
                    msg.append(objectError.getDefaultMessage()).append(" ");
                }
                extMessage = msg.toString();
            }
        } else if (ex instanceof MissingServletRequestParameterException) {
            error = DefaultError.INVALID_PARAMETER;
            extMessage = ex.getMessage();
        } else if (ex instanceof HttpMediaTypeNotSupportedException) {
            error = DefaultError.CONTENT_TYPE_NOT_SUPPORT;
            extMessage = ex.getMessage();
        } else if (ex instanceof HttpMessageNotReadableException) {
            error = DefaultError.INVALID_PARAMETER;
            extMessage = ex.getMessage();
        } else if (ex instanceof MethodArgumentNotValidException) {
            error = DefaultError.INVALID_PARAMETER;
            final BindingResult result = ((MethodArgumentNotValidException) ex).getBindingResult();
            if (result.hasErrors()) {
                extMessage = result.getAllErrors().get(0).getDefaultMessage();
            } else {
                extMessage = ex.getMessage();
            }
        } else if (ex instanceof HttpRequestMethodNotSupportedException) {
            error = DefaultError.METHOD_NOT_SUPPORTED;
            extMessage = ex.getMessage();
        } else if (ex instanceof NoHandlerFoundException) {
            error = DefaultError.SERVICE_NOT_FOUND;
            extMessage = ex.getMessage();
        } else {
            error = DefaultError.SYSTEM_INTERNAL_ERROR;
            extMessage = ex.getMessage();
        }


        Response response = Response.failure(error);
        response.setResult(extMessage);
        return new ResponseEntity<>(response, HttpStatus.INTERNAL_SERVER_ERROR);
    }

    /**
     * BusinessException 业务异常处理
     *
     * @return ResponseEntity
     */
    @ResponseStatus(HttpStatus.OK)
    @ExceptionHandler(BusinessException.class)
    public ResponseEntity handleException(BusinessException e) {
        LOGGER.error("业务异常", e);
        Response response = Response.failure(e.getError());
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

    @ExceptionHandler({BaseException.class})
    public Result BaseExceptionHandler(BaseException e) {
        // 从异常对象中拿到信息
        String message = e.getDefaultMessage();
        String code = e.getCode();
        // 返回
        return Result.succeed(Result.fail(Integer.parseInt(code),message),message);
    }

    @ExceptionHandler({ComFoundException.class})
    public Result ComFoundExceptionHandler(ComFoundException e) {
        // 从异常对象中拿到信息
        String message = e.getMessage();
        // 返回
        return Result.succeed(Result.fail(400,message),message);
    }

    @ExceptionHandler({MybatisPlusException.class})
    public Result MybatisPlusException(MybatisPlusException e) {
        // 从异常对象中拿到信息
        String message = e.getMessage();
        // 返回
        return Result.succeed(Result.fail(400,message),message);
    }

}

Response

package com.xiaoq.store.exception;

import lombok.Data;

import java.io.Serializable;

/**
 * 说明:统一 Rest 返回对象
 *
 * @author zhangwei
 * @date 2017年11月18日23:45:05
 */
@Data
public class Response implements Serializable {

    private static final long serialVersionUID = -5359531292427290394L;

    private String errorCode;
    private String errorMessage;
    private String extMessage;
    private Object result;
    private Status status;
    private Object data;

    public Response() {
        this.status = Status.SUCCEED;
    }

    public Response(IError error) {
        this.errorCode = error.getErrorCode();
        this.errorMessage = error.getErrorMessage();
        this.status = Status.FAILED;
    }

    public static Response success() {
        return new Response();
    }


    public static Response success(Object result) {
        Response response = new Response();
        response.setResult(result);
        return response;
    }

    public static Response failure(String errorCode, String errorMessage) {
        Response response = new Response();
        response.errorCode = errorCode;
        response.errorMessage = errorMessage;
        response.status = Status.FAILED;
        return response;
    }

    public static Response failure(IError error) {
        Response response = new Response();
        response.errorCode = error.getErrorCode();
        response.errorMessage = error.getErrorMessage();
        response.status = Status.FAILED;
        return response;
    }

    public static Response failure(String message) {
        Response response = new Response();
        response.setErrorMessage(message);
        response.status = Status.FAILED;
        return response;
    }

    public static Response failure(String message, Object data) {
        Response response = new Response();
        response.setErrorMessage(message);
        response.setData(data);
        response.status = Status.FAILED;
        return response;
    }

    public static Response warring(Object result) {
        Response response = new Response();
        response.setResult(result);
        response.status = Status.WARRING;
        return response;
    }

    public enum Status {
        /**
         * 状态
         */
        SUCCEED,
        WARRING,
        FAILED;

        Status() {
        }
    }
}

IError

package com.qhzx.exception;

/**
 * 说明:
 *
 * @author zhangwei
 * @version 2017/11/21 15:21.
 */
public interface IError {

    /**
     * 获取nameSpace
     *
     * @return nameSpace
     */
    String getNameSpace();

    /**
     * 获取错误码
     *
     * @return 错误码
     */
    String getErrorCode();

    /**
     * 获取错误信息
     *
     * @return 错误信息
     */
    String getErrorMessage();

    /**
     * 设置错误信息
     *
     * @param errorMessage 错误信息
     */
    void setErrorMessage(String errorMessage);
}

IError

package com.qhzx.exception;

/**
 * 说明:
 *
 * @author zhangwei
 * @version 2017/11/21 15:21.
 */
public interface IError {

    /**
     * 获取nameSpace
     *
     * @return nameSpace
     */
    String getNameSpace();

    /**
     * 获取错误码
     *
     * @return 错误码
     */
    String getErrorCode();

    /**
     * 获取错误信息
     *
     * @return 错误信息
     */
    String getErrorMessage();

    /**
     * 设置错误信息
     *
     * @param errorMessage 错误信息
     */
    void setErrorMessage(String errorMessage);
}

DefaultError

package com.qhzx.exception;


/**
 * 说明:默认异常
 *
 * @author zhangwei
 * @date 2017年11月18日23:45:26
 */
public enum DefaultError implements IError {
    /**
     * 系统内部错误
     */
    SYSTEM_INTERNAL_ERROR("0000", "系统错误"),
    /**
     * 无效参数
     */
    INVALID_PARAMETER("0001", "参数验证失败"),
    /**
     * 服务不存在
     */
    SERVICE_NOT_FOUND("0002", "服务不存在"),
    /**
     * 参数不全
     */
    PARAMETER_REQUIRED("0003", "参数不全"),
    /**
     * 参数过长
     */
    PARAMETER_MAX_LENGTH("0004", "参数过长"),
    /**
     * 参数过短
     */
    PARAMETER_MIN_LENGTH("0005", "参数过短"),
    /**
     * 认证失败
     */
    AUTHENTICATION_ERROR("0006", "认证失败"),
    /**
     * 认证动作失败
     */
    AUTHENTICATION_OPTION_ERROR("0007", "认证失败"),
    /**
     * 请求方法出错
     */
    METHOD_NOT_SUPPORTED("0008", "请求方法出错"),
    /**
     * 不支持的content类型
     */
    CONTENT_TYPE_NOT_SUPPORT("0009", "不支持的content类型"),
    /**
     * json格式化出错
     */
    JSON_FORMAT_ERROR("0010", "json格式化出错"),
    /**
     * 远程调用出错
     */
    CALL_REMOTE_ERROR("0011", "远程调用出错"),
    /**
     * 服务运行SQLException异常
     */
    SQL_EXCEPTION("0012", "服务运行SQL异常"),
    /**
     * 客户端异常 给调用者 app,移动端调用
     */
    CLIENT_EXCEPTION("0013", "客户端异常"),
    /**
     * 服务端异常, 微服务服务端产生的异常
     */
    SERVER_EXCEPTION("0014", "服务端异常"),
    /**
     * 授权失败 禁止访问
     */
    ACCESS_DENIED("0015", "没有访问权限"),
    /**
     * 演示环境 没有权限访问
     */
    SHOW_AUTH_CONTROL("0016", "演示环境,没有权限访问"),
    /**
     * 业务异常
     */
    BUSINESS_ERROR("0017", "业务异常"),

    NO_USER("0018", "用户不存在");

    private static final String NS = "SYS";
    String errorCode;
    String errorMessage;

    DefaultError(String errorCode, String errorMessage) {
        this.errorCode = errorCode;
        this.errorMessage = errorMessage;
    }

    @Override
    public String getNameSpace() {
        return NS;
    }

    @Override
    public String getErrorCode() {
        return NS + "." + this.errorCode;
    }

    @Override
    public String getErrorMessage() {
        return this.errorMessage;
    }

    @Override
    public void setErrorMessage(String errorMessage) {
        this.errorMessage = errorMessage;
    }
}

ComFoundException

package com.qhzx.exception;

/**
 * 编写统一返回异常类
 * @ClassName CaptchaException
 * @Author Blue Email:[email protected]
 * @Date 2022/9/13
 */
public class ComFoundException extends RuntimeException {

    public ComFoundException() {
        super();
    }
 
    public ComFoundException(String message) {
        super(message);
    }
 
    public ComFoundException(String message, Throwable cause) {
        super(message, cause);
    }
 
    public ComFoundException(Throwable cause) {
        super(cause);
    }
 
    protected ComFoundException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
        super(message, cause, enableSuppression, writableStackTrace);
    }

}

BusinessException

package com.qhzx.exception;

import lombok.Data;
import lombok.EqualsAndHashCode;

@EqualsAndHashCode(callSuper = true)
@Data
public class BusinessException extends BaseException {

    private static final long serialVersionUID = 3076984003548588117L;

    private IError error = DefaultError.BUSINESS_ERROR;

    private String extMessage;

    public BusinessException(String message) {
        super(message);
        this.error.setErrorMessage(message);
    }

    public BusinessException(String message, String extMessage) {
        super(message + ":" + extMessage);
        this.error.setErrorMessage(message);
        this.extMessage = extMessage;
    }
}

BaseException

package com.qhzx.exception;

import com.alibaba.druid.util.StringUtils;

/**
 * 基本异常.
 */
class BaseException extends RuntimeException {

    private static final long serialVersionUID = 1L;

    /**
     * 所属模块
     */
    private String module;

    /**
     * 错误码
     */
    private String code;

    /**
     * 错误码对应的参数
     */
    private Object[] args;

    /**
     * 错误消息
     */
    private String defaultMessage;

    public BaseException(String module, String code, Object[] args, String defaultMessage) {
        this.module = module;
        this.code = code;
        this.args = args;
        this.defaultMessage = defaultMessage;
    }

    public BaseException(String module, String code, Object[] args) {
        this(module, code, args, null);
    }

    public BaseException(String module, String defaultMessage) {
        this(module, null, null, defaultMessage);
    }

    public BaseException(String code, Object[] args) {
        this(null, code, args, null);
    }

    public BaseException(String defaultMessage) {
        this(null, null, null, defaultMessage);
    }

    @Override
    public String getMessage() {
        String message = null;
        if (!StringUtils.isEmpty(code)) {
            message = "无";
        }
        if (message == null) {
            message = defaultMessage;
        }
        return message;
    }

    public String getModule()
    {
        return module;
    }

    public String getCode()
    {
        return code;
    }

    public Object[] getArgs()
    {
        return args;
    }

    public String getDefaultMessage()
    {
        return defaultMessage;
    }
}

异常数据
Spring Boot AOP 记录系统操作日志和异常日志到数据库_第1张图片
正确数据
Spring Boot AOP 记录系统操作日志和异常日志到数据库_第2张图片

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