ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

java-在Spring Boot中处理异常的正确方法

2019-11-09 01:00:37  阅读:209  来源: 互联网

标签:spring-rest spring-boot spring-restcontroller spring java


我在阅读Spring文档时发现,从ResponseEntityExceptionHandler创建子类是处理异常的好方法.但是,我尝试以不同的方式处理异常,因为我需要将BusinessException与TechnicalException区别.

创建了一个名为BusinessFault的Bean,其中封装了异常详细信息:

BusinessFault.java

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonInclude(value = Include.NON_NULL)
public class BusinessFault {

    @JsonProperty(value = "category")
    private final String CATEGORY = "Business Failure";
    protected String type;
    protected String code;
    protected String reason;
    protected String description;
    protected String instruction;

    public BusinessFault(String type, String code, String reason) {
        this.type = type;
        this.code = code;
        this.reason = reason;
    }

    public BusinessFault(String type, String code, String reason, String description, String instruction) {
        this.type = type;
        this.code = code;
        this.reason = reason;
        this.description = description;
        this.instruction = instruction;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getReason() {
        return reason;
    }

    public void setReason(String reason) {
        this.reason = reason;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getInstruction() {
        return instruction;
    }

    public void setInstruction(String instruction) {
        this.instruction = instruction;
    }

    public String getCATEGORY() {
        return CATEGORY;
    }
}

创建了一个BusinessException类,该类通过通过其构造函数传递的详细信息创建一个BusinessFault bean来完成工作:

BusinessException.java

import com.rest.restwebservices.exception.fault.BusinessFault;

public abstract class BusinessException extends RuntimeException {

    private BusinessFault businessFault;

    public BusinessException(String type, String code, String reason) {
        this.businessFault = new BusinessFault(type, code, reason);
    }

    public BusinessException(String type, String code, String reason, String description, String instruction) {
        this.businessFault = new BusinessFault(type, code, reason, description, instruction);
    }

    public BusinessException(BusinessFault businessFault) {
        this.businessFault = businessFault;
    }

    public BusinessFault getBusinessFault() {
        return businessFault;
    }

    public void setBusinessFault(BusinessFault businessFault) {
        this.businessFault = businessFault;
    }
}

创建了一个特定的UserNotFoundException类,该类从BusinessException类扩展:

UserNotFoundException.java

import com.rest.restwebservices.exception.fault.BusinessFault;
import com.rest.restwebservices.exception.map.ExceptionMap;

public class UserNotFoundException extends BusinessException {

    public UserNotFoundException(BusinessFault businessFault) {
        super(businessFault);
    }

    public UserNotFoundException(String reason) {
        super(ExceptionMap.USERNOTFOUND.getType(), ExceptionMap.USERNOTFOUND.getCode(), reason);
    }

    public UserNotFoundException(String reason, String description, String instruction) {
        super(ExceptionMap.USERNOTFOUND.getType(), ExceptionMap.USERNOTFOUND.getCode(), reason, description,
                instruction);
    }
}

创建了一个BusinessExceptionHandler,但是它不是@ResponseEntityExceptionHandler的子类,它仅具有@ControllerAdvice批注和处理所有引发的BusinessException的方法:

BusinessExceptionHandler.java

import javax.servlet.http.HttpServletRequest;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import com.rest.restwebservices.controller.UserController;
import com.rest.restwebservices.exception.BusinessException;
import com.rest.restwebservices.exception.fault.BusinessFault;

@ControllerAdvice(basePackageClasses = UserController.class)
public class BusinessExceptionHandler {

    @ExceptionHandler(BusinessException.class)
    @ResponseBody
    public ResponseEntity<BusinessFault> genericHandler(HttpServletRequest request, BusinessException ex) {
        return new ResponseEntity<BusinessFault>(ex.getBusinessFault(), HttpStatus.OK);
    }
}

服务层可以引发UserNotFoundException:

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public User findById(Long id) {
        User user = userRepository.findOne(id);
        if (user == null)
            throw new UserNotFoundException("The ID " + id + " doesn't behave to any user!");

        return user;
    }
}

工作正常.但是我想知道这是否是处理异常的不良做法?

解决方法:

我对您的异常处理有点问题.原则上,捕获运行时异常,对其进行处理并将其发送给客户端绝对是可以的,这可能是使用REST服务并将错误响应作为JSON对象获取的人.如果您能告诉他他做错了什么,他可以做些什么,那就太好了!当然,它会增加一些复杂性,但是使用该API可能很容易且舒适.

但是,请考虑与您的代码一起使用的后端开发人员.尤其是UserService中的公共用户findById(Long id)方法是晦涩的.这样做的原因是您使BusinessException(特别是UserNotFoundException)处于未选中状态.

如果我加入了您的(后端)团队,并且打算使用该服务编写一些业务逻辑,那么我将非常确定我对该方法的期望:我传递了一个用户ID,如果有,则返回一个User对象.找到,否则返回null.这就是为什么我会写这样的代码

User user = userService.findById("42A");
if (user == null) {
  // create a User or return an error or null or whatever
} else {
  // proceed
}

但是,我永远不会知道,第一个条件永远不会为真,因为您永远不会返回null.我怎么知道我必须捕获一个异常?

编译器告诉我抓住它了吗?不,因为未选中.

我会调查一下您的源代码吗?一定不行!您的情况非常简单. UserNotFoundException可能会在几百行代码中的另一个类的另一个方法中引发.有时,无论如何,我还是看不到它,因为UserService只是依赖项中的已编译类.

我可以阅读JavaDoc吗?哈哈哈假设有50%的时间我不愿意,而另外50%的您却忘记记录了.

因此,开发人员必须等到他的代码被使用(无论是由客户端还是在单元测试中)后,才能看到它无法按预期工作,从而迫使他重新设计到目前为止的代码.而且,如果您的整个API是这样设计的,那么未经检查的异常就会无处不在,这可能会非常烦人,既浪费时间和金钱,又很容易避免.

标签:spring-rest,spring-boot,spring-restcontroller,spring,java
来源: https://codeday.me/bug/20191109/2010731.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有