SpringMVC(八)使用@Validated注解实现后台表单校验

 

 

 

 

 

 


依赖jar

        <dependency>  
            <groupId>javax.validation</groupId>  
            <artifactId>validation-api</artifactId>  
            <version>1.1.0.Final</version>  
        </dependency>  
        <dependency>  
            <groupId>org.hibernate</groupId>  
            <artifactId>hibernate-validator</artifactId>  
            <version>5.2.1.Final</version>  
        </dependency>

 @valid,java的jsr303声明了这类接口,hibernate-validator对接口进行实现

配置

1. 配置校验器

 <!-- 校验器,配置validator -->
    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="providerClass" value="org.hibernate.validator.HibernateValidator"></property>
        <property name="validationMessageSource" ref="validationMessageSource"></property>
    </bean>
    
    <!-- 配置validationMessageSource -->
    <bean id="validationMessageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <!-- 指定校验信息的资源文件的基本文件名称,不包括后缀,后缀默认是properties -->
        <property name="basenames">
            <list>
                <value>classpath:validationMessageSource</value>
            </list>
        </property>
        <!-- 指定文件的编码 -->
        <property name="fileEncodings" value="utf8"></property>
        <!-- 对资源文件内容缓存的时间,单位秒 -->
        <property name="cacheSeconds" value="120"></property>
    </bean>

2.  将校验器配置到处理器适配器中

 <!-- 注解驱动 ,配置处理器映射器和处理器适配器-->
 <mvc:annotation-driven validator="validator"></mvc:annotation-driven>

 

JSR303定义的校验类型

空检查

@Null       验证对象是否为null

@NotNull    验证对象是否不为null, 无法查检长度为0的字符串

@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.

@NotEmpty 检查约束元素是否为NULL或者是EMPTY.

 

Booelan检查

@AssertTrue     验证 Boolean 对象是否为 true  

@AssertFalse    验证 Boolean 对象是否为 false  

 

长度检查

@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内  

@Length(min=, max=) Validates that the annotated string is between min and max included.

 

日期检查

@Past           验证 Date 和 Calendar 对象是否在当前时间之前  

@Future     验证 Date 和 Calendar 对象是否在当前时间之后  

@Pattern    验证 String 对象是否符合正则表达式的规则

 

数值检查,建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为"",Integer为null

@Min            验证 Number 和 String 对象是否大等于指定的值  

@Max            验证 Number 和 String 对象是否小等于指定的值  

@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度

@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度

@Digits     验证 Number 和 String 的构成是否合法  

@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。

 

@Range(min=, max=) Checks whether the annotated value lies between (inclusive) the specified minimum and maximum.

@Range(min=10000,max=50000,message="range.bean.wage")
private BigDecimal wage;

 

@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证)

@CreditCardNumber信用卡验证

@Email  验证是否是邮件地址,如果为null,不进行验证,算通过验证。

@ScriptAssert(lang= ,script=, alias=)

@URL(protocol=,host=, port=,regexp=, flags=)

需要注意的是,NotEmpty,NotNull,NotBlank的区别

@NotEmpty 用在集合上

@NotNull用在基本类型上

@NotBlank用在String上

如何使用

创建一个校验器的分组类

分组类设置到注解的groups属性上,表示只有存在这个分组类,才回去校验

//自定义接口类,用于校验分组
public interface ValidateGroup {

}

创建一个pojo类

对于类中需要校验的字段,加上需要的校验注解

public class User implements Serializable{
	private static final long serialVersionUID = 1L;
	@NotBlank(groups={VolidateGroup.class},message="{user.id.is.notnull}")
	private String id;
	private String usercode;
	@NotBlank(message="{user.name.is.notnull}")
	@Length(max=30,min=1,message="{user.name.length.error}")
	private String username;
	private String password;
	private String salt;
	private String locked;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getUsercode() {
		return usercode;
	}
	public void setUsercode(String usercode) {
		this.usercode = usercode;
	}
	public String getUsername() {
		return username;
	}
	public void setUsername(String username) {
		this.username = username;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getSalt() {
		return salt;
	}
	public void setSalt(String salt) {
		this.salt = salt;
	}
	public String getLocked() {
		return locked;
	}
	public void setLocked(String locked) {
		this.locked = locked;
	}
	}

controller中触发参数校验

1. 在提交的校验pojo前面加上@Valid注解,BindingResult的hasError方法检查是否字段校验失败,并获取到校验失败的信息

2. 注解@Validated属性value上设置分组类的信息,只有groups属性上存在分组类,就会生效

  下面的add方法中,id的校验和其他默认的校验都生效

   update方法中,不会校验id,分组类只设置了default.class(pojo的校验注解上没有指定groups的值,默认都是default.class)

@Controller
public class UserController {
	private static final Logger logger = LoggerFactory.getLogger(UserController.class);
	@RequestMapping(value="/add_user.action",method=RequestMethod.POST)
	public String add(Model model,BindingResult result,
			@RequestBody @Validated(value={ValidateGroup.class,Default.class}) User user){
		//需要在controller的形参中,对需要校验的对象加上@validated注解
		//获取校验信息
		if (result.hasErrors()) {
            if (model != null) {
                FieldError error = result.getFieldErrors().get(0);// 为了避免大量的校验在前端堆积,影响用户体验,只返回一个错误提示
                logger.debug("validate error: " + error.getDefaultMessage());
                model.addAttribute("error", error.getDefaultMessage());
            }
        }
		//省略
		return "redirect:list.action";
	}
	@RequestMapping(value="/update_user.action",method=RequestMethod.PUT)
	public String update(Model model,BindingResult result,@RequestBody @Validated(value={Default.class}) User user){
		//省略....
		return "";
	}
}

错误信息的展示,前段使用thymeleaf模板的话,可以使用th:error输出错误信息。

自定义校验注解

@Retention(RetentionPolicy.RUNTIME)
@Target(value={ElementType.FIELD})
@Constraint(validatedBy=PassValidation.class)
public @interface PasswordValidate {
	  //默认消息
	  String message() default "请输入8位小写英文字母";
     //分组
	    Class<?>[] groups() default { };
	 //负载
	   Class<? extends Payload>[] payload() default { };

}

public class PassValidation implements ConstraintValidator<Annotation, String>{
	@Override
	public void initialize(Annotation arg0) {
		
	}
	@Override
	public boolean isValid(String str, ConstraintValidatorContext context) {
		//密码是小写的8位字母,通过校验
		if(str.matches("[a-z]{8}")){
			return true;
		}
		return false;
	}

}

硬编码校验

如果注解@Valid失效情况,可以使用下面方式进行校验

 /**
     * 返回空,表示校验成功,否则校验失败
     * @param object
     * @param <T>
     * @return
     */
    private <T> String  validateParam(T object){
        Validator validator =  Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<T>>  set =  validator.validate(object);
        if(set!=null&&set.size()>0){
            StringBuilder sb = new StringBuilder();
            for (ConstraintViolation<T> ct: set
            ) {
               if(ct.getMessage()!=null&&ct.getMessage().trim().length()>0){
                   sb.append("field:"+ct.getPropertyPath()+",error message:"+ct.getMessage());
               }

            }
            return sb.toString();
        }
        return null;
    }

使用AOP的方式实现校验

对需要参数校验的方法,织入增强,减少代码

@Aspect
@Component
public class CustomerValidatorAOP {
    @Before("execution(* com.example.chapter_1_web.controller.*.update*(..))")
    public void validatorBook(JoinPoint point) {
        //返回目标方法的参数
        Object[] objects =  point.getArgs();
        //获取目标方法签名
        MethodSignature methodSignature = (MethodSignature) point.getSignature();
        Method method = methodSignature.getMethod();
        //获取方法注解
        Annotation[] annotationList = method.getAnnotations();
        //参数注解
        Annotation[][] argAnnotations = method.getParameterAnnotations();
        //参数名称
        String[] argNames = methodSignature.getParameterNames();
        Validator validator =  Validation.buildDefaultValidatorFactory().getValidator();
        for(int i = 0;i<objects.length;i++){
            //如果参数有BingResult,获取错误信息
            if(objects[i] instanceof  BindingResult){
                BindingResult result = (BindingResult) objects[i];
                if(result.hasErrors()){
                    FieldError error = result.getFieldError();
                    //获取错误信息
                    String errorMsg = error.getDefaultMessage();
                    ServletRequestAttributes req = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
                    HttpServletResponse rsp  =  req.getResponse();
                    //如果是返回的是json数据就可以将数据写回,省略。。
                }
            }
        }
    }
}

参考博客:

https://blog.csdn.net/DuShiWoDeCuo/article/details/79080237

https://my.oschina.net/itblog/blog/211693

http://exceptioneye.iteye.com/blog/1305040

 

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值