spring validation 实现字段顺序验证

2018-03-03  本文已影响0人  时彬斌

我们在写接口时会面临很多的校验,比如一个接口中的一个入参实体类中的一个属性的校验,一个接口中一个入参实体类的多个属性的校验,多个接口中一个如参实体类中和接口有关的某几个属性的校验;

前两个都比较简单,不再赘述,主要说第三个,并且我们在校验时最后能实现顺序验证,例如一个接口有username 和 password两个属性,想要的顺序是先验证username再验证password;但是validation在验证时当多个参数同时出现校验异常时返回的错误是随机的,这个时候我们想要实现顺序验证应该怎么做呢。下面我们就一起探讨一下校验的顺序:

validation在设计时已经考虑到了这种问题,提出了group的概念,还是拿username和password来举例,代码如下:

新建一个user实体:


/**

* Created by @author shibinbin on 2018/3/3.

* 此处若写的有GroupSequence则代表重写了Default的验证方法,验证顺序按照顺序进行

*/

@Data

public class User{

@NotEmpty(message ="userName不能为空", groups = {UserNameCheck.class})

private StringuserName;

@NotEmpty(message ="password不能为空", groups = {PasswordCheck.class})

private Stringpassword;

}

新建三个校验接口UserNameCheck、PasswordCheck、UserCheckSequence.
UserNameCheck接口

public interface UserNameCheck {
}

PasswordCheck接口

public interface PasswordCheck {
}

UserCheckSequence顺序接口

/**
 * Created by @author shibinbin on 2018/3/3.
 * 此处的GroupSequence是根据目前的先后顺序进行验证,当存在一个验证不通过的情况则不会验证后一个分组
 * 直接返回验证错误信息,验证顺序是PasswordCheck--》UserNameCheck--》Default
 *
 * 关于Default,此处我springvalidation默认生成的验证接口,验证的范围是所有带有验证信息的属性,
 * 若是属性上方写了验证组,则是验证该组内的属性
 * 若是验证实体类类上写了GroupSequence({}) 则说明重写了Default验证接口,Default就
 * 按照GroupSequence里所写的组信息进行验证
 */
@GroupSequence({PasswordCheck.class, UserNameCheck.class})
public interface UserCheckSequence {
}

在Controller层进行如下设置即可使用顺序验证:

@RestController
public class UserController {

    @RequestMapping(value = "/", method = RequestMethod.POST)
    public Object login(@RequestBody @Validated({UserCheckSequence.class}) User user){
        return "succ";
    }
}

注:若不带RequestBody 则返回值是返回的数据不规范,返回如下所示:

{
    "timestamp": "2018-03-03T10:52:28.457+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "NotEmpty.user.password",
                "NotEmpty.password",
                "NotEmpty.java.lang.String",
                "NotEmpty"
            ],
            "arguments": [
                {
                    "codes": [
                        "user.password",
                        "password"
                    ],
                    "arguments": null,
                    "defaultMessage": "password",
                    "code": "password"
                }
            ],
            "defaultMessage": "password不能为空",
            "objectName": "user",
            "field": "password",
            "rejectedValue": null,
            "bindingFailure": false,
            "code": "NotEmpty"
        }
    ],
    "message": "Validation failed for object='user'. Error count: 1",
    "path": "/"
}

为了更好的去处理异常以及一些运行时异常建议加上如下异常处理句柄:

@RestControllerAdvice
public class SysExceptionHandler {
    @ExceptionHandler (MethodArgumentNotValidException.class)
    public Map<String, Object> paramInvalid(MethodArgumentNotValidException e) {
        Map<String, Object> map = new HashMap <>();
        map.put("code", 404);
        map.put("msg", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
        return map;
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    @ResponseBody
    public Map<String, Object> requestInvalid() {
        Map<String, Object> map = new HashMap <>();
        map.put("code", 404);
        map.put("msg", "请求输入参数格式不正确");
        return map;
    }
}

至此一个完整的springboot校验bean对象的实现已经完成;特别是多个接口复用一个实体类时,用分组的方式更快捷更高效。
代码链接:
https://github.com/binbinshi/springboot-bean-validation

上一篇 下一篇

猜你喜欢

热点阅读