package com.dounine.corgi.jpa.dao;
import com.dounine.corgi.jpa.dto.BaseDto;
import com.dounine.corgi.jpa.dto.Condition;
import com.dounine.corgi.jpa.entity.BaseEntity;
import com.dounine.corgi.jpa.enums.RepExceptionType;
import com.dounine.corgi.jpa.enums.RestrictionType;
import com.dounine.corgi.jpa.exception.RepException;
import com.dounine.corgi.jpa.utils.PrimitiveUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import javax.persistence.criteria.*;
import java.lang.reflect.Method;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
/**
* Created by lgq on 16-9-30.
*/
public class MySpecification<BE extends BaseEntity, BD extends BaseDto> implements Specification<BE> {
private static final Pattern PATTERN = Pattern.compile("\\[[a-zA-Z0-9]+\\]");
private BD dto;
public MySpecification(BD dto) {
this.dto = dto;
}
@Override
public Predicate toPredicate(Root<BE> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
List<Predicate> preList = null;
try {
preList = initPredicates(dto, root, cb);
} catch (RepException e) {
throw e;
}
Predicate[] predicates = preList.toArray(new Predicate[preList.size()]);
return query.where(predicates).getRestriction();
}
private List<Predicate> initPredicates(BD dto, Root<BE> root, CriteriaBuilder cb) throws RepException {
List<Predicate> preList = new ArrayList<>(0); //条件列表
List<Condition> conditions = dto.getConditions() != null ? dto.getConditions() : new ArrayList<>(0);//避免条件列表为空
Stream<Condition> stream = conditions.stream();
stream.forEach(model -> {
Predicate predicate = null;
Class clazz = PrimitiveUtil.switchType(model.getFieldType()); //得到数据类型
String field = model.getField(); //字段
Method[] methods = cb.getClass().getDeclaredMethods();
Method method = null;
try {
for (Method m : methods) {
Class<?>[] types = m.getParameterTypes();
String name = RestrictionType.getRestrict(model.getRestrict());
if (m.getName().equals(name) &&
types[types.length - 1] != Expression.class) {
method = m;
break;
}
}
RestrictionType type = model.getRestrict();
if (type == RestrictionType.LIKE) {
predicate = cb.like(root.get(field).as(clazz),"%"+model.getValues()[0]+ "%");
}else {
Object[] values = PrimitiveUtil.convertValuesByType(model.getValues(), model.getFieldType());
if (type == RestrictionType.IN) {
predicate = (Predicate) method.invoke(cb, root.get(field).as(clazz), values);
} else {
predicate = (Predicate) method.invoke(cb, ArrayUtils.add(values, 0, root.get(field).as(clazz)));
}
}
} catch (Exception e) {
e.printStackTrace();
exceptionHandler(e);
}
if (null != predicate) {
preList.add(predicate);
}
});
return preList;
}
private RepException exceptionHandler(Exception e) {
String msg = "";
RepExceptionType type = RepExceptionType.UNDEFINE;
if (e instanceof IllegalArgumentException) {
Matcher matcher = PATTERN.matcher(e.getMessage());
boolean isFind = matcher.find();
if (isFind) { //字段不匹配
msg = StringUtils.substring(matcher.group(), 1, -1);
type = RepExceptionType.NOT_FIND_FIELD;
} else if (e.getMessage().indexOf("wrong number of arguments") != -1) { //其他错误
msg = "wrong number of arguments";
type = RepExceptionType.ERROR_ARGUMENTS;
} else if (e instanceof NumberFormatException) {
msg = e.getMessage();
type = RepExceptionType.ERROR_NUMBER_FORMAT;
}
} else {
if (e instanceof DateTimeParseException) {
msg = e.getMessage();
type = RepExceptionType.ERROR_PARSE_DATE;
} else {
msg = e.getMessage();
type = RepExceptionType.UNDEFINE;
}
}
throw new RepException(type, msg);
}
/**
* 分页及排序
*
* @param dto
* @return
*/
public PageRequest getPageRequest(BD dto) {
PageRequest pageRequest = null;
if (dto.getSorts() != null && dto.getSorts().size() > 0) {
Sort.Direction dct = Sort.Direction.ASC;
if (dto.getOrder().equals("desc")) {
dct = Sort.Direction.DESC;
}
pageRequest = new PageRequest(dto.getPage(), dto.getLimit(), new Sort(dct, dto.getSorts())); //分页带排序
} else {
pageRequest = new PageRequest(dto.getPage(), dto.getLimit()); //分页不带排序
}
return pageRequest;
}
}