bean通过注解实现字段校验

参数校验是我们程序开发中必不可少的过程。用户在前端页面上填写表单时,前端js程序会校验参数的合法性,当数据到了后端,为了防止恶意操作,保持程序的健壮性,后端同样需要对数据进行校验。后端参数校验最简单的做法是直接在业务方法里面进行判断,当判断成功之后再继续往下执行。但这样带给我们的是代码的耦合,冗余。当我们多个地方需要校验时,我们就需要在每一个地方调用校验程序,导致代码很冗余,且不美观。

那么如何优雅的对参数进行校验呢?JSR303就是为了解决这个问题出现的,本篇文章主要是介绍 JSR303,Hibernate Validator 等校验工具的使用,以及自定义校验注解的使用。

校验框架介绍

JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了。注解如下:

Hibernate validator 在JSR303的基础上对校验注解进行了扩展,扩展注解如下:

Spring validtor 同样扩展了jsr303,并实现了方法参数和返回值的校验

Spring 提供了MethodValidationPostProcessor类,用于对方法的校验

代码实现

添加JAR包依赖

在pom.xml中添加如下依赖:

复制代码

        <!--jsr 303-->
        <dependency>
            <groupId>javax.validation</groupId>
            <artifactId>validation-api</artifactId>
            <version>1.1.0.Final</version>
        </dependency>
        <!-- hibernate validator-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>5.2.0.Final</version>
        </dependency>

复制代码

 

最简单的参数校验

1、Model 中添加校验注解

复制代码

public class Book {
    private long id;

    /**
     * 书名
     */
    @NotEmpty(message = "书名不能为空")
    private String bookName;
    /**
     * ISBN号
     */
    @NotNull(message = "ISBN号不能为空")
    private String bookIsbn;
    /**
     * 单价
     */
    @DecimalMin(value = "0.1",message = "单价最低为0.1")
    private double price; // getter setter .......  }

复制代码

 

2、在controller中使用此校验

复制代码

 /**
     * 添加Book对象
     * @param book
     */
    @RequestMapping(value = "/book", method = RequestMethod.POST)
    public void addBook(@RequestBody @Valid Book book) {
        System.out.println(book.toString());
    }

复制代码

 

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

自定义校验注解

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

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

1、注解定义如下:

复制代码

package com.beiyan.validate.annotation;

import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

/**
 * 自定义参数校验注解
 * 校验 List 集合中是否有null 元素
 */

@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = ListNotHasNullValidatorImpl.class)此处指定了注解的实现类为ListNotHasNullValidatorImpl

public @interface ListNotHasNull {

    /**
     * 添加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 {
        ListNotHasNull[] value();
    }
}

复制代码

 

2、注解实现类: 

复制代码

package com.beiyan.validate.annotation;

import org.springframework.stereotype.Service;

import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.List;

/**
 * 自定义注解ListNotHasNull 的实现类
 * 用于判断List集合中是否含有null元素
 */

@Service
public class ListNotHasNullValidatorImpl implements ConstraintValidator<ListNotHasNull, List> {

    private int value;

    @Override
    public void initialize(ListNotHasNull constraintAnnotation) {
        //传入value 值,可以在校验中使用
        this.value = constraintAnnotation.value();
    }

    public boolean isValid(List list, ConstraintValidatorContext constraintValidatorContext) {
        for (Object object : list) {
            if (object == null) {
                //如果List集合中含有Null元素,校验失败
                return false;
            }
        }
        return true;
    }

}

复制代码

 

3、model添加注解:

复制代码

public class User {

    //其他参数 .......

/**
     * 所拥有的书籍列表
     */
    @NotEmpty(message = "所拥有书籍不能为空")
    @ListNotHasNull(message = "List 中不能含有null元素")
    @Valid
    private List<Book> books;
    //getter setter 方法.......
}

复制代码

 

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

分组验证

对同一个Model,我们在增加和修改时对参数的校验也是不一样的,这个时候我们就需要定义分组验证,步骤如下

1、定义两个空接口,分别代表Person对象的增加校验规则和修改校验规则

复制代码

/**
 * 可以在一个Model上面添加多套参数验证规则,此接口定义添加Person模型新增时的参数校验规则
 */
public interface PersonAddView {
}

/**
 * 可以在一个Model上面添加多套参数验证规则,此接口定义添加Person模型修改时的参数校验规则
 */
public interface PersonModifyView {
}

复制代码

 

2、Model上添加注解时使用指明所述的分组

复制代码

public class Person {
    private long id;
    /**
     * 添加groups 属性,说明只在特定的验证规则里面起作用,不加则表示在使用Deafault规则时起作用
     */
    @NotNull(groups = {PersonAddView.class, PersonModifyView.class}, message = "添加、修改用户时名字不能为空", payload = ValidateErrorLevel.Info.class)
    @ListNotHasNull.List({
            @ListNotHasNull(groups = {PersonAddView.class}, message = "添加上Name不能为空"),
            @ListNotHasNull(groups = {PersonModifyView.class}, message = "修改时Name不能为空")})
    private String name;

    @NotNull(groups = {PersonAddView.class}, message = "添加用户时地址不能为空")
    private String address;

    @Min(value = 18, groups = {PersonAddView.class}, message = "姓名不能低于18岁")
    @Max(value = 30, groups = {PersonModifyView.class}, message = "姓名不能超过30岁")
    private int age;
  //getter setter 方法......
}

复制代码

 

3、启用校验

此时启用校验和之前的不同,需要指明启用哪一组规则

复制代码

  /**
     * 添加一个Person对象
     * 此处启用PersonAddView 这个验证规则
     * 备注:此处@Validated(PersonAddView.class) 表示使用PersonAndView这套校验规则,若使用@Valid 则表示使用默认校验规则,
     * 若两个规则同时加上去,则只有第一套起作用
     */
    @RequestMapping(value = "/person", method = RequestMethod.POST)
    public void addPerson(@RequestBody @Validated({PersonAddView.class, Default.class}) Person person) {
        System.out.println(person.toString());
    }

    /**
     * 修改Person对象
     * 此处启用PersonModifyView 这个验证规则
     */
    @RequestMapping(value = "/person", method = RequestMethod.PUT)
    public void modifyPerson(@RequestBody @Validated(value = {PersonModifyView.class}) Person person) {
        System.out.println(person.toString());
    }

复制代码

 

Spring validator 方法级别的校验

JSR和Hibernate validator的校验只能对Object的属性进行校验,不能对单个的参数进行校验,spring 在此基础上进行了扩展,添加了MethodValidationPostProcessor拦截器,可以实现对方法参数的校验,实现如下:

1、实例化MethodValidationPostProcessor

@Bean
    public MethodValidationPostProcessor methodValidationPostProcessor() {
        return new MethodValidationPostProcessor();
    }

 

2、在所要实现方法参数校验的类上面添加@Validated,如下

@RestController
@Validated
public class ValidateController {
}

 

3、在方法上面添加校验规则:

  @RequestMapping(value = "/test", method = RequestMethod.GET)
    public String paramCheck(@Length(min = 10) @RequestParam String name) {
        System.out.println(name);
        return null;
    }

 

当方法上面的参数校验失败,spring 框架就回抛出异常

复制代码

{
  "timestamp": 1476108200558,
  "status": 500,
  "error": "Internal Server Error",
  "exception": "javax.validation.ConstraintViolationException",
  "message": "No message available",
  "path": "/test"
}

复制代码

从此可以优雅的对参数进行校验了 

写在后面的话:

本篇文章只列举了常用的几种校验方法,其实关于校验的内容还有很多:

校验信息的国际化显示,

组合参数校验,

message中使用EL表达式,

将校验信息绑定到ModelAndView等,这里就不一一列出了,下面这几篇文章写的也不错,读者可以参考:

将校验信息绑定到ModelAndView    http://www.voidcn.com/blog/983836259/article/p-5794496.html

集成Bean Validation 1.1(JSR-349)到SpringMVC   https://my.oschina.net/qjx1208/blog/200946

一 简介

SpringMVC支持与JSR 349 Bean Validation API的集成。借助于Bean验证,可以非常容易地将验证元数据应用到实体类,并且通过合适的视图向用户展示可能的错误结果。在模型类中可以通过注解对属性验证进行定义,常见的注解有:@Size ,@Email ,@Pattern,@Max等,分别验证长度,邮箱格式,自定义正则表达式,最大值(PS:更多相关注解可以百度或者查API)

 

二 测试实例

(1)新建一个动态Java web项目,然后下载“Hibernate Validator”的jar包,下载地址:http://hibernate.org/validator/ ,最后是导入必要的几个jar包和springmvc所需要的jar包,最后的项目结构如下:

wKiom1cfZk6xzmoMAABI_YIswnQ310.png    wKiom1cfZoGg61rwAAAr0yIMEuA577.png

(2)配置文件web.xml:

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
	  http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

	<servlet>
		<servlet-name>springmvc</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>*.html</url-pattern>
	</servlet-mapping>
	
	<filter>
		<filter-name>characterEncodingFilter</filter-name>
		<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>characterEncodingFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

</web-app>

 

在web.xml中定义了springmvc处理请求的后缀是.html,同时设置了编码为UTF-8

(3)配置文件springmvc-servlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
       					   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
       					   http://www.springframework.org/schema/context
       					   http://www.springframework.org/schema/context/spring-context-4.0.xsd
       					   http://www.springframework.org/schema/mvc 
       					   http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

	<context:component-scan base-package="cn.zifangsky.* *.controller" />

	<context:annotation-config />  <!-- 激活Bean中定义的注解 -->
    <mvc:annotation-driven validator="validator"/> 

	<!-- 视图相关配置 -->
	<bean
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="prefix" value="/WEB-INF/pages/" />  <!-- 视图前缀 -->
		<property name="suffix" value=".jsp" />  <!-- 视图后缀 -->
	</bean>
	
	<bean id="messageSource"
          class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:errors" />
    </bean>
    
	<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="validationMessageSource" ref="messageSource"/>
    </bean>
</beans>

在这里,主要是配置了视图相关配置,国际化(PS:在这里就是根据中文和英文网页显示不同的错误提示信息),以及定义了验证相关的配置。需要注意的是,还需要在mvc命名空间的annotation-driven标签中定义验证程序

(4)两个国际化文件errors_zh_CN.properties和errors_en_US.properties:

errors_zh_CN.properties文件:

error.password = \u5BC6\u7801\u662F\u5FC5\u987B\u540C\u65F6\u5305\u542B\u5927\u5199\u5B57\u6BCD\u3001\u5C0F\u5199\u5B57\u6BCD\u548C\u6570\u5B57\u76846-20\u4F4D\u5B57\u7B26
error.username = \u7528\u6237\u540d\u9700\u8981\u0033\u002d\u0032\u0030\u4f4d
error.age = \u5e74\u9f84\u6700\u5927\u662f\u0031\u0032\u0030\u5c81

这里以键值对的形式定义了三个中文错误提示信息,需要注意的是使用了“Unicode编码”,如果开发工具不能自动编码的话,可以在这个网页进行手动转换编码:http://tool.chinaz.com/tools/unicode.aspx

errors_en_US.properties文件:

error.password = Passwords are 6-20 bit characters that must contain both upper and lower case letters and digits at the same time.
error.username = username needs 3-20 bit characters
error.age = Max age is 120 years old

(5)实体类User.java:

package cn.zifangsky.model;

import javax.validation.constraints.Max;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.Email;

public class User {
	@Size(min = 3, max = 20, message = "{error.username}")
	private String username;

	@Email
	private String email;

	@Pattern(regexp = "^((?=.*\\d)(?=.*[a-z])(?=.*[A-Z])).{6,20}$", message = "{error.password}")
	private String password;

	@Max(value = 120, message = "{error.age}")
	private int age;

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

}

 

这里验证了:用户名必须是3-20位,如果验证不通过则通过配置的“message”参数根据语言环境在前台页面显示错误提示信息;邮箱使用默认配置验证了邮箱格式是否正确;密码这一项通过一个正则表达式验证了必须是包含大写字母、小写字母和数字的6-20位的字符;年龄验证了最大是120岁

(6)UserController.java这个controller类:

package cn.zifangsky.controller;

import javax.validation.Valid;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import cn.zifangsky.model.User;

@Controller
public class UserController {

	@RequestMapping(value = "/form")
	public ModelAndView user() {
		ModelAndView modelAndView = new ModelAndView("userForm");
		modelAndView.addObject("user", new User());

		return modelAndView;
	}

	@RequestMapping(value = "/result", method = RequestMethod.POST)
	public ModelAndView processUser(@Valid User user, BindingResult result) {
		ModelAndView modelAndView = new ModelAndView("userResult");
		modelAndView.addObject("u", user);
		// 如果出现验证错误,则转到"userForm"视图
		if (result.hasErrors()) {
			modelAndView.setViewName("userForm");
		} else {
			modelAndView.setViewName("userResult");
		}

		return modelAndView;
	}

}

从代码可以看出,定义了两个方法,user方法负责处理”/form”请求,然后转到“userForm.jsp”这个视图页面;在processUser方法中,对用户输入的验证由@Valid注解触发,该注解被递归地应用到实体类User的各个属性中。同时在这个方法中接收了一个额外的参数result,该参数是一个BindingResult实例,通过使用该参数来检查在将请求参数映射到实体类属性的过程中是否发生了任何验证错误。最后是根据条件转到相关视图页面

(7)三个前台jsp页面:

i)根目录下的index.jsp:

<% response.sendRedirect("form.html"); %>

这个文件就简单的一句话,在项目启动时直接请求“form.html”

ii)userForm.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="mvc"%>
<html>
<head>
<title>SpringMVC Form表单验证</title>
<style type="text/css">
.formFieldError {
	background-color: #FAFFBD;
}
</style>
</head>
<body>

	<h2>用户注册:</h2>
	<mvc:form modelAttribute="user" action="result.html">
		<table>
			<tr>
				<td><mvc:label path="username">用户名:</mvc:label></td>
				<td><mvc:input path="username" cssErrorClass="formFieldError" /></td>
				<td><mvc:errors path="username" /></td>
			</tr>
			<tr>
				<td><mvc:label path="email">邮箱:</mvc:label></td>
				<td><mvc:input path="email" cssErrorClass="formFieldError" /></td>
				<td><mvc:errors path="email" /></td>
			</tr>
			<tr>
				<td><mvc:label path="password">密码:</mvc:label></td>
				<td><mvc:password path="password"
						cssErrorClass="formFieldError" /></td>
				<td><mvc:errors path="password" /></td>
			</tr>
			<tr>
				<td><mvc:label path="age">年龄:</mvc:label></td>
				<td><mvc:input path="age" cssErrorClass="formFieldError" /></td>
				<td><mvc:errors path="age" /></td>
			</tr>
			<tr>
				<td colspan="3"><input type="submit" value="Submit" /></td>
			</tr>
		</table>
	</mvc:form>
</body>
</html>

这个文件中定义的errors标签就是分别显示各个参数验证之后的错误提示信息

iii)userResult.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="mvc"%>
<html>
<head>
<title>SpringMVC Form表单验证结果</title>
</head>
<body>
	<h2>用户注册结果</h2>
	<table>
		<tr>
			<td>用户名:</td>
			<td>${u.username}</td>
		</tr>
		<tr>
			<td>邮箱:</td>
			<td>${u.email}</td>
		</tr>
		<tr>
			<td>密码:</td>
			<td>${u.password}</td>
		</tr>
		<tr>
			<td>年龄:</td>
			<td>${u.age}</td>
		</tr>
	</table>
</body>
</html>

这个文件只是简单的信息展示,不多做解释

三 测试

(1)中文环境下的错误提示:

项目启动后,使用中文类型的浏览器填写表单,可以发现,出现错误后显示的提示信息如下:

wKiom1cfZ3vzrANvAAA2FOO2T5Y787.png

可以发现,出现了预期的提示效果

(2)英文环境下的错误提示:

由于我装的浏览器是中文的,而且也不想更改浏览器的语言,因此我通过在提交表单时抓包手动更改Header中的“Accept-Language”这一项属性,改成“en-US,en;q=0.5”,相当于给服务端说我是英语环境(PS:q参数表示用户的喜爱度,不用管,随便设一个就行)

wKioL1cfaG6TZ8lCAABsq__Axro056.png

最后的显示效果如下:

wKiom1cfZ8fBcVKJAAA5xCyQEqw377.png

注:实际上,应该把页面中其他的一些中文也设置成国际化形式,那样就可以在英文环境中显示成英文了。不过为了减小理解难度,因此在这里就没有添加上这个步骤,当然我在后面可能会单独写一写SpringMVC的国际化

bean validation 分组验证及分组顺序

分组验证及分组顺序

如果我们想在新增的情况验证id和name,而修改的情况验证name和password,怎么办? 那么就需要分组了。

首先定义分组接口:

查看复制到剪贴板打印

  1. public interface First {  
  2. }  
  3.   
  4. public interface Second {  
  5. }  

分组接口就是两个普通的接口,用于标识,类似于java.io.Serializable。

 

接着我们使用分组接口标识实体:

查看复制到剪贴板打印

  1. public class User implements Serializable {  
  2.   
  3.     @NotNull(message = "{user.id.null}", groups = {First.class})  
  4.     private Long id;  
  5.   
  6.     @Length(min = 5, max = 20, message = "{user.name.length.illegal}", groups = {Second.class})  
  7.     @Pattern(regexp = "[a-zA-Z]{5,20}", message = "{user.name.illegal}", groups = {Second.class})  
  8.     private String name;  
  9.   
  10.     @NotNull(message = "{user.password.null}", groups = {First.class, Second.class})  
  11.     private String password;  
  12. }  

 

验证时使用如:

查看复制到剪贴板打印

  1. @RequestMapping("/save")  
  2. public String save(@Validated({Second.class}) User user, BindingResult result) {  
  3.     if(result.hasErrors()) {  
  4.         return "error";  
  5.     }  
  6.     return "success";  
  7. }  

即通过@Validate注解标识要验证的分组;如果要验证两个的话,可以这样@Validated({First.class, Second.class})。

 

接下来我们来看看通过分组来指定顺序;还记得之前的错误消息吗? user.name会显示两个错误消息,而且顺序不确定;如果我们先验证一个消息;如果不通过再验证另一个怎么办?可以通过@GroupSequence指定分组验证顺序:

 

查看复制到剪贴板打印

  1. @GroupSequence({First.class, Second.class, User.class})  
  2. public class User implements Serializable {  
  3.     private Long id;  
  4.   
  5.     @Length(min = 5, max = 20, message = "{user.name.length.illegal}", groups = {First.class})  
  6.     @Pattern(regexp = "[a-zA-Z]{5,20}", message = "{user.name.illegal}", groups = {Second.class})  
  7.     private String name;  
  8.       
  9.     private String password;  
  10. }  

通过@GroupSequence指定验证顺序:先验证First分组,如果有错误立即返回而不会验证Second分组,接着如果First分组验证通过了,那么才去验证Second分组,最后指定User.class表示那些没有分组的在最后。这样我们就可以实现按顺序验证分组了。

       @GroupSequence只能运用在Type(也就是类)下。其中,Default.class不能出现在GroupSequence列表中,且对应类的Object.class是GroupSequence列表中的一部分,一般放在最后。

       Restful风格接口能够返回JSON类型的数据形式:

{

    "code": "400",

    "data": null,

    "messages": [

        {

            "invalidValue": "Name : Donald, Street: Stree no 27, Phone : (123) 123-1234, city: Sydney",

            "message": "Invalid address: Check your phone number or zip code"

        }

    ]

  • 组合约束

    在一些复杂的场景,验证值需要多个约束同时使用,会让人感动过于复杂且啰嗦,如果相同的字段被其他类引用,则相应的约束需完全被拷贝至其他类,这违背了DRY原则(In software engineering, don’t repeat yourself (DRY) is a principle of software development aimed at reducing repetition of all kinds.)。 
    为了解决这个问题,我们可以通过多个基本的约束组合创建更高级别的约束。示例代码如下:

@NotNull
@Size(min = 2, max = 14)
@CheckCase(CaseMode.UPPER)
@Target({ METHOD, FIELD, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = { })
@Documented
@ReportAsSingleViolation
public @interface ValidLicensePlate {

    String message() default "{org.hibernate.validator.referenceguide.chapter06." +
            "constraintcomposition.ValidLicensePlate.message}";

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

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

创建组合约束,仅需要组合其他约束即可,如果组合约束需要验证器,通过@Constraint指定,反之,无需指定,如上代码所示:@Constraint(validatedBy = { })。 
注解@ReportAsSingleViolation使任何组合验证违反时,仅作为单一错误信息。使用和之前的使用方式一致。

 

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: EasyExcel 是一个 Java 的读写 Excel 文件的开源库,它可以方便地实现 Excel 文件的读取、写入和操作。在 EasyExcel 中,校验字段可以通过添加注解实现。 具体步骤如下: 1. 在需要校验字段上添加注解 `@ExcelProperty`,并设置 `index` 属性表示该字段在 Excel 文件中的列位置。 ```java public class User { @ExcelProperty(index = 0) @NotBlank(message = "姓名不能为空") private String name; @ExcelProperty(index = 1) @Pattern(regexp = "^\\d{11}$", message = "手机号格式不正确") private String phone; // 其他字段... } ``` 2. 在读取 Excel 文件时,使用 `EasyExcel.read()` 方法并传入一个 `AnalysisEventListener` 的实现类,重写 `onData()` 方法进行校验。 ```java public class UserExcelListener extends AnalysisEventListener<User> { private List<User> userList = new ArrayList<>(); @Override public void invoke(User user, AnalysisContext context) { // 数据校验 Set<ConstraintViolation<User>> violations = ValidatorUtil.validate(user); if (!violations.isEmpty()) { // 校验未通过,抛出异常 throw new RuntimeException(violations.iterator().next().getMessage()); } // 校验通过,加入列表 userList.add(user); } @Override public void doAfterAllAnalysed(AnalysisContext context) { // 处理数据... } } ``` 在 `invoke()` 方法中,我们使用 `ValidatorUtil` 工具类对读取到的每一条数据进行校验。如果校验不通过,直接抛出异常,否则将数据加入列表。 需要注意的是,`ValidatorUtil` 是一个自定义的校验工具类,它使用了 JSR-303 标准中的注解进行校验。在使用之前需要先引入相关依赖和配置校验器。 ```xml <!-- 引入 Hibernate Validator 校验器 --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.7.Final</version> </dependency> <!-- 配置校验器 --> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/> ``` 以上就是使用 EasyExcel 实现校验字段的步骤,希望对你有所帮助。 ### 回答2: EasyExcel 是一款方便易用的操作 Excel 文件的工具库,可以实现对 Excel 文件的读写操作。在 EasyExcel 中,校验字段是通过注解校验器来实现的。 首先,在实体类的属性上添加校验注解,例如 @NotNull 表示非空校验,@Max 表示最大值校验等等。这些注解可以根据具体需求进行选择和组合使用。 同时,根据需要,我们还可以自定义一些校验器来对字段进行额外的校验。自定义校验器需要实现 Validator 接口,并实现其中的 validate 方法,在该方法中编写具体的校验逻辑。 接下来,在读取或写入 Excel 文件时,使用 EasyExcel 提供的相关方法进行校验操作。在读取操作中,可以通过调用 ReadListener 的 onException 方法来获取校验不通过的数据和原因,并进行相应的处理。在写入操作中,可以在写入数据前进行校验,并将校验不通过的数据进行处理或记录。 总结来说,EasyExcel 校验字段的步骤如下: 1. 在实体类的属性上添加校验注解,标示字段校验规则。 2. 可选:根据需要,自定义校验器对字段进行额外的校验。 3. 在读取或写入 Excel 文件时,使用 EasyExcel 提供的相关方法进行校验操作。 4. 根据校验结果进行相应的处理,如记录错误信息、筛选出不合规的数据等。 使用 EasyExcel 校验字段可以有效地保证数据的准确性和一致性,提高数据处理的效率和可靠性。同时,EasyExcel 提供了丰富的校验注解和灵活的扩展机制,方便根据实际需求进行定制化的校验规则。 ### 回答3: EasyExcel是一款开源的Java操作Excel的工具库,提供了丰富的API和功能,可以方便地进行Excel文件的读写操作。其中一项常用的功能是校验Excel文件中的字段。 EasyExcel的校验字段功能可以帮助用户在读取Excel文件时进行自定义的字段校验。具体使用步骤如下: 首先,用户需要定义一个校验的规则,并将其封装成一个校验器。校验规则可以包括字段数据类型、长度、范围等,校验器需要实现EasyExcel的接口 "AbstractValidateResultCodeListener"。 其次,在读取Excel文件时,使用EasyExcel提供的 "ExcelReaderBuilder" 创建一个读取器,并将校验器传入该读取器中。 然后,使用读取器读取Excel文件,读取过程中,EasyExcel会根据校验规则对每个字段进行校验。 最后,根据校验结果进行相应的处理。EasyExcel读取Excel文件时,会将校验失败的数据进行记录,用户可以通过校验结果对象获取到校验失败的数据以及失败的原因,并进行后续操作,如打印出错误信息、记录日志等。 总之,EasyExcel提供了易于使用的校验字段功能,通过自定义校验规则,可以方便地对Excel文件中的字段进行校验,并获取校验结果,从而使数据处理更加准确和可靠。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值