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()) { Mapmap = 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(); } } }
难道在每个方法都写这么一大堆的异常结果响应处理吗,需要这么麻烦了?NO,参数校验不通过时,会抛出 BindingException 异常,可以在统一异常处理中,做统一处理,这样就不用在每个需要参数校验的地方都用 BindingResult 获取校验结果了。
做统一异常处理,可以使用SpringMVC提供的 @ControllerAdvice
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(); MaperrorMap = 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()); } }
由于以后随着业务的不断扩展,需要定义不同的异常码和规范标准化,所以,这里直接定义通用的异常枚举类。
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; } }
product/controller/BrandController.java
/** * 保存 */ @RequestMapping("/save") //@RequiresPermissions("product:brand:save") public R save(@Validated @RequestBody BrandEntity brand/*,BindingResult result*/){ // if(result.hasErrors()){ // Mapmap = 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(); }