【JSR303 校验入参List中的对象】

1. 简介

项目中使用的spring validate + jsr303对接口的入参对象进行校验。
今天在项目中编写某一个功能时,需要传入一个List对象的数据。然后便产生了对标题所描述问题的思考:JSR303如何校验List中的对象?

2. 问题描述

如下代码:

public ResponseResult orderSent(@Validate @RequestBody List<OrderSentQuery> orderSentQuerys){
	//do something
}
public class OrderSentQuery{

        /**
         * 必填
         * 店铺编号
         */
        @NotNull(message = "店铺编号不能为空")
        @ApiModelProperty(value = "店铺编号", example = "14536871")
        private Integer shopId;

        /**
         * 必填
         * 内部单号
         */
        @NotNull(message = "内部单号不能为空")
        @ApiModelProperty(value = "内部单号", example = "291814")
        private Integer oId;

        /**
         * 必填
         * 线上单号
         */
        @NotEmpty(message = "线上单号不能为空")
        @ApiModelProperty(value = "线上单号", example = "202106166232206600301205")
        private String soId;

        /**
         * 必填
         * 快递公司
         */
        @NotEmpty(message = "快递公司不能为空")
        @ApiModelProperty(value = "快递公司", example = "顺丰快递")
        private String lcName;

        /**
         * 必填
         * 快递单号
         */
        @NotEmpty(message = "快递单号不能为空")
        @ApiModelProperty(value = "快递单号", example = "SF1553517894539045676")
        private String lId;

        /**
         * 必填
         * 快递编码,【物流(快递)公司及打印模板】中的物流公司编号
         */
        @NotEmpty(message = "快递编码不能为空")
        @ApiModelProperty(value = "【物流(快递)公司及打印模板】中的物流公司编号", example = "SF")
        private String lcId;
}

上述代码中存在的问题时JSR303不会对OrderSentQuery中的属性进行校验的。所以我们就需要换种方式去解决它。

3. 问题解决

@ApiOperation("订单发货")
@ResponseBody
@RequestMapping(value = "/orderSent", method = RequestMethod.POST)
public ResponseResult orderSent(@Validated @RequestBody OrderSentQuery orderSentQuery) throws IOException {
        logger.info("订单发货:{}", orderSentQuery.toString());
        orderManager.orderSent(orderSentQuery);
        return new SuccessResponseResult();
}

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

import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;

/**
 * @description:
 * @author: WangYX
 * @create: 2022-02-17 17:55
 * @Version: 1.0.0
 **/
@Data
public class OrderSentQuery {

    @Valid
    @NotNull(message = "数据不能为空")
    @Size(min = 1)
    List<Sent> sent;

    @Data
    @Valid
    public static class Sent {

        /**
         * 必填
         * 店铺编号
         */
        @NotNull(message = "店铺编号不能为空")
        @ApiModelProperty(value = "店铺编号", example = "14536871")
        private Integer shopId;

        /**
         * 必填
         * 内部单号
         */
        @NotNull(message = "内部单号不能为空")
        @ApiModelProperty(value = "内部单号", example = "291814")
        private Integer oId;

        /**
         * 必填
         * 线上单号
         */
        @NotEmpty(message = "线上单号不能为空")
        @ApiModelProperty(value = "线上单号", example = "202106166232206600301205")
        private String soId;

        /**
         * 必填
         * 快递公司
         */
        @NotEmpty(message = "快递公司不能为空")
        @ApiModelProperty(value = "快递公司", example = "顺丰快递")
        private String lcName;

        /**
         * 必填
         * 快递单号
         */
        @NotEmpty(message = "快递单号不能为空")
        @ApiModelProperty(value = "快递单号", example = "SF1553517894539045676")
        private String lId;

        /**
         * 必填
         * 快递编码,【物流(快递)公司及打印模板】中的物流公司编号
         */
        @NotEmpty(message = "快递编码不能为空")
        @ApiModelProperty(value = "【物流(快递)公司及打印模板】中的物流公司编号", example = "SF")
        private String lcId;
    }
}

将List类型的数据转换成入参对象中的一个属性,并且在List对象上添加@Valid注解,以及在List的泛型对象上也要添加@Valid注解。

在编写的过程中还遇到了一个问题:Sent这个内部类需要添加static,设置为静态的。否则在调用接口的时候会抛出如下异常:
non-static inner classes like this can only by instantiated using default, no-argument constructor

问题描述:
服务端使用 @RequestBody 来接受参数,web端使用json传递数据的时候,报错。

问题的本质原因是:内部非静态类无法实例化。

//错误示例
public class A {
	class B;
	
	class B{
     int id ;
    }
}

//示例正确
public class A {
	class B;
	
	static class B implements Serializable{
     int id ;
    }
}

我这里出现上述异常的原因是采用内部类这种类型的数据。如果把Sent定义成普通的POJO,可以完全忽略上述的问题。

4. JSR303的使用及配置

  1. 引入依赖
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

如果在项目中引入了spring-boot-starter-web则不需要在另外引入jar包,在spring-boot-starter-web中已经引入了对应的jar包。
在这里插入图片描述
2. 添加JSR303的配置

    /**
     * Function:配置 JSR303 Bean Validator 定义
     *
     * @author Wangyx
     * @date 2021/12/28 16:31
     * @version 1.0.0
     */
    @Bean
    public Validator validator() {
        return new LocalValidatorFactoryBean();
    }
  1. 在全局的异常处理中拦截JSR303中出现的异常。
    /**
     * Function:数据校验异常处理
     *
     * @author Wangyx
     * @date 2021/12/28 17:54
     * @version 1.0.0
     */
    @ExceptionHandler(value = {MethodArgumentNotValidException.class, BindException.class})
    @ResponseBody()
    public ErrorResponseResult handleValidException(Exception e) {
        BindingResult bindingResult = null;
        if (e instanceof MethodArgumentNotValidException) {
            bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
        } else if (e instanceof BindException) {
            bindingResult = ((BindException) e).getBindingResult();
        }
        Map<String, String> errorMap = new HashMap<>();
        bindingResult.getFieldErrors().forEach((fieldError) -> errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()));
        return new ErrorResponseResult(new CommonException(CommonExceptionEnum.PARAME_ERROR, CommonExceptionEnum.PARAME_ERROR.getMsg() + ":" + errorMap.toString()));
    }

这样就可以避免在业务代码中处理JSR303中出现的异常。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值