前幾天看了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
- import java.io.Serializable;
- import org.springframework.data.jpa.repository.JpaRepository;
- public interface MyRepository<T, ID extends Serializable>
- extends JpaRepository<T, ID> {
- String sharedCustomMethod();
- }
- import java.io.Serializable;
- import org.springframework.data.jpa.repository.JpaRepository;
- public interface MyRepository<T, ID extends Serializable>
- extends JpaRepository<T, ID> {
- String sharedCustomMethod();
- }
其中sharedCustomMethod是全局的共享自定義方法。
然後在建一個實現類MyCustomRepository
- import java.io.Serializable;
- import javax.persistence.EntityManager;
- import org.springframework.data.jpa.repository.support.JpaEntityInformation;
- import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
- import org.springframework.data.repository.NoRepositoryBean;
- @NoRepositoryBean
- public class MyCustomRepository<T, ID extends Serializable>
- extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
- private final EntityManager entityManager;
- public MyCustomRepository(Class<T> domainClass, EntityManager em) {
- super(domainClass, em);
- // TODO Auto-generated constructor stub
- entityManager=em;
- }
- public MyCustomRepository(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {
- super(entityInformation, entityManager);
- this.entityManager = entityManager;
- }
- public String sharedCustomMethod() {
- return "hello sharedCustomMethod";
- // implementation goes here
- }
- }
- import java.io.Serializable;
- import javax.persistence.EntityManager;
- import org.springframework.data.jpa.repository.support.JpaEntityInformation;
- import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
- import org.springframework.data.repository.NoRepositoryBean;
- @NoRepositoryBean
- public class MyCustomRepository<T, ID extends Serializable>
- extends SimpleJpaRepository<T, ID> implements MyRepository<T, ID> {
- private final EntityManager entityManager;
- public MyCustomRepository(Class<T> domainClass, EntityManager em) {
- super(domainClass, em);
- // TODO Auto-generated constructor stub
- entityManager=em;
- }
- public MyCustomRepository(final JpaEntityInformation<T, ?> entityInformation, final EntityManager entityManager) {
- super(entityInformation, entityManager);
- this.entityManager = entityManager;
- }
- public String sharedCustomMethod() {
- return "hello sharedCustomMethod";
- // implementation goes here
- }
- }
注意 @NoRepositoryBean一定要有的,還有全局的擴展實現類不要用Imp作爲後綴名,不然會報異常的(目前還沒搞清楚報異常的具體原因,個人猜測可能是和局部的擴展有衝突吧)。
然後在定義MyRepositoryFactory
- import java.io.Serializable;
- import static org.mockito.Mockito.*;
- import javax.persistence.EntityManager;
- import org.springframework.data.jpa.repository.JpaRepository;
- import org.springframework.data.jpa.repository.support.JpaEntityInformation;
- import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
- import org.springframework.data.repository.core.RepositoryMetadata;
- public class MyRepositoryFactory extends JpaRepositoryFactory {
- public MyRepositoryFactory(EntityManager entityManager) {
- super(entityManager);
- // TODO Auto-generated constructor stub
- }
- @Override
- @SuppressWarnings("unchecked")
- protected JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager em) {
- JpaEntityInformation<Object, Serializable> entityMetadata = mock(JpaEntityInformation.class);
- when(entityMetadata.getJavaType()).thenReturn((Class<Object>) metadata.getDomainType());
- return new MyCustomRepository<Object, Serializable>(entityMetadata, em);
- }
- /*
- * (non-Javadoc)
- *
- * @see
- * org.springframework.data.repository.support.RepositoryFactorySupport#
- * getRepositoryBaseClass()
- */
- @Override
- protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
- return MyCustomRepository.class;
- }
- }
- import java.io.Serializable;
- import static org.mockito.Mockito.*;
- import javax.persistence.EntityManager;
- import org.springframework.data.jpa.repository.JpaRepository;
- import org.springframework.data.jpa.repository.support.JpaEntityInformation;
- import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
- import org.springframework.data.repository.core.RepositoryMetadata;
- public class MyRepositoryFactory extends JpaRepositoryFactory {
- public MyRepositoryFactory(EntityManager entityManager) {
- super(entityManager);
- // TODO Auto-generated constructor stub
- }
- @Override
- @SuppressWarnings("unchecked")
- protected JpaRepository<?, ?> getTargetRepository(RepositoryMetadata metadata, EntityManager em) {
- JpaEntityInformation<Object, Serializable> entityMetadata = mock(JpaEntityInformation.class);
- when(entityMetadata.getJavaType()).thenReturn((Class<Object>) metadata.getDomainType());
- return new MyCustomRepository<Object, Serializable>(entityMetadata, em);
- }
- /*
- * (non-Javadoc)
- *
- * @see
- * org.springframework.data.repository.support.RepositoryFactorySupport#
- * getRepositoryBaseClass()
- */
- @Override
- protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
- return MyCustomRepository.class;
- }
- }
接着在建一個MyRepositoryFactoryBean
- import java.io.Serializable;
- import javax.persistence.EntityManager;
- import org.springframework.data.jpa.repository.JpaRepository;
- import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
- import org.springframework.data.repository.core.support.RepositoryFactorySupport;
- public class MyRepositoryFactoryBean<T extends JpaRepository<Object, Serializable>> extends JpaRepositoryFactoryBean<T, Object, Serializable> {
- @Override
- protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
- return new MyRepositoryFactory(em);
- }
- }
- import java.io.Serializable;
- import javax.persistence.EntityManager;
- import org.springframework.data.jpa.repository.JpaRepository;
- import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
- import org.springframework.data.repository.core.support.RepositoryFactorySupport;
- public class MyRepositoryFactoryBean<T extends JpaRepository<Object, Serializable>> extends JpaRepositoryFactoryBean<T, Object, Serializable> {
- @Override
- protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
- return new MyRepositoryFactory(em);
- }
- }
最後在配置文件裏需要定義
<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。
呵呵 這樣你就可以使用全局的自定義擴展庫了。
- public interface UserDao extends MyRepository<User, Long> ,JpaSpecificationExecutor<User>{
- }
- public interface UserDao extends MyRepository<User, Long> ,JpaSpecificationExecutor<User>{