Spring 引导启动器数据剩余,@Notnull 约束不起作用

Spring boot starter data rest, @Notnull constraint not working

我正在尝试将 @NotNull 约束添加到我的 Person 对象中,但我仍然可以 @POST 一个带有空电子邮件的新 Person。我正在使用 Spring boot rest 和 MongoDB。

实体class:

import javax.validation.constraints.NotNull;

public class Person {
    @Id 
    private String id;
    private String username;
    private String password;
    @NotNull // <-- Not working
    private String email;
    // getters & setters
}

存储库class:

@RepositoryRestResource(collectionResourceRel = "people", path = "people")
public interface PersonRepository extends MongoRepository<Person, String> {
}

申请class:

@SpringBootApplication
public class TalentPoolApplication {
    public static void main(String[] args) {
        SpringApplication.run(TalentPoolApplication.class, args);
    }
}

pom.xml

...
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.4.0.BUILD-SNAPSHOT</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-mongodb</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-rest</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>
...

当我通过 Postman @POST 一个新对象时,例如:

{
  "username": "deadpool",
  "email": null
}

我仍然 STATUS 201 使用此负载创建:

{
    "username": "deadpool",
    "password": null,
    "email": null
     ....
     ....
}

我遇到了同样的问题,但仅启用验证对我不起作用,这确实适用于 JPA 和 MongoDb 以节省其他人在这方面花费的时间。这不仅使验证工作正常,而且我得到一个很好的 restful 400 错误而不是默认的 500。

必须将其添加到我的 build.gradle 依赖项中

    compile('org.hibernate:hibernate-validator:4.2.0.Final')

和此配置 class

@Configuration
public class CustomRepositoryRestConfigurerAdapter extends RepositoryRestConfigurerAdapter {


   @Bean
   public Validator validator() {
       return new LocalValidatorFactoryBean();
   }

   @Override
   public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
       validatingListener.addValidator("afterCreate", validator());
       validatingListener.addValidator("beforeCreate", validator());
       validatingListener.addValidator("afterSave", validator());
       validatingListener.addValidator("beforeSave", validator());
   }
}

我发现制作我自己的 @NotNull 注释版本更好,它也可以验证空字符串。

@Documented
@Constraint(validatedBy = NotEmptyValidator.class)
@Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotEmpty {


    String message() default "{validator.notEmpty}";

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

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

}

public class NotEmptyValidator implements ConstraintValidator<NotEmpty, Object> {

    @Override
    public void initialize(NotEmpty notEmpty) { }

    @Override
    public boolean isValid(Object obj, ConstraintValidatorContext cxt) {
        return obj != null && !obj.toString().trim().equals("");
    }

}

您可以使用以下代码进行验证

@Configuration
@Import(value = MongoAutoConfiguration.class)
public class DatabaseConfiguration extends AbstractMongoConfiguration 
{

  @Resource
  private Mongo mongo;

  @Resource
  private MongoProperties mongoProperties;

  @Bean
  public ValidatingMongoEventListener validatingMongoEventListener() {
    return new ValidatingMongoEventListener(validator());
  }

  @Bean
  public LocalValidatorFactoryBean validator() {
    return new LocalValidatorFactoryBean();
  }

  @Override
  protected String getDatabaseName() {
    return mongoProperties.getDatabase();
  }

  @Override
  public Mongo mongo() throws Exception {
    return mongo;
  }

}

通常,@RestRepository 将解析为一个控制器,而不是自己处理验证,除非您重写默认行为或通过包含一些 @HandleBeforeSave@HandleBeforeCreate、...到您的代码。

一个解决方案是删除 @HandleBeforeSave@HandleBeforeCreate、... 然后 spring 将再次处理验证。

或者如果你想保留它们,你可以像这样为任何对象验证提供一个处理程序:

@Component
@RepositoryEventHandler
public class EntityRepositoryEventHandler {

    @Autowired
    private Validator validator;

    @HandleBeforeSave
    @HandleBeforeCreate
    public void validate(Object o) {
        Set<ConstraintViolation<Object>> violations = this.validator.validate(o);

        if (!violations.isEmpty()) {
            ConstraintViolation<Object> violation = violations.iterator().next();

            // do whatever your want here as you got a constraint violation !

            throw new RuntimeException();
        }
    }
}