使用Spring Data Envers演示实体修订的示例应用程序。
背景
Spring Data Jpa提供粗略的审计信息。但是,如果您正在寻找确切的变化是什么 制作到一个实体,你可以用Spring Data Envers 这样做。
顾名思义,Spring DataEnvers利用并简化了Hibernate Envers的使用。
依赖关系和配置
为了启用 Envers 功能,我们首先将spring-data-envers作为依赖项包含在内。
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-envers</artifactId>
</dependency>
接下来是通知Spring Boot我们希望启用Envers的功能。这可以通过注释 aclass with 来完成。@Configuration
@EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class)
示例可以在存储库配置中看到:
@Configuration
@EnableJpaRepositories(
repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class
)
public class RepositoryConfiguration {
}
启用实体审核
通过注释anwith,我们通知Spring我们希望对各自的实体进行审计。 以下示例显示我们希望审核与Book相关的所有活动:@Entity
@Audited
@Entity
@Audited
public class Book {
@Id
@GeneratedValue
private Long id;
@NotBlank
private String author;
@NotBlank
private String title;
}
接下来是扩展 aclass,以便允许我们利用审计修订功能。这可以通过将RevisionRepository接口扩展到我们的类来完成。在BookRepository 中可以看到一个例子:Repository
Repository
public interface BookRepository extends JpaRepository<Book, Long>, RevisionRepository<Book, Long, Integer> {
}
验证
我们将利用来验证我们的实施是否有效。@SpringBootTest
创建时创建初始修订
@SpringBootTest
class BookRepositoryRevisionsTest {
@Autowired
private BookRepository repository;
@Test
void initialRevision() {
Book book = repository.save(
Book.builder().author("Rudyard Kipling").title("Jungle Book").build()
);
Revisions<Integer, Book> revisions = repository.findRevisions(book.getId());
assertThat(revisions)
.isNotEmpty()
.allSatisfy(revision -> assertThat(revision.getEntity())
.extracting(Book::getId, Book::getAuthor, Book::getTitle)
.containsExactly(book.getId(), book.getAuthor(), book.getTitle())
);
}
}
修订号将增加,最新版本可用
@SpringBootTest
class BookRepositoryRevisionsTest {
@Autowired
private BookRepository repository;
@Test
void updateIncreasesRevisionNumber() {
Book book = repository.save(
Book.builder().author("Rudyard Kipling").title("Jungle Book").build()
);
book.setTitle("If");
repository.save(book);
Optional<Revision<Integer, Book>> revision = repository.findLastChangeRevision(book.getId());
assertThat(revision)
.isPresent()
.hasValueSatisfying(rev ->
assertThat(rev.getRevisionNumber()).hasValue(2)
)
.hasValueSatisfying(rev ->
assertThat(rev.getEntity())
.extracting(Book::getTitle)
.containsOnly("If")
);
}
}
删除后,除其ID外,所有实体信息都将被删除
@SpringBootTest
class BookRepositoryRevisionsTest {
@Autowired
private BookRepository repository;
@Test
void deletedItemWillHaveRevisionRetained() {
Book book = repository.save(
Book.builder().author("Rudyard Kipling").title("Jungle Book").build()
);
repository.delete(book);
Revisions<Integer, Book> revisions = repository.findRevisions(book.getId());
assertThat(revisions).hasSize(2);
Iterator<Revision<Integer, Book>> iterator = revisions.iterator();
Revision<Integer, Book> initialRevision = iterator.next();
Revision<Integer, Book> finalRevision = iterator.next();
assertThat(initialRevision)
.satisfies(rev ->
assertThat(rev.getEntity())
.extracting(Book::getId, Book::getAuthor, Book::getTitle)
.containsExactly(book.getId(), book.getAuthor(), book.getTitle())
);
assertThat(finalRevision)
.satisfies(rev -> assertThat(rev.getEntity())
.extracting(Book::getId, Book::getTitle, Book::getAuthor)
.containsExactly(book.getId(), null, null)
);
}
}
以上所有测试都可以在BookRepositoryRevisionsTest 中找到。