Spring Boot统一异常处理方案示例

一、异常处理的原则
1、调用方法的时候返回布尔值来代替返回null,这样可以 NullPointerException。由于空指针是java异常里最恶心的异常。
2、 catch块里别不写代码。空catch块是异常处理里的错误事件,因为它只是捕获了异常,却没有任何处理或者提示。通常你起码要打印出异常信息,当然你最好根据需求对异常信息进行处理。
3、能抛受控异常(checked Exception)就尽量不抛受非控异常(unchecked Exception[Error或者RuntimeException的异常])。通过去掉重复的异常处理代码,可以提高代码的可读性。
4、 绝对不要让你的数据库相关异常显示到客户端。由于绝大多数数据库和SQLException异常都是受控异常,在Java中,你应该在DAO层把异常信息处理,然后返回处理过的能让用户看懂并根据异常提示信息改正操作的异常信息。
5、 在Java中,一定要在数据库连接,数据库查询,流处理后,在finally块中调用close()方法。
二、示例说明
本示例以“前后端分离模式”进行演示,调试用的异常信息通过日志的形式打印出来,代码并不完整,仅从异常处理进行部分代码示例。
1、创建异常类

@Getter //通过lombok插件实现省写setter或者getter方法
public class SellException extends RuntimeException {
    private Integer code;
    private String message;

 public SellException(ResultEnum resultEnum) {
    super(resultEnum.getMessage());
    this.code = resultEnum.getCode();
}

 public SellException(ResultEnum resultEnum) {
    super(resultEnum.getMessage());
    this.code = resultEnum.getCode();
}
}

2、使用Handler类捕获异常,统一格式返回给前端

@ControllerAdvice
public class SellExceptionHandler {

@ExceptionHandler(value = SellException.class)
@ResponseBody
public ResultVO handlerSellerException(SellException e){
    return ResultVOUtil.error(e.getCode(),e.getMessage());
}

}

返回结果类:
public class ResultVOUtil {

 public static ResultVO success(Object object) {
    ResultVO resultVO = new ResultVO();
    resultVO.setData(object);
    resultVO.setCode(0);
    resultVO.setMsg("成功");
    return resultVO;
}
  public static ResultVO success() {
    return success(null);
}

 public static ResultVO error(Integer code,String msg) {
    ResultVO resultVO = new ResultVO();
    resultVO.setCode(code);
    resultVO.setMsg(msg);
    return resultVO;
}
}
@Data
public class ResultVO<T> implements Serializable{
private static final long serialVersionUID = 8960474786737581150L;

private Integer code;//错误码
private String message;//错误信息
private T data;//具体内容
}

3、通过枚举定义统一异常的信息,方便定义管理

@Getter
public enum ResultEnum {

    SUCCESS(0,"成功"),

    PARAM_ERROR(1,"参数不正确"),

    PRODUCT_NOT_EXIST(10,"商品不存在"),

    PRODUCT_STOCK_ERROR(11,"商品库存不正确"),

    ORDER_NOT_EXIST(12,"订单不存在"),

    ORDERDETAIL_NOT_EXIST(13,"订单详情不存在"),

    ORDER_STATUS_ERROR(14,"订单状态不正确"),

    ORDER_UPDATE_FAIL(15,"订单更新失败"),

    ORDER_DETAIL_EMPTY(16,"订单详情为空"),

    CART_EMPTY(18,"购物车为空"),

    ORDER_OWNER_ERROR(19,"该订单不属于当前用户"),
    ;

    private Integer code;
    private String message;

ResultEnum(Integer code, String message) {
    this.code = code;
    this.message = message;
}
}


4、使用异常类
① controller层处理页面传来参数的校验,如参数不正确,抛出自定义异常,由handler捕获返回给页面。

@RestController
@RequestMapping("/buyer/order")

@Slf4j
public class BuyerOrderController {

@Autowired
private OrderService orderService;

@Autowired
private BuyerService buyerService;

//创建订单
@PostMapping("/create")
public ResultVO<Map<String,String>> create(@Valid OrderForm orderForm,
                                           BindingResult bindingResult){
    if (bindingResult.hasErrors()){
        log.error("[创建订单] 参数不正确,orderForm={}",orderForm);
        throw new SellException(ResultEnum.PARAM_ERROR.getCode(),
                bindingResult.getFieldError().getDefaultMessage());
    }
    OrderDTO orderDTO = OrderForm2OrderDTOConverter.convert(orderForm);
    if (CollectionUtils.isEmpty(orderDTO.getOrderDetailList())){
        log.error("[创建订单] 购物不能为空");
        throw new SellException(ResultEnum.CART_EMPTY);
    }

    OrderDTO createResult = orderService.create(orderDTO);
    Map<String,String> map = new HashMap<>();
    map.put("orderId",createResult.getOrderId());

    return ResultVOUtil.success(map);

}
//订单列表
@GetMapping("/list")
public ResultVO<List<OrderDTO>> list(@RequestParam("openid") String openid,
                                     @RequestParam(value = "page",defaultValue = "0") Integer page,
                                     @RequestParam(value = "size",defaultValue = "10") Integer size){
    if (StringUtils.isEmpty(openid)){
        log.error("[查询订单列表] openid为空");
        throw new SellException(ResultEnum.PARAM_ERROR);
    }
    PageRequest request = new PageRequest(page, size);
    Page<OrderDTO> orderDTOPage = orderService.findList(openid, request);

    return ResultVOUtil.success(orderDTOPage.getContent());
}

//订单详情
@GetMapping("/detail")
public ResultVO<OrderDTO> detail(@RequestParam("openid") String openid,
                                 @RequestParam("orderId") String orderId){

    OrderDTO orderDTO = buyerService.findOrderOne(openid, orderId);
    return ResultVOUtil.success(orderDTO);
}

//取消订单
@PostMapping("/cancel")
public ResultVO<OrderDTO> cancel(@RequestParam("openid") String openid,
                                 @RequestParam("orderId") String orderId) {

    buyerService.cancelOrderOne(openid, orderId);
    return ResultVOUtil.success();
}   

}

② service处理返回的结果的异常,抛出自定义异常,由handler捕获返回给页面。

@Service
@Slf4j

public class BuyerServiceImpl implements BuyerService {

@Autowired
private OrderService orderService;

@Override
public OrderDTO findOrderOne(String openid, String orderId) {
   return checkOrderOwner(openid, orderId);
}

@Override
public OrderDTO cancelOrderOne(String openid, String orderId) {
    OrderDTO orderDTO = checkOrderOwner(openid, orderId);
    if (orderDTO == null){
        log.error("[取消订单] 查不到该订单,orderDTO={}",orderId);
        throw new SellException(ResultEnum.ORDER_NOT_EXIST);
    }
    return orderService.cancel(orderDTO);
}

private OrderDTO checkOrderOwner(String openid, String orderId) {
    OrderDTO orderDTO = orderService.findOne(orderId);
    if (orderDTO == null){
        return null;
    }
    if (!orderDTO.getBuyerOpenid().equalsIgnoreCase(openid)){
        log.error("[查询订单] 订单的openid不一致,openid={},orderDTO={}",openid,orderDTO);
        throw new SellException(ResultEnum.ORDER_OWNER_ERROR);
    }
    return orderDTO;
}

}
Last modification:October 28th, 2019 at 06:11 pm

Leave a Comment