> 文档中心 > Spring Boot【定制化】~ AOP统一结果处理以及异常拦截

Spring Boot【定制化】~ AOP统一结果处理以及异常拦截


1、简介

用处:统一结果处理与异常拦截。

2、配置步骤

2.1、创建一个spring boot项目(idea)

完整项目结构!

2.2、导入依赖(需要使用到简化环境搭建)

    org.springframework.boot    spring-boot-starter-aop    com.alibaba    fastjson    1.2.76    org.apache.commons    commons-lang3    org.springframework.boot    spring-boot-starter-web    org.springframework.boot    spring-boot-devtools    runtime    true    org.projectlombok    lombok    true    org.springframework.boot    spring-boot-starter-test    test          org.junit.vintage     junit-vintage-engine     

2.3、yml

注意:我们这个测试不需要yml(写上来防止你们疑惑!)

spring:  application:    name: springboot-day02-aop-exception    #服务名称(项目名)

2.4、需要使用的工具类

注意:直接复制使用,工具类方法太多所以直接抽取几个用到的方法(不是重点)。

1、StringUtils

/** * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 20:10 */public class StringUtils extends org.apache.commons.lang3.StringUtils{ public static boolean isEmpty(String str)    { return isNull(str) || "".equals(str.trim());    } public static boolean isNotEmpty(String str)    { return !isEmpty(str);    }    public static boolean isNull(Object object)    { return object == null;    }    public static boolean isNotNull(Object object)    { return !isNull(object);    }    }

2、ServletUtils

/** * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 20:10 */public class ServletUtils{    /**     * 响应字符串     * @param response 响应     * @param string 内容     * @return 结果     */    public static String parseString(HttpServletResponse response, String string)    { try {     response.setStatus(200);     response.setContentType("application/json");     response.setCharacterEncoding("utf-8");     response.getWriter().print(string); } catch (IOException e) {     e.printStackTrace(); } return null;    }}

2.5、需要使用的枚举以及状态

1、ErrorEnum

/** * @author cms * @version 1.0.0.0 * @Date: 2022/3/16 13:17 */public enum ErrorEnum {    /* 参数错误P0100 - P0200 */    P_ERROR_NULL("P0100", "参数%s不能为空"),    P_NOT_EXIST("P0101", "%s不存在"),    P_FORMAT_ERROR("P0102", "%s格式不正确"),    /* 系统内部错误S0100 - Sxxx */    S_CATCH_AUTH("S0104", "%s"),    S_TOKEN_EXPIRED("S0104", "Token过期"),    S_ERROR("S0105","系统异常 练习管理员!佳佳吖!"),    ;    private String code;    private String message;    ErrorEnum() {    }    ErrorEnum(String code, String message) { this.code = code; this.message = message;    }    public String getCode() { return code;    }    public String getMessage() { return message;    }    /**     * @param message 填充内容     * @return 结果     */    public String getMessage(String message) { if (StringUtils.isNotEmpty(message)) {     return String.format(this.message, message); } return "";    }    public void setCode(String code) { this.code = code;    }    public void setMessage(String message) { this.message = message;    }    }

2、状态码常量类

/** * 返回状态码 *  * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 20:05 */public class HttpStatus {    /**     * 操作成功     */    public static final int SUCCESS = 200;    /**     * 不允许的http方法     */    public static final int BAD_METHOD = 405;    /**     * 系统内部错误     */    public static final int ERROR = 500;    }

2.6、统一结果返回格式对象

/** * 统一结果格式返回控制类 * * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 19:23 */public class ResultReturn extends LinkedHashMap{    public static final Date newDateTime = new Date();    public static final String CODE = "code";    public static final String MSG = "message";    public static final String DATE_TIME = "datetime";    public static final String DATA = "data";    public ResultReturn() {}    public ResultReturn(Object code, String msg, Date datetime, Object data)    { super.put(CODE, code); super.put(MSG, msg); super.put(DATE_TIME, datetime.getTime()); if (StringUtils.isNotNull(data)) {     super.put(DATA, data); }    }    /**     * 成功状态码统一:200     *     * @return 返回结果     */    public static Object success(Object data)    { return new ResultReturn(200, "success", newDateTime, data);    }    public static Object success()    { return ResultReturn.success(null);    }    /**     * 错误返回     *     * @param errorEnum 错误枚举信息     * @return 返回结果     */    public static Object error(ErrorEnum errorEnum)    { return new ResultReturn(errorEnum.getCode(), errorEnum.getMessage(), new Date(), null);    }    public static Object error(Object code, String errorMsg)    { return new ResultReturn(code, errorMsg, newDateTime, null);    }    public static ResultReturn error(RuanjiaExceptionHandler e)    { return new ResultReturn(e.getCode(), e.getMessage(), newDateTime, null);    }}

2.7、Controller统一返回结果(AOP)

1、自定义注解

作用:如果有不想被Aop拦截的controller方法,就是用该注解标识。

/** * 默认返回结果 * * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 19:17 */@Target({ ElementType.TYPE, ElementType.METHOD }) //用于方法上@Retention(RetentionPolicy.RUNTIME) //保留政策:运行时@Documentedpublic @interface OriginalReturn{}

2、统一结果拦截类(AOP切面类)

作用(重点):使用Aop实现统一结果拦截。

/** * 使用Aop拦截统一结果 * * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 19:15 */@Aspect@Slf4j@Componentpublic class ResultAspectj{    @Pointcut("execution(public * com.ruanjia.controller..*.*(..))")    public void result() {};    /** AOP拦截所有Controller控制器结果 */    @Around("result()")    public Object afterReturningMethod(ProceedingJoinPoint point) throws Throwable { Object proceed = point.proceed(); /* 模型和视图 -> 直接放行 */ if (proceed instanceof ModelAndView || proceed instanceof View) {     return proceed; } Method method = ((MethodSignature) point.getSignature()).getMethod(); /* 方法上标志@OriginalReturn -> 直接放行 */ if (method.isAnnotationPresent(OriginalReturn.class)) {     return proceed; } return ResultReturn.success(proceed);    }}

2.8、全局异常拦截

1、自定义异常类

作用:处理系统业务异常(这里还可以细写,可以根据自己需要增加自定义异常!)

/** * 自定义异常 * * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 20:02 */@Datapublic class RuanjiaExceptionHandler extends RuntimeException{    private Object code;    private String message;    public RuanjiaExceptionHandler(ErrorEnum errorCodeEnum)    { this.code = errorCodeEnum.getCode(); this.message = errorCodeEnum.getMessage();    }    /**     * @param errorCodeEnum 枚举     * @param message 替换字符串     */    public RuanjiaExceptionHandler(ErrorEnum errorCodeEnum, String message)    { super(errorCodeEnum.getMessage(message)); if (StringUtils.isNotEmpty(message)) {     this.message = errorCodeEnum.getMessage(message); } else {     this.message = errorCodeEnum.getMessage(); } this.code = errorCodeEnum.getCode();    }    /**     * @param message 异常提示信息     */    public RuanjiaExceptionHandler(String message)    { this.code = HttpStatus.ERROR; this.message = message;    }}

2、全局异常类

作用:拦截所有Controller异常

/** * 全局异常捕获: *     @ControllerAdvice 包含@Component,可以被扫描到。统一处理异常。 *     @ExceptionHandler(Exception.class) 用在方法上面表示遇到这个异常就执行以下方法。 * * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 19:15 */@Slf4j@ControllerAdvicepublic class SystemGlobalExceptionHandler{    /**     * 自定义异常     *     * @param e 算术异常     * @param response  响应结果     */    @ExceptionHandler(RuanjiaExceptionHandler.class)    public void ruanjiaExceptionHandler(RuanjiaExceptionHandler e, HttpServletResponse response)    { log.error("===========RuanjiaExceptionHandler(自定义异常)=========="); e.printStackTrace(); ServletUtils.parseString(response, JSON.toJSONString(ResultReturn.error(e.getCode(), e.getMessage())));    }    /**     * 算术异常     *     * @param e  异常对象     * @param response  响应结果     */    @ExceptionHandler(ArithmeticException.class)    public void handlerArithmeticException(ArithmeticException e, HttpServletResponse response)    { log.error("===========ArithmeticException(算术异常)=========="); e.printStackTrace(); ServletUtils.parseString(response, JSON.toJSONString(ResultReturn.error(HttpStatus.ERROR, e.getMessage())));    }    /**     * GET/POST不支持异常     *     * @param e  异常对象     * @param request   请求     * @param response  响应结果     */    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)    public void handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request, HttpServletResponse response)    { log.error("===========HttpRequestMethodNotSupportedException(GET/POST 不支持异常)=========="); String requestURI = request.getRequestURI(); log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod()); e.printStackTrace(); ServletUtils.parseString(response, JSON.toJSONString(ResultReturn  .error(HttpStatus.BAD_REQUEST,"请求地址【"+requestURI+"】,不支持【"+e.getMethod()+"】请求")));    }}

此致!配置完成,进入测试环节!

2.9、编写Controller测试类

/** * @author cms * @version 1.0.0.0 * @Date: 2022/5/21 19:11 */@RestControllerpublic class TestController{    /**     * 统一结果返回测试     *      * @return 结果     */    @GetMapping("/result")    public Object result()    { return "同意结果返回测试!";    }    /**     * 算术异常(全局异常处理程序拦截)     *      * @return 结果     */    @GetMapping("/error1")    public Object error()    { int a = 10/0; return a;    }    /**     * 自定义异常拦截(全局异常处理程序拦截)     *      * @param username 用户名     * @return 返回结果     */    @GetMapping("/error2")    public Object error2(String username)    { if (StringUtils.isEmpty(username)) {     throw new RuanjiaExceptionHandler(ErrorEnum.S_CATCH_AUTH, "用户名不能为空!"); } return username;    }}

效果图:

1、统一结果返回测试

2、系统算术异常拦截

3、自定义异常拦截

结束语:不要半途而废!