验证不适用于嵌套对象

时间:2017-09-29 08:11:18

标签: spring spring-mvc

我试图通过将请求参数直接绑定到用户实体而不是逐字段复制值来简化我的代码,但我似乎无法以这种方式进行验证。

控制器:

    @Autowired
    private UserValidator validator;

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.setValidator(validator);
    }

    @PreAuthorize("isAnonymous()")
    @RequestMapping("/register")
    public List<String> register(@Valid @ModelAttribute RegisterRequest request, BindingResult result){
        return result.getAllErrors().stream().map(error -> error.getCodes()[1]).collect(Collectors.toList());
    }

验证

@Component
public class UserValidator implements Validator {

    @Autowired
    private UserRepository repo;

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

    @Override
    public void validate(Object target, Errors errors) {
        if(target instanceof RegisterRequest){
            RegisterRequest request = (RegisterRequest)target;
            if(isRegistered(request))
                errors.rejectValue("User.Email", "InUse");
            if(!isRepassCorrect(request))
                errors.rejectValue("Repassword", "NoMatch");
        }

    }

    private boolean isRegistered(RegisterRequest request){
        return repo.findByEmail(request.getUser().getEmail())!=null;
    }

    private boolean isRepassCorrect(RegisterRequest request){
        return request.getPassword().equals(request.getRepassword());
    }

}

模型(请注意,嵌套对象使用@Valid注释):

public class RegisterRequest {

    @Valid
    private User user = new User();

    @NotEmpty
    private String password;

    @NotEmpty
    private String repassword;

    //Generated getters and setters for all fields

}

@Entity
@Table(name = "users")
public class User implements Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 3726459440738726042L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @NotEmpty
    @Email
    @Column(name = "email", nullable = false)
    private String email;

    @NotEmpty
    @Column(name = "hash", nullable = false)
    private String hash;

    @ManyToOne(fetch = FetchType.EAGER)
    @JoinColumn(referencedColumnName = "id")
    private UserRole role;

    @Column(name = "enabled", nullable = false)
    private boolean enabled;

    @NotEmpty
    @Column(name = "name", nullable = false)
    private String name;

    @Column(name = "company")
    private String company;

    //Getters, setters, equals and hashCode

}

问题是只有密码和服务字段被正确验证,才会忽略用户类中的验证注释,并且任何只有匹配密码的请求都会通过,同时应该会出现错误。空密码或不同的密码会出现预期的错误。

1 个答案:

答案 0 :(得分:2)

在你initBinder中使用addValidator方法代替setValidator,并通过在注释中添加MaV名称来告诉它要验证哪个MaV对象:

@InitBinder("request")

... @Valid @ModelAttribute("request") RegisterRequest request