异常统一处理

1.JSR3030基本用法学习

  • 1)、给Bean添加校验注解:javax.validation.constraints,并定义自己的message提示

  • 2)、开启校验功能@Valid 效果:校验错误以后会有默认的响应;

  • 3)、给校验的bean后紧跟一个BindingResult,就可以获取到校验的结果

a)给bean定义自己的message

@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
    private static final long serialVersionUID = 1L;
​
    /**
     * 品牌id
     */
    @TableId
    private Long brandId;
    /**
     * 品牌名
     */
    @NotBlank(message = "品牌名不能为空")
    private String name;
    /**
     * 品牌logo地址
     */
    @NotEmpty(message = "URL地址不能为空")
    @URL(message = "logo必须是一个合法的url地址")
    private String logo;
    /**
     * 介绍
     */
    private String descript;
    /**
     * 显示状态[0-不显示;1-显示]
     */
    private Integer showStatus;
    /**
     * 检索首字母
     */
    @NotEmpty
    @Pattern(regexp = "/^[a-zA-Z]$/", message = "检索首字母必须是一个字母")
    private String firstLetter;
    /**
     * 排序
     */
    @NotNull
    @Min(value = 0, message = "排序必须大于等于0")
    private Integer sort;
​
}

b)Controller 中需要校验的参数Bean前添加 @Valid 开启校验功能

紧跟在校验的Bean后添加一个BindingResult,BindingResult封装了前面Bean的校验结果。

@RestController
@RequestMapping("product/brand")
public class BrandController {
​
    @RequestMapping("/save")
    public R save (@Valid @RequestBody BrandEntity brand, BindingResult bindingResult)  {
        if (bindingResult.hasErrors()) {
            Map map = new HashMap<>();
            bindingResult.getFieldErrors().forEach( (item) -> {
                String message = item.getDefaultMessage();
                String field = item.getField();
                map.put( field , message );
            } );
            return R.error( 400 , "提交的数据不合法 !" ).put("data", map);
        }
                else
                {
                    brandService.save(brand);
        return R.ok();
                }
    }
​
}

2.异常的统一处理

难道在每个方法都写这么一大堆的异常结果响应处理吗,需要这么麻烦了?NO,参数校验不通过时,会抛出 BindingException 异常,可以在统一异常处理中,做统一处理,这样就不用在每个需要参数校验的地方都用 BindingResult 获取校验结果了。

做统一异常处理,可以使用SpringMVC提供的 @ControllerAdvice

系统错误码

2.1 在 gulimall-product 服务创建异常类文件:

product/exception/GulimallExceptionControllerAdvice.java

package com.lcl.gulimall.product.exception;
​
import com.lcl.common.exception.BizCodeEnum;
import com.lcl.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
​
import java.util.HashMap;
import java.util.Map;
​
/**
 * 集中处理所有异常
 *
 */
​
@Slf4j
//@ResponseBody
//@ControllerAdvice(basePackages = "com.lcl.gulimall.product.controller")
// 处理product.controller包下边的异常
@RestControllerAdvice(basePackages = "com.lcl.gulimall.product.controller")
public class GulimallExceptionControllerAdvice {
​
  @ExceptionHandler(value = MethodArgumentNotValidException.class)
  public R handleValidException(MethodArgumentNotValidException e){
    log.error("数据校验出现问题{},异常类型:{}", e.getMessage(), e.getClass());
    BindingResult bindingResult = e.getBindingResult();
​
    Map errorMap = new HashMap<>();
    bindingResult.getFieldErrors().forEach((fieldError)->{
      errorMap.put(fieldError.getField(),fieldError.getDefaultMessage());
    });
​
    return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(),
        BizCodeEnum.VALID_EXCEPTION.getMsg()).put("data", errorMap);
​
  }
​
  /**
   * 通用的异常处理方法
   * @description 如果找不到具体的异常处理方法,则由该方法处理
   *
   * @param throwable
   * @return
   */
  @ExceptionHandler(value = Throwable.class)
  public R handleException(Throwable throwable){
    log.error("错误:", throwable);
    return R.error(BizCodeEnum.UNKNOW_EXCEPTION.getCode(), BizCodeEnum.UNKNOW_EXCEPTION.getMsg()); 
  }
}

2.2、在gulimall-common 服务创建通用的异常代码枚举类

由于以后随着业务的不断扩展,需要定义不同的异常码和规范标准化,所以,这里直接定义通用的异常枚举类。

gulimall-common/src/main/java/com/lcl/common/exception/BizCodeEnum.java

package com.lcl.common.exception;
​
/***
 * 错误码和错误信息定义类
 * 1. 错误码定义规则为5为数字
 * 2. 前两位表示业务场景,最后三位表示错误码。例如:100001。10:通用 001:系统未知异常
 * 3. 维护错误码后需要维护错误描述,将他们定义为枚举形式
 * 错误码列表:
 *  10: 通用
 *      001:参数格式校验
 *  11: 商品
 *  12: 订单
 *  13: 购物车
 *  14: 物流
 *
 *
 */
public enum BizCodeEnum {
  UNKNOW_EXCEPTION(10000, "系统未知异常"),
  VALID_EXCEPTION(10001, "参数格式校验失败");
​
  private int code;
  private String msg;
  BizCodeEnum(int code, String msg){
    this.code = code;
    this.msg = msg;
  }
​
  public int getCode(){
    return code;
  }
​
  public String getMsg(){
    return msg;
  }
}

2.3、修改原方法的异常处理

product/controller/BrandController.java

/**
     * 保存
     */
    @RequestMapping("/save")
    //@RequiresPermissions("product:brand:save")
    public R save(@Validated @RequestBody BrandEntity brand/*,BindingResult result*/){
//        if(result.hasErrors()){
//            Map map = new HashMap<>();
//            //1、获取校验的错误结果
//            result.getFieldErrors().forEach((item)->{
//                //FieldError 获取到错误提示
//                String message = item.getDefaultMessage();
//                //获取错误的属性的名字
//                String field = item.getField();
//                map.put(field,message);
//            });
//
//            return R.error(400,"提交的数据不合法").put("data",map);
//        }else {
//
//        }
​
        brandService.save(brand);
​
        return R.ok();
    }

你可能感兴趣的:(java)