繁体   English   中英

创建自定义存储库以使用Spring Data JPA

[英]Create Custom Repository to Spring Data JPA

我尝试按照此教程创建custom repositoryhttps : //www.baeldung.com/spring-data-jpa-method-in-all-repositories

我的应用构建失败,并出现以下错误:

NoSuchBeanDefinitionException: No qualifying bean of type 'com.example.demo.dao.ExtendedStudentRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

我的完整源代码: https : //github.com/sesong11/springjpa-custom-repo

有很多类似的问题,但是没有一个适合我。 也许是当前版本2.1.1的Spring问题,或者我错过了一些配置。

要使测试正常进行,您必须执行以下操作:

1)将basePackagesStudentJPAH2Config的错误定义替换为com.example.demo.dao ,或者最好将其删除为多余的:

@Configuration
@EnableJpaRepositories(repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
}

2)亦取代basePackages@ComponentScan@EntityScanDemoApplicationcom.example.demo.daocom.example.demo.entity 或者最好完全删除这些和@EnableTransactionManagement批注:

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

3)向实体Student添加一个无参数的构造函数

4)更正您的测试类-使用@DataJpaTest测试DAO层并导入您的StudentJPAH2Config配置:

@RunWith(SpringRunner.class)
@DataJpaTest
@Import(StudentJPAH2Config.class)
public class ExtendedStudentRepositoryIntegrationTest {
   //...
}

通过这些更正,我已经成功运行了您的测试。

在运行测试之前,让我们确保主应用程序正在运行。 实际上,它存在一些问题。

1. IllegalArgumentException :不是托管类型: com.example.demo.entity.Student类。

问题是@EntityScan("com.example.demo.entity.*") 软件包名称不正确,因此不扫描Student类。

解决方案是@EntityScan("com.example.demo.entity")

2. PropertyReferenceException :找不到类型为Student属性attributeContainsText

问题在于没有设置存储库基类 ,并且JpaQueryLookupStrategy认为它应该从方法名称findByAttributeContainsText构造一个RepositoryQuery 它识别出模式findBy{EntityPropertyName} ,但在Student找不到字段attributeContainsText

未设置存储库基类,因为未应用配置StudentJPAH2Config 如果无法扫描配置,则不会应用该配置。 @ComponentScan("com.example.demo.dao")不扫描StudentJPAH2Config所在的包。

解决方案是@ComponentScan("com.example.demo") ,它将扫描"com.example.demo""com.example.demo.dao"软件包1

现在,当应用程序正常时,让我们回到测试中。

3. NoSuchBeanDefinitionException :没有可用的com.example.demo.dao.ExtendedStudentRepository类型的合格Bean。

问题在于StudentJPAH2Config不能构成整个配置 ,并且缺少一些bean。

解决方案是列出所有配置类。

@ContextConfiguration(classes = { StudentJPAH2Config.class, DemoApplication.class })

要么

@ContextConfiguration(classes = DemoApplication.class)

要么

@SpringBootTest

4. JpaSystemException :没有实体com.example.demo.entity.Student默认构造函数。

问题在于, Hibernate 2需要 Student 的默认构造函数

@Entity
public class Student {

    @Id
    private long id;
    private String name;

    public Student() {}

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    // getters & setters

}

1 @ComponentScan("com.example.demo.dao")是多余的,因为将扫描此软件包,因为其中存在@SpringBootApplication
2 Hibernate是Spring应用程序中的默认JPA提供程序。

进行了以下更改:

@SpringBootApplication
@ComponentScan("com.example.demo.dao")
@EntityScan("com.example.demo.entity")
@EnableJpaRepositories(basePackages = "com.example.demo.dao",
        repositoryBaseClass = ExtendedRepositoryImpl.class)
@EnableTransactionManagement
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }


}

对于StudentJPAH2Config类

@Configuration
@ComponentScan("com.example.demo")
@EnableJpaRepositories(basePackages = "com.example.demo.dao",
        repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
    // additional JPA Configuration
}

学生班缺少空的构造函数:

@Entity
public class Student {

    public Student() {
    }

    public Student(long id, String name) {
        this.id = id;
        this.name = name;
    }

    @Id
    private long id;
    private String name;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

结果

在此处输入图片说明

和应用程序运行状态

在此处输入图片说明

您对自定义Spring Data JPA存储库基类的实现确实起作用。 Spring Boot Application Context中只有几项需要解决。 您确实已将Spring Boot Starter模块声明为依赖项,因此我提交了具有更改的Pull请求 ,该更改将将手动配置上下文的所有责任移交给了Spring Auto Configuration工厂提供程序。

以下是有关通过测试所需的一些更改的注释,以及每个更改的一些简短详细信息。 注意,要在测试范围之外运行Spring Boot Application,您将需要向类路径添加适当的JDBC供应商依赖项,以及任何Spring应用程序属性以定义数据源属性。 定义数据源属性后,Spring Auto Config应该使用合理的设置来照顾任何EntityManager和TransactionManager。 请参阅Spring Boot功能-使用SQL数据库

更改说明:

  • 删除了所有Spring Configuration注释( @SpringBootApplication@EnableJpaRepositories )。 应用程序pom配置为依赖于Spring Boot Starter模块,这些模块已经通过spring.factories提供了Spring Auto Configuration类,同时还确保满足所有其他依赖性。
  • @EnableJpaRepositories不需要声明basePackages因为Auto Config模块将默认使用Spring Main Application类下面的所有软件包。 仍然需要声明附加的repositoryBaseClass
  • @ComponentScan被删除,因为Auto Config模块将对Spring Main Application类下的所有软件包执行ComponentScan,该软件包已经在项目的顶级软件包中。 此外,这是声明要扫描的basePackages值将不包含@ConfigurationStudentJPAH2Config
  • @EntityScan作为自动配置模块被删除后,将在Spring Main Application类下的所有软件包中执行扫描。
  • @EnableTransactionManagement已删除,因为“自动配置”模块将执行相同的操作。
  • 删除了默认的application.properties因为它们依赖于H2 ,但是pom仅在测试范围的类路径中提供了该依赖关系。 此外,属性文件中设置的所有配置属性通常在存在H2时由Spring Starters自动配置。
  • Student为休眠添加了默认的构造函数。 除非使用@PersistenceConstructor@Immutable ,否则Hibernate在管理实体时需要此构造函数。
  • ExtendedStudentRepositoryIntegrationTest为单元测试应用程序上下文配置的Spring Boot自动配置。 这与在DemoApplicationTests为Spring Boot集成测试定义的上下文配置相同。 当直接将@ContextConfigurationStudentJPAH2Config一起StudentJPAH2Config ,在Spring Boot Main Application类上定义的配置(即ComponentScan,EntityScan,TransactionManagement)未应用到Spring Test Application Context。

关于Spring Auto Configuration的一些注意事项,因为这是阻碍该项目成功运行的主要问题:

Spring Application Starters(通常)分为两种类型的依赖关系。

  • autoconfigure模块在其POM中声明了最小的依赖关系集,但是在编译过程中使用许多依赖关系来构建。 自动配置模块还通过位于包的META-INF中的spring.factories文件通告Configuration类和工厂。 Spring Boot在引导阶段将加载这些配置类。 最后,配置类将有选择地声明Bean,并根据在上下文中声明的其他Bean以及在类路径上实际找到的依赖项来进行其他应用程序上下文更改/增强。 这允许所有常规/合理的默认配置,这些配置均基于要引入的库和最少的属性集。
  • starter模块(通常)不提供太多/任何类。 它们的目的是提供POM,这些POM声明特定Spring项目的良好开发基线所需的依赖关系。 启动程序模块还依赖于适用的autoconfigure模块,这些模块与这些依赖项配对,使您可以快速开始使用应用程序运行。

在大多数情况下,使用Spring Starters时,主驱动程序不应弄清楚需要在Spring上下文中手动配置的内容,而应该弄清楚在基线不适合您的情况下应取消配置的内容。 当像您一样在线上关注以下教程/示例时,请记住,可能会显示一些与配置有关的项目。 有时可能需要这些配置说明,但通常它们是为了显示非启动Spring应用程序中所需的配置或透明性的详细信息。

您需要在实现的类中添加注释。 您必须添加@Component或@Service批注,以使Spring能够进行注入

@Component
public class ExtendedRepositoryImpl<T, ID extends Serializable>
extends SimpleJpaRepository<T, ID> implements ExtendedRepository<T, ID> {

我认为您忘了注释ExtendedStudentRepository bean

package com.example.demo.dao;

import com.example.demo.entity.Student;
@Repository
public interface ExtendedStudentRepository extends ExtendedRepository<Student, Long> {
}

您需要进行以下更改才能解决此问题。 另外,由于我本地没有JDK 11,因此我使用JDK 8执行了此操作。 另外,为了执行问题复制,我执行了ExtendedStudentRepositoryIntegrationTest.java。

  1. 在StudentJPAH2Config.java中,需要添加组件扫描。
 @Configuration @ComponentScan("com.example.demo") @EnableJpaRepositories(basePackages = "com.example.demo.dao", repositoryBaseClass = ExtendedRepositoryImpl.class) public class StudentJPAH2Config { 
  1. 在DemoApplication中,基本软件包名称必须更正。
 @SpringBootApplication @ComponentScan("com.example.demo.dao") @EntityScan("com.example.demo.entity") @EnableTransactionManagement public class DemoApplication { 

更改#1的原因是测试配置中没有组件扫描,spring无法在正确的软件包中查找依赖项。 #2是必需的,因为Student.java直接位于com.example.demo.entity包中,而不是在其任何子包中。 您也可以在测试配置文件StudentJPAH2Config中指定@EntityScan,尽管这不是必需的。

现在,这解决了您面临的直接问题,但是仍然可以通过其他一些非常直接的问题来欢迎您,并且您可以从这里继续进行下去。

您必须将@Primary批注放在ExtendedRepositoryImpl类上。 它应该工作。

Spring基本上不能限定依赖项。 @Primary将确保无论您在哪里为ExtendedRepository接口注入依赖项,首先将合格的bean(class)都为ExtendedRepositoryImpl

您必须删除@ContextConfiguration(classes = { StudentJPAH2Config.class })并在测试类ExtendedStudentRepositoryIntegrationTest上添加@SpringBootTest批注,它将解决当前存在的错误NoSuchBeanDefinitionException

但是我又遇到了类似的错误:

Caused by: java.lang.IllegalArgumentException: Not a managed type: class com.example.demo.entity.Student

这是因为Spring无法扫描Entity Student

为此,你必须改变@EntityScan("com.example.demo.entity.*")@EntityScan("com.example.demo.entity")DemoApplication类。

我再次得到错误:

Caused by: org.springframework.data.mapping.PropertyReferenceException: No property attributeContainsText found for type Student!

这是因为方法findByAttributeContainsText()不是有效的方法。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM