hibernate validate实际应用

1:于struts结合

1.1:下载struts2-fullhibernatecore-plugin-2.2.2(目前最新的是2.2.2),

     它支持的hibernate    validate中,最新的版本是4.0.2,也是使用这个版本的原因

1.2struts配置文件中,包继承hibernate-default(需要同时继承多个包时,先后顺序对校验有影响)

<package name="recevaccount" extends="default,hibernate-default" namespace="">

1.3action的属性上添加约束

@not null

private String name;

  

对一个对象的校验,需要使用Valid,它会校验Emp对象中的约束

@Valid

private Emp emp;

 

也可以添加自定义约束

@MyOwnValid

private User user;

1.4:校验不通过时,错误信息会由struts2-fullhibernatecore-plugin插件放入Actionfielderroractionerror中。

     前台使用struts标签传递数据时:<s:textfield>,错误信息存放在fielderroractionerror

     前台使用一般的html表单时:<input>,错误信息存放在fielderror中。

1.5:如1.3所示,假如Emp10个字段,全部添加相应的约束,jsp传递到action中的参数只有emp.nameemp.id,则只会校验nameid上对应的约束,即:request parameter中的键所对应的约束。

 

 

 

2:校验的错误信息如何存入Action

1.3中的emp为例,前台通过emp.name,emp.age传递2个参数到后台,如果数据校验不通过,对应的错误信息存放在一个键值对中,键即是emp.name,emp.age;类约束默认存放在emp.null中。在所有属性都校验完之后,struts2-fullhibernatecore-plugin插件会遍历request.parameter中所有参数的键(这里是emp.nameemp.age),将错误信息存放到fielderroractionerror中。

所以,当类约束校验不通过时,由于没有从前台传递以emp.null为键的参数到后台,所以类约束的错误信息是没办法放入action中的。

 

 

3:如何指定错误信息对应的field

上面提到过,默认情况下类约束是没办法放入actionerror中的,所以即便校验不通过,也不会跳转到input页面。可以通过如下方式指定一个field来存放错误信息,但是该field必须要是前台传递到后台数据的键才行,原因可参考2.

//禁用默认

arg1.disableDefaultConstraintViolation();

arg1.buildConstraintViolationWithTemplate("错误信息").addNode("field").addConstraintViolation();

校验不通过后,类约束的错误信息将会放入emp.field中。

 

 

4:一个自定义类约束的例子

//该注解可以应用在:方法,域,注解类型上

@Target({ElementType.METHOD,ElementType.FIELD,ElementType.TYPE})

//注解在运行期通过反射读取

@Retention(RetentionPolicy.RUNTIME)

@Constraint(validatedBy = LeaveHourCheckValidator.class)

//在生成JavaDoc时,该注解会被添加到java文档中

@Documented

public @interface LeaveHourCheck {

  //定义错误消息

  String message() default "请假小时验证不通过";

  //定义所在的组

  Class<?>[] groups() default {};

  //定义级别条件的严重级别

  Class<? extends Payload>[] payload() default {};

}

 

//3.6版本和4.0有所不同

public class LeaveHourCheckValidator implements ConstraintValidator<LeaveHourCheck, HrLeave>{

    private LeaveService leaveService;

   

    public void initialize(LeaveHourCheck arg0) {

        WebApplicationContext wc = null;

        if (wc == null) {

            wc = WebApplicationContextUtils

                    .getRequiredWebApplicationContext(ServletActionContext

                            .getServletContext());

        }

        leaveService = wc.getBean(LeaveService.class);

    }

 

    public boolean isValid(HrLeave leave, ConstraintValidatorContext arg1) {

        ……………………

       

        //禁用默认

        arg1.disableDefaultConstraintViolation();

        arg1.buildConstraintViolationWithTemplate(message).addNode("hour").addConstraintViolation();

       

        return flag;

    }

}

 

 

 

5:同一个实体类的同一个field,不同操作进行不同的校验

假如有如下新需求,在保存时,年龄数必须小于20小时,修改时年龄必须大于25小时。由于在约束的Annotation中是没办法指定一个变量的,所以无法在使用约束时,通过参数进行区分。可以通过ActionContext.getContext().getName()获得Action的名字,不同的操作进行不同的校验

 

6:如何对数组对象进行校验

考虑如下情况:假如需要一次保存多个员工,前台通过js将数据封装成emp[0].name,emp[0].age,emp[1].name,emp[1].age……传递到后台,后台通过List<Emp> list进行接收,想通过hibernate validate进行校验,校验不通过时返回input页面。

假如我们使用默认情况:校验不通过时,错误信息存放在list.null中;指定一个field:校验不通过时,存放在list.field中。由此可见,没有哪一种情况对应的键出现在requestparameter中,所以错误信息无法放入Action中。

解决办法,在校验不通过时,自己手动将错误信息放入Action中,如下所示:

Object obj = ActionContext.getContext().getActionInvocation().getAction();

    if (!(obj instanceof ActionSupport)) {

         LOG.warn(obj.getClass().getPackage()+obj.getClass().getName() + "转换Action方法出错");

    }

ActionSupport support = (ActionSupport)obj;

 

 

 

 

 

 

 

 

另一种校验思路

上面的方法虽然可以有效的进行数据校验,将校验代码从Action中分离出来,但是不同的Action,不同的封装Bean需要不同的类约束(业务逻辑的需要,自带的约束远远不够用),这就导致了需要创建很多的自定义约束。到最后每个约束是干什么的自己都不清楚,维护起来也比较麻烦。可以通过如下方式解决。

 

1:自定义一个接口,所有的封装Bean都继承该接口。

public interface IValidate {

    public ReturnValue validate(RecevParameters parameter);

}

 

2:封装Bean,每个Bean,在自己的封装Bean中,写自己的校验方法。

public class RecevAccountBean implements IValidate {

……field……

 

……get,set……

 

    //========================进行数据校验=========================

    public ReturnValue validate(RecevParameters parameter) {

        String actionName = parameter.getActionName();

        if ("saveRecevAccountDeal".equals(actionName)) {

         

        }

        return null;

    }

}

 

3:自定义约束类,通过回调,每个封装Bean处理自己的校验,将错误信息封装成对象,统一返回到约束中进行处理。约束只对接口进行校验

@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})

//注解在运行期通过反射读取

@Retention(RetentionPolicy.RUNTIME)

@Constraint(validatedBy = BeanCheckValidator.class)

//在生成JavaDoc时,该注解会被添加到java文档中

@Documented

public @interface BeanCheck {

    //定义错误消息

    String message() default "单据校验不通过";

    //定义所在的组

    Class<?>[] groups() default {};

    //定义级别条件的严重级别

    Class<? extends Payload>[] payload() default {};

}

 

 

public class BeanCheckValidator implements ConstraintValidator<BeanCheck, IValidate> {

    private BeanCheck check;

   

    public void initialize(BeanCheck constraintAnnotation) {

        this.check = constraintAnnotation;

    }

 

    public boolean isValid(IValidate validator, ConstraintValidatorContext context) {

        if (validator==null) {

            return true;

        }

 

        ActionContext actionContext = ActionContext.getContext();

        

        //存放Action的名字

        RecevParameters parameter = new RecevParameters();

        parameter.setActionName(actionContext.getName());

        parameter.setAnnotation(check);

       

        ReturnValue value = validator.validate(parameter);

       

        if (value==null || value.getErrors()==null) {

            return true;

        }

       

        boolean keepInAction = value.isKeepInAction();   //是否需要将错误信息存入ActionError

        boolean keepInField = value.isKeepInFields();    //是否需要将错误信息存入FieldError

        Map<String, String> map = value.getErrors();

       

        for (String string : value.getErrors().keySet()) {

            if(keepInAction) {

                ActionErrorUtil.addActionError(actionContext, map.get(string));

            }

            if(keepInField) {

                ActionErrorUtil.addFieldError(actionContext, string, map.get(string));

            }

        }

        return true;

    }

}

你可能感兴趣的:(Hibernate)