JSR303 校验扩展(分组、按顺序校验)
1.在spring MVC 项目中使用JSR303 校验数据合法性,一般情况下使用方法为
(1)在接受数据的实体使用注解标添加校验规则
package com.hzsj.wechatdto; import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank; public class MemberApplyDto {
@NotBlank(message="注册号不能为空")
@Length(max=6,min=6,message="注册号必须为6位")
private String registerId; @NotBlank(message="姓名不能为空")
@Length(max=50,message="长度不能超过50个字符")
private String name; @NotBlank(message="选择性别")
private String gender; @NotBlank(message="请填写身份证号码")
@Length(max = 18,message="身份证号码不能超过18个字符")
private String cardNo; @NotBlank(message="请选择省")
private String province; @NotBlank(message="请选择市")
private String cityName; @NotBlank(message="请选择县")
private String countyName; @NotBlank(message="请填写详细地址")
@Length(max=50,message="不能超过50个字符")
private String detailAddress; @NotBlank(message="请选择婚姻状况")
private String marriage; @NotBlank(message="请填写公司名称")
@Length(max=30,message="公司名称不能超过30个字符")
private String companyName; @NotBlank(message="请填写公司电话")
@Length(max=20,message="公司电话不能超过20个字符")
private String companyTel; @NotBlank(message="请填写公司地址")
@Length(max=50,message="公司地址不能超过50个字符")
private String companyAddress; @NotBlank(message="请填写个人简历")
@Length(max=200,message="个人简历不能超过200字符")
private String persomResume; @NotBlank(message="请选择渠道平台")
private String channelType; @NotBlank(message="请填写保荐人")
@Length(max=20,message="保荐人不能超过20个字符")
private String recommend; @NotBlank(message="uuidCode不能为空")
private String uuidCode; public String getRegisterId() {
return registerId;
} public void setRegisterId(String registerId) {
this.registerId = registerId;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public String getCardNo() {
return cardNo;
} public void setCardNo(String cardNo) {
this.cardNo = cardNo;
} public String getProvince() {
return province;
} public void setProvince(String province) {
this.province = province;
} public String getCityName() {
return cityName;
} public void setCityName(String cityName) {
this.cityName = cityName;
} public String getCountyName() {
return countyName;
} public void setCountyName(String countyName) {
this.countyName = countyName;
} public String getDetailAddress() {
return detailAddress;
} public void setDetailAddress(String detailAddress) {
this.detailAddress = detailAddress;
} public String getMarriage() {
return marriage;
} public void setMarriage(String marriage) {
this.marriage = marriage;
} public String getCompanyName() {
return companyName;
} public void setCompanyName(String companyName) {
this.companyName = companyName;
} public String getCompanyTel() {
return companyTel;
} public void setCompanyTel(String companyTel) {
this.companyTel = companyTel;
} public String getCompanyAddress() {
return companyAddress;
} public void setCompanyAddress(String companyAddress) {
this.companyAddress = companyAddress;
} public String getPersomResume() {
return persomResume;
} public void setPersomResume(String persomResume) {
this.persomResume = persomResume;
} public String getChannelType() {
return channelType;
} public void setChannelType(String channelType) {
this.channelType = channelType;
} public String getRecommend() {
return recommend;
} public void setRecommend(String recommend) {
this.recommend = recommend;
} public String getUuidCode() {
return uuidCode;
} public void setUuidCode(String uuidCode) {
this.uuidCode = uuidCode;
} }
(2)在Controller中使用BindResult 接收校验的结果
@RequestMapping(value="/apply",method=RequestMethod.POST)
@ResponseBody
public ResultVo memberApply(@Valid MemberApplyDto dto,BindingResult bindingResult,Errors errors){
ResultVo<Object> resultVo = new ResultVo<>();
if(errors.hasErrors()){
List<FieldError> errorsList = bindingResult.getFieldErrors();
Map<String, String> map = new HashMap<>();
for(FieldError fieldError:errorsList){
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
resultVo.setCode(StatusEnums.DATAVALID_ERROR.getCode());
resultVo.setData(map);
resultVo.setMsg(StatusEnums.DATAVALID_ERROR.getMsg());
return resultVo;
}
LoginVo vo = memberApplyService.submitApply(dto);
resultVo.setCode(StatusEnums.SUCCESS.getCode());
resultVo.setMsg(StatusEnums.SUCCESS.getMsg());
resultVo.setData(vo);
return resultVo;
}
2.如果没有特殊需求的情况下使用上面的校验即可。但是遇到其他情况上面的校验就不能满足或者不能灵活应对了。例如
(1)实体中的字段校验按照顺序进行,如果第一个字段校验失败,则接下来的校验不再进行。
(2)实体的字段校验按情况分类,分组校验,再不同方法中校验的字段和顺序不同。
(3)自定义校验规则。
刚好今天遇到上面的三种情况,接下来用实例一一解答。针对上面的需求,JSR303校验中专门提供了group (验证规则所属组)和 @GroupSequence(验证组的顺序) 来实现。
我的需求是表单中的字段按个按顺序校验,如果有前面的字段校验失败,则中断校验并返回校验结果。我的表单中有十几个字段,我的想法是为每个字段定义一个组,然后按照组的顺序进行校验(如果字段很多会比较麻烦,暂时不知道有什么更好的办法, 如果有人知道的话请指教。)于是上面的实体类就变成了下面的样子
package com.hzsj.wechatdto; import java.io.Serializable; import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotBlank; import com.hzsj.common.util.annotation.IsUndefined;
public class MemberApplyDto implements Serializable {
/**
*
*/
private static final long serialVersionUID = -7063091764413674200L; @NotBlank(message="注册号不能为空",groups={Default.class})
@Length(max=6,min=6,message="注册号必须为6位",groups={Default.class})
private String registerId; @NotBlank(message="请填写姓名",groups={Validate1.class})
@Length(max=50,message="长度不能超过50个字符",groups={Validate1.class})
private String name; @NotBlank(message="选择性别",groups={Validate2.class})
private String gender; @NotBlank(message="请填写身份证号码",groups={Validate3.class})
@Length(max = 18,message="身份证号码不能超过18个字符",groups={Validate3.class})
private String cardNo; @NotBlank(message="请选择户籍地区",groups={Validate4.class})
@IsUndefined(message="请选择户籍地区",groups={Validate4.class})
private String province; @NotBlank(message="请选择户籍地区",groups={Validate5.class})
@IsUndefined(message="请选择户籍地区",groups={Validate5.class})
private String cityName; @NotBlank(message="请选择户籍地区",groups={Validate6.class})
@IsUndefined(message="请选择户籍地区",groups={Validate6.class})
private String countyName; @NotBlank(message="请填写详细地址",groups={Validate7.class})
@Length(max=50,message="不能超过50个字符",groups={Validate7.class})
private String detailAddress; @NotBlank(message="请选择婚姻状况",groups={Validate8.class})
private String marriage; @NotBlank(message="请填写公司名称",groups={Validate9.class})
@Length(max=30,message="公司名称不能超过30个字符",groups={Validate9.class})
private String companyName; @NotBlank(message="请填写公司电话",groups={Validate10.class})
@Length(max=20,message="公司电话不能超过20个字符",groups={Validate10.class})
private String companyTel; @NotBlank(message="请填写公司地址",groups={Validate11.class})
@Length(max=50,message="公司地址不能超过50个字符",groups={Validate11.class})
private String companyAddress; @NotBlank(message="请填写个人履历",groups={Validate12.class})
@Length(max=200,message="个人履历不能超过200字符",groups={Validate12.class})
private String persomResume; @NotBlank(message="请选择渠道平台",groups={Validate13.class})
private String channelType; @NotBlank(message="请填写保荐人",groups={Validate14.class})
@Length(max=20,message="保荐人不能超过20个字符",groups={Validate14.class})
private String recommend; @NotBlank(message="uuidCode不能为空",groups={Default.class})
private String uuidCode; public String getRegisterId() {
return registerId;
} public void setRegisterId(String registerId) {
this.registerId = registerId;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getGender() {
return gender;
} public void setGender(String gender) {
this.gender = gender;
} public String getCardNo() {
return cardNo;
} public void setCardNo(String cardNo) {
this.cardNo = cardNo;
} public String getProvince() {
return province;
} public void setProvince(String province) {
this.province = province;
} public String getCityName() {
return cityName;
} public void setCityName(String cityName) {
this.cityName = cityName;
} public String getCountyName() {
return countyName;
} public void setCountyName(String countyName) {
this.countyName = countyName;
} public String getDetailAddress() {
return detailAddress;
} public void setDetailAddress(String detailAddress) {
this.detailAddress = detailAddress;
} public String getMarriage() {
return marriage;
} public void setMarriage(String marriage) {
this.marriage = marriage;
} public String getCompanyName() {
return companyName;
} public void setCompanyName(String companyName) {
this.companyName = companyName;
} public String getCompanyTel() {
return companyTel;
} public void setCompanyTel(String companyTel) {
this.companyTel = companyTel;
} public String getCompanyAddress() {
return companyAddress;
} public void setCompanyAddress(String companyAddress) {
this.companyAddress = companyAddress;
} public String getPersomResume() {
return persomResume;
} public void setPersomResume(String persomResume) {
this.persomResume = persomResume;
} public String getChannelType() {
return channelType;
} public void setChannelType(String channelType) {
this.channelType = channelType;
} public String getRecommend() {
return recommend;
} public void setRecommend(String recommend) {
this.recommend = recommend;
} public String getUuidCode() {
return uuidCode;
} public void setUuidCode(String uuidCode) {
this.uuidCode = uuidCode;
} public interface Validate1{};
public interface Validate2{};
public interface Validate3{};
public interface Validate4{};
public interface Validate5{};
public interface Validate6{};
public interface Validate7{};
public interface Validate8{};
public interface Validate9{};
public interface Validate10{};
public interface Validate11{};
public interface Validate12{};
public interface Validate13{};
public interface Validate14{};
public interface Default{};
}
其中特别说明:实体类中的这些 interface 用来定义一个验证组,类似一个标识。然后为每个字段指定相应的验证组,其余字段使用默认的验证组。
接下来声明一个验证序列,指定这个序列需要验证哪些组和验证的顺序。
package com.hzsj.wechatdto; import javax.validation.GroupSequence; @GroupSequence(value={MemberApplyDto.Validate1.class,
MemberApplyDto.Validate2.class,
MemberApplyDto.Validate3.class,
MemberApplyDto.Validate4.class,
MemberApplyDto.Validate5.class,
MemberApplyDto.Validate6.class,
MemberApplyDto.Validate7.class,
MemberApplyDto.Validate8.class,
MemberApplyDto.Validate9.class,
MemberApplyDto.Validate10.class,
MemberApplyDto.Validate11.class,
MemberApplyDto.Validate12.class,
MemberApplyDto.Validate13.class,
MemberApplyDto.Validate14.class,
MemberApplyDto.Default.class, })
public interface ApplySequence { }
我指定的是验证所有组,并按照组的顺序验证。如果在某些情况下只需要验证其中部分字段的话,可重新定义一个验证序列,在接下的Controller中去使用这个序列。
@RequestMapping(value="/apply",method=RequestMethod.POST)
@ResponseBody
public ResultVo memberApply(@Validated({ApplySequence.class}) MemberApplyDto dto,BindingResult bindingResult,Errors errors){
ResultVo<Object> resultVo = new ResultVo<>();
if(errors.hasErrors()){
List<FieldError> errorsList = bindingResult.getFieldErrors();
Map<String, String> map = new HashMap<>();
for(FieldError fieldError:errorsList){
map.put(fieldError.getField(), fieldError.getDefaultMessage());
}
resultVo.setCode(StatusEnums.DATAVALID_ERROR.getCode());
resultVo.setData(map);
resultVo.setMsg(StatusEnums.DATAVALID_ERROR.getMsg());
return resultVo;
}
LoginVo vo = memberApplyService.submitApply(dto);
resultVo.setCode(StatusEnums.SUCCESS.getCode());
resultVo.setMsg(StatusEnums.SUCCESS.getMsg());
resultVo.setData(vo);
return resultVo;
}
在Controller中需要的注意的是将原来的@Valid 替换成@Validated 。同时指定了我所需要的验证序列是按照自己定义的验证序列。
@Valid是javax.validation里的。
@Validated是@Valid 的一次封装,是Spring提供的校验机制使用。
相比@Valid @Validated 提供了几个新功能
(1)可以通过groups对验证进行分组
(2)按照序列组来验证
(3)验证多个实体
到此基本实现了按照顺序按个验证字段的合法性,但是同时发现了另外的一种情况,前端字段为空的时候会传过来的undefined,导致原来的验证规则失效。所有我们需要自己去定义一个验证规则去验证undefined。上面的实体使用的 @IsUndefined 就是我自行定义的。
首先定义一个注解,同时指定实现校验规则的类 validatedBy = {UndefinedValiadator.class}
package com.hzsj.common.util.annotation; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import javax.validation.Constraint;
import javax.validation.Payload; @Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER,ElementType.CONSTRUCTOR,ElementType.ANNOTATION_TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = {UndefinedValiadator.class})
public @interface IsUndefined { //提示信息
String message() default ""; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {};
}
其次,实现这个校验规则
package com.hzsj.common.util.annotation; import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext; import org.springframework.util.StringUtils; public class UndefinedValiadator implements ConstraintValidator<IsUndefined,String>{ @Override
public void initialize(IsUndefined constraintAnnotation) {
} @Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if(StringUtils.isEmpty(value)){
return false;
}
if("undefined".equals(value)){
return false;
}else{
return true;
}
} }
至此完成了一个自定义的规则,可以在自己的实体类中去使用了
JSR303 校验扩展(分组、按顺序校验)的更多相关文章
- ESLint – 可扩展的 JavaScript & JSX 校验工具
ESLint 是一个开源的 JavaScript 代码校验工具,最初是由 Nicholas C. Zakas 在2013年创建的.经常被用来发现问题的模式或代码,不符合特定的风格准则. ESLint ...
- Solon详解(六)- Solon的校验扩展框架使用与扩展
Solon详解系列文章: Solon详解(一)- 快速入门 Solon详解(二)- Solon的核心 Solon详解(三)- Solon的web开发 Solon详解(四)- Solon的事务传播机制 ...
- 点分十进制IP校验、转换,掩码校验
/***************************************************************************** * 点分十进制IP校验.转换,掩码校验 * ...
- Struts2 对Action中所有方法进行输入校验、单个方法进行校验
index.jsp: <body> <s:fielderror /> <form action="${pageContext.request.contextPa ...
- 更加灵活的参数校验,Spring-boot自定义参数校验注解
上文我们讨论了如何使用@Min.@Max等注解进行参数校验,主要是针对基本数据类型和级联对象进行参数校验的演示,但是在实际中我们往往需要更为复杂的校验规则,比如注册用户的密码和确认密码进行校验,这个时 ...
- Form的is_valid校验规则及验证顺序
一.验证顺序 查看form下的源码了解顺序 BaseForm为基类,中间包含了is_valid校验方法 @html_safe class BaseForm: ......... self.is_b ...
- EasyUI 扩展自己定义EasyUI校验规则 验证规则(经常使用的)
比如 校验输入框仅仅能录入0-1000之间 最多有2位小数的数字 表单<input type="text" id="rate" name="ra ...
- 扩展对EasyUI的校验规则
var myReg = RegExp(/[(\*)(\|)(\\)(\:)(\")(\/)(\<)(\>)(\?)]+/); $.extend($.fn.validatebox. ...
- easyui validate -- radio、checkbox 校验扩展,事件域名
事件域名: $(dom).on('click.myNameSpace',function(){ ... }),其中‘.myNameSpace’便是域名: 目前作用:$(dom).off('click. ...
随机推荐
- 【Wince-DataTable填充ListView】DataTable的数据填充到ListView控件,适用.Net2.0
在开发WinCE6.0程序的时候,要把DataTable的数据显示到ListView控件上,无法使用绑定, 只能使用循环遍历. 思路:外循环遍历行,内循环遍历列 //DataTable:dt2 //L ...
- 【leetcode】1250. Check If It Is a Good Array
题目如下: Given an array nums of positive integers. Your task is to select some subset of nums, multiply ...
- rgb三基色与rgba
主要解释什么是三基色和RGBA ㈠三基色含义 三基色是指红,绿,蓝三色,人眼对红.绿.蓝最为敏感,大多数的颜色可以通过红.绿.蓝三色按照不同的比例合成产生. ㈡三基色原理 ⑴自然界中的绝大部分彩色,都 ...
- 清除eclipse 里面主函数的加载记录 launch configuration删除
我们eclipse 里面执行的程序,应用 把他记录下来,生成配置文件. 当我们导出行的jar包的时候,需要制定运行的主函数. 会看到很多的历史主程序,带来方便的同时,也产生了影响. 需要清除写记录的 ...
- jquery timeStamp属性 语法
jquery timeStamp属性 语法 作用:timeStamp 属性包含从 1970 年 1 月 1 日到事件被触发时的毫秒数.直线模组 语法:event.timeStam 参数: 参数 描述 ...
- BZOJ 1212: [HNOI2004]L语言 trie
长度小于 10 是关键信息~ #include <cstdio> #include <cstring> #include <algorithm> #define N ...
- Miller Rabin 算法简介
0.1 一些闲话 最近一次更新是在2019年11月12日.之前的文章有很多问题:当我把我的代码交到LOJ上,发现只有60多分.我调了一个晚上,尝试用{2, 3, 5, 7, 11, 13, 17, 1 ...
- input选择框默认样式修改
input选择框是无法直接修改样式,我们只能间接来改变它样式. 原理:用图片来代替原来的input选择框,原来的input选择框定位到图片上方并让它opacity为0,鼠标点击时用js来改变图片,这样 ...
- 通过Flink实现个推海量消息数据的实时统计
背景 消息报表主要用于统计消息任务的下发情况.比如,单条推送消息下发APP用户总量有多少,成功推送到手机的数量有多少,又有多少APP用户点击了弹窗通知并打开APP等.通过消息报表,我们可以很直观地看到 ...
- python中的实例方法、类方法、静态方法的区别
Python 除了拥有实例方法外,还拥有静态方法和类方法,跟Java相比需要理解这个类方法的含义. class Foo(object): def test(self)://定义了实例方法 print( ...