1: hibernate-validator basics
1. Introduction:
By using the annotations Annotations to add constraints to the attributes of a class or class, check the legality of the attribute value during the runtime.
2. Function:
Parameter verification is very important in API interface development, because the client may pass fewer parameters, or the value is illegal, or even the parameter value is malicious, so the legality of parameters transmitted by the client must be verified. Among them, annotating the verification rules of parameter values to attributes through annotation is a relatively elegant way.
3. Commonly used constraint annotations
4. Get a first-time hibernate-validator
public class Address { @NotNull private String line1; private String line2; private String zip; private String state; @Length(max = 20) @NotNull private String country; @Range(min = -2, max = 50, message = "Floor out of range") public int floor; // getter&&setter}Two: Integrate verification of hibernate-validator
This example is integrated based on SpringMVC+FastJson integration (//www.VeVB.COM/article/139094.htm). You can first look at this article (with source code for download) and integrate hibernate-validator based on this article.
Integration steps:
1. Introduce hibernate-validator dependency in pom.xml
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.4.1.Final</version></dependency>
2. Configure the validator in [xxx]-servlet.xml: HibernateValidator
<!-- <mvc:annotation-driven> Add validator attribute validator="validator" --><mvc:annotation-driven validator="validator"> <mvc:message-converters register-defaults="true"> <!-- Configure Fastjson to replace the original jackson support --> <bean> <property name="supportedMediaTypes"> <list> <value>text/html;charset=UTF-8</value> <value>application/json</value> </list> </property> <property name="features"> <list> <value>QuoteFieldNames</value> <value>WriteMapNullValue</value> </list> </property> </bean> </mvc:message-converters> </mvc:annotation-driven> <bean id="validator"> <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/> <property name="validationMessageSource" ref="messageSource"/> </bean> <bean id="messageSource"> <property name="basenames"> <list> <value>classpath:conf/settings/validation</value> <value>classpath:org/hibernate/validator/ValidationMessages</value> </list> </property> <property name="useCodeAsDefaultMessage" value="false"/> <property name="defaultEncoding" value="UTF-8"/> <property name="cacheSeconds" value="60"/> </bean>
3. Define the verification message file description validation.properties in the src/main/resources/conf/settings location
validation.common.not.null=This field cannot be empty validation.common.not.range=Length illegal validation.common.format.error=Format error validation.param.age=Age under 18 years old rep.error.unknown=Unknown error
4. Create a new entity class for testing
UserEntity
package com.mengdee.manage.validator;import javax.validation.constraints.Min;import javax.validation.constraints.NotNull;import javax.validation.constraints.Null;import javax.validation.constraints.Pattern;import org.hibernate.validator.constraints.Email;import org.hibernate.validator.constraints.Length;import org.hibernate.validator.constraints.NotBlank;public class UserEntity { @Null(groups={GroupA.class}) @NotNull(groups={GroupB.class}) @Min(value = 1, message="id value must be greater than 0", groups={GroupB.class}) private Long id; @NotBlank(groups={GroupA.class, GroupB.class}) @Pattern(regexp="^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$", message="Composition of 6-21 letters and numbers, cannot be pure numbers or pure English", groups={GroupA.class, GroupB.class}) private String password; @NotBlank(groups={GroupA.class, GroupB.class}) @Pattern(regexp="^((13[0-9])|(15[^4,//D])|(18[0,3-9]))//d{8}$", message="The mobile phone number format is incorrect") private String phone; @NotBlank(groups={GroupB.class}) @Length(min=6, max=12, message="Nickname length is 6 to 12 bits") private String nickname; @Min(value=18, message="{validation.param.age}") private int age; @NotBlank(groups={GroupA.class}) @Email(message="{validation.common.format.error}") private String email; @NotBlank @Length(min=3, max=10, message="{validation.common.not.range}") private String username; public UserEntity() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } 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 String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; }}UserModel
package com.mengdee.manage.validator;import javax.validation.constraints.Min;import javax.validation.constraints.Pattern;import org.hibernate.validator.constraints.Email;import org.hibernate.validator.constraints.Length;import org.hibernate.validator.constraints.NotBlank;public class UserModel { @Min(value = 1, message="id value must be greater than 0") private long id; @NotBlank @Length(min=6, max=12, message="Nickname length is 6 to 12 digits") private String nickname; @Min(value=18, message="{validation.param.age}") private int age; @NotBlank @Email(message="{validation.common.format.error}") private String email; @NotBlank @Pattern(regexp="^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,20}$", message="Composition of 6-21 letters and numbers, cannot be pure numbers or pure English") private String password; @NotBlank @Length(min=3, max=10, message="{validation.common.not.range}") private String username; @NotBlank @Pattern(regexp="^((13[0-9])|(15[^4,//D])|(18[0,3-9]))//d{8}$", message="The mobile phone number format is incorrect") private String phone; public UserModel() { } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getNickname() { return nickname; } public void setNickname(String nickname) { this.nickname = nickname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } 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 String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } }UserDetail:
package com.mengdee.manage.validator;import org.hibernate.validator.constraints.NotBlank;public class UserDetail { private Long id; @NotBlank private String address; @NotBlank private String company; public UserDetail() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getCompany() { return company; } public void setCompany(String company) { this.company = company; }}Testing with ValidController
package com.mengdee.manage.controller;import javax.servlet.http.HttpServletRequest;import javax.validation.Valid;import org.springframework.stereotype.Controller;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import com.mengdee.manage.validator.UserModel;@Controller@RequestMapping("/Valid")public class ValidController extends BaseController { // http://localhost:8081/platform-springmvc-webapp/Valid/test?age=18&nickname=mengdee&id=1&[email protected]&password=root123&username=123&phone=18321758957 @RequestMapping(value = "/test", method = RequestMethod.GET) public @ResponseBody Object validation(HttpServletRequest request, @Valid UserModel user, BindingResult bindingResult){ if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); return super.ResponseJsonError(fieldError); } return "ok"; } // A method to verify multiple objects at the same time requires binding multiple results BindingResult. A @Valid appears, which corresponds to a BindingResult declared later. @RequestMapping(value = "/test2", method = RequestMethod.GET) public @ResponseBody Object validationMore(HttpServletRequest request, @Valid UserModel user, BindingResult bindingResult, @Valid UserDetail userDetail, BindingResult bindingResult2){ if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); return super.ResponseJsonError(fieldError); } if (bindingResult2.hasErrors()) { FieldError fieldError = bindingResult2.getFieldError(); return super.ResponseJsonError(fieldError); } return "ok"; }}Notes on use:
1. For multiple fields, the order of system verification seems to be different from the order of field declaration, as if it is unnecessary.
2. For each verification, if there is no message attribute, the system will use the default, such as the corresponding @NotBlank is equivalent to @NotBlank (message="cannot be empty")
3. For reference types such as String, you must use it in conjunction with @NotNull, @NotEmpty or @NotBlank. If you do not write an empty constraint, after testing, this field will not participate in verification. If you use @Pattern, @Length, @Email, etc. alone, it will not be verified. You must use an empty constraint to limit it.
@Min: used for basic data types, such as int, long, etc.
@NotNull: The value of any object cannot be null
@NotEmpty: The element of the collection object is not 0, that is, the collection is not empty, and it can also be used for strings not null
@NotBlank: It can only be used for string not null, and the length in the string trim() will be greater than 0
Three: Group verification @Validated
1. The role of grouping (use scenario):
Each verification annotation constraint has a group attribute, which is used to specify which group the constraint belongs to. In this way, multiple sets of constraints can be configured on the same field. When using it, you only need to specify which set of constraints to use. For example, when registering users and modifying user information, the id must be empty when registering, and the id must not be empty when modifying user information. When using it, you only need to assign these two constraints to different groups. For example, when adding, using group A's constraints, and using group B's constraints when updating.
2. A packet is an empty interface
GroupA and GroupB
package com.mengdee.manage.validator;public interface GroupA {}package com.mengdee.manage.validator;public interface GroupB {}When using @Validated({GroupA.class})
3. Group Sequence @GroupSequence
By default, the constraint verification of different groups is unordered, and the group sequence is verified in sequence in the group before and after order, such as first verifying the constraints of GroupA group, and then verifying the constraints of GroupB group. If there are requirements for the verification order of groups, for example, you must first verify Group A and then verify Group B, you can use @GroupSequence to define the order of each group
Use scenarios:
(1) Constraint verification in the second group relies on a stable state to run, and this stable state is verified by the first group.
(2) Verification of a certain group is time-consuming, and the CPU and memory usage rate is relatively large. The best choice is to put it last for verification. Therefore, when performing group verification, an orderly verification method is still needed, which proposes the concept of group sequence.
A group can be defined as a sequence of other groups, and it must comply with the order specified in the sequence when used for verification. When using group sequence verification, if the group verification before the sequence fails, the subsequent groups will no longer be validated.
Define group sequence using annotation GroupSequence: GroupAB
package com.mengdee.manage.validator;import javax.validation.GroupSequence;@GroupSequence({GroupA.class, GroupB.class})public interface GroupAB {ValidationController
package com.mengdee.manage.controller;import javax.servlet.http.HttpServletRequest;import org.springframework.stereotype.Controller;import org.springframework.validation.BindingResult;import org.springframework.validation.FieldError;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.ResponseBody;import com.mengdee.manage.validator.GroupA;import com.mengdee.manage.validator.GroupAB;import com.mengdee.manage.validator.GroupB;import com.mengdee.manage.validator.UserEntity;@Controller@RequestMapping("/validated")public class ValidationController extends BaseController { // GroupA is specified during verification, so that only the constraints containing GroupA are checked. If there is no inclusion, there will be no verification. For example, for phone, the group specified by @NotBlank, and @Pattern does not specify a group, then only one constraint is checked empty, and the mobile phone number format is not checked// http://localhost:8081/platform-springmvc-webapp/validated/groupA?password=root123&phone=123 @RequestMapping(value = "/groupA", method = RequestMethod.GET) public @ResponseBody Object groupA(HttpServletRequest request, @Validated({GroupA.class}) UserEntity user, BindingResult bindingResult){ if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); return this.ResponseJsonError(fieldError); } return "ok"; } // http://localhost:8081/platform-springmvc-webapp/validated/groupB?phone=123&password=root123&id=1 @RequestMapping(value = "/groupB", method = RequestMethod.GET) public @ResponseBody Object groupB(HttpServletRequest request, @Validated({GroupB.class}) UserEntity user, BindingResult bindingResult){ if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); return this.ResponseJsonError(fieldError); } return "ok"; } // groupAB // http://localhost:8081/platform-springmvc-webapp/validated/groupAB?phone=111&password=root123&nickname=123&[email protected] // @Validated({GroupA.class, GroupB.class}): The relationship between GroupA and GroupB is or, just like the OR in the database. As long as one condition is met, the constraint will be verified. Use multiple groups at the same time to note that there is no attribute in sequence between multiple groups. It is not to verify group A first, and then verify group B. // Because the constraints of id are empty and non-empty are checked, the attribute is commented out first @RequestMapping(value = "/groupAB", method = RequestMethod.GET) public @ResponseBody Object groupAB(HttpServletRequest request, @Validated({GroupA.class, GroupB.class}) UserEntity user, BindingResult bindingResult){ if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); return this.ResponseJsonError(fieldError); } return "ok"; } // default // http://localhost:8081/platform-springmvc-webapp/[email protected]&age=18 // @Validated If groups are not specified, verify that there is no group attribute (the same as @Valid function at this time). If there are multiple constraints on a field, no group must be specified. If the specified group is partially constrained and partial constraints do not specify the constraint, then @RequestMapping(value = "/default", method = RequestMethod.GET) is not checked when using @Validated @ResponseBody Object defaultGroup(HttpServletRequest request, @Validated UserEntity user, BindingResult bindingResult){ if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); return this.ResponseJsonError(fieldError); } return "ok"; } //localhost:8081/platform-springmvc-webapp/validated/sequence?phone=123&password=root123&email=123&nickname=123 // For multiple constraints on a property, and multiple constraints are not all in the same group, the order of checking is checked according to the order defined by the GroupSequence @RequestMapping(value = "/sequence", method = RequestMethod.GET) public @ResponseBody Object sequence(HttpServletRequest request, @Validated({GroupAB.class}) UserEntity user, BindingResult bindingResult){ if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); return this.ResponseJsonError(fieldError); } return "ok"; }}Four: Custom hibernate validation annotation
When the annotation provided by hibernate validation cannot meet the requirements, you can customize the verification constraints.
Custom annotation constraint steps:
Create annotation @Phone
package com.mengdee.manage.validator;import java.lang.annotation.Target;import javax.validation.Constraint;import javax.validation.Payload;import static java.lang.annotation.ElementType.ANNOTATION_TYPE;import static java.lang.annotation.ElementType.CONSTRUCTOR;import static java.lang.annotation.ElementType.FIELD;import static java.lang.annotation.ElementType.METHOD;import static java.lang.annotation.ElementType.PARAMETER;import static java.lang.annotation.RetentionPolicy.RUNTIME;import java.lang.annotation.Documented;import java.lang.annotation.Retention;@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER })@Retention(RUNTIME)@Documented@Constraint(validatedBy = {PhoneConstraint.class})public @interface Phone { String message() default "Mobile phone number format error"; String regexp() default "^((13[0-9])|(15[^4,//D])|(18[0,3-9]))//d{8}$"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default { }; @Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER }) @Retention(RUNTIME) @Documented public @interface List { Phone[] value(); } }Create a constraint verification class corresponding to the annotation of the mobile phone number
package com.mengdee.manage.validator;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;public class PhoneConstraint implements ConstraintValidator<Phone, String> { private String regexp; @Override public void initialize(Phone phoneAnnotation) { this.regexp = phoneAnnotation.regexp(); } @Override public boolean isValid(String value, ConstraintValidatorContext context) { if (value == null) { return true; // HV000028: Unexpected exception during isValid call } if (value.matches(regexp)) { return true; } return false; }}Use annotation @Phone on attributes
package com.mengdee.manage.validator;import org.hibernate.validator.constraints.NotBlank;public class UserDetail { @NotBlank @Phone private String phone; public UserDetail() { } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; }}Test Notes
// http://localhost:8081/platform-springmvc-webapp/Valid/test3?address=123&company=456&phone=123 @RequestMapping(value = "/test3", method = RequestMethod.GET) public @ResponseBody Object validationCustomAnnotation(HttpServletRequest request, @Valid UserDetail userDetail, BindingResult bindingResult){ if (bindingResult.hasErrors()) { FieldError fieldError = bindingResult.getFieldError(); return super.ResponseJsonError(fieldError); } return "ok"; }Download the complete code: http://xiazai.VeVB.COM/201804/yuanma/platform-springmvc-webapp(VeVB.COM).rar
Summarize
The above is the entire content of this article. I hope that the content of this article has certain reference value for everyone's study or work. If you have any questions, you can leave a message to communicate. Thank you for your support to Wulin.com.
Reference article: