美文网首页
在spring中优雅地处理异常

在spring中优雅地处理异常

作者: 白日做梦的咸鱼 | 来源:发表于2020-02-18 01:04 被阅读0次

@ExceptionHandler

使用@ExceptionHandler注解可以在拦截当前类中方法抛出的异常,如下面例子中

@RestController
@RequestMapping("/user")
public class UserController {


    @GetMapping("/throwException")
    public String throwException(){
        //抛出一个异常
        int a = 1/0;
        return "abcd";
    }

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public String handleException(){
        return "handle";
    }
}

使用get请求中访问 localhost:8080/user/throwException可以得到如下信息

handle

@ControllerAdvice

看了上面的例子,我们会想 假如有多个controller都会抛出异常,难道要在每个controller中都写一个这样的方法进行异常捕获吗?可不可以将ExceptionHandler配置成全局的异常捕获,方法很简单只需要新建一个类在上面添加@ControllerAdvice注解然后将异常拦截方法添加到其中即可

@ControllerAdvice
public class ExceptionHandleAdvice {

    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public String handleException(){
        return "global handle";
    }

}

使用全局异常处理返回统一的错误信息

在日常工作中开发API的时候往往需要返回详细统一的错误信息给前端小伙伴方便前端进行错误信息的处理和展示(当然你也可以一个接口一个格式,不怕被打的话( ̄ ̄"))。在这样的情况如何优雅得进行异常处理就变得很重要了。一下是个人对异常处理的一些意见,分享给小伙伴参考,有不同意见的小伙伴可以交流。

通常我们会通过code表示具体的错误类型、message给出错误的信息。因此我们可以得到以及基本的错误信息模板如下方

{
    "code": 404,
    "message": "No message available",
    "path": "/u",
    "timestamp": "2020-02-17T14:20:48.049+0000",
}

定义错误信息枚举

将错误信息定义成枚举可以帮助我们管理code避免相同的错误返回不一样的code值或者不同的错误返回了同一个code。

public enum ErrorEnum {

    USER_NOT_FOUND_ERROR(1000,"用户不存在");

    ErrorEnum(int code, String message){
        this.code = code;
        this.message =message;
    }
    
}

定义返回错误信息实体类

public class ErrorResponse {

    private int code;

    private String message;

    private LocalDateTime timestamp;

    private String path;

    public ErrorResponse() {
    }
    
    //利用一个静态工厂方法快速创建实例
    public static ErrorResponse build(ErrorEnum errorEnum,String path){
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setCode(errorEnum.getCode());
        errorResponse.setMessage(errorEnum.getMessage());
        errorResponse.setPath(path);
        errorResponse.setTimestamp(LocalDateTime.now());
        return errorResponse;
    }
}

创建基础异常类

创建一个基础的异常,让我们的全局ExceptionHandler拦截这个异常。

public abstract class BaseException extends RuntimeException {

    private ErrorEnum error;
    
    public BaseException(ErrorEnum error) {
        this.error = error;
    }

    public ErrorEnum getError() {
        return error;
    }

    public void setError(ErrorEnum error) {
        this.error = error;
    }
}

创建ControllerAdvice

使用@ControllerAdvice创建全局异常拦截器并拦截我们上面定义好的基础异常类,在方法内部进行错误信息的返回。

@ControllerAdvice
public class ExceptionHandleAdvice {

    @ExceptionHandler(value = BaseException.class)
    //以写入到response的body方式返回
    @ResponseBody
    public ErrorResponse handleException(BaseException e, HttpServletRequest request){
        return ErrorResponse.build(e.getError(),request.getRequestURI());
    }

}

使用

在完成了上面的工作之后,终于到了我们使用的时候,在我们使用的时候我们通常都会抛出更加具体的异常、下面我们以获取用户信息为例子,当查找不到用户的时候我们会抛出UserNotFoundException

public class UserNotFoundException extends BaseException {

    public UserNotFoundException() {
        super(ErrorEnum.USER_NOT_FOUND_ERROR);
    }
}
@RestController
@RequestMapping("/user")
public class UserController {

    private UserDAO userDAO;

    public UserController(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    @GetMapping("/{userId}")
    public User getUserById(@PathVariable("userId") String userId) {
        User user = this.userDAO.getUserById(userId);
        if (user == null) {
            throw new UserNotFoundException();
        }
        return user;
    }
    
}

快打开你的浏览器输入熟悉的localhost:8080/user/123457,然后

{
    "code": 1000,
    "message": "用户不存在",
    "timestamp": "2020-02-17T23:03:46.6924162",
    "path": "/user/1234567"
}

以后我们只需要创建和抛出BaseException的子类就可以完成对异常信息的统一格式返回,再也不用担心被前端小伙伴打了。

最后

以上的代码只是个人的一种实现,有所不足请小伙伴们给出建议。

如果对你有一点帮助给个start鼓励一下呗(´・ω・`)。

demo源码

相关文章

网友评论

      本文标题:在spring中优雅地处理异常

      本文链接:https://www.haomeiwen.com/subject/hrewfhtx.html