1

当我添加自定义修订实体时,我开始收到错误:

2020-12-13 00:22:29.418 ERROR 80983 --- [ost-startStop-1] o.s.b.web.embedded.tomcat.TomcatStarter  : Error starting Tomcat context. Exception: org.springframework.beans.factory.UnsatisfiedDependencyException. Message: Error creating bean with name 'webSecurityConfig': Unsatisfied dependency expressed through field 'userDetailsService'; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userDetailsServiceImpl': Unsatisfied dependency expressed through field 'userRepository'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'userRepository': Cannot create inner bean '(inner bean)#4384acd' of type [org.springframework.orm.jpa.SharedEntityManagerCreator] while setting bean property 'entityManager'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name '(inner bean)#4384acd': Cannot resolve reference to bean 'entityManagerFactory' while setting constructor argument; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is java.lang.NoClassDefFoundError: org/hibernate/resource/beans/spi/ManagedBeanRegistry

我的修订:

package ...;

import org.hibernate.envers.DefaultRevisionEntity;
import org.hibernate.envers.RevisionEntity;

import javax.persistence.Entity;

@Entity
@RevisionEntity(MyRevisionListener.class)
public class MyRevision extends DefaultRevisionEntity {

    private String username;

    public String getUsername() { return username; }

    public void setUsername(String username) { this.username = username; }
}

我的修订监听器:

package ...;

// import de.xxxxx.carorderprocess.models.User;
import org.hibernate.envers.RevisionListener;
// import org.springframework.security.core.Authentication;
// import org.springframework.security.core.context.SecurityContext;
// import org.springframework.security.core.context.SecurityContextHolder;

// import java.util.Optional;

public class MyRevisionListener implements RevisionListener {

    @Override
    public void newRevision(Object revisionEntity) {

        /* String currentUser = Optional.ofNullable(SecurityContextHolder.getContext())
                .map(SecurityContext::getAuthentication)
                .filter(Authentication::isAuthenticated)
                .map(Authentication::getPrincipal)
                .map(User.class::cast)
                .map(User::getUsername)
                .orElse("Unknown-User"); */

        MyRevision audit = (MyRevision) revisionEntity;
        audit.setUsername("dd");

    }
}

网络安全配置:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserDetailsServiceImpl userDetailsService;

UserDetailsS​​erviceImpl:

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    UserRepository userRepository;

    @Override
    @Transactional
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));

        return UserDetailsImpl.build(user);
    }

}

用户存储库:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);

    Boolean existsByUsername(String username);
}

pom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>de.xxxxxxx</groupId>
    <artifactId>carorderprocess</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>carorderprocess</name>
    <description>Demo project for Spring Boot</description>

    <dependencyManagement>
        <dependencies>

        </dependencies>
    </dependencyManagement>


    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>

        <dependency>
            <groupId>com.fasterxml.jackson.datatype</groupId>
            <artifactId>jackson-datatype-jsr310</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
            <scope>provided</scope>
        </dependency>

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


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
            <version>2.2.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.17</version>
        </dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.1</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.16</version>
            <scope>provided</scope>
        </dependency>


        <dependency>
            <groupId>javax.persistence</groupId>
            <artifactId>persistence-api</artifactId>
            <version>1.0.2</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.5.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-envers</artifactId>
            <version>2.4.1</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-envers</artifactId>
            <version>5.4.25.Final</version>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <executions>
                    <execution>
                        <id>compile</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>
4

3 回答 3

1

你的代码看起来不错。但仅仅确定根本原因可能还不够。

查看异常很明显应用程序失败了,因为它无法找到 bean 依赖项

你可以尝试以下

  1. 首先在 build.gradle 或 pom.xml 中检查您的库导入。通常,除了 Spring Boot Data JPA 和 Hibernate Envers 之外,您不需要任何其他 Hibernate 库

  2. 尝试删除/禁用 Hibernate Envers 审计代码和库依赖项,看看您是否可以启动并运行您的应用程序。这将帮助您确定错误是由 Hibernate Envers 引起的,还是您的应用程序代码存在其他问题。

如果以上不起作用,请提供更多信息

  1. 您使用的是哪个版本的 Spring Boot
  2. 您导入了哪些库(build.gradle 或 maven pom 文件)
  3. 您的项目中有哪些其他配置 - 您是否有任何其他 JPA 配置文件或任何其他与 Hibernate 或 JPA 相关的自定义配置
  4. 主应用程序类上有哪些注释
  5. 您的 Repository 类的目录结构,以及您进行组件扫描的目录(如果您已覆盖它)
于 2020-12-13T13:56:29.427 回答
1

我认为您的问题可能与您的pom.xml.

请首先删除spring-data-envers依赖项,除非您查询不需要它的审计表。即使在这种情况下,如果需要,您也可以单独使用 Envers 来获取该信息。

请注意,正如 Sunit 答案的评论中所指出的,您将需要删除该属性repositoryFactoryBeanClass,它不能再采用该值EnversRevisionRepositoryFactoryBean。但是您可能仍然需要包含@EnableJpaRepositories注释。

尽管我最初表示您可以让 Spring Boot 管理您的版本,spring-boot-starter-parenthibernate-xxx由于5.2.17.Final.

但是,正如您所指出的,您需要使用该方法forRevisionsOfEntityWithChanges来查询您的审计实体。正如您在 java 文档中看到的那样,该方法是AuditQueryCreator在 version中引入的5.3

因此,您需要提供以下依赖项:

<dependency> 
  <groupId>org.hibernate</groupId> 
  <artifactId>hibernate-envers</artifactId> 
  <version>5.3.20.Final</version> 
</dependency>

但除此之外,您还需要提供两者的兼容版本hibernate-entitymanagerhibernate-core

<dependency> 
  <groupId>org.hibernate</groupId> 
  <artifactId>hibernate-entitymanager</artifactId> 
  <version>5.3.20.Final</version> 
</dependency>

<dependency> 
  <groupId>org.hibernate</groupId> 
  <artifactId>hibernate-core</artifactId> 
  <version>5.3.20.Final</version> 
</dependency>
于 2020-12-15T23:15:23.780 回答
1

根据我从上述所有评论中了解到的情况,您的要求是

  • 使用 Envers 审计
  • 并使用方法forRevisionsOfEntityWithChanges获取所有修订的列表,其中包含更改的内容

请从做这些开始

  • 删除spring-data-envers库的依赖。
  • 只保留库hibernate-envers- 版本5.4.23.Final也对我有用
  • repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class@EnableJpaRepositories注释中移除
  • 所有 Repository 类都应该只扩展自JpaRespository而不是扩展自RevisionRepository. 你不需要RevisionRepository

您现在应该能够启动并运行您的应用程序。

现在回到问题上来,如何使用forRevisionsOfEntityWithChanges方法获得所有带有更改的修订。

  • 像这样创建一个 AuditConfiguration 类,以创建AuditReaderbean

     @Configuration
     public class AuditConfiguration {
    
     private final EntityManagerFactory entityManagerFactory;
    
     AuditConfiguration(EntityManagerFactory entityManagerFactory) {
         this.entityManagerFactory = entityManagerFactory;
     }
    
     @Bean
     AuditReader auditReader() {
         return AuditReaderFactory.get(entityManagerFactory.createEntityManager());
     }
    

    }

  • 在您的AuditRevisionEntity班级中,添加以下注释。没有这个,这个类的序列化将无法工作。例如

    @JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
    public class AuditRevisionEntity extends DefaultRevisionEntity {
    
  • 在您的实体类中添加选项withModifiedFlag = true@Audited注释。没有这个,您将无法获得包含所有更改的实体修订。例如

     @Audited(withModifiedFlag = true)
     public class Customer {
    
  • 修改此实体审计表和字段 *_mod 的数据库表。例如,如果您有一个customer包含字段name, age,address列的表,则将列name_mod, age_mod,添加address_modcustomer_audit表中

  • 最后,在您的服务方法中添加以下代码以获取带有更改的审核修订

     @Autowired
     private AuditReader auditReader;
    
     public List<?> getRevisions(Long id) {
     AuditQuery auditQuery = auditReader.createQuery()
                 .forRevisionsOfEntityWithChanges(Customer.class, true)
             .add(AuditEntity.id().eq(id));
     return auditQuery.getResultList();
    

    }

我将尝试在今天某个时候在 Github 上发布相同的代码,以便您查看工作代码。

于 2020-12-16T03:52:11.987 回答