基于Spring会话的javax约束验证

时间:2013-11-18 17:36:19

标签: spring validation spring-mvc bean-validation

我想要完成的是在自定义约束中访问我的Spring会话

示例方案:

自定义约束@UniqueEmail验证电子邮件尚未在系统中使用。此验证在编辑端点上执行,如果用户没有更改电子邮件,则应忽略,第1:因为不需要它,第2次:因为查询该电子邮件的数据库实际上将返回结果,即用户自己,虽然没有办法在没有访问会话的情况下告诉它

这有效:

如果我通过@InitBinder使用自定义编辑器使用模型属性,我可以在验证发生之前在待验证的bean中设置属性,如此

@InitBinder(value="myModelObj")
protected void initBinder(WebDataBinder binder, HttpSession session) {
    User user = (User) session.getAttribute("user");
    binder.registerCustomEditor(User.class, "user", new UidPropertyEditor(user));
}

@RequestMapping(...)
public String updateUser(@Valid @ModelAttribute("myModelObj") MyModelObj form){
    ...
}

MyModelObj有一个属性,将替换为实际的会话用户。问题:

  1. bean中必须有一个属性来保存用户,即使它不能通过Web表单编辑
  2. 网页表单也必须提交此属性,在我的情况下使用输入[type =" hidden"]字段(用户可以随意更改,我们永远不会信任用户发送的内容)
  3. 这不起作用

    新端点必须使用@RequestBody而不是@ModelAttribute,这意味着(afaik)@InitBinder不再工作,因此无法访问会话对象。

    如何(如果可能)可以从自定义约束中访问会话?

    public class EmailIsUniqueStringValidator implements ConstraintValidator<EmailIsUnique, String> {
    
    @Autowired
    private UserDAO userDAO;
    
    HttpSession session; //Somehow initialized
    
    @Override
    public void boolean isValid(String email, ConstraintValidatorContext context) {
        User user = (User) session.getAttribute("user");
        if(user.getEmail().equals(email)){
            return true; // No need to validate
        }
        else if(userDAO.emailInUse(email)) {
            return false;
        }
    }
    

    非理想方法:

    我现在正在做的是手动在控制器中执行与会话相关的验证,这意味着我有2个点可以执行验证。

    this post中还有其他一些有趣的选项,但如果有办法访问会话......

    提前致谢

1 个答案:

答案 0 :(得分:9)

这可以使用RequestContextHolder来实现,如下所示:

public class EmailIsUniqueStringValidator implements ConstraintValidator<EmailIsUnique,         String> {

@Autowired
private UserDAO userDAO;

HttpSession session;

@Override
public void boolean isValid(String email, ConstraintValidatorContext context) {
    ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
    session = attr.getRequest().getSession();

    User user = (User) session.getAttribute("user");
    if(user.getEmail().equals(email)){
        return true; // No need to validate
    }
    else if(userDAO.emailInUse(email)) {
        return false;
    }
}