SpringBoot實現自定義Repository
SpringBoot實現的JPA封裝了JPA的特性,只需要寫介面即可,但是有的時候約定的寫法不符合我們的開發要求,沒有很好的靈活性,這就需要我們自己去定義一下方法實現自己的封裝Repository。
借鑑網上配置:
- 新增所需要的依賴包
<!-- spring-data-jpa程式的啟動項依賴,底層為hibernate實現,若不使用此框架則可以依賴其他的orm框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId >spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- web程式的啟動項依賴,通過此依賴可引入內嵌的tomcat等web必須的jars -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mysql依賴,使用spring-data-jpa需要指定一個數據庫方言,用於連線資料庫,即mysql驅動 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
- 定義BaseRepository介面實現JPARepository介面
package com.redsoft.spirit.dao;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;
/**
* @author 楊雷
*
*/
@NoRepositoryBean
public interface BaseRepository<T, ID extends Serializable> extends JpaRepository<T,ID>{
public HashMap<String, Object> sqlQuery(String queryString, String countSql, Map<String, ?> values, int offset, int limit, String countName, String rowsName);
public List<T> sqlQuery(String queryString, Map<String, ?> values);
public List<T> sqlQuery(String queryString, Object ... values);
public HashMap<String, Object> retrieve(String queryString, String countHql, Map<String, ?> values, int offset, int limit, String countName, String rowsName);
}
- 定義BaseRepository的實現類,所有的DAO實現BaseRepository介面後,具體的實現方法由該實現類去操作。
package com.redsoft.spirit.dao;
import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.util.Assert;
/**
* dao的封裝類.
*
* <pre>
* 封裝一些涉及到原生sql的增刪改查分頁等功能
* </pre>
*
* @author 楊雷
* @since 1.0
*
*/
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {
//父類沒有不帶引數的構造方法,這裡手動構造父類
public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
super(domainClass, entityManager);
System.out.println("建構函式" + domainClass);
this.entityManager = entityManager;
this.entityClass = domainClass;
}
@PersistenceContext
private EntityManager entityManager;
private Class<T> entityClass;
/**
* 查詢分頁的方法.
* <pre>
* 帶著條件進行動態拼接sql的查詢方法
* </pre>
*
*/
@Override
public HashMap<String, Object> sqlQuery(String queryString, String countSql, Map<String, ?> values, int offset,
int limit, String countName, String rowsName) {
Assert.hasText(queryString, "queryString不能為空");
HashMap<String, Object> map = new HashMap<String, Object>();
Query query = entityManager.createNativeQuery(queryString);
Query countQuery = entityManager.createNativeQuery(countSql);
//給條件賦上值
if (values != null && !values.isEmpty()) {
for (Map.Entry<String, ?> entry : values.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
countQuery.setParameter(entry.getKey(), entry.getValue());
}
}
query.setFirstResult(offset);
query.setMaxResults(limit);
query.unwrap(SQLQuery.class).setResultTransformer(new BeanTransformerAdapter(this.entityClass));
Object results = query.getResultList();
Object resultsCount = countQuery.getSingleResult();
map.put(countName, resultsCount);
map.put(rowsName, results);
return map;
}
@Override
public List sqlQuery(String queryString, Map<String, ?> values) {
Session session = entityManager.unwrap(org.hibernate.Session.class);
SQLQuery query = session.createSQLQuery(queryString);
// //給條件賦上值
// if (values != null && !values.isEmpty()) {
// for (Map.Entry<String, ?> entry : values.entrySet()) {
// query.setParameter(entry.getKey(), entry.getValue());
// }
// }
if (values != null) {
query.setProperties(values);
}
query.setResultTransformer(new BeanTransformerAdapter(this.entityClass));
return query.list();
}
@Override
public List sqlQuery(String queryString, Object... values) {
Query query = entityManager.createNativeQuery(queryString);
// Session session = entityManager.unwrap(org.hibernate.Session.class);
// SQLQuery query = session.createSQLQuery(queryString);
if (values != null) {
for (int i = 0; i < values.length; i++) {
query.setParameter(i + 1, values[i]);
}
}
query.unwrap(SQLQuery.class).setResultTransformer(new BeanTransformerAdapter(this.entityClass));
return query.getResultList();
}
@Override
public HashMap<String, Object> retrieve(String queryString, String countHql, Map<String, ?> values, int offset,
int limit, String countName, String rowsName) {
HashMap<String, Object> map = new HashMap<String, Object>();
Query query = entityManager.createQuery(queryString);
Query countQuery = entityManager.createQuery(countHql);
//給條件賦上值
if (values != null && !values.isEmpty()) {
for (Map.Entry<String, ?> entry : values.entrySet()) {
query.setParameter(entry.getKey(), entry.getValue());
countQuery.setParameter(entry.getKey(), entry.getValue());
}
}
query.setFirstResult(offset);
query.setMaxResults(limit);
Object results = query.getResultList();
Object resultsCount = countQuery.getSingleResult();
map.put(countName, resultsCount);
map.put(rowsName, results);
return map;
}
}
- 新增將結果轉換成實體類的介面卡類
package com.redsoft.spirit.dao;
import java.beans.PropertyDescriptor;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.transform.ResultTransformer;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.NotWritablePropertyException;
import org.springframework.beans.PropertyAccessorFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.support.JdbcUtils;
import org.springframework.util.StringUtils;
public class BeanTransformerAdapter<T>
implements ResultTransformer
{
private static final long serialVersionUID = 8149706114474043039L;
protected final Log logger = LogFactory.getLog(getClass());
private Class<T> mappedClass;
private boolean checkFullyPopulated = false;
private boolean primitivesDefaultedForNullValue = false;
private Map<String, PropertyDescriptor> mappedFields;
private Set<String> mappedProperties;
public BeanTransformerAdapter()
{
}
public BeanTransformerAdapter(Class<T> mappedClass)
{
initialize(mappedClass);
}
public BeanTransformerAdapter(Class<T> mappedClass, boolean checkFullyPopulated)
{
initialize(mappedClass);
this.checkFullyPopulated = checkFullyPopulated;
}
public void setMappedClass(Class<T> mappedClass)
{
if (this.mappedClass == null) {
initialize(mappedClass);
}
else if (!this.mappedClass.equals(mappedClass))
throw new InvalidDataAccessApiUsageException("The mapped class can not be reassigned to map to " +
mappedClass + " since it is already providing mapping for " + this.mappedClass);
}
protected void initialize(Class<T> mappedClass)
{
this.mappedClass = mappedClass;
this.mappedFields = new HashMap();
this.mappedProperties = new HashSet();
PropertyDescriptor[] pds = BeanUtils.getPropertyDescriptors(mappedClass);
for (PropertyDescriptor pd : pds)
if (pd.getWriteMethod() != null) {
this.mappedFields.put(pd.getName().toLowerCase(), pd);
String underscoredName = underscoreName(pd.getName());
if (!pd.getName().toLowerCase().equals(underscoredName)) {
this.mappedFields.put(underscoredName, pd);
}
this.mappedProperties.add(pd.getName());
}
}
private String underscoreName(String name)
{
if (!StringUtils.hasLength(name)) {
return "";
}
StringBuilder result = new StringBuilder();
result.append(name.substring(0, 1).toLowerCase());
for (int i = 1; i < name.length(); i++) {
String s = name.substring(i, i + 1);
String slc = s.toLowerCase();
if (!s.equals(slc))
result.append("_").append(slc);
else {
result.append(s);
}
}
return result.toString();
}
public final Class<T> getMappedClass()
{
return this.mappedClass;
}
public void setCheckFullyPopulated(boolean checkFullyPopulated)
{
this.checkFullyPopulated = checkFullyPopulated;
}
public boolean isCheckFullyPopulated()
{
return this.checkFullyPopulated;
}
public void setPrimitivesDefaultedForNullValue(boolean primitivesDefaultedForNullValue)
{
this.primitivesDefaultedForNullValue = primitivesDefaultedForNullValue;
}
public boolean isPrimitivesDefaultedForNullValue()
{
return this.primitivesDefaultedForNullValue;
}
protected void initBeanWrapper(BeanWrapper bw)
{
}
protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd)
throws SQLException
{
return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType());
}
public static <T> BeanPropertyRowMapper<T> newInstance(Class<T> mappedClass)
{
BeanPropertyRowMapper newInstance = new BeanPropertyRowMapper();
newInstance.setMappedClass(mappedClass);
return newInstance;
}
public Object transformTuple(Object[] tuple, String[] aliases)
{
Object mappedObject = BeanUtils.instantiate(this.mappedClass);
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);
initBeanWrapper(bw);
Set populatedProperties = isCheckFullyPopulated() ? new HashSet() : null;
for (int i = 0; i < aliases.length; i++) {
String column = aliases[i];
PropertyDescriptor pd = (PropertyDescriptor)this.mappedFields.get(column.replaceAll(" ", "").toLowerCase());
if (pd == null) continue;
try {
Object value = tuple[i];
try {
bw.setPropertyValue(pd.getName(), value);
} catch (TypeMismatchException e) {
if ((value == null) && (this.primitivesDefaultedForNullValue))
this.logger.debug("Intercepted TypeMismatchException for column " + column + " and column '" +
column + "' with value " + value + " when setting property '" + pd.getName() + "' of type " + pd.getPropertyType() +
" on object: " + mappedObject);
else {
throw e;
}
}
if (populatedProperties != null)
populatedProperties.add(pd.getName());
}
catch (NotWritablePropertyException ex) {
throw new DataRetrievalFailureException("Unable to map column " + column +
" to property " + pd.getName(), ex);
}
}
if ((populatedProperties != null) && (!populatedProperties.equals(this.mappedProperties))) {
throw new InvalidDataAccessApiUsageException("Given ResultSet does not contain all fields necessary to populate object of class [" +
this.mappedClass + "]: " + this.mappedProperties);
}
return mappedObject;
}
public List transformList(List list)
{
return list;
}
}
- 擴充套件jpaRepository,讓所有的repository共享起自定義的方法。RepositoryFactoryBean負責返回一個RepositoryFactory,Spring Data Jpa將使用RepositoryFactory來建立Repository具體實現。
package com.redsoft.spirit.dao;
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.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import javax.persistence.EntityManager;
import java.io.Serializable;
/**
* Created by konghao on 2016/12/7.
*/
public class BaseRepositoryFactoryBean<R extends JpaRepository<T, I>, T,
I extends Serializable> extends JpaRepositoryFactoryBean<R, T, I> {
public BaseRepositoryFactoryBean(Class<? extends R> repositoryInterface) {
super(repositoryInterface);
}
@Override
protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
return new BaseRepositoryFactory(em);
}
//建立一個內部類,該類不用在外部訪問
private static class BaseRepositoryFactory<T, I extends Serializable>
extends JpaRepositoryFactory {
private final EntityManager em;
public BaseRepositoryFactory(EntityManager em) {
super(em);
this.em = em;
}
//設定具體的實現類是BaseRepositoryImpl
@Override
protected Object getTargetRepository(RepositoryInformation information) {
return new BaseRepositoryImpl<T, I>((Class<T>) information.getDomainType(), em);
}
//設定具體的實現類的class
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
return BaseRepositoryImpl.class;
}
}
}
- 主類上指定自己的工廠類
@SpringBootApplication
@EnableJpaRepositories(basePackages = {"com.redsoft"}, repositoryFactoryBeanClass = BaseRepositoryFactoryBean.class)//指定自己的工廠類
public class EPIPApplication extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application) {
return application.sources(EPIPApplication.class);
}
public static void main(String[] args) throws InterruptedException {
ApplicationContext ctx = SpringApplication.run(EPIPApplication.class, args);
}
}
相關推薦
SpringBoot實現自定義Repository
SpringBoot實現的JPA封裝了JPA的特性,只需要寫介面即可,但是有的時候約定的寫法不符合我們的開發要求,沒有很好的靈活性,這就需要我們自己去定義一下方法實現自己的封裝Repository。 借鑑網上配置: 新增所需要的依賴包 &l
springboot實現自定義的Interceptor攔截器
構建springboot專案 這裡使用的是eclipse,簡單化 其他實體之類的程式碼省略 專案程式碼 application.properties # 資料來源配置 sp
springboot 實現自定義註解
1、定義一個註解 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Test { } 注意: @Target
springboot實現自定義註解
1:引入jar包<!-- Spring Boot aop 代理 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactI
SpringBoot 通過自定義註解實現AOP切面程式設計例項
一直心心念的想寫一篇關於AOP切面例項的博文,拖更了許久之後,今天終於著手下筆將其完成。 基礎概念 1、切面(Aspect) 首先要理解‘切’字,需要把物件想象成一個立方體,傳統的面向物件變成思維,類定義完成之後(封裝)。每次例項化一個物件,對類定義中的成員變數賦值,就相當於對這個立方體進行了一個定義,
基於springboot通過自定義註解和AOP實現許可權驗證
這篇文章主要介紹自定義註解配合AOP的使用來完成一個簡單的許可權驗證的功能。 一、移入依賴 <parent> <groupId>org.springframework.boot</groupId> <artifactId>sprin
springboot自動以filter,interceptor,listener實現自定義過濾、攔截、監聽
1:自定義攔截器 (1)實現Filter介面 (2)添加註解WebFilter,指定要過濾的路徑、指定filer的名字、指定初始化引數 (3)新增@ServletComponentScan註解開啟掃描servlet元件 package top.lrshu
springboot aop 自定義註解方式實現一套完善的日誌記錄(完整原始碼)
一:功能簡介 本文主要記錄如何使用aop切面的方式來實現日誌記錄功能。 主要記錄的資訊有: 操作人,方法名,引數,執行時間,操作型別(增刪改查),詳細描述,返回值。 二:專案結構圖 三:MAVEM依賴 本專案有兩個pom檔案,父類的pom檔案主要作用是對子類pom檔案依賴的版本號進行統一管理。 1.最外層
[springBoot] Springboot 整合redis並實現自定義序列化遇到的問題
當我們使用@Cacheable註解的時候會將返回的物件快取起來,我們會發現預設快取的值是二進位制的,不方便檢視,為此我們自定義序列化配置,改成JSON格式的 配置如下: pom.xml <?xml version="1.0" encoding="UTF-8"?&
SpringBoot第四講擴充套件和封裝Spring Data JPA(一)_自定義Repository和建立自己的BaseRepository
這一講主要介紹Spring Data JPA的封裝。和設計相關的東西都是仁者見仁,智者見智的事情,如果你有更好的封裝方案可以和我交流,互相學習。這一講會講如下一些內容 - 擴充套件Spring Data JPA實現自己的一些特殊方法 - 建立一個自己的Bas
使用SpringBoot通過自定義註解+AOP+全域性異常處理實現引數統一非空校驗
一、前言 在我們寫後臺介面時,難免對引數進行非空校驗,如果一兩個還好,但如果需要寫大量的介面,及必填引數太多的時候,會給我們開發帶來大量的重複工作,及很多相似程式碼。而sping自帶的@RequestParam註解並不能完全滿足我們的需求,因為
springboot rabbitMQ 自定義MessageConverter和ClassMapper實現訊息序列化
背景:公司專案使用springboot + rabbitMQ 處理訂單和推送訊息,最開始的時候,producer都是直接convertAndSend的json資料, consumer也是接收json資料,然後在轉化為Bean去處理邏輯。當然,這樣雖然沒啥大問題,但是感覺很麻煩,後來查閱文件,
SpringBoot MVC實現自定義RequestBody註解
實現環境:SpringBoot 2.1.1,JDK 1.8 一、MVC實現RequestBody註解原始碼解析 1. @RequestBody 原始碼: @Target(ElementType.PARAMETER) @Retention(RetentionPolicy.
SpringBoot使用AOP實現自定義介面快取
一、引入pom.xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data
Spring技術內幕之Spring Data JPA-自定義Repository實現
1.自定義Repository方法介面,讓介面的實現類來繼承這個中間介面而不是Repository介面 package com.data.jpa.dao; import java.io.Serializable; import java.util.List; impor
SpringBoot使用自定義註解實現簡單引數加密解密(註解+HandlerMethodArgumentResolver)
# 前言 > 我黃漢三又回來了,快半年沒更新部落格了,這半年來的經歷實屬不易, > 疫情當頭,本人實習的公司沒有跟員工共患難,直接辭掉了很多人。 > 作為一個實習生,本人也被無情開除了。所以本人又得重新準備找工作了。 > 算了,感慨一下,本來想昨天發的,但昨天是清明,哀悼時期,就留到了今天發。 話不多說,
如何實現自定義同步組件
nds 允許 oid try unlock all 同步 while name package com.chen;import java.util.concurrent.TimeUnit;import java.util.concurrent.locks.AbstractQ
JS簡單實現自定義右鍵菜單
ans idt 右鍵 動畫 忘記 span spa round 部分 RT,一個簡單的例子,僅僅講述原理 <div id="menu" style="width: 0;height: 0;background: cadetblue;position: absolu
Notification的基本用法以及使用RemoteView實現自定義布局
解決 edi ngs 取消 ets lsp 過程 net tde Notification的作用 Notification是一種全局效果的通知,在系統的通知欄中顯示。既然作為通知,其基本作用有: 顯示接收到短消息、即時信息等 顯示客戶端的推送(廣告、優惠、新聞等)
Spring Boot下如何自定義Repository中的DAO方法
hibernate reat 軟件測試 bst pass update pop 後綴 mark 環境配置介紹 jdk 1.8, spring Boot 1.5.3.RELEASE, MySQL, Spring Data, JPA 問題描述 Spring Data提供了一套簡