java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java校验validate

Java校验validate介绍和使用实例

作者:Roc Lau

这篇文章主要介绍了Java校验validate介绍和使用的相关资料,还介绍了如何使用@Valid和@Validated注解进行声明式校验,以及如何处理复杂校验需求,通过自定义校验注解来实现,需要的朋友可以参考下

Java校验validate

日常开发中,我们时常需要提供可靠的 API 接口,此时对于请求的入参就需要校验,以保证最终数据入库的正确性,这就成了必不可少的活。例如说,用户注册时,会校验手机格式的正确性、邮箱格式的正确性、密码非弱密码等。

但是如果使用 if-else 这种代码去校验, 那么需要校验的地方有很多情况下,代码量就会变的十分臃肿,若是一个类请求参数校验字段又多的化,相信各位小伙伴对不会开心,这么干肯定不合适,代码也不优雅,那么如何解决这个问题呢?

答案就是下面要介绍的 validation

validation介绍

validation 技术在Java中运用最早在2009 年,Java 官方提出了 Bean Validation 规范,而后经历了JSR303、JSR349、JSR380 三次标准的更迭,发展到了 2.0 。

Bean Validation 和 我们以前学习过的 JPA 一样,只提供规范,不提供具体的实现。因此实际使用过程,常用的是 hibernate 的校验组件:org.hibernate.hibernate-validator

常见的注解

通常情况下,在javax.validation.constraints 包下,定义了一系列的约束(constraint)注解,一共 22 个注解,快速略过即可。如下:

空和非空检查

数值检查

Boolean 值检查

长度检查

日期检查

其它检查

Hibernate Validator 附加的约束注解,在org.hibernate.validator.constraints 包下,定义了一系列的约束(constraint)注解。常见的如示。

其他的就不一一列举了,有感兴趣的小伙伴可以去源码包看看。

@Valid和 @Validated

对于初学者来说,很容易搞混 @Valid 和 @Validated 注解。

spring-boot-starter-web 依赖里,已经默认引入 hibernate-validator 依赖,所以本示例使用的是 Hibernate Validator 作为 Bean Validation 的实现框架。

1、简单校验

编写实体类(这里以常用的用户注册为场景)

@Data
public class SysUser {
    private Long userId;
    /**
     * 账号
     */
    @NotBlank(message = "用户名不能为空")
    @Size(min = 6, message = "用户名长度不能小于6个字符")
    private String username;
    /**
     * 密码
     */
    @NotEmpty(message = "密码不能为空")
    @Size(min = 8, message = "密码长度不能小于8个字符")
    private String password;
    /**
     * 手机号
     */
    @NotBlank(message = "手机号不能为空")
    @Size(min = 11, max = 11, message = "手机号长度不对")
    private String mobile;
}

编写前端控制器

@RestController
@RequestMapping("/user")
public class SysUserController {
    @PostMapping("/add")
    public R addUser(@RequestBody @Valid SysUser sysUser) {
        System.out.println("走到这里说明校验成功");
        System.out.println(sysUser);
        return R.ok(R.SUCCESS_MSG);
    }
}

编写前端响应封装实体

public class R extends HashMap<String, Object> {
    private static final long serialVersionUID = 1L;
    public static final String SUCCESS_MSG = "操作成功!";
    public static final String FAIL_MSG = "操作失败!";
    public R() {
        this.put((String) "code", 0);
    }
    public static R error() {
        return error(500, "未知异常,请联系管理员");
    }
public static R error(String msg) { return error(500, msg); } public static R error(int code, String msg) { R r = new R(); r.put((String) "code", code); r.put((String) "msg", msg); return r; } public static R ok(String msg) { R r = new R(); r.put((String) "msg", msg); return r; } public static R ok(Object object) { R r = new R(); r.put("result", object); return r; } public static R ok(int code, String msg) { R r = new R(); r.put((String) "code", code); r.put((String) "msg", msg); return r; } public static R ok(Map&lt;String, Object&gt; map) { R r = new R(); r.putAll(map); return r; } public static R ok() { return new R(); } public R put(String key, Object value) { super.put(key, value); return this; } 

编写自定义异常(用于后续业务抛出异常错误)

public class RRException extends RuntimeException {

private static final long serialVersionUID = 1L;

private String msg;

private int code = 500;

public RRException(String msg) {

super(msg);

this.msg = msg;

}

public RRException(String msg, Throwable e) {

super(msg, e);

this.msg = msg;

}

public RRException(String msg, int code) {

super(msg);

this.msg = msg;

this.code = code;

}

public RRException(String msg, int code, Throwable e) {

super(msg, e);

this.msg = msg;

this.code = code;

}

public String getMsg() {

return msg;

}

public void setMsg(String msg) {

this.msg = msg;

}

public int getCode() {

return code;

}

public void setCode(int code) {

this.code = code;

}

}

当访问/user/add这个post接口时,如果参数不符合Model中定义的话,程序中就回抛出400异常状态码,并提示错误信息,如下所示。

{
“timestamp”: “2021-05-20T01:08:28.831+0000”,
“status”: 400,
“error”: “Bad Request”,
“errors”: [
{
“codes”: [ “Size.sysUser.mobile”, “Size.mobile”, “Size.java.lang.String”, “Size” ],
“arguments”: [ { “codes”: [ “sysUser.mobile”, “mobile” ], “arguments”: null, “defaultMessage”: “mobile”, “code”: “mobile” },
11,
11
],
“defaultMessage”: “手机号长度不对”,
“objectName”: “sysUser”,
“field”: “mobile”,
“rejectedValue”: “155833013”,
“bindingFailure”: false,
“code”: “Size”
}
],
“message”: “Validation failed for object=‘sysUser'. Error count: 1”,
“path”: “/user/add”
}

自定义校验注解

虽然 JSR303 和 Hibernate Validtor 已经提供了很多校验注解,但是当面对复杂参数校验时,还是不能满足我们的要求,这时候我们就需要 自定义校验注解。

下面以“List数组中不能含有null元素”为实例自定义校验注解

1、注解定义如示。

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})

@Retention(RUNTIME)

@Documented

@Constraint(validatedBy = ListNotHaveNullValidatorImpl.class)//此处指定了注解的实现类

public @interface ListNotHaveNull {

/**

* 添加value属性,可以作为校验时的条件,若不需要,可去掉此处定义

/

int value() default 0;

String message() default “List集合中不能含有null元素”;

Class<?>[] groups() default {};

Class<? extends Payload>[] payload() default {};

/*

* 定义List,为了让Bean的一个属性上可以添加多套规则

*/

@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})

@Retention(RUNTIME)

@Documented

@interface List {

ListNotHaveNull[] value();

}

}

编写自定义校验实现类

@Service
public class ListNotHaveNullValidatorImpl implements ConstraintValidator<ListNotHaveNull, List> {
private int value;
@Override
public void initialize(ListNotHaveNull constraintAnnotation) {
//传入value 值,可以在校验中使用
this.value = constraintAnnotation.value();
}
public boolean isValid(List list, ConstraintValidatorContext constraintValidatorContext) {
for (Object object : list) {
if (object == null) {
//如果List集合中含有Null元素,校验失败
return false;
} else if (object instanceof String) {
String value = object.toString();
if (value.trim().length() == 0){
return false;
}
}
}
return true;
}
}

model中添加注解:

@Data
public class SysRole {
private Long roleId; @NotBlank(message = "角色名不能为空") private String name; @NotEmpty(message = "资源列表不能为空") @ListNotHaveNull(message = "List 中不能含有null元素") @Valid private List&lt;String&gt; paths; 

编写前端控制器

@PostMapping(“/addRole”)

public R addRole(@RequestBody @Valid SysRole sysRole) {

System.out.println(“走到这里说明校验成功”);

System.out.println(sysRole);

return R.ok(R.SUCCESS_MSG);

}

使用方法同 “简单校验”,在在需要校验的Model上面加上@Valid即可。

通用的Validtor校验工具类

public class ValidatorUtils {
private ValidatorUtils() { }
private static Validator validator; static { validator = Validation.buildDefaultValidatorFactory().getValidator(); } /** * 校验对象 * * @param object 待校验对象 * @param groups 待校验的组 * @throws RRException 校验不通过,则报RRException异常 */ public static void validateEntity(Object object, Class&lt;?&gt;... groups) throws RRException { Set&lt;ConstraintViolation&lt;Object&gt;&gt; constraintViolations = validator.validate(object, groups); if (!constraintViolations.isEmpty()) { Iterator&lt;ConstraintViolation&lt;Object&gt;&gt; iterator = constraintViolations.iterator(); StringBuilder msg = new StringBuilder(); while (iterator.hasNext()) { ConstraintViolation&lt;Object&gt; constraint = iterator.next(); msg.append(constraint.getMessage()).append(','); } throw new RRException(msg.toString().substring(0,msg.toString().lastIndexOf(','))); } } 

使用方式,在接收到前端传递的参数后,使用ValidatorUtils.validateEntity(【参数名】);即可校验,支持分组校验,分组需要定义分组接口。

总结

到此这篇关于Java校验validate介绍和使用的文章就介绍到这了,更多相关Java校验validate内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文