Spring Data JPA 全局DAO的擴展(第一次用JPA時總是提示 另人抓狂的錯誤: No property find for type class )

前幾天看了springside4的mini-web代碼發現確實有不少新的東東,咱這次單說說Spring Data JPA吧。 

引用springside4的 wiki關於對Spring Data JPA的簡介 

Spring Data JPA在JPA上又做了一層封裝,只要編寫接口就夠了,不用寫一行實現代碼,CRUD方法啦,分頁啦,自動將findByLoginName()的方法定義翻譯成適當的QL啦都由它包了:

public interface UserDao extends PagingAndSortingRepository<User, Long> { 
User findByLoginName(String loginName); 

使用上很簡單,快速瀏覽一下下面的資料就夠了。 

只有一個坑爹的地方,如果要爲UserDao擴展方法(而不是接口),要新增一個UserDaoCustom接口,這時候,實現類的名字必須是UserDaoImpl,而不是UserDaoCustomImpl。

另外,除了智能地翻譯連Less,Not,And,Or都支持的方法名,它當然也可以直接用@Query在方法上標註複雜的查詢語句。 

資料 
官方文檔

使用 Spring Data JPA 簡化 JPA 開發 IBM DW上的中文版教程.

 如果看完上面的資料 也許你對Spring Data JPA有了初步的認識,動動手你就知道他的強大,但是對DAO的擴展上有點麻煩,上面紅字部分是對單個dao進行擴展的方法。下面我們來說一下對全局DAO的擴展,創建你自己的CustomRepository。

 

首先咱們要建一個自己的擴展接口類MyRepository

 

Java代碼 複製代碼 收藏代碼
  1. import java.io.Serializable;   
  2.   
  3. import org.springframework.data.jpa.repository.JpaRepository;   
  4.   
  5. public interface MyRepository<T, ID extends Serializable>    
  6. extends JpaRepository<T, ID> {   
  7.   
  8. String  sharedCustomMethod();   
  9. }  
[java] view plaincopy
  1. import java.io.Serializable;  
  2.   
  3. import org.springframework.data.jpa.repository.JpaRepository;  
  4.   
  5. public interface MyRepository<T, ID extends Serializable>   
  6. extends JpaRepository<T, ID> {  
  7.   
  8. String  sharedCustomMethod();  
  9. }  

 

其中sharedCustomMethod是全局的共享自定義方法。

 

然後在建一個實現類MyCustomRepository

Java代碼 複製代碼 收藏代碼
  1. import java.io.Serializable;   
  2.   
  3. import javax.persistence.EntityManager;   
  4.   
  5. import org.springframework.data.jpa.repository.support.JpaEntityInformation;   
  6. import org.springframework.data.jpa.repository.support.SimpleJpaRepository;   
  7. import org.springframework.data.repository.NoRepositoryBean;   
  8.   
  9. @NoRepositoryBean  
  10. public class MyCustomRepository<T, ID extends Serializable>    
  11. extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {   
  12.   
  13.        
  14. private final EntityManager entityManager;   
  15.        
  16. public MyCustomRepository(Class<T> domainClass, EntityManager em) {   
  17.         super(domainClass, em);   
  18.         // TODO Auto-generated constructor stub  
  19.            
  20.         entityManager=em;   
  21.     }   
  22.   
  23. public MyCustomRepository(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {   
  24.     super(entityInformation, entityManager);   
  25.     this.entityManager = entityManager;   
  26. }   
  27.   
  28.   
  29. public String sharedCustomMethod() {   
  30.     return "hello sharedCustomMethod";   
  31.   // implementation goes here  
  32. }    
  33. }  
[java] view plaincopy
  1. import java.io.Serializable;  
  2.   
  3. import javax.persistence.EntityManager;  
  4.   
  5. import org.springframework.data.jpa.repository.support.JpaEntityInformation;  
  6. import org.springframework.data.jpa.repository.support.SimpleJpaRepository;  
  7. import org.springframework.data.repository.NoRepositoryBean;  
  8.   
  9. @NoRepositoryBean  
  10. public class MyCustomRepository<T, ID extends Serializable>   
  11. extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {  
  12.   
  13.       
  14. private final EntityManager entityManager;  
  15.       
  16. public MyCustomRepository(Class<T> domainClass, EntityManager em) {  
  17.         super(domainClass, em);  
  18.         // TODO Auto-generated constructor stub  
  19.           
  20.         entityManager=em;  
  21.     }  
  22.   
  23. public MyCustomRepository(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {  
  24.     super(entityInformation, entityManager);  
  25.     this.entityManager = entityManager;  
  26. }  
  27.   
  28.   
  29. public String sharedCustomMethod() {  
  30.     return "hello sharedCustomMethod";  
  31.   // implementation goes here  
  32. }   
  33. }  

 

 注意 @NoRepositoryBean一定要有的,還有全局的擴展實現類不要用Imp作爲後綴名,不然會報異常的(目前還沒搞清楚報異常的具體原因,個人猜測可能是和局部的擴展有衝突吧)。

 

然後在定義MyRepositoryFactory

Java代碼 複製代碼 收藏代碼
  1. import java.io.Serializable;   
  2.   
  3. import static org.mockito.Mockito.*;   
  4.   
  5. import javax.persistence.EntityManager;   
  6.   
  7. import org.springframework.data.jpa.repository.JpaRepository;   
  8. import org.springframework.data.jpa.repository.support.JpaEntityInformation;   
  9. import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;   
  10. import org.springframework.data.repository.core.RepositoryMetadata;   
  11.   
  12.   
  13. public class MyRepositoryFactory extends JpaRepositoryFactory {   
  14.   
  15.     public MyRepositoryFactory(EntityManager entityManager) {   
  16.         super(entityManager);   
  17.         // TODO Auto-generated constructor stub  
  18.     }   
  19.     @Override  
  20.     @SuppressWarnings("unchecked")   
  21.     protected JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager em) {   
  22.   
  23.         JpaEntityInformation<Object, Serializable> entityMetadata = mock(JpaEntityInformation.class);   
  24.         when(entityMetadata.getJavaType()).thenReturn((Class<Object>) metadata.getDomainType());   
  25.         return new MyCustomRepository<Object, Serializable>(entityMetadata, em);   
  26.     }   
  27.   
  28.     /*  
  29.      * (non-Javadoc)  
  30.      *   
  31.      * @see  
  32.      * org.springframework.data.repository.support.RepositoryFactorySupport# 
  33.      * getRepositoryBaseClass() 
  34.      */  
  35.     @Override  
  36.     protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {   
  37.   
  38.         return MyCustomRepository.class;   
  39.     }   
  40. }  
[java] view plaincopy
  1. import java.io.Serializable;  
  2.   
  3. import static org.mockito.Mockito.*;  
  4.   
  5. import javax.persistence.EntityManager;  
  6.   
  7. import org.springframework.data.jpa.repository.JpaRepository;  
  8. import org.springframework.data.jpa.repository.support.JpaEntityInformation;  
  9. import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;  
  10. import org.springframework.data.repository.core.RepositoryMetadata;  
  11.   
  12.   
  13. public class MyRepositoryFactory extends JpaRepositoryFactory {  
  14.   
  15.     public MyRepositoryFactory(EntityManager entityManager) {  
  16.         super(entityManager);  
  17.         // TODO Auto-generated constructor stub  
  18.     }  
  19.     @Override  
  20.     @SuppressWarnings("unchecked")  
  21.     protected JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager em) {  
  22.   
  23.         JpaEntityInformation<Object, Serializable> entityMetadata = mock(JpaEntityInformation.class);  
  24.         when(entityMetadata.getJavaType()).thenReturn((Class<Object>) metadata.getDomainType());  
  25.         return new MyCustomRepository<Object, Serializable>(entityMetadata, em);  
  26.     }  
  27.   
  28.     /* 
  29.      * (non-Javadoc) 
  30.      *  
  31.      * @see 
  32.      * org.springframework.data.repository.support.RepositoryFactorySupport# 
  33.      * getRepositoryBaseClass() 
  34.      */  
  35.     @Override  
  36.     protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {  
  37.   
  38.         return MyCustomRepository.class;  
  39.     }  
  40. }  

 

接着在建一個MyRepositoryFactoryBean

Java代碼 複製代碼 收藏代碼
  1. import java.io.Serializable;   
  2.   
  3. import javax.persistence.EntityManager;   
  4.   
  5. import org.springframework.data.jpa.repository.JpaRepository;   
  6. import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;   
  7. import org.springframework.data.repository.core.support.RepositoryFactorySupport;   
  8.   
  9. public class MyRepositoryFactoryBean<T extends JpaRepository<Object, Serializable>> extends JpaRepositoryFactoryBean<T, Object, Serializable> {   
  10.   
  11.        
  12.     @Override  
  13.     protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {   
  14.   
  15.         return new MyRepositoryFactory(em);   
  16.     }   
  17. }  
[java] view plaincopy
  1. import java.io.Serializable;  
  2.   
  3. import javax.persistence.EntityManager;  
  4.   
  5. import org.springframework.data.jpa.repository.JpaRepository;  
  6. import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;  
  7. import org.springframework.data.repository.core.support.RepositoryFactorySupport;  
  8.   
  9. public class MyRepositoryFactoryBean<T extends JpaRepository<Object, Serializable>> extends JpaRepositoryFactoryBean<T, Object, Serializable> {  
  10.   
  11.       
  12.     @Override  
  13.     protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {  
  14.   
  15.         return new MyRepositoryFactory(em);  
  16.     }  
  17. }  

 
最後在配置文件裏需要定義

<jpa:repositories base-package="org.springside.examples.miniweb"  transaction-manager-ref="transactionManager" 

 factory-class="org.springside.examples.miniweb.dao.account.MyRepositoryFactoryBean"

entity-manager-factory-ref="entityManagerFactory"/>

 其實這裏還有個repository-impl-postfix=" "個人理解他是來定義局部擴展庫的實現類的後綴的默認是Imp。

 

 呵呵 這樣你就可以使用全局的自定義擴展庫了。

 

Java代碼 複製代碼 收藏代碼
  1. public interface UserDao extends MyRepository<User, Long> ,JpaSpecificationExecutor<User>{   
  2.   
  3. }  
[java] view plaincopy
  1. public interface UserDao extends MyRepository<User, Long> ,JpaSpecificationExecutor<User>{  
發佈了3 篇原創文章 · 獲贊 1 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章