package com.chehaha.common.data.service;
import java.io.Serializable;
import java.util.List;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import com.chehaha.common.data.pojo.Criterion;
import com.chehaha.common.data.pojo.DataMode;
public interface ICrudService {
<T> T get(Serializable id,Class<T> clazz);
<T> T findOne(List<Criterion> criteria, Class<T> clazz);
<T> T save(T entity,Class<T> clazz);
<T> T save(T entity);
<T> T saveGeneric(T entity,Class<?> clazz);
<T> void delete(T entity, Class<T> clazz);
<T> void delete(T entity);
<T> List<T> getAll(Class<T> clazz);
<T> List<T> getAll(Class<T> clazz, Sort sort);
<T> List<T> getAll(Class<T> clazz,DataMode mode);
<T> List<T> getAll(Class<T> clazz,DataMode mode, Sort sort);
<T> List<T> getGenericAll(Class<?> clazz);
<T> List<T> getGenericAll(Class<?> clazz,DataMode mode);
<T> List<T> find(Class<T> clazz, List<Criterion> criteria);
<T> List<T> find(Class<T> clazz, List<Criterion> criteria, DataMode mode);
<T> List<T> find(Class<T> clazz, List<Criterion> criteria, Sort sort);
<T> List<T> find(Class<T> clazz, List<Criterion> criteria, Sort sort,DataMode mode);
<T> List<T> findGeneric(Class<?> clazz, List<Criterion> criteria);
<T> List<T> findGeneric(Class<?> clazz, List<Criterion> criteria,DataMode mode);
<T> Page<T> getAllByPage(Class<T> clazz,Pageable page);
<T> Page<T> getGenericAllByPage(Class<?> clazz,Pageable page);
<T> Page<T> findByPage(Class<T> clazz, List<Criterion> criteria,Pageable page);
<T> Page<T> findByPage(Class<T> clazz, List<Criterion> criteria,Pageable page,DataMode mode);
<T> Page<T> findGenericByPage(Class<?> clazz, List<Criterion> criteria,Pageable page);
<T> Page<T> findGenericByPage(Class<?> clazz, List<Criterion> criteria,Pageable page,DataMode mode);
// <T> List<T> search(Class<T> clazz,Predicate predicate);
}
-----------------------------------------------------------------------------
1.参数设定2.值设定3.builder匹配方法选择。这里用表达式来区分
package com.chehaha.common.data.pojo;
import java.io.Serializable;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class Criterion implements Serializable {
private static final long serialVersionUID = 815285616955434414L;
private final static String regex = "\\|";
private String property;
private Expression expression;
private Object value;
public static Criterion instance(String key,Object value){
Criterion c = new Criterion();
String[] keys = key.split(regex);
c.setExpression(keys.length == 1 ? Expression.Equal : Expression.set(keys[1]));
c.setProperty(keys[0]);
switch(c.getExpression()){
case Between:
Map<String,Object> data = (Map<String,Object>)value;
String type = data.get("type").toString();
if("date".equals(type)){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
DateRangeCriterion o = new DateRangeCriterion();
try {
o.setBegin(sdf.parse(data.get("begin").toString()));
o.setEnd(sdf.parse(data.get("end").toString()));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
c.setValue(o);
}else if("int".equals(type)){
IntegerRangeCriterion o = new IntegerRangeCriterion();
o.setBegin(Integer.parseInt(data.get("begin").toString()) );
o.setEnd(Integer.parseInt(data.get("end").toString()));
c.setValue(o);
}else if("long".equals(type)){
LongRangeCriterion o = new LongRangeCriterion();
o.setBegin(Long.parseLong(data.get("begin").toString()) );
o.setEnd(Long.parseLong(data.get("end").toString()));
c.setValue(o);
}else if("float".equals(type)){
FloatRangeCriterion o = new FloatRangeCriterion();
o.setBegin(Float.parseFloat(data.get("begin").toString()) );
o.setEnd(Float.parseFloat(data.get("end").toString()));
c.setValue(o);
}else{
DoubleRangeCriterion o = new DoubleRangeCriterion();
o.setBegin(Double.parseDouble(data.get("begin").toString()) );
o.setEnd(Double.parseDouble(data.get("end").toString()));
c.setValue(o);
}
break;
case In:
if(value instanceof String){
c.setValue(Arrays.asList(value.toString().split(",")));
}else if(value instanceof List){
c.setValue(value);
}
break;
default:
c.setValue(value);
break;
}
return c;
}
public String getProperty() {
return property;
}
public void setProperty(String property) {
this.property = property;
}
public Expression getExpression() {
return expression;
}
public void setExpression(Expression expression) {
this.expression = expression;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
--------------------------------
package com.chehaha.common.data.pojo;
public enum Expression {
Equal,NotEqual,Less,LessThan,Great,GreatThan,Between,In,Like,StartLike,EndLike;
public static Expression set(String val){
if("less".equals(val)){
return Less;
}else if("less-than".equals(val)){
return LessThan;
}else if("great".equals(val)){
return Great;
}else if("great-than".equals(val)){
return GreatThan;
}else if("between".equals(val)){
return Between;
}else if("in".equals(val)){
return In;
}else if("like".equals(val)){
return Like;
}else if("like-start".equals(val)){
return StartLike;
}else if("like-end".equals(val)){
return EndLike;
}else if("not".equals(val)){
return NotEqual;
}else{
return Equal;
}
}
}
--------------------------------------------------------------
具体创建两个对象SimpleJpaRepository 操作实体对象,具体操作参数对象Specification
package com.chehaha.common.data.service.impl;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Expression;
import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import com.chehaha.common.exception.FrameworkException;
import com.chehaha.common.exception.code.F1;
import com.chehaha.common.exception.code.F3;
import com.chehaha.common.util.json.impl.FastjsonUtil;
import com.chehaha.shop.entity.ShopDiscountInfo;
import com.chehaha.shop.pojo.ActiveStatus;
import com.fasterxml.jackson.core.JsonProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//import com.querydsl.core.types.Predicate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.JpaContext;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaEntityInformationSupport;
import org.springframework.data.jpa.repository.support.QueryDslJpaRepository;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.chehaha.common.data.pojo.*;
import com.chehaha.common.data.service.ICrudService;
import com.chehaha.common.util.string.StringUtil;
@Service
@Transactional(readOnly = true)
public class CrudServiceImpl implements ICrudService {
private static final Logger log = LoggerFactory.getLogger(CrudServiceImpl.class);
@Autowired
private JpaContext context;
private <T> SimpleJpaRepository<T, Serializable> getGenericRepository(Class<?> clazz) {
// ((java.lang.reflect.ParameterizedType)clazz.getGenericSuperclass()).getActualTypeArguments()[0];
Class<T> entityClass = (Class<T>) clazz;
return getRepository(entityClass);
}
private <T> SimpleJpaRepository<T, Serializable> getRepository(Class<T> clazz) {
EntityManager em = context.getEntityManagerByManagedType(clazz);
JpaEntityInformation<T, ?> jei = JpaEntityInformationSupport.getEntityInformation(clazz, em);
return new SimpleJpaRepository<T, Serializable>(jei, em);
}
private <T> QueryDslJpaRepository<T, Serializable> getDslRepository(Class<T> clazz) {
EntityManager em = context.getEntityManagerByManagedType(clazz);
JpaEntityInformation<T, Serializable> jei = (JpaEntityInformation<T, Serializable>) JpaEntityInformationSupport
.getEntityInformation(clazz, em);
return new QueryDslJpaRepository<T, Serializable>(jei, em);
}
private <T> Expression<? extends T> castToType(Class<T> clazz, Object o) {
return (Expression<? extends T>) o;
}
private <T> List<T> clearPropertyCollection(Class<T> clazz, List<T> list) throws IllegalAccessException,
IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException {
List<Field> listFields = new ArrayList<Field>();
Field[] allFields = clazz.getDeclaredFields();
for (Field f : allFields) {
if (Collection.class.isAssignableFrom(f.getType())) {
listFields.add(f);
}
}
for (T item : list) {
for (Field field : listFields) {
clazz.getMethod(StringUtil.getSetterName(field.getName()), field.getType()).invoke(item, (Object) null);
// field.setAccessible(true);
// field.set(item, null);
}
}
return list;
}
private <T> Specification<T> getSpec(List<Criterion> criteria, boolean isNone) {// ,Class<?> clazz) {
// Class<T> entityClass = (Class<T>)clazz;
return new Specification<T>() {
@Override
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
if (isNone) {
return builder.disjunction();
}
Predicate pred = builder.conjunction();
Path<?> exp = null;
String[] attr;
boolean isSingle = true;
for (Criterion cr : criteria) {
attr = cr.getProperty().split("\\.");
isSingle = attr[0].indexOf(",") < 0;
if (isSingle) {
exp = root.get(attr[0]);
}
if (attr.length > 1) {
exp = root.join(attr[0]).get(attr[1]);
}
switch (cr.getExpression()) {
case Equal:
pred = builder.and(pred, builder.equal(exp, cr.getValue()));
break;
case NotEqual:
pred = builder.and(pred, builder.notEqual(exp, cr.getValue()));
break;
case Like:
String key1 = cr.getValue().toString();
if (isSingle) {
pred = builder.and(pred, builder.like((Expression<String>) exp, "%" + key1 + "%"));
} else {
String[] attrs = attr[0].split(",");
List<Predicate> muti = new ArrayList<Predicate>();
for (String a : attrs) {
muti.add(builder.like((Expression<String>) root.<String>get(a), "%" + key1 + "%"));
}
pred = builder.and(pred, builder.or(muti.toArray(new Predicate[muti.size() - 1])));
}
break;
case StartLike:
String key2 = cr.getValue().toString();
if (isSingle) {
pred = builder.and(pred, builder.like((Expression<String>) exp, "%" + key2));
} else {
String[] attrs = attr[0].split(",");
List<Predicate> muti = new ArrayList<Predicate>();
for (String a : attrs) {
muti.add(builder.like((Expression<String>) root.<String>get(a), "%" + key2));
}
pred = builder.and(pred, builder.or(muti.toArray(new Predicate[muti.size() - 1])));
}
break;
case EndLike:
String key3 = cr.getValue().toString();
if (isSingle) {
pred = builder.and(pred, builder.like((Expression<String>) exp, key3 + "%"));
} else {
String[] attrs = attr[0].split(",");
List<Predicate> muti = new ArrayList<Predicate>();
for (String a : attrs) {
muti.add(builder.like((Expression<String>) root.<String>get(a), key3 + "%"));
}
pred = builder.and(pred, builder.or(muti.toArray(new Predicate[muti.size() - 1])));
}
break;
case Great:
if (cr.getValue() instanceof Number) {
pred = builder.and(pred, builder.gt((Expression<Number>) exp, (Number) cr.getValue()));
} else if (cr.getValue() instanceof Date) {
pred = builder.and(pred, builder.greaterThan((Expression<Date>) exp, (Date) cr.getValue()));
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
pred = builder.and(pred, builder.greaterThan((Expression<Date>) exp,
sdf.parse(cr.getValue().toString())));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case GreatThan:
if (cr.getValue() instanceof Number) {
pred = builder.and(pred, builder.ge((Expression<Number>) exp, (Number) cr.getValue()));
} else if (cr.getValue() instanceof Date) {
pred = builder.and(pred,
builder.greaterThanOrEqualTo((Expression<Date>) exp, (Date) cr.getValue()));
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
pred = builder.and(pred, builder.greaterThanOrEqualTo((Expression<Date>) exp,
sdf.parse(cr.getValue().toString())));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case Less:
if (cr.getValue() instanceof Number) {
pred = builder.and(pred, builder.lt((Expression<Number>) exp, (Number) cr.getValue()));
} else if (cr.getValue() instanceof Date) {
pred = builder.and(pred, builder.lessThan((Expression<Date>) exp, (Date) cr.getValue()));
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
pred = builder.and(pred,
builder.lessThan((Expression<Date>) exp, sdf.parse(cr.getValue().toString())));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case LessThan:
if (cr.getValue() instanceof Number) {
pred = builder.and(pred, builder.le((Expression<Number>) exp, (Number) cr.getValue()));
} else if (cr.getValue() instanceof Date) {
pred = builder.and(pred,
builder.lessThanOrEqualTo((Expression<Date>) exp, (Date) cr.getValue()));
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
pred = builder.and(pred, builder.lessThanOrEqualTo((Expression<Date>) exp,
sdf.parse(cr.getValue().toString())));
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case Between:
Class<?> cls = (Class<?>) ((ParameterizedType) cr.getValue().getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
if (Date.class.equals(cls)) {
DateRangeCriterion range = (DateRangeCriterion) cr.getValue();
pred = builder.and(pred, builder.between((Expression<? extends Date>) exp, range.getBegin(),
range.getEnd()));
} else if (Integer.class.equals(cls)) {
IntegerRangeCriterion range = (IntegerRangeCriterion) cr.getValue();
pred = builder.and(pred,
builder.between((Expression<Integer>) exp, range.getBegin(), range.getEnd()));
} else if (Long.class.equals(cls)) {
LongRangeCriterion range = (LongRangeCriterion) cr.getValue();
pred = builder.and(pred,
builder.between((Expression<Long>) exp, range.getBegin(), range.getEnd()));
} else if (Float.class.equals(cls)) {
FloatRangeCriterion range = (FloatRangeCriterion) cr.getValue();
pred = builder.and(pred,
builder.between(exp.as(Float.class), range.getBegin(), range.getEnd()));
} else {
DoubleRangeCriterion range = (DoubleRangeCriterion) cr.getValue();
pred = builder.and(pred,
builder.between(exp.as(Double.class), range.getBegin(), range.getEnd()));
}
break;
case In:
List<String> list = (List<String>) cr.getValue();
pred = builder.and(pred, exp.in(list));
break;
default:
break;
}
}
return pred;
}
};
}
@Override
public <T> T get(Serializable id, Class<T> clazz) {
// TODO Auto-generated method stub
return getRepository(clazz).findOne(id);
}
@Override
public <T> T findOne(List<Criterion> criteria, Class<T> clazz) {
Specification<T> spec = getSpec(criteria, false);
// TODO Auto-generated method stub
return getRepository(clazz).findOne(spec);
}
@Override
@Transactional
public <T> T save(T entity, Class<T> clazz) {
// TODO Auto-generated method stub
return getRepository(clazz).save(entity);
}
@Override
@Transactional
public <T> T save(T entity) {
// TODO Auto-generated method stub
return save(entity, (Class<T>) entity.getClass());
}
@Override
@Transactional
public <T> void delete(T entity, Class<T> clazz) {
// TODO Auto-generated method stub
getRepository(clazz).delete(entity);
}
@Override
@Transactional
public <T> void delete(T entity) {
delete(entity, (Class<T>) entity.getClass());
}
@Override
@Transactional
public <T> T saveGeneric(T entity, Class<?> clazz) {
// TODO Auto-generated method stub
return getGenericRepository(clazz).save(entity);
}
public <T> List<T> getAll(Class<T> clazz, DataMode mode) {
return getAll(clazz, mode, null);
}
public <T> List<T> getAll(Class<T> clazz, DataMode mode, Sort sort) {
List<Criterion> criteria = new ArrayList<Criterion>();
return find(clazz, criteria, sort, mode);
}
public <T> List<T> getAll(Class<T> clazz, Sort sort) {
return getAll(clazz, DataMode.All, sort);
}
public <T> List<T> getAll(Class<T> clazz) {
return getAll(clazz, DataMode.All);
}
public <T> List<T> getGenericAll(Class<?> clazz, DataMode mode) {
List<Criterion> criteria = new ArrayList<Criterion>();
return findGeneric(clazz, criteria, mode);
}
public <T> List<T> getGenericAll(Class<?> clazz) {
return getGenericAll(clazz, DataMode.All);
}
public <T> List<T> find(Class<T> clazz, List<Criterion> criteria) {
return find(clazz, criteria, DataMode.NoDetail);
}
public <T> List<T> find(Class<T> clazz, List<Criterion> criteria, Sort sort) {
return find(clazz, criteria, sort, DataMode.NoDetail);
}
public <T> List<T> find(Class<T> clazz, List<Criterion> criteria, DataMode mode) {
return find(clazz, criteria, null, mode);
}
public <T> List<T> find(Class<T> clazz, List<Criterion> criteria, Sort sort, DataMode mode) {
boolean isNone = (mode == DataMode.None);
Specification<T> spec = getSpec(criteria, isNone);
List<T> list = getRepository(clazz).findAll(spec, sort);
if (mode == DataMode.NoDetail) {
try {
// StatefulPersistenceContext.initializeNonLazyCollections()
// 看如何阻止该方法运行
list = clearPropertyCollection(clazz, list);
} catch (Exception e) {
log.error("can't remove entity's collection properties....");
}
}
return list;
}
public <T> List<T> findGeneric(Class<?> clazz, List<Criterion> criteria) {
return findGeneric(clazz, criteria, DataMode.NoDetail);
}
public <T> List<T> findGeneric(Class<?> clazz, List<Criterion> criteria, DataMode mode) {
boolean isNone = (mode == DataMode.None);
Specification<Object> spec = getSpec(criteria, isNone);
List<T> list = (List<T>) getGenericRepository(clazz).findAll(spec);
if (mode == DataMode.NoDetail) {
try {
// StatefulPersistenceContext.initializeNonLazyCollections()
// 看如何阻止该方法运行
list = clearPropertyCollection((Class<T>) clazz, (List<T>) list);
} catch (Exception e) {
log.error("can't remove entity's collection properties....");
}
}
return list;
}
public <T> Page<T> getAllByPage(Class<T> clazz, Pageable page) {
List<Criterion> criteria = new ArrayList<Criterion>();
return findByPage(clazz, criteria, page);
}
public <T> Page<T> getGenericAllByPage(Class<?> clazz, Pageable page) {
List<Criterion> criteria = new ArrayList<Criterion>();
return findGenericByPage(clazz, criteria, page);
}
public <T> Page<T> findByPage(Class<T> clazz, List<Criterion> criteria, Pageable page) {
return findByPage(clazz, criteria, page, DataMode.NoDetail);
}
public <T> Page<T> findByPage(Class<T> clazz, List<Criterion> criteria, Pageable page, DataMode mode) {
boolean isNone = (mode == DataMode.None);
Specification<T> spec = getSpec(criteria, isNone);
Page<T> pagenation = getRepository(clazz).findAll(spec, page);
if (mode == DataMode.NoDetail) {
try {
clearPropertyCollection(clazz, pagenation.getContent());
} catch (Exception e) {
log.error("can't remove entity's collection properties....");
}
}
return pagenation;
}
public <T> Page<T> findGenericByPage(Class<?> clazz, List<Criterion> criteria, Pageable page) {
return findGenericByPage(clazz, criteria, page, DataMode.NoDetail);
}
public <T> Page<T> findGenericByPage(Class<?> clazz, List<Criterion> criteria, Pageable page, DataMode mode) {
boolean isNone = (mode == DataMode.None);
Specification<T> spec = getSpec(criteria, isNone);
Page<T> pagenation = (Page<T>) getGenericRepository(clazz).findAll((Specification<Object>) spec, page);
if (mode == DataMode.NoDetail) {
try {
// clearPropertyCollection(clazz, pagenation.getContent());
} catch (Exception e) {
log.error("can't remove entity's collection properties....");
}
}
return pagenation;
}
// public <T> List<T> search(Class<T> clazz, com.querydsl.core.types.Predicate
// predicate) {
// return getDslRepository(clazz).findAll(predicate);
// }
}
jpa 理解
1. spirngboot jpa 默认使用的是spring.datasource下的数据源。如果使用多数据源则重新配置@bean @Qualify Datasource
2. 配置数据库原地址后 可以配置jpa的核心 EntityManageFactory管理器 ,然后可以配置管理核心操作EntityManage 接口
3. 使用方式可以有 3.1. 用entitymanage直接操作 ,增删改查都写入自己定义的工具类中(非接口形式,简单)
3.2 可以继续配置封装到自定jpa接口中进行使用,此接口继承jpaRepository 后使用此接口了。(接口形式,一般)
3.3 使用系统自带的封装了entitymanage 的类 simpleJpaRepository 进行使用 (接口形式,难)
3种方法都是围绕核心entitymanage进行封装,可以继承接口 后使用,可以直接封装到类里头直接使用 。