统一异常处理

1、创建统一异常处理器

guigu-common中创建exception包,创建统一异常处理器类UnifiedExceptionHandler

package com.atguigu.common.exception;

@Slf4j
@Component //Spring容易自动管理
@RestControllerAdvice //在controller层添加通知。如果使用@ControllerAdvice,则方法上需要添加@ResponseBody
public class UnifiedExceptionHandler {

    /**
     * 未定义异常
     */
    @ExceptionHandler(value = Exception.class) //当controller中抛出Exception,则捕获
    public R handleException(Exception e) {
        log.error(e.getMessage(), e);
        return R.error();
    }
}

2.启动类上添加扫描

@SpringBootApplication
@ComponentScan({"com.atguigu.srb", "com.atguigu.common"})
public class ServiceCoreApplication {

3.创建自定义异常类

目标:使用一个或较少的异常类,可以捕获和显示所有的异常信息。
方案:因此,我们可以创建一个自定义异常类(必须是运行时异常),在程序中抛出这个自定义异常对象,并在统一异常处理器中捕获自定义异常对象

package com.atguigu.common.exception;

@Data
@NoArgsConstructor
public class BusinessException extends RuntimeException {

    //状态码
    private Integer code;

    //错误消息
    private String message;

}

3.1 添加异常处理方法

UnifiedExceptionHandler类中添加

/**
* 自定义异常
*/
@ExceptionHandler(BusinessException.class)
public R handleBusinessException(BusinessException e){
    log.error(e.getMessage(), e);
    return R.error().message(e.getMessage()).code(e.getCode());
}

4、修改Controller

在AdminIntegralGradeController的方法中添加异常处理,业务中需要的位置抛出BusinessException自定义异常

@ApiOperation("新增积分等级")
@PostMapping("/save")
public R save(
    @ApiParam(value = "积分等级对象", required = true)
    @RequestBody IntegralGrade integralGrade){

    //如果借款额度为空就手动抛出一个自定义的异常!
    if(integralGrade.getBorrowAmount() == null){
        //BORROW_AMOUNT_NULL_ERROR(-201, "借款额度不能为空"),
        throw new BusinessException(ResponseEnum.BORROW_AMOUNT_NULL_ERROR);
    }

    boolean result = integrationService.save(integralGrade);
    if (result) {
        return R.ok().message("保存成功");
    } else {
        return R.error().message("保存失败");
    }
}

5. 断言优化

目标:以优雅的 Assert(断言) 方式来校验业务的异常情况,消除 if else
示例:

package com.atguigu.srb.core;
import org.junit.jupiter.api.Test;
import org.springframework.util.Assert;

public class AssertTests {

	//if else的用法
    @Test
    public void test1() {
        Object o = null;
        if (o == null) {
            throw new IllegalArgumentException("用户不存在.");
        }
    }

	//断言的用法:更为简洁
    @Test
    public void test2() {
        // 另一种写法
        Object o = null;
        Assert.notNull(o, "用户不存在.");
    }
}

5.1自定义断言

用断言的方式封装异常的抛出

package com.atguigu.common.exception;

@Slf4j
public abstract class Assert {

    /**
     * 断言对象不为空
     * 如果对象obj为空,则抛出异常
     * @param obj 待判断对象
     */
    public static void notNull(Object obj, ResponseEnum responseEnum) {
        if (obj == null) {
            log.info("obj is null...............");
            throw new BusinessException(responseEnum);
        }
    }
}

5.2 修改controller

在controller中用断言替换if else

 Assert.notNull(integralGrade.getBorrowAmount(), ResponseEnum.BORROW_AMOUNT_NULL_ERROR);

六、Controller上层异常

6.1、异常分类

对异常按阶段进行分类,大体可以分成:进入Controller前的异常 和 业务层异常,具体可以参考下图:
统一异常处理_第1张图片

6.2、处理Controller上层异常

UnifiedExceptionHandler中添加

/**
     * Controller上一层相关异常
     */
@ExceptionHandler({
    NoHandlerFoundException.class,
    HttpRequestMethodNotSupportedException.class,
    HttpMediaTypeNotSupportedException.class,
    MissingPathVariableException.class,
    MissingServletRequestParameterException.class,
    TypeMismatchException.class,
    HttpMessageNotReadableException.class,
    HttpMessageNotWritableException.class,
    MethodArgumentNotValidException.class,
    HttpMediaTypeNotAcceptableException.class,
    ServletRequestBindingException.class,
    ConversionNotSupportedException.class,
    MissingServletRequestPartException.class,
    AsyncRequestTimeoutException.class
        })
public R handleServletException(Exception e) {
    log.error(e.getMessage(), e);
    //SERVLET_ERROR(-102, "servlet请求异常"),
    return R.error().message(ResponseEnum.SERVLET_ERROR.getMessage()).code(ResponseEnum.SERVLET_ERROR.getCode());
}

7.测试

你可能感兴趣的:(work,java)