簡體   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