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

1.自定义Repository方法接口,让接口的实现类来继承这个中间接口而不是Repository接口

  1. package com.data.jpa.dao;

  2. import java.io.Serializable;
  3. import java.util.List;
  4. import java.util.Map;

  5. import org.springframework.data.jpa.repository.JpaRepository;
  6. import org.springframework.data.repository.NoRepositoryBean;
  7. /**
  8. * 自定义Repository的方法接口
  9. * @author xiaowen
  10. * @param <T> 领域对象即实体类
  11. * @param <ID>领域对象的注解
  12. */
  13. @NoRepositoryBean
  14. public interface CustomRepository <T, ID extends Serializable> extends JpaRepository<T, ID> {
  15. /**
  16. * 保存对象<br/>
  17. * 注意:如果对象id是字符串,并且没有赋值,该方法将自动设置为uuid值
  18. * @param item
  19. * 持久对象,或者对象集合
  20. * @throws Exception
  21. */
  22. public void store(Object... item);

  23. /**
  24. * 更新对象数据
  25. *
  26. * @param item
  27. * 持久对象,或者对象集合
  28. * @throws Exception
  29. */
  30. public void update(Object... item);

  31. /**
  32. * 执行ql语句
  33. * @param qlString 基于jpa标准的ql语句
  34. * @param values ql中的?参数值,单个参数值或者多个参数值
  35. * @return 返回执行后受影响的数据个数
  36. */
  37. public int executeUpdate(String qlString, Object... values);

  38. /**
  39. * 执行ql语句
  40. * @param qlString 基于jpa标准的ql语句
  41. * @param params key表示ql中参数变量名,value表示该参数变量值
  42. * @return 返回执行后受影响的数据个数
  43. */
  44. public int executeUpdate(String qlString, Map<String, Object> params);

  45. /**
  46. * 执行ql语句,可以是更新或者删除操作
  47. * @param qlString 基于jpa标准的ql语句
  48. * @param values ql中的?参数值
  49. * @return 返回执行后受影响的数据个数
  50. * @throws Exception
  51. */
  52. public int executeUpdate(String qlString, List<Object> values);

  53. /***还可以定义分页相关方法,此处暂不支持**/
  54. }
2.自定义repository的方法接口实现类,作为Repository代理的自定义类来执行,该类主要提供自定义的公用方法
  1. package com.data.jpa.dao.impl;

  2. import java.io.Serializable;
  3. import java.lang.reflect.Field;
  4. import java.lang.reflect.Method;
  5. import java.util.List;
  6. import java.util.Map;

  7. import javax.persistence.EntityManager;
  8. import javax.persistence.Id;
  9. import javax.persistence.Query;

  10. import org.apache.log4j.Logger;
  11. import org.springframework.data.jpa.repository.support.SimpleJpaRepository;

  12. import com.data.jpa.dao.CustomRepository;
  13. import com.data.jpa.util.ReflectHelper;
  14. import com.data.jpa.util.UUIDUtil;

  15. /**
  16. * 自定义repository的方法接口实现类,该类主要提供自定义的公用方法
  17. *
  18. * @author xiaowen
  19. * @date 2016年5月30日 @ version 1.0
  20. * @param <T>
  21. * @param <ID>
  22. */
  23. public class CustomRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, Serializable>
  24. implements CustomRepository<T, Serializable> {

  25. @SuppressWarnings("unused")
  26. private Logger logger = Logger.getLogger(CustomRepositoryImpl.class);
  27. /**
  28. * 持久化上下文
  29. */
  30. private final EntityManager entityManager;

  31. public CustomRepositoryImpl(Class<T> domainClass, EntityManager em) {
  32. super(domainClass, em);
  33. this.entityManager = em;
  34. }

  35. @Override
  36. public void store(Object... item) {
  37. if(null!=item){
  38. for(Object entity : item){
  39. innerSave(entity);
  40. }
  41. }
  42. }

  43. @Override
  44. public void update(Object... item) {
  45. if (null != item) {
  46. for (Object entity : item) {
  47. entityManager.merge(entity);
  48. }
  49. }
  50. }

  51. @Override
  52. public int executeUpdate(String qlString, Object... values) {
  53. Query query = entityManager.createQuery(qlString);
  54. if (values != null) {
  55. for (int i = 0; i < values.length; i++) {
  56. query.setParameter(i + 1, values[i]);
  57. }
  58. }
  59. return query.executeUpdate();
  60. }

  61. @Override
  62. public int executeUpdate(String qlString, Map<String, Object> params) {
  63. Query query = entityManager.createQuery(qlString);
  64. for (String name : params.keySet()) {
  65. query.setParameter(name, params.get(name));
  66. }
  67. return query.executeUpdate();
  68. }

  69. @Override
  70. public int executeUpdate(String qlString, List<Object> values) {
  71. Query query = entityManager.createQuery(qlString);
  72. for (int i = 0; i < values.size(); i++) {
  73. query.setParameter(i + 1, values.get(i));
  74. }
  75. return query.executeUpdate();
  76. }

  77. /**
  78. * 保存对象
  79. * @param item 保存对象
  80. * @return
  81. */
  82. private Serializable innerSave(Object item) {
  83. try {
  84. if(item==null)return null;
  85. Class<?> clazz = item.getClass();
  86. Field idField = ReflectHelper.getIdField(clazz);
  87. Method getMethod = null;
  88. if(idField!=null){
  89. Class<?> type = idField.getType();
  90. Object val = idField.get(item);
  91. if(type == String.class && (val==null || "".equals(val))){
  92. idField.set(item, UUIDUtil.uuid());
  93. }
  94. }else{
  95. Method[] methods = clazz.getDeclaredMethods();
  96. for (Method method : methods) {
  97. Id id = method.getAnnotation(Id.class);
  98. if (id != null) {
  99. Object val = method.invoke(item);
  100. if(val==null || "".equals(val)){
  101. String methodName = "s" + method.getName().substring(1);
  102. Method setMethod = clazz.getDeclaredMethod(methodName, method.getReturnType());
  103. if(setMethod!=null){
  104. setMethod.invoke(item, UUIDUtil.uuid());
  105. }
  106. }
  107. getMethod = method;
  108. break;
  109. }
  110. }
  111. }
  112. entityManager.persist(item);
  113. entityManager.flush();
  114. if(idField!=null){
  115. return (Serializable) idField.get(item);
  116. }
  117. if(getMethod!=null){
  118. return (Serializable)getMethod.invoke(item);
  119. }
  120. return null;
  121. } catch (Exception e) {
  122. e.printStackTrace();
  123. throw new RuntimeException(e);
  124. }
  125. }
  126. }
3. 扩展jpaRepository,让所有的repository共享起自定义的方法 
  1. package com.data.jpa.config;

  2. import java.io.Serializable;

  3. import javax.persistence.EntityManager;

  4. import org.springframework.data.jpa.repository.JpaRepository;
  5. import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
  6. import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean;
  7. import org.springframework.data.repository.core.RepositoryMetadata;
  8. import org.springframework.data.repository.core.support.RepositoryFactorySupport;

  9. import com.data.jpa.dao.impl.CustomRepositoryImpl;
  10. /**
  11. * 创建一个自定义的FactoryBean去替代默认的工厂类
  12. * @author xiaowen
  13. * @date 2016年5月30日
  14. * @ version 1.0
  15. * @param <R>
  16. * @param <T>
  17. * @param <I>
  18. */
  19. public class CustomRepositoryFactoryBean <R extends JpaRepository<T, I>, T, I extends Serializable>
  20. extends JpaRepositoryFactoryBean<R, T, I> {

  21. @SuppressWarnings("rawtypes")
  22. protected RepositoryFactorySupport createRepositoryFactory(EntityManager em) {
  23. return new CustomRepositoryFactory(em);
  24. }

  25. private static class CustomRepositoryFactory<T, I extends Serializable>
  26. extends JpaRepositoryFactory {

  27. private final EntityManager em;

  28. public CustomRepositoryFactory(EntityManager em) {
  29. super(em);
  30. this.em = em;
  31. }

  32. @SuppressWarnings("unchecked")
  33. protected Object getTargetRepository(RepositoryMetadata metadata) {
  34. return new CustomRepositoryImpl<T, I>(
  35. (Class<T>) metadata.getDomainType(), em);
  36. }

  37. protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
  38. return CustomRepositoryImpl.class;
  39. }
  40. }

  41. }
4.配置factory-class
  1. package com.data.jpa.config;

  2. import org.springframework.context.annotation.Configuration;
  3. import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
  4. import org.springframework.data.web.config.EnableSpringDataWebSupport;
  5. /**
  6. * 通过注解配置factory-class
  7. * @author xiaowen
  8. * @date 2016年5月30日
  9. * @ version 1.0
  10. */
  11. @Configuration
  12. @EnableJpaRepositories(basePackages = "com.data.jpa**.dao",
  13. repositoryFactoryBeanClass = CustomRepositoryFactoryBean.class)
  14. @EnableSpringDataWebSupport
  15. public class JpaDataConfig {

  16. }
当然也可以在xml文件中配置
  1. <repositories base-package="com.acme.repository"
  2. factory-class="com.acme.MyRepositoryFactoryBean" />


5.使用自定义的CustomRepository接口
  1. package com.data.jpa.dao;

  2. import com.data.jpa.dao.domain.Persion;

  3. /**
  4. * PersionRepository,通过继承自定义的CustomRepository获取提供自定义的公用方法,当然也可以自定义方法
  5. * @author xiaowen
  6. * @date 2016年5月30日
  7. * @ version 1.0
  8. */
  9. public interface PersionRepository extends CustomRepository<Persion, Integer> {
  10. /**
  11. * 通过用户名查询用户
  12. * @param userName
  13. * @return
  14. */
  15. public Persion findByuserName(String userName);
  16. }

6.使用PersionRepository,直接通过Spring的注解注入即可

  1. package com.data.jpa.controller;

  2. import org.springframework.beans.factory.annotation.Autowired;
  3. import org.springframework.stereotype.Controller;
  4. import org.springframework.web.bind.annotation.RequestMapping;
  5. import org.springframework.web.bind.annotation.ResponseBody;

  6. import com.data.jpa.dao.PersionRepository;

  7. @Controller
  8. @RequestMapping("/perison")
  9. public class PersionController {
  10. @Autowired
  11. private PersionRepository persionRepository;

  12. @RequestMapping("/index")
  13. public String index(){
  14. return "index";

  15. }

  16. @RequestMapping("/search")
  17. public @ResponseBody String search(String userName){
  18. persionRepository.findByuserName(userName);

  19. return "success!";
  20. }

  21. }



相关实体类/工具类代码

1.Persion

  1. package com.data.jpa.dao.domain;

  2. import javax.persistence.Entity;
  3. import javax.persistence.Id;
  4. import javax.persistence.Table;
  5. /**
  6. * persion类
  7. * @author xiaowen
  8. * @date 2016年5月30日
  9. * @ version 1.0
  10. */
  11. @Entity
  12. @Table(name = "t_persion")
  13. public class Persion {
  14. @Id
  15. private String id;

  16. private String userName;

  17. private String userSex;

  18. /**
  19. * @return the id
  20. */
  21. public String getId() {
  22. return id;
  23. }

  24. /**
  25. * @param id the id to set
  26. */
  27. public void setId(String id) {
  28. this.id = id;
  29. }

  30. /**
  31. * @return the userName
  32. */
  33. public String getUserName() {
  34. return userName;
  35. }

  36. /**
  37. * @param userName the userName to set
  38. */
  39. public void setUserName(String userName) {
  40. this.userName = userName;
  41. }

  42. /**
  43. * @return the userSex
  44. */
  45. public String getUserSex() {
  46. return userSex;
  47. }

  48. /**
  49. * @param userSex the userSex to set
  50. */
  51. public void setUserSex(String userSex) {
  52. this.userSex = userSex;
  53. }



  54. }
2.UUID工具类
  1. package com.data.jpa.util;

  2. import java.util.UUID;

  3. /**
  4. * UUID工具类
  5. * @author xiaowen
  6. * @date 2016年5月30日
  7. * @ version 1.0
  8. */
  9. public class UUIDUtil {
  10. /**
  11. * 获取生成的uuid
  12. * @return
  13. */
  14. public static String uuid(){
  15. return UUID.randomUUID().toString().replaceAll("-", "");
  16. }

  17. }
3. 反射相关方法工具类

  1. package com.data.jpa.util;

  2. import java.lang.reflect.Field;

  3. import javax.persistence.Id;

  4. /**
  5. * 反射相关方法工具类
  6. * @author xiaowen
  7. * @date 2016年5月30日
  8. * @ version 1.0
  9. */
  10. public class ReflectHelper {
  11. /**
  12. * 获取实体类的字段信息
  13. * @param clazz 实体类
  14. * @return 字段集合
  15. */
  16. public static Field getIdField(Class<?> clazz){
  17. Field[] fields = clazz.getDeclaredFields();
  18. Field item = null;
  19. for (Field field : fields) {
  20. //获取实体类中标识@Id的字段
  21. Id id = field.getAnnotation(Id.class);
  22. if (id != null) {
  23. field.setAccessible(true);
  24. item = field;
  25. break;
  26. }
  27. }
  28. if(item==null){
  29. Class<?> superclass = clazz.getSuperclass();
  30. if(superclass!=null){
  31. item = getIdField(superclass);
  32. }
  33. }
  34. return item;


  35. }
  36. }



https://blog.csdn.net/u011659172/article/details/51537602

原文地址:https://www.cnblogs.com/xiang--liu/p/9710244.html