使用Spring Data Events执行验证的应用程序示例


通过@RepositoryEventHandler使用事件实现Spring Data REST中的前后操作,Spring Data REST可以帮助开发人员在将Repository类转换为REST端点时,只需很少代码就能创建REST应用程序。在此示例中,我们将探讨如何在使用@RepositoryEventHandler及其相关注释持久化实体之前和之后执行操作。

实体和存储库类
有两个@Entity: Author 和 Book,以及相应的JpaRepository 类: AuthorRepository 和BookRepository

Author:

@Entity
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Author {

    @Id
    @GeneratedValue
    private Long id;

    @NotBlank
    private String name;

    @OneToMany(mappedBy = "author", cascade = CascadeType.REMOVE)
    private Set<Book> books;

    private Status status;

    public enum Status {

        ACTIVE,

        INACTIVE

    }
}

其JpaRepository如下:
public interface AuthorRepository extends JpaRepository<Author, Long> {
}

Book:

@Entity
@Data
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Book {

    @Id
    @GeneratedValue
    private Long id;

    @JoinColumn
    @ManyToOne(optional = false)
    @NotNull
    private Author author;

    @NotBlank
    private String title;

}

其仓储:
public interface BookRepository extends JpaRepository<Book, Long> {
}

我们可以看到,这两个类都是普通的JPA实体类,没有任何其他配置。一旦我们启动应用程序,就会有两个REST端点可用; /authors和/books。

添加作者验证
我们将确保一个Author的Book必须是ACTIVE添加到数据库之前。为此,我们将使用带@HandleBeforeCreate的@RepositoryEventHandler。

通过使用RepositoryEventHandler注释我们的类,我们通知Spring该类将管理与存储库相关的事件。除此之外,我们将使用HandleBeforeCreate,它指示在持久给定之前需要执行该方法@Entity。

我们将在AuthorRepositoryEventHandler中实现我们的验证:

@RepositoryEventHandler
@AllArgsConstructor
@SuppressWarnings("unused")
public class AuthorRepositoryEventHandler {

    @HandleBeforeCreate
    public void validateAuthorStatus(Book book) {
        Author author = book.getAuthor();

        Assert.isTrue(Author.Status.ACTIVE == author.getStatus(),
"book author must be active");
    }

}

我们可以看到,方法validateAuthorStatus将Book作为入参并验证Author的status,确保Author是ACTIVE。

配置类
接下来是通知应用程序我们想要注册AuthorRepositoryEventHandler为a Bean,因此将在使用相关实体时触发。这可以在RepositoryHandlerConfiguration中找到:

@Configuration 
public  class  RepositoryHandlerConfiguration { @Bean public AuthorRepositoryEventHandler authorRepositoryEventHandler(){
         return new AuthorRepositoryEventHandler(); 
    } 
}

验证实施
与往常一样,我们将通过集成测试验证我们的实现。在下面的测试中,我们将创建一个Author 带状态INACTIVE,然后创建一个Book关联到这个Author关联。

我们期望返回Internal Server Error:book author must be active:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class BookRepositoryRestTests {

    @Autowired
    private MockMvc mvc;

    @Test
    public void createBookWithInactiveAuthor() throws Exception {
        String authorUri = getAuthorUri(INACTIVE);

        JSONObject request = new JSONObject();

        request.put("author", authorUri);
        request.put(
"title", "If");

        mvc.perform(
                post(
"/books")
                        .content(request.toString())
        )
                .andExpect(status().isInternalServerError())
                .andExpect(jsonPath(
"$.message", is("book author must be active")));
    }

    private String getAuthorUri(Author.Status status) throws Exception {
        JSONObject request = new JSONObject();

        request.put(
"name", "Rudyard Kipling");
        request.put(
"status", status.name());

        return mvc.perform(
                post(
"/authors")
                        .content(request.toString())
        )
                .andExpect(status().isCreated())
                .andReturn().getResponse().getHeader(LOCATION);
    }

}


通过正确的实现,上面的测试应该通过。