SpringMVCJSR-303规范进行校验简单示例

后端验证,需要引入validation-api-2.0.1.GA.jar、hibernate-validator-6.0.10.Final.jar和jboss-logging-3.3.2.Final.jar,具体用什么版本的jar包自行选择。

jstl.jar、standard.js用于jsp页面的标签引用

springmvc配置文件





  
  
  


  
    
    
  
    

useCodeAsDefaultMessage设置为false,如果为true则如下面的用户姓名字段会提示用户姓名长度为min~max个字符,占位符的值无法被替换;

Controller相关设置,在model前添加@Valid注解;Controller的方法中@valid对应的@ModelAttribute参数与bindingResult之间不能有参数,它们必须紧挨在一起,否则报错;(我之前就是在它们之间有HttpServletRequest参数,一直报400错误;当然你可以去掉model中验证规则的注解,只是验证将不起作用;)

@RequestMapping(value="/create", method=RequestMethod.POST)
public String createFormHandle(@Valid @ModelAttribute("formModel") UserModel formModel, BindingResult bindingResult) {
	if (bindingResult.hasErrors()) {
		return "sys/user/create";
	}

	try {
	    User entity = new User();
	    BeanUtils.copyProperties(formModel, entity);
	    CurrentUser currentUser = getCurrentUser();
	    entity.setCreateBy(currentUser.getUserId());
            entity.setCreateDatetime(new Date());
	    userService.insert(entity);
	} catch (Exception e) {
	    bindingResult.reject("User.exists", "User已经存在");
	    return "sys/user/create";
	}
	return String.format("redirect:/%s", "sys/user/list";);
}

jsp页面内容设置,这里举个例子,不一一列举。

引入:<%@ taglib uri="http://www.springframework.org/tags/form" prefix="sf" %>

    

验证元素注解

Bean Validation 中内置的 constraint
@Null   被注释的元素必须为 null(用于对象,如包装类型Integer、Double、Date等)
@NotNull    被注释的元素必须不为 null(用于对象,如包装类型Integer、Double、Date等)
@AssertTrue     被注释的元素必须为 true
@AssertFalse    被注释的元素必须为 false
@Min(value)     被注释的元素必须是一个数字,其值必须大于等于指定的最小值(value为整型long类型)
@Max(value)     被注释的元素必须是一个数字,其值必须小于等于指定的最大值(value为整型long类型)
@DecimalMin(value)  被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)  被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max=, min=)   被注释的元素的大小必须在指定的范围内(不能用于整型)
@Digits (integer, fraction)     被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past   被注释的元素必须是一个过去的日期
@Future     被注释的元素必须是一个将来的日期
@Pattern(regex=,flag=)  被注释的元素必须符合指定的正则表达式
Hibernate Validator 附加的 constraint
@NotBlank(message =)   验证字符串非null,且长度必须大于0
@Email  被注释的元素必须是电子邮箱地址
@Length(min=,max=)  被注释的字符串的大小必须在指定的范围内
@NotEmpty   被注释的字符串的必须非空
@Range(min=,max=,message=)  被注释的元素必须在合适的范围内(min和max为整型long类型)

示例:验证字符串

/**
* 用户姓名.
*/
@NotBlank(message="用户姓名不能为空")
@Length(min=2, max=6, message="用户姓名长度为{min}~{max}个字符")
private String userName;	

/**
* 用户姓名助记码.
*/
@NotBlank(message="用户姓名助记码不能为空")
@Length(max=6, message="用户姓名助记码最长为{max}个字符")
private String mnemonic;

/**
* 登录名.
*/
@NotBlank(message="")
@Length(min=2, max=6, message="登录名不能为空,且长度为{min}~{max}个字符")
private String loginName;
		
/**
* 登录密码.
*/
@NotBlank(message="登录密码不能为空")
@Length(max=6, message="登录密码最长为{max}个字符")
private String loginPwd;	

/**
* 备注信息.
*/
@Length(max=6, message="备注最长{max}个字符")
private String remark;
jsp验证信息

SpringMVCJSR-303规范进行校验简单示例_第1张图片

字符串必填,增加@NotBlank注解。

用户姓名同时验证必填和字符串长度,出现两行验证信息;这种情况请参考登录名,将@NotBlank的message设置为空,验证信息全写在@Length的message上。

示例:验证数值

HV000030: No validator could be found for constraint 'javax.validation.constraints.Size' validating type 'java.lang.Integer'. Check configuration for 'sex'

字段上添加@Size注解,不论字段是否包装类都报该错误,基本类型的始终被当做包装类型,与是否加@NotNull和@NotBlank无关。原来是@Size只能用于String、Collection、Map和Array(测试过String类型,提示信息 个数在{min}~{max}之间,这个也是搞不懂);


整型数值

/**
 * 年龄
 */
@NotNull(message="年龄不能为空")
@Range(min=18, max=65, message="年龄范围为{min}~{max}岁")
private int age;
	
/**
 * 性别
 */
@NotNull(message="性别不能为空")
@Range(min=2, max=9, message="性别取值范围为{min}~{max}")
private Integer sex;

/**
 * 状态(0:停用;1:正常;2:锁定;).
 */
@NotNull(message="状态不能为空")
@Min(value=0, message="状态不能小于{value}")
@Max(value=2, message="状态不能大于{value}")
private Integer status;
jsp验证信息


上面的年龄用基本类型,报错,空字符串无法转成int,修改为如性别的包装类型;

如:性别为null,则不进行值范围的验证;不为null才验证值范围。

示例:浮点型

@NotNull(message="工资不能为空")
@DecimalMin(value="1234.5", inclusive=true, message="工资必须大于或等于{value}")
@DecimalMax(value="6789.0", inclusive=false, message="工资必须小于{value}")
@Digits(integer=4, fraction=1)
private Double salary;


@DecimalMin和@DecimalMax只能设置值大小,不能限定小数位数;inclusive为true则包含某指,为false则不包含;

@Digits的integer表示整数位数,fraction表示小数位数;

@Digits只能设置整数位数和小数位数,而不能设置某些具体值范围(如三位数,但实际使用可能就不是刚好要100到999,可能能是更细的范围);

所以浮点型的在必要时候为@DecimalMin、@DecimalMax和@Digits的组合使用。

示例:日期

/**
 * 出生日期.
 */
@DateTimeFormat(pattern = "yyyy-MM-dd")
@NotNull(message="出生日期不能为空")
@Past
private Date birthday;

/**
* 创建时间.
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm")
@NotNull(message="创建时间不能为空")
@PastOrPresent
private Date createDatetime;
	
/**
* 更新时间.
*/
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm")
@NotNull(message="更新时间不能为空")
@Future
private Date updateDatetime;

/**
 * 更新时间1.
 */
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm")
@NotNull(message="更新时间1不能为空")
@FutureOrPresent
private Date updateDatetime1;

日期类型须配合@DateTimeFormat使用,否则提交时会提示String不能转为Date;

经测试

@Past需要一个过去的时间(为现在时间仍会出现错误提示)

@PastOrPresent需要一个过去或现在的时间

@Future需要一个将来的时间

@FutureOrPresent需要一个将来或现在的时间(为现在时间仍会出现错误提示)

示例:正则表达式

/**
* 登录密码.
*/
@Pattern(regexp="^[a-zA-Z0-9_]{6,20}$", message="登录密码只能包含字符、数字、下划线,且字符串长度为6~20")
private String loginPwd;

2. 对象级联校验

只须在关联对象属性上加上@Valid

public class UserModel {
	/**
	* 用户姓名.
	*/
	@NotBlank(message="用户姓名不能为空")
	@Length(min=2, max=6, message="用户姓名长度为{min}~{max}个字符")
	private String userName;	
	
	public String getUserName() {
		return userName;
	}
	
	public void setUserName(String userName) {
		this.userName = userName;
	}
	
	/**
	 * 用户其他信息
	 */
	@Valid
	private UserExtModel userExtModel;
	
	public UserExtModel getUserExtModel() {
		return userExtModel;
	}

	public void setUserExtModel(UserExtModel userExtModel) {
		this.userExtModel = userExtModel;
	}
}

public class UserExtModel {
	private Integer userId;

	public Integer getUserId() {
		return userId;
	}
	
	public void setUserId(Integer userId) {
		this.userId = userId;
	}
	
	@NotBlank(message="联系电话不能为空")
	private String phone;

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}
	
	private String userIdCard;
	
	public String getUserIdCard() {
		return userIdCard;
	}

	public void setUserIdCard(String userIdCard) {
		this.userIdCard = userIdCard;
	}
}

注意关联对象字段的引用

SpringMVCJSR-303规范进行校验简单示例_第2张图片

@ConvertGroup不知道怎么用

分组校验

SpringMVCJSR-303规范进行校验简单示例_第3张图片

在需要验证的Controller加上@Validated,里面为验证的分组(分组内容);

public interface GroupA {

}

public interface GroupB {

}

model

@NotBlank(message="用户姓名不能为空", groups={Default.class})
@Length(min=2, max=6, message="用户姓名长度为{min}~{max}个字符", groups={GroupA.class})
private String userName;

@NotBlank(message="身份证号不能为空", groups={GroupB.class})
@Length(min=15, message="身份证最小长度{min}")
private String userIdCard;

如果添加了分组(groups),需要验证的每个注解都要加上对应分组(每个注解上的groups为数组,可添加多个分组);

任何分组都要验证的注解,要加groups={Default.class}否则不验证该注解内容。

自定义验证器

示例:性别(GB/T 2261.1-2003(0:未知的性别;1:男性;2:女性;5:女性改(变)为男性;6:男性改(变)为女性;9:未说明的性别;));这个没法用数值范围;(参考:https://blog.csdn.net/poortess/article/details/78136170)

性别枚举

/**
 * 性别(GB/T 2261.1-2003(0:未知的性别;1:男性;2:女性;5:女性改(变)为男性;6:男性改(变)为女性;9:未说明的性别;)).
 * @author chensan
 *
 */
public enum GenderEnum {
	/**
	 * 未知的性别
	 */
	UNKNOWN(0),
	/**
	 * 男性
	 */
	MALE(1),
	/**
	 * 女性
	 */
	FEMALE(2),
	/**
	 * 女性改(变)为男性
	 */
	FEMALE_TO_MALE(5),
	/**
	 * 男性改(变)为女性
	 */
	MALE_TO_FEMALE(6),
	/**
	 * 未说明的性别
	 */
	UNSTATED(9);
	
	private Integer gender;
	
	private GenderEnum(Integer gender) {
		this.gender = gender;
	}
	
	@JsonValue
	public Integer getGender() {
		return this.gender;
	}
	
	@JsonCreator
	public static boolean isInEnum(Integer sex) {
		if (sex == null) {
			return true;
		}
		for (GenderEnum gender : GenderEnum.values()) {
			if (gender.gender.equals(sex)) {
				return true;
			}
		}
		return false;
	}
}

自定义Validator

/**
 * 自定义性别Validator
 */
public class CheckGenderValidator implements ConstraintValidator {
    @Override
    public void initialize(CheckGenderConstraint constraintAnnotation) {
    }

    @Override
    public boolean isValid(Integer value, ConstraintValidatorContext context) {
    	return GenderEnum.isInEnum(value);
    }
}

验证器注解

/**
 * 用枚举指定参数
 */
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = CheckGenderValidator.class)
@Documented
public @interface CheckGenderConstraint {
    /**
     * 用来定义默认得消息模版, 当这个约束条件被验证失败的时候,通过此属性来输出错误信息.
     * @return
     */
    String message() default "请填写正确的性别";

    /**
     * 用于指定这个约束条件属于哪(些)个校验组
     * @return
     */
    Class[] groups() default {};

    /**
     * Bean Validation API 的使用者可以通过此属性来给约束条件指定严重级别. 这个属性并不被API自身所使用.
     * @return
     */
    Class[] payload() default {};
}

model字段引入自定义验证器注解(如果自定义验证内容参与分组,如下添加groups)

@NotNull(message="性别不能为空")
@CheckGenderConstraint(groups={GroupB.class})
private Integer sex;

model方式校验应用于web,接口校验则需要用到hibernate的校验模式(后续用到 会添加)。

问题:

当某字段不为空或为某值,才可以(且必须)填写某些内容,这些内容才验证规则,这种根据实际情况判断是否参与验证,如何动态选择验证器分组呢(或分组能解决吗)。

文章参考:https://www.cnblogs.com/mr-yang-localhost/p/7812038.html









你可能感兴趣的:(SpringMVC,JSR-303规范,后端验证)