【问题标题】:Spring boot starter data rest, @Notnull constraint not workingSpring Boot 启动器数据休息,@Notnull 约束不起作用
【发布时间】:2016-08-07 13:19:56
【问题描述】:

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

实体类:

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
}

存储库类:

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

应用类:

@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
     ....
     ....
}

【问题讨论】:

  • 好的,所以无论你收到什么参数,在对象前用@Valid标记
  • @dambros 他的存储库有一个@RepositoryRestResource 注释,在这种情况下你不需要控制器。如果你使用它,Spring 会自动为 REST 调用创建一个控制器。
  • @oxyt,所以这仅适用于基于 JPA 的实现,因为在通过 JPA 插入/更新数据之前会进行有效性检查,并且它会干净地沸腾。我认为这对 Spring Data Hateoas 团队在 Web 级别提出了很好的功能要求。我认为您应该在他们的 github 位置打开一个,看看您是否收到有关此问题的更多反馈。
  • @oxyt,在这里打开了一个 github 问题 - github.com/spring-projects/spring-hateoas/issues/446
  • 你必须启用validation

标签: json spring mongodb rest spring-data-rest


【解决方案1】:

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

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

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

还有这个配置类

@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());
   }
}

【讨论】:

  • 我在添加您的配置时不断收到此错误:java.lang.AbstractMethodError: org.hibernate.validator.engine.ValidatorFactoryImpl.close()V 你有任何想法如何解决这个问题? (最后的 V 不是错字)
【解决方案2】:

我发现制作自己的@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("");
    }

}

【讨论】:

  • 谢谢谢赫阿卜杜勒,我稍后会试试这个:)
【解决方案3】:

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

@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;
  }

}

【讨论】:

    【解决方案4】:

    通常,@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();
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-08
      • 2018-08-28
      • 2023-01-30
      • 2021-06-04
      • 2019-07-03
      • 1970-01-01
      • 1970-01-01
      • 2021-07-15
      相关资源
      最近更新 更多