Spring Project elegant exception handling

Foreword

Today's Java Web MVC project is a multi-mode built, usually we are all unified exception thrown Service layer, including custom exceptions and some unusual accident occur, for transaction rollback, and the caller's Service Controller then bear responsibility for exception handling, because he is the last line of defense interactive Web front-end, if not processed at this time, the user will see forced to look ignorant on the page

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4
    at cn.keats.TestAdd.main(TestAdd.java:20)

This has the following disadvantages:

  1. Very friendly user experience, a user may be Tucao one: What is XX website. Then no longer visited
  2. If the user is a peer, he not only saw the construction project code, and see thrown is so low index out of bounds exception will be looked down upon others
  3. Users see the site in question, called customer service, customer service to find products, wake up the sleeping / playing the game for you. Not only will you sleep well finish up the game play can not change the code had to be criticized

Hey, truly suffered. So in general our approach would be something like this:

Exception Handling

General Controller process

Service code is as follows:

@Service
public class DemoService {
    public String respException(String param){
        if(StringUtils.isEmpty(param)){
            throw new MyException(ExceptionEnum.PARAM_EXCEPTION);
        }
        int i = 1/0;
        return "你看不见我!";
    }
}

Controller code is as follows:

@RestController
public class DemoController {
    @Autowired
    private DemoService demoService;
    
    @PostMapping("respException")
    public Result respException(){
        try {
            return Result.OK(demoService.respException(null)); 
        } catch (MyException e){
            return Result.Exception(e, null);
        }
        catch (Exception e) {
            return Result.Error();
        }
    } 
}

If at this time send the following request:

http://localhost/respException

The server captures the abnormality MyException custom exception return Json string parameters:

{
    "code": 1,
    "msg": "参数异常",
    "data": null
}

And when we make up the parameters:

http://localhost/respException?param=zhangsan

The server caught by zero exceptions, will return to the front page unknown error

{
    "code": -1,
    "msg": "未知错误",
    "data": null
}

This will avoid some of the problems to a certain extent, such as parameters error can allow users to modify its parameters, of course, with students generally need to make the front page of the calibration parameters, the parameters will have passed when the server sends a request again, On the one hand reduce the pressure on the server, on the one hand the problem of pre-saving time for both parties. But there is a downside wrote that all of the Controller section on unusual methods are the same, the code is very redundant. And not conducive to maintenance, and some students are not familiar with exception mechanism might like to pass the buck as an exception caught a throw, throw again and again come back again, just playing. . . (I once took over a foot classmate code to handle exceptions this way, then that would be abnormal hide and seek with it! Hateful) We have a global transaction in the Service, may have overall log processing in the system, these are based on the Spring a big kill: AOP (Aspect oriented programming) implementation, AOP what is it?

AOP

Spring Framework AOP is thought aspect-oriented programming, using AOP called "cross" technique, the multi-functional business processes involve general extraction and individually packaged to form a separate section, at the right time these facets transverse cut to business processes specified location. If we used the OOP idea is to execute business processes from top to bottom, then, AOP is equivalent to when we execute the business of cross-cutting knife, as shown below:

image-20191201205830708

While the Advice (notification) is a significant term AOP thought, into the pre-notification (the Before), post-notification (afterReturning), abnormality notification (AfterThrowing), the final notification (the After) and surround notification (Around) are five. Significance of specific notification indicated I will not go into details here, online will explain about the Spring core principles mentioned. And we know Service transaction is actually based on the transaction rollback AOP AfterThrowing notice achieve. We custom log processing can also be customized according to different notifications different entrance requirements. That being the case, why do not we cut a custom global exception handler is to simplify our code? But wait, and continue to look down.

The elegant handle exceptions

Spring in version 3.2 already provides the functionality for us: @ControllerAdvice comment. This annotation layer captures Controller thrown exception, and exception processing method according @ExceptionHandler annotation configuration. The following is an example of construction, the main code is as follows:

Result type:

This generic manner using Result, facilitating configuration of the Swagger out parameters. Using a static factory method is initialized object name only intended to see more. For Error object does not exist the problem of shared variables, double check the lock lazy singleton to save server resources (of course better to run the entire project has not been initialized makes it more comfortable.)

package cn.keats.util;

import cn.keats.exception.MyException;
import lombok.Data;

/**
 * 功能:统一返回结果,直接调用对应的工厂方法
 *
 * @author Keats
 * @date 2019/11/29 18:20
 */
@Data
public class Result<T>  {
    private Integer code;
    private String msg;
    private T data;

    /**
     * 功能:响应成功
     *
     * @param data 响应的数据
     * @return woke.cloud.property.transformat.Result
     * @author Keats
     * @date 2019/11/30 8:54
     */
    public static <T> Result<T> OK(T data){
        return new Result<>(0, "响应成功", data);
    }

    private static Result errorResult;
    /**
     * 功能:返回错误,此错误不可定制,全局唯一。一般是代码出了问题,需要修改代码
     *
     * @param
     * @return Result
     * @author Keats
     * @date 2019/11/30 8:55
     */
    public static Result Error(){
        if(errorResult == null){
            synchronized (Result.class){
                if(errorResult == null){
                    synchronized (Result.class){
                        errorResult = new Result<>(-1, "未知错误", null);
                    }
                }
            }
        }
        return errorResult;
    }

    /**
     * 功能:返回异常,直接甩自定义异常类进来
     *
     * @param e 自定义异常类
     * @param data 数据,如果没有填入 null 即可
     * @return woke.cloud.property.transformat.Result<T>
     * @author Keats
     * @date 2019/11/30 8:55
     */
    public static <T> Result<T> Exception(MyException e, T data){
        return new Result<>(e.getCode(), e.getMsg(), data);
    }

    /**
     * 功能:为了方便使用,使用静态工厂方法创建对象。如需新的构造方式,请添加对应的静态工厂方法
     *
     * @author Keats
     * @date 2019/11/30 8:56
     */
    private Result(Integer code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
}

Custom exception class:

package cn.keats.exception;

import lombok.Getter;

/**
 * 功能:系统自定义异常类。继承自RuntimeException,方便Spring进行事务回滚
 *
 * @author Keats
 * @date 2019/11/29 18:50
 */
@Getter
public class MyException extends RuntimeException{
    private Integer code;
    private String msg;

    public MyException(ExceptionEnum eEnum) {
        this.code = eEnum.getCode();
        this.msg = eEnum.getMsg();
    }
}

Exception code enumeration class:

package cn.keats.exception;

import lombok.AllArgsConstructor;
import lombok.Getter;

/**
 * 功能:异常枚举
 *
 * @author Keats
 * @date 2019/11/29 18:49
 */
@Getter
@AllArgsConstructor
public enum ExceptionEnum {
    PARAM_EXCEPTION(1,"参数异常"),
    USER_NOT_LOGIN(2,"用户未登录"),
    FILE_NOT_FOUND(3,"文件不存在,请重新选择");


    private Integer code;
    private String msg;
}

Abnormal section:

Which is spring @RestControllerAdvice 4.3 added a new annotation, is @ControllerAdvice and @ResponseBody shorthand way similar to the relationship of @RestController and @Controller

package cn.keats.advice;

import cn.keats.exception.MyException;
import cn.keats.util.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 功能:全局异常处理器,Controller异常直接抛出
 *
 * @return
 * @author Keats
 * @date 2019/11/30 10:28
 */
@Slf4j
@RestControllerAdvice
public class ExceptionAdvice {
    /**
     * 功能:其余非预先规避的异常返回错误
     *
     * @param e
     * @return woke.cloud.property.transformat.Result
     * @author Keats
     * @date 2019/11/30 10:08
     */
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result ResponseException(Exception e) {
        log.error("未知错误,错误信息:", e);
        return Result.Error();
    }

    /**
     * 功能:捕捉到 MyException 返回对应的消息
     *
     * @param e
     * @return woke.cloud.property.transformat.Result
     * @author Keats
     * @date 2019/11/30 10:07
     */
    @ExceptionHandler(value = MyException.class)
    @ResponseBody
    public Result myException(MyException e) {
        log.info("返回自定义异常:异常代码:" + e.getCode() + "异常信息:" + e.getMsg());
        return Result.Exception(e, null);
    }
}

At this point the Controller method can be written:

package cn.keats.controller;

import cn.keats.service.DemoService;
import cn.keats.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class DemoController {
    @Autowired
    private DemoService demoService;

    @PostMapping("respException")
    public Result respException(String param) throws Exception {
        return Result.OK(demoService.respException(param));
    }
    
    @PostMapping("respError")
    public Result respError() throws Exception {
        return Result.OK(demoService.respException(null));
    }
}

Most of exception handling code omitted, so we just need to focus on business, on the one hand to improve the code quality, readability, it also improves the speed of our development. Miya!

Start the project, test no problem.

image-20191201213847490

image-20191201213912251

I am Keats, a love of technology programmer, given the limited technology, if there are any flaws or paper Xiongtai there are other better advice / implementation, welcome to leave comments, Thank you!

Guess you like

Origin www.cnblogs.com/keatsCoder/p/11967890.html