SpringBoot 中怎么来处理前端传来参数校验异常

1、前提

  • 导入依赖
	 <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>2.0.1.Final</version>
        </dependency>

2、直接校验,返回系统给你的错误信息

  • 从前端传来的封装对象,该对象的bean(BrandEntity 为例)属性你添加了校验注解(@NotNull,@NotEmpty 等)。
  • @Valid标注在controller里面的请求体,告诉spring该实体类的属性需要校验,那么一旦校验不通过就会返回错误信息给前端
    @RequestMapping("/save")
    public R save(@Valid @RequestBody BrandEntity brand ){
    
    

3、利用BindingResult

  @RequestMapping("/save")
    public R save(@Valid @RequestBody BrandEntity brand , BindingResult result){
    
    
  • BindingResult里面就封装的对应实体类的校验结果
  • BindingResult
public interface BindingResult extends Errors {
    
    
    String MODEL_KEY_PREFIX = BindingResult.class.getName() + ".";

    @Nullable
    Object getTarget();

    Map<String, Object> getModel();

    @Nullable
    Object getRawFieldValue(String var1);

    @Nullable
    PropertyEditor findEditor(@Nullable String var1, @Nullable Class<?> var2);

    @Nullable
    PropertyEditorRegistry getPropertyEditorRegistry();

    String[] resolveMessageCodes(String var1);

    String[] resolveMessageCodes(String var1, String var2);

    void addError(ObjectError var1);

    default void recordFieldValue(String field, Class<?> type, @Nullable Object value) {
    
    
    }

    default void recordSuppressedField(String field) {
    
    
    }

    default String[] getSuppressedFields() {
    
    
        return new String[0];
    }
}

  • 它继承于Errors
public interface Errors {
    
    
    String NESTED_PATH_SEPARATOR = ".";

    String getObjectName();

    void setNestedPath(String var1);

    String getNestedPath();

    void pushNestedPath(String var1);

    void popNestedPath() throws IllegalStateException;

    void reject(String var1);

    void reject(String var1, String var2);

    void reject(String var1, @Nullable Object[] var2, @Nullable String var3);

    void rejectValue(@Nullable String var1, String var2);

    void rejectValue(@Nullable String var1, String var2, String var3);

    void rejectValue(@Nullable String var1, String var2, @Nullable Object[] var3, @Nullable String var4);

    void addAllErrors(Errors var1);

    boolean hasErrors();

    int getErrorCount();

    List<ObjectError> getAllErrors();

    boolean hasGlobalErrors();

    int getGlobalErrorCount();

    List<ObjectError> getGlobalErrors();

    @Nullable
    ObjectError getGlobalError();

    boolean hasFieldErrors();

    int getFieldErrorCount();

    List<FieldError> getFieldErrors();

    @Nullable
    FieldError getFieldError();

    boolean hasFieldErrors(String var1);

    int getFieldErrorCount(String var1);

    List<FieldError> getFieldErrors(String var1);

    @Nullable
    FieldError getFieldError(String var1);

    @Nullable
    Object getFieldValue(String var1);

    @Nullable
    Class<?> getFieldType(String var1);
}
  • 再次封装成自己想返回的数据
  • R是我另外一篇文章用来做封装给前端数据的示例R示例
        if (result.hasErrors()){
    
    
            // 获取错误结果
            Map<String,String> map = new HashMap<>();
            result.getFieldErrors().forEach((item)->{
    
    
                // FieldError 获取错误提示
                String message = item.getDefaultMessage();
                String field = item.getField();
                map.put(field,message);
            });
           return R.error(400,"提交数据不合法").put("data",map);
        }

4、集中处理

  • 统一异常处理,利用SpringMVC提供的ControllerAdvice
  • 抽取处理异常的类 ExcExceptionControllerAdvice
  • @RestControllerAdvice 的basePackages指定你需要处理的controller
  • @ExceptionHandler(value = MethodArgumentNotValidException.class) value :你需要处理什么样的异常
@Slf4j
//@ControllerAdvice(basePackages = "")
@RestControllerAdvice(basePackages = "")
public class ExcExceptionControllerAdvice {
    
    

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public R handleValidException(MethodArgumentNotValidException e){
    
    
        log.error("数据校验出现问题{},异常类型,{}",e.getMessage(),e.getClass());
        BindingResult bindingResult = e.getBindingResult();
        Map<String,String> map = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError)->{
    
    
            map.put(fieldError.getField(),fieldError.getDefaultMessage());
        });
        return R.error(BizCodeEnume.VAILD_EXCEPTION.getCode(),BizCodeEnume.VAILD_EXCEPTION.getMsg()).put("data",map);
    }
    @ExceptionHandler(value = Throwable.class)
    public R handleException(Throwable throwable){
    
    
        log.error("错误:" + throwable);
        return R.error(BizCodeEnume.UNKNOW_EXCEPTION.getCode(),BizCodeEnume.UNKNOW_EXCEPTION.getMsg());
    }
}
  • 在使用该集中处理的时候,必须要controller抛出异常,所以在请求参数中去掉BindingResult那么处理类中就会感知到异常。
  @RequestMapping("/save")
    public R save(@Valid @RequestBody BrandEntity brand){
    
    
  • 规范系统错误码
/**
	错误码和错误信息定义类
	1 错误码定义规则为5个数字
	2 前两位代表错误场景,后三位代码错误码,例如10001.10代表通用,001系统异常
	3 维护错误码后需要维护错误描述,将他们定义为枚举形式
*/
public enum BizCodeEnume {
    
    

    UNKNOW_EXCEPTION(10000,"系统未知异常"),
    VAILD_EXCEPTION(10001,"参数格式检验失败");

    private int code;
    private String msg;

    BizCodeEnume(int code, String msg) {
    
    
        this.code = code;
        this.msg = msg;
    }

    public String getMsg() {
    
    
        return msg;
    }

    public int getCode() {
    
    
        return code;
    }
}

5、增强(JSR303分组校验)

public @interface NotBlank {
    
    
    String message() default "{javax.validation.constraints.NotBlank.message}";
    Class<?>[] groups() default {
    
    };
  • 所以我们定义一个接口作为标识,不用做任何操作
  • 例如
public interface AddGroup {
    
    
}

  • 在注解上面标记
	@NotBlank(groups = AddGroup.class)
	private String brandName;
  • 并在对应方法中写明,那么该名字就只会在save方法的时候校验
  • @Validated与上面没用分组的@Valid不一样,这里需要注意
    @RequestMapping("/save")
    public R save(@Validated({
    
     AddGroup.class }) @RequestBody BrandEntity brand ){
    
    /

猜你喜欢

转载自blog.csdn.net/JISOOLUO/article/details/105584217