CustomerSpecs.java 3.08 KB
package com.bsth.entity.search;

import com.bsth.entity.search.exception.UnrecognizableSearchSymbolException;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.*;
import java.lang.reflect.Method;
import java.util.*;

/**
 * 
 * @ClassName: CustomerSpecs
 * @Description: 用于动态条件查询的Specification
 * @author PanZhao
 * @date 2016年3月16日 下午4:05:22
 * 
 * @param <T>
 */
public class CustomerSpecs<T> implements Specification<T> {

	Logger logger = LoggerFactory.getLogger(this.getClass());
	
	private Map<String, Object> map;

	// 查询操作符
	private static Set<String> eSet;

	static {
		eSet = new TreeSet<String>();
		for (SearchOperator s : SearchOperator.values()) {
			eSet.add(s.toString());
		}
	}

	private static Class<PredicatesBuilder> preBuilderClazz = PredicatesBuilder.class;
	private static Class<CriteriaBuilder> cBuilderClazz = CriteriaBuilder.class;
	private static Class<Object> objClazz = Object.class;

	// 查询参数分隔符
	public static final String separator = "_";

	/**
	 * 构造函数
	 * 
	 * @param map
	 */
	public CustomerSpecs(Map<String, Object> map) {
		this.map = map;
	}

	@Override
	public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query,
			CriteriaBuilder cb) {
		List<Predicate> predicates = new ArrayList<>();
		
		for (Map.Entry<String, Object> entry : map.entrySet()) {
			Object value = entry.getValue();
			String[] searchs = StringUtils.split(entry.getKey(), separator);
			if (null == searchs || searchs.length < 2)
				continue;
			// 值为空的不参与查询
			if (value == null || (value instanceof String && value.equals(""))) 
				continue;

            // 如果是布尔值,转换,限定 'true','false' 字符串
            if ("true".equals(value)) {
                value = Boolean.TRUE;
            }
            if ("false".equals(value)) {
                value = Boolean.FALSE;
            }
			
			try {
				if(!eSet.contains(searchs[1]))
					throw new UnrecognizableSearchSymbolException(searchs[1]);
				
				// 根据操作符调用对应静态函数
				Method method = preBuilderClazz.getMethod(searchs[1],
						cBuilderClazz, Path.class, objClazz);

				Predicate predicate = (Predicate) method.invoke(null, cb,
						createPath(root, searchs[0]), value);

				predicates.add(predicate);
			} catch (Exception e) {
				logger.error("Specification search error.", e);
			}
		}
		Predicate[] pre = new Predicate[predicates.size()];
		return query.where(predicates.toArray(pre)).getRestriction();
	}
	
	/**
	 * 生成Path
	 * @param root
	 * @param field
	 * @return
	 */
	public Path<T> createPath(Root<T> root, String field){
		Path<T> p = null;
		
		if(field.indexOf(".") == -1)
			p = root.get(field);
		else{
			String[] fs = field.split("\\.");
			
			p = root.get(fs[0]);
			for(int i = 1; i < fs.length; i ++){
				p = p.get(fs[i]);
			}
		}
		return p;
	}
}