Spring技術內幕之Spring Data JPA-自定義Repository實現
阿新 • • 發佈:2019-02-17
1.自定義Repository方法介面,讓介面的實現類來繼承這個中間介面而不是Repository介面
2.自定義repository的方法介面實現類,作為Repository代理的自定義類來執行,該類主要提供自定義的公用方法package com.data.jpa.dao; import java.io.Serializable; import java.util.List; import java.util.Map; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.repository.NoRepositoryBean; /** * 自定義Repository的方法介面 * @author xiaowen * @param <T> 領域物件即實體類 * @param <ID>領域物件的註解 */ @NoRepositoryBean public interface CustomRepository <T, ID extends Serializable> extends JpaRepository<T, ID> { /** * 儲存物件<br/> * 注意:如果物件id是字串,並且沒有賦值,該方法將自動設定為uuid值 * @param item * 持久物件,或者物件集合 * @throws Exception */ public void store(Object... item); /** * 更新物件資料 * * @param item * 持久物件,或者物件集合 * @throws Exception */ public void update(Object... item); /** * 執行ql語句 * @param qlString 基於jpa標準的ql語句 * @param values ql中的?引數值,單個引數值或者多個引數值 * @return 返回執行後受影響的資料個數 */ public int executeUpdate(String qlString, Object... values); /** * 執行ql語句 * @param qlString 基於jpa標準的ql語句 * @param params key表示ql中引數變數名,value表示該引數變數值 * @return 返回執行後受影響的資料個數 */ public int executeUpdate(String qlString, Map<String, Object> params); /** * 執行ql語句,可以是更新或者刪除操作 * @param qlString 基於jpa標準的ql語句 * @param values ql中的?引數值 * @return 返回執行後受影響的資料個數 * @throws Exception */ public int executeUpdate(String qlString, List<Object> values); /***還可以定義分頁相關方法,此處暫不支援**/ }
3. 擴充套件jpaRepository,讓所有的repository共享起自定義的方法package com.data.jpa.dao.impl; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.List; import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.Id; import javax.persistence.Query; import org.apache.log4j.Logger; import org.springframework.data.jpa.repository.support.SimpleJpaRepository; import com.data.jpa.dao.CustomRepository; import com.data.jpa.util.ReflectHelper; import com.data.jpa.util.UUIDUtil; /** * 自定義repository的方法介面實現類,該類主要提供自定義的公用方法 * * @author xiaowen * @date 2016年5月30日 @ version 1.0 * @param <T> * @param <ID> */ public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, Serializable> implements CustomRepository<T, Serializable> { @SuppressWarnings("unused") private Logger logger = Logger.getLogger(CustomRepositoryImpl.class); /** * 持久化上下文 */ private final EntityManager entityManager; public CustomRepositoryImpl(Class<T> domainClass, EntityManager em) { super(domainClass, em); this.entityManager = em; } @Override public void store(Object... item) { if(null!=item){ for(Object entity : item){ innerSave(entity); } } } @Override public void update(Object... item) { if (null != item) { for (Object entity : item) { entityManager.merge(entity); } } } @Override public int executeUpdate(String qlString, Object... values) { Query query = entityManager.createQuery(qlString); if (values != null) { for (int i = 0; i < values.length; i++) { query.setParameter(i + 1, values[i]); } } return query.executeUpdate(); } @Override public int executeUpdate(String qlString, Map<String, Object> params) { Query query = entityManager.createQuery(qlString); for (String name : params.keySet()) { query.setParameter(name, params.get(name)); } return query.executeUpdate(); } @Override public int executeUpdate(String qlString, List<Object> values) { Query query = entityManager.createQuery(qlString); for (int i = 0; i < values.size(); i++) { query.setParameter(i + 1, values.get(i)); } return query.executeUpdate(); } /** * 儲存物件 * @param item 儲存物件 * @return */ private Serializable innerSave(Object item) { try { if(item==null)return null; Class<?> clazz = item.getClass(); Field idField = ReflectHelper.getIdField(clazz); Method getMethod = null; if(idField!=null){ Class<?> type = idField.getType(); Object val = idField.get(item); if(type == String.class && (val==null || "".equals(val))){ idField.set(item, UUIDUtil.uuid()); } }else{ Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { Id id = method.getAnnotation(Id.class); if (id != null) { Object val = method.invoke(item); if(val==null || "".equals(val)){ String methodName = "s" + method.getName().substring(1); Method setMethod = clazz.getDeclaredMethod(methodName, method.getReturnType()); if(setMethod!=null){ setMethod.invoke(item, UUIDUtil.uuid()); } } getMethod = method; break; } } } entityManager.persist(item); entityManager.flush(); if(idField!=null){ return (Serializable) idField.get(item); } if(getMethod!=null){ return (Serializable)getMethod.invoke(item); } return null; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); } } }
4.配置factory-classpackage com.data.jpa.config; import java.io.Serializable; import javax.persistence.EntityManager; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.support.JpaRepositoryFactory; import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; import org.springframework.data.repository.core.RepositoryMetadata; import org.springframework.data.repository.core.support.RepositoryFactorySupport; import com.data.jpa.dao.impl.CustomRepositoryImpl; /** * 建立一個自定義的FactoryBean去替代預設的工廠類 * @author xiaowen * @date 2016年5月30日 * @ version 1.0 * @param <R> * @param <T> * @param <I> */ public class CustomRepositoryFactoryBean <R extends JpaRepository<T, I>, T, I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> { @SuppressWarnings("rawtypes") protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) { return new CustomRepositoryFactory(em); } private static class CustomRepositoryFactory<T, I extends Serializable> extends JpaRepositoryFactory { private final EntityManager em; public CustomRepositoryFactory(EntityManager em) { super(em); this.em = em; } @SuppressWarnings("unchecked") protected Object getTargetRepository(RepositoryMetadata metadata) { return new CustomRepositoryImpl<T, I>( (Class<T>) metadata.getDomainType(), em); } protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) { return CustomRepositoryImpl.class; } } }
package com.data.jpa.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.web.config.EnableSpringDataWebSupport;
/**
* 通過註解配置factory-class
* @author xiaowen
* @date 2016年5月30日
* @ version 1.0
*/
@Configuration
@EnableJpaRepositories(basePackages = "com.data.jpa**.dao",
repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
@EnableSpringDataWebSupport
public class JpaDataConfig {
}
當然也可以在xml檔案中配置
<repositories base-package="com.acme.repository"
factory-class="com.acme.MyRepositoryFactoryBean" />
5.使用自定義的CustomRepository介面
package com.data.jpa.dao;
import com.data.jpa.dao.domain.Persion;
/**
* PersionRepository,通過繼承自定義的CustomRepository獲取提供自定義的公用方法,當然也可以自定義方法
* @author xiaowen
* @date 2016年5月30日
* @ version 1.0
*/
public interface PersionRepository extends CustomRepository<Persion, Integer> {
/**
* 通過使用者名稱查詢使用者
* @param userName
* @return
*/
public Persion findByuserName(String userName);
}
6.使用PersionRepository,直接通過Spring的註解注入即可
package com.data.jpa.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.data.jpa.dao.PersionRepository;
@Controller
@RequestMapping("/perison")
public class PersionController {
@Autowired
private PersionRepository persionRepository;
@RequestMapping("/index")
public String index(){
return "index";
}
@RequestMapping("/search")
public @ResponseBody String search(String userName){
persionRepository.findByuserName(userName);
return "success!";
}
}
相關實體類/工具類程式碼
1.Persion
package com.data.jpa.dao.domain;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* persion類
* @author xiaowen
* @date 2016年5月30日
* @ version 1.0
*/
@Entity
@Table(name = "t_persion")
public class Persion {
@Id
private String id;
private String userName;
private String userSex;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the userName
*/
public String getUserName() {
return userName;
}
/**
* @param userName the userName to set
*/
public void setUserName(String userName) {
this.userName = userName;
}
/**
* @return the userSex
*/
public String getUserSex() {
return userSex;
}
/**
* @param userSex the userSex to set
*/
public void setUserSex(String userSex) {
this.userSex = userSex;
}
}
2.UUID工具類
package com.data.jpa.util;
import java.util.UUID;
/**
* UUID工具類
* @author xiaowen
* @date 2016年5月30日
* @ version 1.0
*/
public class UUIDUtil {
/**
* 獲取生成的uuid
* @return
*/
public static String uuid(){
return UUID.randomUUID().toString().replaceAll("-", "");
}
}
3. 反射相關方法工具類package com.data.jpa.util;
import java.lang.reflect.Field;
import javax.persistence.Id;
/**
* 反射相關方法工具類
* @author xiaowen
* @date 2016年5月30日
* @ version 1.0
*/
public class ReflectHelper {
/**
* 獲取實體類的欄位資訊
* @param clazz 實體類
* @return 欄位集合
*/
public static Field getIdField(Class<?> clazz){
Field[] fields = clazz.getDeclaredFields();
Field item = null;
for (Field field : fields) {
//獲取實體類中標識@Id的欄位
Id id = field.getAnnotation(Id.class);
if (id != null) {
field.setAccessible(true);
item = field;
break;
}
}
if(item==null){
Class<?> superclass = clazz.getSuperclass();
if(superclass!=null){
item = getIdField(superclass);
}
}
return item;
}
}