SpringBoot异常处理--荆轲

SpringBoot异常处理
做Web应用的时候,请求处理过程中发生错误是非常常见的情况。Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容。但是页面很不友好,我们需要发送给一些参数让前端开发者识别就可以了。
1.状态码抛异常
处理Web请求时引发的任何未处理的异常都会导致服务器返回HTTP 500响应。 但是,您自己编写的任何异常都可以使用@ResponseStatus注释(它支持HTTP规范定义的所有HTTP状态代码)进行注释。 当一个带注释的异常从一个控制器方法抛出,而不是在其他地方处理时,它将自动地使用指定的状态码返回适当的HTTP响应。
测试用例:

首先写一个异常处理类

@ResponseStatus(value= HttpStatus.NOT_FOUND, reason="找不到内容")
public class TdUserNotFoundException extends RuntimeException {

}
测试类加了一个注解@ResponseStatus,就是当出现这个异常的时候的返回状态。

然后写controller让其抛出TdUserNotFoundException这个异常

运行SpringBoot工程,通过swagger UI工具进行测试,测试结果为:



内容有自定义的返回码和错误信息,这样就解决了异常的问题,这样又会出现很多问题,比如必须指定抛出的异常是哪个异常,并且用哪个异常处理类去处理。
2. 单一Controller 异常处理
 以在Controller中添加@ExceptionHandler注解,以专门处理由同一控制器中的请求处理(@RequestMapping)方法抛出的异常。 这样的方法可以处理没有@ResponseStatus注释的异常,不需要自定义异常了,可以将用户重定向到专用的错误视图,可以构建完全自定义的错误响应。
这个处理方法关键就是异常处理方法写在一个Controller内,当这个Controller出现异常的时候会自动调用(注意,注解一定要用@Controller)。
异常处理方法:

@ExceptionHandler(DataIntegrityViolationException.class)
public TdException conflict() {
    TdException tdException = new TdException(TdResponseInfo._100100);
    return  tdException;
}
_100100(100100, "操作失败,数据校验失败,请检查数据"),
这个方法监控了一个DataIntegrityViolationException异常,当数据写入数据库会对内容进行校验,看看是否满足要求,比如非空校验,用户名的唯一性校验。

业务方法:

@RequestMapping("/createTdUser1")
public String createTdUser1(TdUserDto tdUserDto){
    throw new DataIntegrityViolationException("1111");
}
如果上面方法出现DataIntegrityViolationException异常会被自动捕捉。

测试:


用户名admin在数据库已经有了,再次插入会报错。



3.全局异常处理

控制器建议允许您使用完全相同的异常处理技术,但将其应用于整个应用程序,而不仅仅是应用于单个控制器。 可以把它们看作是一个注解驱动的拦截器。

@RestControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {
    private static final Logger LOGGER = LoggerFactory.getLogger(GlobalExceptionHandler.class);
@ExceptionHandler({RollbackException.class,MySQLIntegrityConstraintViolationException.class,DataIntegrityViolationException.class})
    public ExceptionBody sqlException(Exception e) {
        LOGGER.error("数据库异常:{}", e.getMessage(), e);
        return new ExceptionBody(TdResponseInfo._100100);
    }
}
同样是拦截数据库检验异常,可以专门写一个全局的异常处理类,注解使用
@RestControllerAdvice这样直接注入到@RestController里面,所有到的Contoller出现异常会被自动拦截。

同样是一个情景,当用户注册一个username就不能有相同的username,在数据库里面添加唯一性约束,然后在实体类也添加约束。

表字段
/**
 * 用户名
 */
@Column(nullable = false,name = "username",length = 10,unique = true)
private String username;
Controller:
Controller方法:
@RequestMapping(value = "/createTdUser",method = RequestMethod.POST)
public RespBody<TdUser> createTdRole(TdUserDto tdUserDto){
    TdUser tdUser = new TdUser();
    BeanUtils.copyProperties(tdUserDto,tdUser);
    if (StringUtils.isBlank(tdUser.getUsername()) || StringUtils.isBlank(tdUser.getPassword())){
        logger.info("用户名或者密码为空");
        return new RespBody<>(TdResponseInfo._100100,null);
    }
    tdUser.setSalt(tdUserDto.getUsername());
    tdUser.setCreateTime(new Date());
    tdUser.setModifiedTime(new Date());
    tdUser.setLocked(1);
    tdUser.setRemark("安存管理员");
    TdUser tdUserRes = tdUserService.createTdUser(tdUser);
    return new RespBody<>(TdResponseInfo._100000,tdUserRes);
}
预计TdUser tdUserRes = tdUserService.createTdUser(tdUser);行发生异常。

开始测试:


测试结果:



4.自定义异常处理

有的时候需要自定义一些已知的异常,当异常发生终止程序运行,抛出指定的返回码和返回信息。这个时候可以自定义异常拦截。

public class TdException extends RuntimeException

自定义异常处理器,注入到@RestController

@ExceptionHandler(TdException.class)
public ExceptionBody TdExceptionHandler(TdException tdException) {
    return new ExceptionBody(tdException.getCode(), tdException.getMessage());
}

使用:

if (tarObjRequest == null || tarObjService.findOneById(tarObjRequest.getId()) == null){
    logger.error("操作对象不存在");
    logger.info("操作对象不存在");
    throw  new TdException(TdResponseInfo._100104);
这样就可以通过全局异常处理拦截自定义异常了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值