[英]Create Custom Repository to Spring Data JPA
我嘗試按照此教程創建custom repository
: https : //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)將basePackages
中StudentJPAH2Config
的錯誤定義替換為com.example.demo.dao
,或者最好將其刪除為多余的:
@Configuration
@EnableJpaRepositories(repositoryBaseClass = ExtendedRepositoryImpl.class)
public class StudentJPAH2Config {
}
2)亦取代basePackages
在@ComponentScan
和@EntityScan
在DemoApplication
類com.example.demo.dao
和com.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 {
//...
}
通過這些更正,我已經成功運行了您的測試。
在運行測試之前,讓我們確保主應用程序正在運行。 實際上,它存在一些問題。
IllegalArgumentException
:不是托管類型: com.example.demo.entity.Student
類。 問題是@EntityScan("com.example.demo.entity.*")
。 軟件包名稱不正確,因此不掃描Student
類。
解決方案是@EntityScan("com.example.demo.entity")
。
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 。
現在,當應用程序正常時,讓我們回到測試中。
NoSuchBeanDefinitionException
:沒有可用的com.example.demo.dao.ExtendedStudentRepository
類型的合格Bean。 問題在於StudentJPAH2Config
不能構成整個配置 ,並且缺少一些bean。
解決方案是列出所有配置類。
@ContextConfiguration(classes = { StudentJPAH2Config.class, DemoApplication.class })
要么
@ContextConfiguration(classes = DemoApplication.class)
要么
@SpringBootTest
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數據庫 。
@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
值將不包含@Configuration
類StudentJPAH2Config
。 @EntityScan
作為自動配置模塊被刪除后,將在Spring Main Application類下的所有軟件包中執行掃描。 @EnableTransactionManagement
已刪除,因為“自動配置”模塊將執行相同的操作。 application.properties
因為它們依賴於H2
,但是pom僅在測試范圍的類路徑中提供了該依賴關系。 此外,屬性文件中設置的所有配置屬性通常在存在H2時由Spring Starters自動配置。 Student
為休眠添加了默認的構造函數。 除非使用@PersistenceConstructor
或@Immutable
,否則Hibernate在管理實體時需要此構造函數。 ExtendedStudentRepositoryIntegrationTest
為單元測試應用程序上下文配置的Spring Boot自動配置。 這與在DemoApplicationTests
為Spring Boot集成測試定義的上下文配置相同。 當直接將@ContextConfiguration
與StudentJPAH2Config
一起StudentJPAH2Config
,在Spring Boot Main Application類上定義的配置(即ComponentScan,EntityScan,TransactionManagement)未應用到Spring Test Application Context。 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。
@Configuration @ComponentScan("com.example.demo") @EnableJpaRepositories(basePackages = "com.example.demo.dao", repositoryBaseClass = ExtendedRepositoryImpl.class) public class StudentJPAH2Config {
@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.