SpringBoot线上问题:@RequestBody参数中使用@Valid校验失效

1. 本地代码模拟:

前台参数校验,在@RequestBody参数中使用@Valid

    @RequestMapping(value = "/goodsAdd",method = RequestMethod.POST)
    public void addGoods(@RequestHeader String userCode,@RequestBody @Valid Goods goods) {
        goodsService.addGoods(goods);
    }

VO层校验,加上@NotBlank/NotNull/NotEmpty注解:

@Data
public class Goods {
    @Valid
    @NotEmpty(message = "商品id不能为空")
    private String goodsId;
}

封装下Response输出格式

package com.evan;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

/**
 * 请求响应结果
 * @param <T>
 */
@ApiModel(description = "返回对象")
@Data
public class Response<T> {
	public final static String CODE_OK = "200";
	public final static String MSG_OK = "ok";
	public final static String CODE_ERROR = "5000";
	public final static String MSG_ERROR = "error";
	@ApiModelProperty(value = "返回码,200为成功,其他为失败", required = true)
	private String resultCode;
	@ApiModelProperty(value = "返回码描述", required = true)
	private String resultMsg;
	@ApiModelProperty(value = "结果签名", required = true)
	private String sign;
	@ApiModelProperty(value = "详细数据", required = false)
	private T data;

	public Response() {
		resultCode = CODE_OK;
		resultMsg = MSG_OK;
	}

	public Response(String resultCode, String resultMsg) {
		this.resultCode = resultCode;
		this.resultMsg = resultMsg;
	}

	/**
	 * 成功结果
	 *
	 * @param data
	 * @param      <T>
	 * @return
	 */
	public static <T> Response<T> ok(T data, String sign) {
		Response<T> response = new Response<>();
		response.setData(data);
		response.setSign(sign);
		return response;
	}

	/**
	 * 成功结果
	 *
	 * @param data
	 * @param      <T>
	 * @return
	 */
	public static <T> Response<T> ok(T data) {
		Response<T> response = new Response<>();
		response.setData(data);
		return response;
	}


	/**
	 * 失败结果
	 *
	 * @param data
	 * @param      <T>
	 * @return
	 */
	public static <T> Response<T> error(T data) {
		Response<T> response = new Response<>();
		response.setData(data);
		return error(CODE_ERROR, MSG_ERROR, data);
	}

	/**
	 * 失败结果
	 *
	 * @param code
	 * @param msg
	 * @param data
	 * @param      <T>
	 * @return
	 */
	public static <T> Response<T> error(String code, String msg, T data) {
		Response<T> response = new Response<>(code, msg);
		response.setData(data);
		return response;
	}

	/**
	 * 失败结果
	 *
	 * @param data
	 * @param      <T>
	 * @return
	 */
	public static <T> Response<T> error(Exception exception, T data) {
		return errorException(exception, data);
	}

	/**
	 * 失败结果
	 * @param data
	 * @param      <T>
	 * @return
	 */
	public static <T> Response<T> errorException(Exception exception, T data) {
		Response<T> response = new Response<>();
		response.setData(data);
		response.setResultMsg(exception.getMessage());
		return response;
	}
}


这里简单使用@ControllerAdvice全局统一处理 数据校验异常 的结果

@RestControllerAdvice
@Slf4j
public class ExceptionAdvice {
   @ExceptionHandler(Exception.class)
    public Response<?> handleException(Exception e) {
        return Response.error( e.getMessage());
    }
}
2.线上问题复现:

当请求实体中goodsId为空时,偶然会返回400异常,这样明显不够友好,但是这种偶然性发生校验异常也很不正常,后面参考了spring3.1 issue说明了@Valid这种校验性需要另外捕获下MethodArgumentNotValidException以及Bind这个异常类,才能避免400异常
在这里插入图片描述

3.程序中添加这类校验性异常,统一异常处理:
@RestControllerAdvice
@Slf4j
public class ExceptionAdvice {
   @ExceptionHandler(Exception.class)
    public Response<?> handleException(Exception e) {
        return Response.error( e.getMessage());
    }
     /**
     * 拦截参数校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Response<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException methodArgumentNotValidException) {
        StringBuilder errorMessage=new StringBuilder();
        List<ObjectError> objectErrors=methodArgumentNotValidException.getBindingResult().getAllErrors();
        if (!CollectionUtils.isEmpty(objectErrors)) {
            for (int i = 0; i < objectErrors.size(); i++) {
                if (i == 0) {
                    errorMessage.append(objectErrors.get(i).getDefaultMessage());
                } else {
                    errorMessage.append(",");
                    errorMessage.append(objectErrors.get(i).getDefaultMessage());
                }
            }
        }else {
            errorMessage.append("MethodArgumentNotValidException occured.");
        }
        return Response.error("400", errorMessage.toString(),null);
    }
}

4.前台请求层处理:
   @RequestMapping(value = "/goodsAdd",method = RequestMethod.POST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public void addGoods(@RequestHeader String userCode,@RequestBody @Valid Goods goods) {
        goodsService.addGoods(goods);
    }

经验证,线上不再复现校验400异常,到此问题解决,参考文章:

https://github.com/spring-projects/spring-framework/issues/14790
https://blog.csdn.net/weixin_30409927/article/details/105448171

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

RachelHwang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值