Spring技术内幕之Spring Data JPA-自定义Repository实现

原创 2016年05月30日 15:12:40

1.自定义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);
	
	/***还可以定义分页相关方法,此处暂不支持**/
}
2.自定义repository的方法接口实现类,作为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);
		} 
	}
}
3. 扩展jpaRepository,让所有的repository共享起自定义的方法 

package 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;
		}
	}

}
4.配置factory-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;

		
	}
}



版权声明:本文为博主原创文章,未经博主允许不得转载。

Spring data 接口之 自定义Repository 接口

虽然说spring data 提供了很多DAO 接口,但是依然可能不能满足我们日常的使用,所以,有时我们需要自定义接口方法...
  • zgf19930504
  • zgf19930504
  • 2016年01月18日 15:53
  • 5345

Spring boot中结合Specification自定义Repository实现

Spring Data  JPA中封装了很多条件查询的方法,我们可以使用封装的方法和@Query注解进行条件查询。这些都是比较简单的,直接调用接口就行。但是要想实现动态查询,就比较复杂了。下面我将结合...
  • Java_Mike
  • Java_Mike
  • 2017年07月27日 21:23
  • 765

Spring Data Repository有趣的定义query方法

基本使用方法 继承接口并声明查询方法 interface PersonRepository extends RepositoryPerson, Long> { List findByLa...
  • u013128651
  • u013128651
  • 2017年03月29日 15:10
  • 2455

Spring Data JPA 全局DAO的扩展

前几天看了springside4的mini-web代码发现确实有不少新的东东,咱这次单说说Spring Data JPA吧。 引用springside4的 wiki关于对Spring Data...
  • YYZhQ
  • YYZhQ
  • 2012年09月22日 11:41
  • 29031

Spring Data JPA使用JpaRepository自动装配报No qualifying bean of type错误

今天遇到一个问题折腾蛮久的,在这里记录一下。 毕竟是才刚开始使用Jpa这个技术,总是会遇到各种配置问题。 使用Spring Data Jpa非常的方便,一些简单的操作基本上都不用写具体的实现, ...
  • lusyoe
  • lusyoe
  • 2016年10月05日 17:38
  • 3059

SPRING-DATA-JPA 全局DAO配置

配置文件:spring-jpa.xml
  • z69183787
  • z69183787
  • 2015年01月08日 19:20
  • 10594

spring data mongodb学习以及为repository提供可扩展的自定义方法

Spring Data 概述 Spring Data : Spring 的一个子项目。用于简化数据库访问,支持NoSQL 和 关系数据存储。其主要目标是使数据库的访问变得方便快捷。 SpringDat...
  • Victor_Cindy1
  • Victor_Cindy1
  • 2016年08月08日 15:22
  • 8741

spring-data-jpa 使用方法

转自:http://blog.csdn.net/linlinv3/article/details/46605719 spring-data-jpa 使用方法 ...
  • MyArrow
  • MyArrow
  • 2016年03月02日 16:45
  • 8482

spring data 接口之 JpaRepository,JpaSpecificationExecutor

spring data 接口之 自定义Repository 接口
  • zgf19930504
  • zgf19930504
  • 2016年01月18日 15:52
  • 9341

详细介绍springData

1.什么是SpringData? Spring Data 项目的目的是为了简化构建基于 Spring 框架应用的数据访问计数,包括非关系数据库、Map-Reduce 框架、云数据服务等等...
  • wu920604
  • wu920604
  • 2016年09月20日 14:51
  • 34994
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Spring技术内幕之Spring Data JPA-自定义Repository实现
举报原因:
原因补充:

(最多只允许输入30个字)