Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spring JPA自定义实现(孔乙己的茴香豆) #13

Open
SherryLang opened this issue Jun 9, 2017 · 0 comments
Open

Spring JPA自定义实现(孔乙己的茴香豆) #13

SherryLang opened this issue Jun 9, 2017 · 0 comments

Comments

@SherryLang
Copy link
Owner

SherryLang commented Jun 9, 2017

主要目的

获取EntityManager的实例,使用实例的方法来实现creatQuery

第一种实现:最原始的方式

package com.xxxxx.repository.base.impl;

import java.io.Serializable;
import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;

import com.xxxxx.repository.base.BasicRepository;
import com.xxxxx.support.GenericsTool;

/** 
 * 对外相当于simpleJpaRepository的功能
 * implements BasicRepository<T, ID>的部分可以不要,并且去掉@Override注解,相当于JPA的方法全部使用em自定义实现
*/
public class BasicDAO<T, ID extends Serializable> implements BasicRepository<T, ID>{

	@PersistenceContext
	protected EntityManager entityManager;

	private BasicRepository<T, ID> basicRepository;

	@SuppressWarnings("unchecked")
	private BasicRepository<T, ID> getBasicRepository() {
		if (null == basicRepository) {
			//通过反射,Class声明的范型参数的类型,用于实例化BasicRepositoryImpl对象,效果同Factory 
			basicRepository = new BasicRepositoryImpl<T, ID>(
					(Class<T>) GenericsTool.getSuperClassGenricType(getClass()), entityManager);
		}
		return basicRepository;
	}

 	@Override
	public List<T> findAll() {
		return getBasicRepository().findAll();
	}
	
	@Override
        // ...(父类的方法全部Override一遍)

}

其中用到的工具类方法如下:

package com.xxxxx.constant;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 反射转换对象什么的泛型参数类型
 */
public class GenericsTool {
	
	private static final Logger log = LoggerFactory.getLogger(GenericsTool.class);
	
	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型
	 * @param clazz 类对象
	 * @return 泛型类型
	 */
	public static Class<?> getSuperClassGenricType(Class<?> clazz) {
		return getSuperClassGenricType(clazz, 0);
	}
	
	/**
	 * 通过反射,获得定义Class时声明的父类的范型参数的类型
	 * @param clazz 类对象
	 * @param index 泛型位置,从0开始
	 * @return 泛型类型
	 */
	public static Class<?> getSuperClassGenricType(Class<?> clazz, int index) {
		Type genType = clazz.getGenericSuperclass();
		if (!(genType instanceof ParameterizedType)) {
			log.warn(clazz.getSimpleName() + "'s superclass not ParameterizedType");
			return Object.class;
		}
		Type[] params = ((ParameterizedType)genType).getActualTypeArguments();
		if (index >= params.length || index < 0) {
			log.warn("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: " + params.length);
			return Object.class;
		}
		if (!(params[index] instanceof Class<?>)) {
			log.warn(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
			return Object.class;
		}
		return (Class<?>)params[index];
	}
}

第二种实现:Factory构造Bean,然而在接口中暴露了函数体

6月9日白天的代码
《深入实践Spring Boot》P83:自定义的接口必须在程序启动时装配,才能正常使用……

第三种实现:实现CccPageRepository接口,避免使用default修饰

CccPageRepository 接口继承自JpaRepository,只要需要定义方法名(避免暴露函数体),并且使用@NoRepositoryBean注解:

package com.xxxx.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;

import com.xxxx.domain.CccPage;
@NoRepositoryBean
public interface CccPageRepository extends JpaRepository<CccPage, Long>{
	List<CccPage> findByDocNo(String docNo);
	List<CccPage> searchCccByKeyword(String fieldName, String[] keywords);
}

实现类内部定义私有的EntityManager实体,并且用@Autowired注入,用构造函数构造自身(包括父类):

package com.xxxx.repository;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;

import com.xxxx.domain.CccPage;

@Repository
public class CccPageRepositoryImpl extends SimpleJpaRepository<CccPage, Long> implements CccPageRepository {

	private String[] fields = { "model", "productName", "docNo", "remarks" };
        
        //私有成员变量em
	private EntityManager em;
	 
	@Autowired
	public CccPageRepositoryImpl (EntityManager em) {
		super(CccPage.class, em);
		this.em = em;
	}

	@SuppressWarnings("unchecked")
	public List<CccPage> findByDocNo(String docNo) {
		Query query = em.createQuery("from CccPage where docNo=:docNo");
		query.setParameter("docNo", docNo);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<CccPage> searchCccByKeyword(String fieldName, String[] keywords) {
		StringBuilder sqlString = new StringBuilder("");
		//隐藏函数体,主要功能是构造自定义的sqlString
		System.out.println(sqlString.toString());

		Query query = em.createQuery(sqlString.toString());
		List<CccPage> res = query.getResultList();
		return res;
	}

}

第四种实现:反射获取em实例

关键:基类BasicDAO 反射获取EntityManager实例

package com.xxxx.repository.base;

import java.lang.reflect.Field;

import javax.persistence.EntityManager;

import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

public interface BasicDAO {
	/**
	 * 通过SimpleJpaRepository的em属性,反射获取EntityManager的实例
	 * 
	 * @return
	 */
	default EntityManager getEntityManager() {
		try {
			Field f = SimpleJpaRepository.class.getDeclaredField("em");
			f.setAccessible(true);
			return (EntityManager) f.get(this);
		} catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
			LoggerFactory.getLogger(BasicDAO.class)
					.error("not get current entityManager from reflect SimpleJpaRepository's field", e);
		}
		return null;
	}
}

CccPageRepository 继承JpaRepository和基类BasicDAO

package com.xxxx.repository;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;

import com.xxxx.domain.CccPage;
import com.xxxx.repository.base.BasicDAO;

/* 注意这里要继承BasicDAO!*/
@NoRepositoryBean
public interface CccPageRepository extends JpaRepository<CccPage, Long>, BasicDAO {

	List<CccPage> findByDocNo(String docNo);

	List<CccPage> searchCccByKeyword(String fieldName, String[] keywords);
}

实现类CccPageRepositoryImpl

package com.xxxx.repository;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Repository;

import com.xxxx.domain.CccPage;

@Repository
public class CccPageRepositoryImpl extends SimpleJpaRepository<CccPage, Long> implements CccPageRepository {

	private String[] fields = { "model", "productName", "docNo", "remarks" };

	/*
	 * private EntityManager em;
	 */
	public CccPageRepositoryImpl (EntityManager em) {
		super(CccPage.class, em);
	}

	@SuppressWarnings("unchecked")
	public List<CccPage> findByDocNo(String docNo) {
		Query query = getEntityManager().createQuery("from CccPage where docNo=:docNo");
		query.setParameter("docNo", docNo);
		return query.getResultList();
	}

	@SuppressWarnings("unchecked")
	public List<CccPage> searchCccByKeyword(String fieldName, String[] keywords) {
		StringBuilder sqlString = new StringBuilder("");
		//隐藏函数体,主要功能是构造自定义的sqlString
		System.out.println(sqlString.toString());

		Query query = getEntityManager().createQuery(sqlString.toString());
		List<CccPage> res = query.getResultList();
		return res;
	}
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant