春季MVC:如何进行验证?

2022-08-31 07:15:02

我想知道对用户输入执行表单验证的最干净和最好的方法是什么。我看到一些开发人员实现了org.springframework.validation.Validator。关于这个问题:我看到它验证了一个类。是否必须使用用户输入中的值手动填充类,然后将其传递给验证程序?

我对验证用户输入的最干净,最好的方法感到困惑。我知道使用然后手动检查的传统方法,但我不想在我的.关于这方面的一些好建议将不胜感激。我没有在此应用程序中使用Hibernate。request.getParameter()nullsController


答案 1

使用Spring MVC,有3种不同的方法来执行验证:使用注释,手动或两者混合使用。没有一种独特的“最干净和最好的方法来验证”,但可能有一种更适合你的项目/问题/上下文。

让我们有一个用户:

public class User {

    private String name;

    ...

}

方法 1 :如果您有Spring 3.x+和简单的验证要做,请使用注释(也称为JSR-303注释)。javax.validation.constraints

public class User {

    @NotNull
    private String name;

    ...

}

你的库中需要一个 JSR-303 提供程序,比如 Hibernate Validator,它是参考实现(这个库与数据库和关系映射无关,它只是执行验证 :-)。

然后在你的控制器中,你会有这样的东西:

@RequestMapping(value="/user", method=RequestMethod.POST)
public createUser(Model model, @Valid @ModelAttribute("user") User user, BindingResult result){
    if (result.hasErrors()){
      // do something
    }
    else {
      // do something else
    }
}

请注意@Valid:如果用户碰巧有一个空名称,则 result.hasErrors() 将为 true。

方法 2 :如果您有复杂的验证(如大型业务验证逻辑、跨多个字段的条件验证等),或者由于某种原因您无法使用方法 1,请使用手动验证。最好将控制器的代码与验证逻辑分开。不要从头开始创建验证类,Spring提供了一个方便的界面(从Spring 2开始)。org.springframework.validation.Validator

所以假设你有

public class User {

    private String name;

    private Integer birthYear;
    private User responsibleUser;
    ...

}

并且您希望执行一些“复杂”验证,例如:如果用户的年龄小于18岁,则责任用户不得为空,责任用户的年龄必须超过21岁。

你会做这样的事情

public class UserValidator implements Validator {

    @Override
    public boolean supports(Class clazz) {
      return User.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {
      User user = (User) target;

      if(user.getName() == null) {
          errors.rejectValue("name", "your_error_code");
      }

      // do "complex" validation here

    }

}

然后在您的控制器中,您将拥有:

@RequestMapping(value="/user", method=RequestMethod.POST)
    public createUser(Model model, @ModelAttribute("user") User user, BindingResult result){
        UserValidator userValidator = new UserValidator();
        userValidator.validate(user, result);

        if (result.hasErrors()){
          // do something
        }
        else {
          // do something else
        }
}

如果存在验证错误,则 result.hasErrors() 将为 true。

注意:您也可以在控制器的@InitBinder方法中设置验证器,使用“binder.setValidator(...)”(在这种情况下,混合使用方法 1 和 2 是不可能的,因为您替换了默认验证程序)。或者,您可以在控制器的默认构造函数中实例化它。或者有一个@Component/@Service UserValidator,你注入(@Autowired)到你的控制器中:非常有用,因为大多数验证器都是单例+单元测试模拟变得更容易+你的验证器可以调用其他Spring组件。

方法 3 :为什么不结合使用这两种方法呢?使用注释验证简单的东西,如“name”属性(它快速完成,简洁且更具可读性)。保留对验证者的繁重验证(当编写自定义复杂验证批注需要数小时时,或者只是在无法使用批注时)。我在以前的一个项目上做了这个,它就像一个魅力,快速而简单。

警告:不得将验证处理误认为是异常处理阅读这篇文章,了解何时使用它们。

引用:


答案 2

有两种方法可以验证用户输入:注释和继承Spring的Veristator类。对于简单的情况,注释很好。如果您需要复杂的验证(例如跨字段验证,例如。“验证电子邮件地址”字段),或者如果您的模型在应用程序中的多个位置使用不同的规则进行验证,或者如果您无法通过在其上放置注释来修改模型对象,那么Spring的基于继承的验证器就是要走的路。我将展示两者的示例。

无论您使用哪种类型的验证,实际的验证部分都是相同的:

RequestMapping(value="fooPage", method = RequestMethod.POST)
public String processSubmit(@Valid @ModelAttribute("foo") Foo foo, BindingResult result, ModelMap m) {
    if(result.hasErrors()) {
        return "fooPage";
    }
    ...
    return "successPage";
}

如果您使用的是批注,则您的类可能如下所示:Foo

public class Foo {

    @NotNull
    @Size(min = 1, max = 20)
    private String name;

    @NotNull
    @Min(1)
    @Max(110)
    private Integer age;

    // getters, setters
}

上面的注释是注释。您也可以使用Hibernate的,但它看起来不像您正在使用Hibernate。javax.validation.constraintsorg.hibernate.validator.constraints

或者,如果您实现Spring的验证器,则可以按如下方式创建一个类:

public class FooValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return Foo.class.equals(clazz);
    }

    @Override
    public void validate(Object target, Errors errors) {

        Foo foo = (Foo) target;

        if(foo.getName() == null) {
            errors.rejectValue("name", "name[emptyMessage]");
        }
        else if(foo.getName().length() < 1 || foo.getName().length() > 20){
            errors.rejectValue("name", "name[invalidLength]");
        }

        if(foo.getAge() == null) {
            errors.rejectValue("age", "age[emptyMessage]");
        }
        else if(foo.getAge() < 1 || foo.getAge() > 110){
            errors.rejectValue("age", "age[invalidAge]");
        }
    }
}

如果使用上述验证器,您还必须将验证器绑定到Spring控制器(如果使用注释,则不需要):

@InitBinder("foo")
protected void initBinder(WebDataBinder binder) {
    binder.setValidator(new FooValidator());
}

另请参阅春季文档

希望有所帮助。


推荐