JSR303 数据检验

原文:https://blog.csdn.net/qq_28867949/article/category/7370730

一、JSR-303简介

JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。

此实现与 Hibernate ORM 没有任何关系。 JSR 303 用于对 Java Bean 中的字段的值进行验证。 
Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中对表单提交的数据方便地验证。 
注:可以使用注解的方式进行验证

二、准备校验时使用的JAR

validation-api-1.0.0.GA.jar:JDK的接口; 
hibernate-validator-4.2.0.Final.jar是对上述接口的实现; 
log4j、slf4j、slf4j-log4j

三、JSR 303 基本的校验规则

空检查 
@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 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。

数值检查 
建议使用在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=) 被指定的元素必须在合适的范围内 
@Range(min=10000,max=50000,message=”range.bean.wage”) 
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证) 
@CreditCardNumber信用卡验证 
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。 
@ScriptAssert(lang= ,script=, alias=) 
@URL(protocol=,host=, port=,regexp=, flags=)

四、案例分析

在使用的时候直接对JavaBean进行注解既可以实现对属性的验证

 1 public class Order {
 2     // 必须不为 null, 大小是 10
 3     @NotNull
 4     @Size(min = 10, max = 10)
 5     private String orderId;
 6     // 必须不为空
 7     @NotEmpty
 8     private String customer;
 9     // 必须是一个电子信箱地址
10     @Email
11     private String email;
12     // 必须不为空
13     @NotEmpty
14     private String address;
15     // 必须不为 null, 必须是下面四个字符串‘created‘, ‘paid‘, ‘shipped‘, ‘closed‘其中之一
16     // @Status 是一个定制化的 contraint
17     @NotNull
18     @Status
19     private String status;
20     // 必须不为 null
21     @NotNull
22     private Date createDate;
23     // 嵌套验证
24     @Valid
25     private Product product;
26
27    // getter 和setter方法
28 }
    @NotNull(message = "adultTax不能为空")
    private Integer adultTax;

    @NotNull(message = "adultTaxType不能为空")
    @Min(value = 0, message = "adultTaxType 的最小值为0")
    @Max(value = 1, message = "adultTaxType 的最大值为1")
    private Integer adultTaxType;

    @NotNull(message = "reason信息不可以为空")
    @Pattern(regexp = "[1-7]{1}", message = "reason的类型值为1-7中的一个类型")
    private String reason;//订单取消原因

五、下边是一个完整的例子

public class ValidateTestClass{

    @NotNull(message = "reason信息不可以为空")
    @Pattern(regexp = "[1-7]{1}", message = "reason的类型值为1-7中的一个类型")
    private String reason;//订单取消原因

    //get、set方法、有参构造方法、无参构造方法、toString方法省略

    /**
     * 验证参数:就是验证上述注解的完整方法
     * @return
     */
    public void validateParams() {
        //调用JSR303验证工具,校验参数
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<ValidateTestClass>> violations = validator.validate(this);
        Iterator<ConstraintViolation<ValidateTestClass>> iter = violations.iterator();
        if (iter.hasNext()) {
            String errMessage = iter.next().getMessage();
            throw new ValidationException(errMessage);
        }
    }
}

我们可以写一个测试类进行验证

public class ValidateTestClassValidateTest{

    @Test
    public void validateParam(){
        ValidateTestClass validateTestClass = new ValidateTestClass();
        validateTestClass .setReason(12);

        validateTestClass .validateParams(); //调用验证的方法
    }
}

ok!这样就可以进行测试。

并且我们在使用的时候一定要注意,对于某一种验证规则是适用于一种数据类型的,简单说来,正则则表达式的验证对象可以为String类型的,但是不可以为Integer类型的数据,那么当我们使用正则表达式进行验证的时候就会出现错误。 
类似于:

javax.validation.UnexpectedTypeException: HV000030: No validator could be found for type: java.lang.Integer.
at org.hibernate.validator.internal.engine.constraintvalidation.ConstraintValidatorManager.verifyResolveWasUnique(ConstraintValidatorManager.java:218)

意思就是你这个验证的注解不应该对该类型进行注解。

六、 json输入的验证

Spring mvc 3.0.5中对于json格式的输入直接使用@valid标注有问题,目前这个bug还未修复 (见 SPR-6709),预计在3.1 m2版本中会修复。 
在此之前,可以通过如下几种方式来对json(或xml)格式的输入来进行验证。 
1:在handler method中直接对输入结果进行验证

@RequestMapping("/validJson1")
@ResponseBody
public JsonResult processSubmitjson(@RequestBody ValidModel vm,
        HttpServletRequest request) {
    JsonResult jsonRst = new JsonResult();  

    Set<ConstraintViolation<ValidModel>> set = validator.validate(vm);
    for (ConstraintViolation<ValidModel> violation : set) {  

        String propertyPath = violation.getPropertyPath().toString();
        ;
        String message = violation.getMessage();
        log.error("invalid value for: ‘" + propertyPath + "‘: "
                + message);
    }
    if (!set.isEmpty()){
        jsonRst.setSuccess(false);
        jsonRst.setMsg("输入有误!");
        return jsonRst;
    }  

    jsonRst.setSuccess(true);
    jsonRst.setMsg("输入成功!");
    return jsonRst;
} 

可通过修改后的helloworld.jsp中的json valid test1按钮进行调用测试。

2:将此验证逻辑封装为一个AOP,当需验证的对象前有@valid标注和@RequestBody标注时开始验证 
新增handler method如下

@RequestMapping("/validJson2")
 @ResponseBody
 public JsonResult testJson4(@RequestBody @Valid ValidModel vm){
    log.info("handle json for valid");
    return new JsonResult(true,"return ok");
 } 

这里没有对输入值做任何验证,所有的验证都在AOP中完成。 
修改pom.xml增加对AOP相关类库的引用。

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.6.11</version>
</dependency>  

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>2.2.2</version>
</dependency>  

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aop</artifactId>
    <version>${org.springframework.version}</version>
</dependency>  

修改servet context xml,增加对aop的支持。

<!-- enable Spring AOP support -->
<aop:aspectj-autoproxy proxy-target-class="true" />  

最后,新增AOP类

public class CustomerValidatorAOP {
  private Validator validator;  

  @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)")
  private void controllerInvocation() {
  }  

  @Around("controllerInvocation()")
  public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {  

    MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
    Method method = methodSignature.getMethod();
    Annotation[] annotationList = method.getAnnotations();
   /* for(Annotation anno:annotationList){
        System.out.println(ResponseBody.class.isInstance(anno));
    }
*/
    Annotation[][] argAnnotations = method.getParameterAnnotations();
    String[] argNames = methodSignature.getParameterNames();
    Object[] args = joinPoint.getArgs();  

    for (int i = 0; i < args.length; i++) {
      if (hasRequestBodyAndValidAnnotations(argAnnotations[i])) {
        Object ret = validateArg(args[i], argNames[i]);
        if(ret != null){
            return ret;
        }
      }
    }  

    return joinPoint.proceed(args);
  }  

  private boolean hasRequestBodyAndValidAnnotations(Annotation[] annotations) {
    if (annotations.length < 2)
      return false;  

    boolean hasValid = false;
    boolean hasRequestBody = false;  

    for (Annotation annotation : annotations) {
      if (Valid.class.isInstance(annotation))
        hasValid = true;
      else if (RequestBody.class.isInstance(annotation))
        hasRequestBody = true;  

      if (hasValid && hasRequestBody)
        return true;
    }
    return false;
  }  

  private JsonResult validateArg(Object arg, String argName) {
    BindingResult result = getBindingResult(arg, argName);
    validator.validate(arg, result);
    if (result.hasErrors()) {
      JsonResult jsonresult = new JsonResult();
      jsonresult.setSuccess(false);
      jsonresult.setMsg("fail");
      return jsonresult;
    }
    return null;
  }  

  private BindingResult getBindingResult(Object target, String targetName) {
    return new BeanPropertyBindingResult(target, targetName);
  }  

  @Required
  public void setValidator(Validator validator) {
    this.validator = validator;
  }  

这里只考虑了输入为json格式的情况,仅仅作为一种思路供参考,实际使用时需要根据项目具体情况进行调整。 
可通过修改后的helloworld.jsp中的json valid test2按钮进行调用测试。

七、和SpringMVC的配置

参考·:http://www.php.cn/java-article-372190.html

原文地址:https://www.cnblogs.com/pingxin/p/p00088.html

时间: 2024-11-06 03:52:21

JSR303 数据检验的相关文章

CRC16数据检验-用于AISG协议通讯数据检验

CRC16数据检验,欧洲标准 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace WorkTool_AISG { public class CRC { private static ushort[] crc16table =new ushort[] { 0x0000, 0x1189, 0x2312,

java之struts2之数据检验

1.使用struts2时,有时候需要对数据进行相关的验证.如果对数据的要求比较严格,或对安全性要求比较高时,前端 js 验证还不够, 需要在后端再进行一次验证,保证数据的安全性. 2.struts2提供了两种机制来进行后端的数据验证. 编程方式 验证框架 3.通过编程方式来进行数据检验需要继承ActionSupport类.在ActionSupport类中有一个validate方法,在该方法中实现数据校验.如果要通过编程方式进行校验,那么需要在处理类的Action中重写validate方法.在ac

常用JSR-303数据校验

常用JSR-303数据校验 下载 JSR 303 – Bean Validation 规范 在任何时候,当你要处理一个应用程序的业务逻辑,数据校验是你必须要考虑和面对的事情.应用程序必须通过某种手段来确保输入进来的数据从语义上来讲是正确的.在通常的情况下,应用程序是分层的,不同的层由不同的开发人员来完成.很多时候同样的数据验证逻辑会出现在不同的层,这样就会导致代码冗余和一些管理的问题,比如说语义的一致性等.为了避免这样的情况发生,最好是将验证逻辑与相应的域模型进行绑定. Bean Validat

springmvc JSR303数据校验

7.4.数据验证 7.4.1.编程式数据验证 Spring 2.x提供了编程式验证支持,详见[4.16.2 数据验证]章节,在此我们重写[4.16.2.4.1.编程式验证器]一节示例. (1.验证器实现 复制cn.javass.chapter4.web.controller.support.validator.UserModelValidator 到cn.javass.chapter7.web.controller.support.validator.UserModelValidator. (2

多线程,内存存放数据检验

背景:为提高帐户校验效率,将原来的数据库检验方式变更为将数据存于内存,动态变更内存数据,检验取内存数据的方式,解决检验问题 方案: 1. 创建对象Map用于存放帐户当前可用金额信息 2. 检验时,判断金额信息是否存在,存在则使用内存金额进行校验,不存在则查询数据库获取最新的可用金额信息 3. 检验通过,则更新可用金额 4.每隔一段时间,对内存消息进行核对,将数据库查询到的信息更新到内存中 关键点实现: 1. 存放帐户可用金额的对用,必须是线程安全的,使用ConcurrentHashMap,可以在

JSR-303 数据校验学习

@ConfigurationProperties标识的类支持JSR-303校验 JSR 303 - Bean Validation 介绍及最佳实践 一.JSR-303简介JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator. 此实现与 Hibernate ORM 没有任何关系. JSR 303 用于对 Java Bean 中的字段的值进行验证. Spring MVC 3.x 之中也大力支持 JSR-30

正态分布数据检验-偏度峰度检验法

正态数据偏度峰度检验法 置信度:1-alpha数据样本数:nsig1=sqrt(6.0*(n-2)/(n+1)/(n+3));sig2=sqrt(24.0*n*(n-2)*(n-3)/(n+1)/(n+1)/(n+3)/(n+5));mu2=3.0-6.0/(n+1);样本中心矩B2=A2-A1*A1;B3=A3-3.0*A2*A1+2.0*A1*A1*A1;B4=A4-4.0*A3*A1+6.0*A2*A1*A1-3.0*A1*A1*A1*A1;Ak为k阶样本矩 sum(xi^k)/n 样本偏

数据检验插件: Validate插件 添加自定义表单验证

jQuery.validator.addMethod("ValiPass", function(value, element,params) { var exp = new RegExp(params);//实例化正则对象,参数为传入的正则表达式 return exp.test(value);      //测试是否匹配 }, "密码必须包含数字.字母大.小写.符号四种"); 然后表单验证中 rules: { newPassword: { minlength: 8,

如何通过数据指导产品优化

设计师生来就是要解决问题的.那如何才能更好.更高效地解决问题?首先要求我们能发现问题,数据分析就是一种常用的发现问题的手段.通过数据定位问题,然后用设计方案来尝试解决问题,之后再用量化的数据指标来评估问题是否解决了,解决了多少.通过迭代优化,问题就能够得到较好解决. 本文结合自己在在登录产品的体验优化中积累的一些实战经验,重现过程中的设计点滴,有效果明显的方案,也有效果不明显的优化尝试,最后将总结一些通用的设计思路. 登录失败的原因在哪? 登录框一般是个较简单的界面,它包括:账户名和登录密码.校