ProjectSimpleJpaRepository.java 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572
  1. package cn.efunbox.base.data;
  2. import cn.efunbox.base.util.SnowflakeIdUtil;
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.data.domain.Sort;
  6. import org.springframework.data.domain.Sort.Direction;
  7. import org.springframework.data.jpa.domain.Specification;
  8. import org.springframework.data.jpa.repository.support.JpaEntityInformation;
  9. import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
  10. import org.springframework.transaction.annotation.Transactional;
  11. import org.springframework.util.ReflectionUtils;
  12. import org.springframework.util.StringUtils;
  13. import javax.persistence.EntityManager;
  14. import javax.persistence.TypedQuery;
  15. import javax.persistence.criteria.CriteriaBuilder;
  16. import javax.persistence.criteria.CriteriaQuery;
  17. import javax.persistence.criteria.Predicate;
  18. import javax.persistence.criteria.Root;
  19. import javax.persistence.metamodel.Attribute;
  20. import javax.persistence.metamodel.Attribute.PersistentAttributeType;
  21. import java.io.Serializable;
  22. import java.lang.reflect.Field;
  23. import java.lang.reflect.Member;
  24. import java.lang.reflect.Method;
  25. import java.util.*;
  26. public class ProjectSimpleJpaRepository<E, ID extends Serializable> extends SimpleJpaRepository<E, ID> implements ProjectJpaRepository<E, ID> {
  27. // 日志记录器
  28. private static final Logger logger = LoggerFactory.getLogger(ProjectSimpleJpaRepository.class);
  29. // jpa管理器对象
  30. private EntityManager entityManager;
  31. // 实体信息
  32. private JpaEntityInformation<E, ID> entityInformation;
  33. /**
  34. * 构造方法
  35. */
  36. public ProjectSimpleJpaRepository(JpaEntityInformation<E, ID> entityInformation, EntityManager entityManager) {
  37. super(entityInformation, entityManager);
  38. // 保留该对象,方便后续使用
  39. this.entityInformation = entityInformation;
  40. this.entityManager = entityManager;
  41. }
  42. /**
  43. * 功能: <br/>
  44. *
  45. * 重写:xtwin <br/>
  46. *
  47. * @version :2016年7月26日 下午3:23:06<br/>
  48. *
  49. * @param sample
  50. * @return <br/>
  51. * @see ProjectJpaRepository#count(Object)
  52. */
  53. @Override
  54. public long count(E sample) {
  55. return count(getSpecification(sample));
  56. }
  57. /**
  58. * 功能: <br/>
  59. *
  60. * 重写:xtwin <br/>
  61. *
  62. * @version :2016年8月17日 下午12:05:21<br/>
  63. *
  64. * @param sample
  65. * @return <br/>
  66. * @see ProjectJpaRepository#exists(Object)
  67. */
  68. @Override
  69. public boolean exists(E sample) {
  70. return count(sample) > 0L;
  71. }
  72. /**
  73. * 功能: <br/>
  74. *
  75. * 重写:xtwin <br/>
  76. *
  77. * @version :2016年7月26日 下午3:23:06<br/>
  78. *
  79. * @param id
  80. * @return <br/>
  81. * @see ProjectJpaRepository#find(Serializable)
  82. */
  83. @Override
  84. public E find(ID id) {
  85. Optional<E> optional = findById(id);
  86. if (optional.isPresent()) {
  87. return optional.get();
  88. }
  89. return null;
  90. }
  91. /**
  92. * 功能:根据ids查询 <br/>
  93. *
  94. * @author xtwin <br/>
  95. * @version 2016年3月30日 下午6:28:23 <br/>
  96. */
  97. @Override
  98. public List<E> findByIds(List<ID> ids){
  99. return findAllById(ids);
  100. }
  101. /**
  102. * 功能: <br/>
  103. *
  104. * 重写:xtwin <br/>
  105. *
  106. * @version :2016年7月26日 下午3:23:06<br/>
  107. *
  108. * @param start
  109. * @param offset
  110. * @return <br/>
  111. * @see ProjectJpaRepository#find(Long, Integer)
  112. */
  113. @Override
  114. public List<E> find(Long start, Integer offset) {
  115. return find(start, offset, null);
  116. }
  117. /**
  118. * 功能: <br/>
  119. *
  120. * 重写:xtwin <br/>
  121. *
  122. * @version :2016年7月29日 上午10:20:21<br/>
  123. *
  124. * @param start
  125. * @param offset
  126. * @param sort
  127. * @return <br/>
  128. * @see ProjectJpaRepository#find(Long, Integer, Sort)
  129. */
  130. @Override
  131. public List<E> find(Long start, Integer offset, Sort sort) {
  132. return find(null, start, offset, sort);
  133. }
  134. /**
  135. * 功能: <br/>
  136. *
  137. * 重写:xtwin <br/>
  138. *
  139. * @version :2016年8月2日 上午11:58:30<br/>
  140. *
  141. * @param sample
  142. * @return <br/>
  143. * @see ProjectJpaRepository#findFirst(Object)
  144. */
  145. @Override
  146. public E findFirst(E sample) {
  147. return findFirst(sample, null);
  148. }
  149. /**
  150. * 功能: <br/>
  151. *
  152. * 重写:xtwin <br/>
  153. *
  154. * @version :2016年8月2日 上午11:58:30<br/>
  155. *
  156. * @param sample
  157. * @param sort
  158. * @return <br/>
  159. * @see ProjectJpaRepository#findFirst(Object, Sort)
  160. */
  161. @Override
  162. public E findFirst(E sample, Sort sort) {
  163. List<E> list = find(sample, 0L, 1, sort);
  164. return null == list || list.isEmpty() ? null : list.get(0);
  165. }
  166. /**
  167. * 功能: <br/>
  168. *
  169. * 重写:xtwin <br/>
  170. *
  171. * @version :2016年7月26日 下午3:23:06<br/>
  172. *
  173. * @param sample
  174. * @return <br/>
  175. * @see ProjectJpaRepository#find(Object)
  176. */
  177. @Override
  178. public List<E> find(E sample) {
  179. return find(sample, null);
  180. }
  181. /**
  182. * 功能: <br/>
  183. *
  184. * 重写:xtwin <br/>
  185. *
  186. * @version :2016年7月29日 上午10:20:21<br/>
  187. *
  188. * @param sample
  189. * @param sort
  190. * @return <br/>
  191. * @see ProjectJpaRepository#find(Object, Sort)
  192. */
  193. @Override
  194. public List<E> find(E sample, Sort sort) {
  195. return find(sample, null, null,sort);
  196. }
  197. /**
  198. * 功能: <br/>
  199. *
  200. * 重写:xtwin <br/>
  201. *
  202. * @version :2016年7月26日 下午3:23:06<br/>
  203. *
  204. * @param sample
  205. * @param start
  206. * @param offset
  207. * @return <br/>
  208. * @see ProjectJpaRepository#find(Object, Long, Integer)
  209. */
  210. @Override
  211. public List<E> find(E sample, Long start, Integer offset) {
  212. return find(sample, start, offset, null);
  213. }
  214. /**
  215. * 功能: <br/>
  216. *
  217. * 重写:xtwin <br/>
  218. *
  219. * @version :2016年7月29日 上午9:44:56<br/>
  220. *
  221. * @param sample
  222. * @param start
  223. * @param offset
  224. * @param sort
  225. * @return <br/>
  226. * @see ProjectJpaRepository#find(Object, Long, Integer, Sort)
  227. */
  228. @Override
  229. public List<E> find(E sample, Long start, Integer offset, Sort sort) {
  230. // 创建qbe
  231. Specification<E> spec = getSpecification(sample);
  232. if (null == sort) {
  233. // 默认按id降序排序
  234. sort = Sort.by(Direction.DESC, entityInformation.getIdAttribute().getName());
  235. }
  236. // 取得查询对象
  237. TypedQuery<E> query = getQuery(spec, sort);
  238. // 起始条数,从零开始
  239. if (null != start) {
  240. // TODO 此处只接受整形值
  241. query.setFirstResult(start.intValue());
  242. }
  243. // 查询条数
  244. if (null != offset) {
  245. query.setMaxResults(offset);
  246. }
  247. // 执行查询
  248. return query.getResultList();
  249. }
  250. /**
  251. * 功能: 更新操作,不更新为null的字段 <br/>
  252. *
  253. * 重写:xtwin <br/>
  254. *
  255. * @version :2016年8月1日 上午9:37:15<br/>
  256. *
  257. * @param entity
  258. * @return <br/>
  259. * @see ProjectJpaRepository#update(Object)
  260. */
  261. @Override
  262. @Transactional
  263. public E update(E entity) {
  264. return update(entity, true);
  265. }
  266. /**
  267. * Saves all given entities.
  268. *
  269. * @param entities
  270. * @return the saved entities
  271. * @throws IllegalArgumentException in case the given domain is {@literal null}.
  272. */
  273. @Override
  274. @Transactional
  275. public <S extends E> List<S> save(Iterable<S> entities) {
  276. return insertOrUpdateBatch(entities);
  277. }
  278. /**
  279. * Saves a given domain. Use the returned instance for further operations as the save operation might have changed the
  280. * domain instance completely.
  281. *
  282. * @param entity
  283. * @return the saved domain
  284. */
  285. @Override
  286. @Transactional
  287. public <S extends E> S save(S entity) {
  288. if (entityInformation.isNew(entity)) {
  289. setSnowflakeIdId(entity);
  290. entityManager.persist(entity);
  291. return entity;
  292. } else {
  293. return entityManager.merge(entity);
  294. }
  295. }
  296. /**
  297. * 功能: 动态数据更新,可以选择是否需要更新null字段 <br/>
  298. *
  299. * 重写:xtwin <br/>
  300. *
  301. * @version :2016年8月1日 上午9:37:05<br/>
  302. *
  303. * @param entity
  304. * @param ignoreNull
  305. * @return <br/>
  306. * @see ProjectJpaRepository#update(Object, boolean)
  307. */
  308. @Override
  309. @Transactional
  310. public E update(E entity, boolean ignoreNull) {
  311. // 取得当前实体的id
  312. ID id = entityInformation.getId(entity);
  313. // 检查id是否为空Ø
  314. if (Objects.isNull(id)) {
  315. return save(entity);
  316. }
  317. if (id instanceof String) {
  318. if (org.apache.commons.lang3.StringUtils.isBlank((String) id)) {
  319. return save(entity);
  320. }
  321. }
  322. // 查询库中当前对象的信息
  323. E persist = find(id);
  324. // 检查该id对应的数据是否存在
  325. if (null == persist) {
  326. return save(entity);
  327. // throw new RuntimeException("The update domain id is not exist : " + id);
  328. }
  329. // 标识是否发生了变化
  330. boolean isChanged = false;
  331. // 取得所有属性
  332. for (Attribute<? super E, ?> attr : entityManager.getMetamodel().entity(getDomainClass()).getAttributes()) {
  333. // 依次处理每个字段
  334. /*PersistentAttributeType patype = attr.getPersistentAttributeType();
  335. if (PersistentAttributeType.MANY_TO_ONE.equals(patype)
  336. || PersistentAttributeType.ONE_TO_MANY.equals(patype)) {
  337. // 忽略
  338. continue;
  339. }*/
  340. Member member = attr.getJavaMember();
  341. Field field = null;
  342. if (member instanceof Field) {
  343. field = (Field) member;
  344. } else {
  345. field = ReflectionUtils.findField(getDomainClass(), attr.getName());
  346. }
  347. // 取得字段值
  348. Object value = ReflectionUtils.getField(field, entity);
  349. if (null != value || ! ignoreNull) {
  350. // 旧值
  351. Object oldValue = ReflectionUtils.getField(field, persist);
  352. if ((null == value && null != oldValue)
  353. || (null != value && ! value.equals(oldValue))) {
  354. // 将新值更新到持久化对象中
  355. ReflectionUtils.setField(field, persist, value);
  356. // 标记为发生了更新
  357. isChanged = true;
  358. }
  359. }
  360. }
  361. if (isChanged) {
  362. persist = save(persist);
  363. } else {
  364. // 没有发生变更,忽略更新
  365. logger.debug("has no changed : {}", id);
  366. }
  367. // 执行保存并返回
  368. return persist;
  369. }
  370. /**
  371. * update all given entities.
  372. *
  373. * @param entities
  374. * @return the saved entities
  375. * @throws IllegalArgumentException in case the given domain is {@literal null}.
  376. */
  377. @Override
  378. @Transactional
  379. public <S extends E> List<S> update(Iterable<S> entities) {
  380. return insertOrUpdateBatch(entities);
  381. }
  382. private <S extends E> List<S> insertOrUpdateBatch(Iterable<S> entities) {
  383. List<S> result = new ArrayList<>();
  384. if (entities == null) {
  385. return result;
  386. }
  387. Iterator<S> iterator = entities.iterator();
  388. int i = 0;
  389. int count = 0;
  390. //遍历循环 每20个 insert 批量插入/更新 一次库
  391. while (iterator.hasNext()) {
  392. S entity = iterator.next();
  393. if (entityInformation.isNew(entity)) {
  394. setSnowflakeIdId(entity);
  395. entityManager.persist(entity);
  396. } else {
  397. update(entity);
  398. }
  399. result.add(entity);
  400. i++;
  401. if (i % 20 == 0) {
  402. entityManager.flush();
  403. entityManager.clear();
  404. count=0;
  405. }else {
  406. count++;
  407. }
  408. }
  409. //判断 是否有剩余未flush的 最后flush
  410. if (count>0){
  411. entityManager.flush();
  412. entityManager.clear();
  413. }
  414. return result;
  415. }
  416. /**
  417. * 功能:获取qbe <br/>
  418. *
  419. * @author xtwin <br/>
  420. * @version 2016年7月29日 上午9:43:25 <br/>
  421. */
  422. protected Specification<E> getSpecification(E sample) {
  423. return null == sample ? null : new Specification<E>() {
  424. @Override
  425. public Predicate toPredicate(Root<E> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
  426. try {
  427. // 获取qbe
  428. return ProjectSimpleJpaRepository.this.toPredicate(sample, root, query, cb);
  429. } catch (Exception e) {
  430. throw new RuntimeException("toPredicate fail with error : " + String.valueOf(e), e);
  431. }
  432. }
  433. };
  434. }
  435. /**
  436. * 功能:转为查询样板,可以由子类重写 <br/>
  437. *
  438. * @author xtwin <br/>
  439. * @version 2016年7月29日 上午10:15:27 <br/>
  440. * @throws IllegalAccessException
  441. * @throws IllegalArgumentException
  442. */
  443. protected Predicate toPredicate(E sample, Root<E> root, CriteriaQuery<?> query, CriteriaBuilder cb) throws Exception {
  444. // 存放查询条件
  445. List<Predicate> list = new ArrayList<Predicate>();
  446. // 处理实体中的所有字段
  447. for (Attribute<? super E, ?> attr : entityManager.getMetamodel().entity(getDomainClass()).getAttributes()) {
  448. // 依次处理每个字段
  449. PersistentAttributeType patype = attr.getPersistentAttributeType();
  450. // 打印日志
  451. logger.debug("the attr type is : {}", patype);
  452. if (PersistentAttributeType.MANY_TO_ONE.equals(patype)
  453. || PersistentAttributeType.ONE_TO_MANY.equals(patype)) {
  454. // 忽略
  455. continue;
  456. }
  457. Object value = null;
  458. Member member = attr.getJavaMember();
  459. if (member instanceof Method) {
  460. value = ReflectionUtils.invokeMethod((Method) member, sample);
  461. } else if (member instanceof Field) {
  462. //((Field) member).setAccessible(true);
  463. // 确保可以访问
  464. ReflectionUtils.makeAccessible((Field) member);
  465. // 取得字段的值
  466. value = ((Field) member).get(sample);
  467. }
  468. if (null != value) {
  469. Predicate tmp = null;
  470. //like 查询放在最前面
  471. List<Predicate> likePredicate = new ArrayList<Predicate>();
  472. if (String.class.isAssignableFrom(attr.getJavaType()) ) {
  473. if(!StringUtils.isEmpty(value)){
  474. StringBuilder stringBuilder=new StringBuilder(((String) value).trim());
  475. //如果以 % 开头和结尾 表示 like 查询
  476. if("%".equals(stringBuilder.substring(0,1)) || stringBuilder.toString().endsWith("%")){
  477. tmp = cb.like(root.get(attr.getName()), (String) value);
  478. likePredicate.add(tmp);
  479. }else{
  480. tmp = cb.equal(root.get(attr.getName()), value);
  481. list.add(tmp);
  482. }
  483. }
  484. } else {
  485. tmp = cb.equal(root.get(attr.getName()), value);
  486. list.add(tmp);
  487. }
  488. if(likePredicate.size()>0){
  489. list.addAll(0,likePredicate);
  490. }
  491. }
  492. }
  493. // where条件
  494. return list.isEmpty() ? null : cb.and(list.toArray(new Predicate[list.size()]));
  495. }
  496. protected void setSnowflakeIdId(E entity){
  497. try {
  498. Field field = ReflectionUtils.findField(entity.getClass(),entityInformation.getIdAttribute().getName());
  499. if(entityInformation.getIdAttribute().getType().getJavaType().getName().equals("java.lang.Long")){
  500. ReflectionUtils.makeAccessible(field);
  501. ReflectionUtils.setField(field, entity, SnowflakeIdUtil.getSnowflakeIdUtil().nextId());
  502. }else if(entityInformation.getIdAttribute().getType().getJavaType().getName().equals("java.lang.String")) {
  503. logger.debug(" uuid entityInformation.getIdAttribute().getName() ={}",entityInformation.getIdAttribute().getName());
  504. ReflectionUtils.makeAccessible(field);
  505. ReflectionUtils.setField(field, entity, SnowflakeIdUtil.getSnowflakeIdUtil().nextCode());
  506. }
  507. }catch (Exception e){
  508. logger.error("Reflect set id 出错 mag ={}",e.getMessage(),e);
  509. }
  510. }
  511. }