ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resourcePatternResolver.getResources(“classpath:/rule/**/*.drl”);
/**
* 检索对象 HQL 解析器
*/
@SuppressWarnings("unchecked")
public class HqlParser implements SearcherParser {
protected final Log logger = LogFactory.getLog(getClass());
private Dto2PoCache dto2PoCache;
public Dto2PoCache getDto2PoCache() {
return dto2PoCache;
}
public void setDto2PoCache(Dto2PoCache dto2PoCache) {
this.dto2PoCache = dto2PoCache;
}
/**
* 解析查询条件,生成查询语句
* @param request 查询请求
* @return 查询语句
*/
public String parse(SearchRequest request) {
StringBuilder hql = new StringBuilder();
try {
//如果有集合查询,则加上distinct
if (this.hasMemberOf(request)) {
request.setDistinct(true);
}
// dynamic search response
SearchResponse response = new SearchResponse();
// from clause
String fromClause = resolveFromClause(request, response);
if (StringUtils.isBlank(fromClause)) {
throw new DynamicBuildHqlFailedException(request, fromClause);
} else {
if (logger.isDebugEnabled()) {
logger.debug("from clause -> " + fromClause);
}
}
// select clause
String selectClause = resolveSelectClause(request, response);
// condition clause
String whereClause = resolveWhereClause(request, response);
if (!StringUtils.isBlank(whereClause)) {
if (logger.isDebugEnabled()) {
logger.debug("where clause -> " + whereClause);
}
}
// group clause
String groupClause = resolveGroupClause(request, response);
if (!StringUtils.isBlank(groupClause)) {
if (logger.isDebugEnabled()) {
logger.debug("group clause -> " + groupClause);
}
}
// having clause
String havingClause = resolveHavingClause(request, response);
if (!StringUtils.isBlank(havingClause)) {
if (logger.isDebugEnabled()) {
logger.debug("having clause -> " + havingClause);
}
}
// order clause
String orderClause = resolveOrderClause(request, response);
if (!StringUtils.isBlank(orderClause)) {
if (logger.isDebugEnabled()) {
logger.debug("order clause -> " + orderClause);
}
}
// result resolver, query object
hql.append(selectClause).append(" ")
.append(fromClause).append(" ")
.append(whereClause).append(" ")
.append(groupClause).append(" ")
.append(havingClause).append(" ")
.append(orderClause);
String q = hql.toString().replaceAll("[ ]+", " ");
if (logger.isDebugEnabled()) {
logger.debug("build hql - > " + q);
}
Formatter formatter = new Formatter(q);
logger.info("Hql Parser Result -> " + formatter.format());
return q;
} catch (Exception e) {
logger.error("Dynamic build hql failed, " + e.getMessage());
throw new DynamicBuildHqlFailedException(request, hql.toString());
}
}
/**
* resolve dynamic search from clause
* @return from clause or ""
*/
private String resolveFromClause(SearchRequest request,
SearchResponse response) {
// entity resolver, at least one entity should be provided
// here entity name should be mapped to hibernate class name
StringBuilder sb = new StringBuilder();
List<SearchEntityDto> entities = request.getEntities();
if (null == entities || entities.size() < 1) {
response.setSuccess(false);
} else {
sb.append("from ");
for (int i = 0; i < entities.size(); ++i) {
String clazz = entities.get(i).getValue();
//将DTO类名转成PO类名
Class poClass = dto2PoCache.lookupEnityClazz(clazz);
String poClassName = poClass.getName();
poClassName = poClassName.substring(poClassName.lastIndexOf(".") + 1);
if (i == entities.size() - 1) {
sb.append(poClass.getName()).append(" ").append(poClassName).append(" ");
} else {
sb.append(poClass.getName()).append(" ").append(poClassName).append(",");
}
}
handleMemberOf(request, sb);
}
return sb.toString();
}
/**
* 做两表或多表关联查询时,将查询条件的DTO的属性值替换成相应的实体属性
*/
private String replaceProperty(SearchRequest request, String property) {
if (property !=null && !property.startsWith("'") && property.indexOf('.') > 0) {
return replaceDtoClassWithPoClass(request, property);
} else {
return property;
}
}
/**
* 将 DTO 和相应的属性转化为 PO 以及相应的属性
*/
private String replaceDtoClassWithPoClass(SearchRequest request, String property) {
if (property == null) {
return null;
}
// 将DTO中的属性映射成PO中的属性,如: DtoClass.dtoProperty 映射成 PoClass.poProperty
for (SearchEntityDto searchEntity: request.getEntities()) {
// 将 DTO 类名转成 PO 类名
String dtoClassName = searchEntity.getValue();
Class<?> poClass = dto2PoCache.lookupEnityClazz(dtoClassName);
dtoClassName = dtoClassName.substring(dtoClassName.lastIndexOf(".") + 1);
String poClassName = poClass.getName();
Map<String, String> propertyMapping = dto2PoCache.lookupPropertyMapping(searchEntity.getValue());
poClassName = poClassName.substring(poClassName.lastIndexOf(".") + 1);
String regex = dtoClassName + "[.[A-Za-z_]+]+";
Pattern ptn = Pattern.compile(regex);
Matcher m = ptn.matcher(property);
StringBuilder sb = new StringBuilder();
boolean matched = false;
while (m.find()) {
matched = true;
String s = m.group();
//DtoClass前面部分
sb.append(property.substring(0,m.start()));
//PO
sb.append(poClassName);
sb.append('.');
//PO属性值
String s2 = propertyMapping.get( (s.substring(s.indexOf('.') + 1)).trim() );
if (StringUtils.isBlank(s2)) {
s2 = s.substring(s.indexOf('.') + 1);
}
sb.append(s2);
//DtoClass.property后面部分
sb.append(property.substring(m.end()));
}
property = matched ? sb.toString() : property;
}
return property;
}
/**
* resolve dynamic search select clause
* @return select clause or ""
*/
private String resolveSelectClause(SearchRequest request,
SearchResponse response) {
// property resolver
StringBuilder sb = new StringBuilder("");
List<SearchPropertyDto> properties = request.getProperties();
if (null == properties || properties.size() < 1) {
// no specific property, search entity
String clazz = request.getEntities().get(0).getValue();
// 将DTO类名转成PO类名
Class<?> poClass = dto2PoCache.lookupEnityClazz(clazz);
String poClassName = poClass.getName();
poClassName = poClassName.substring(poClassName.lastIndexOf(".") + 1);
// TODO
sb.append("select ").append(request.isDistinct() ? "distinct " : "").append(poClassName).append(" ");
// sb.append("select ").append("distinct ").append(poClassName).append(" ");
} else {
// specify request entity property
sb.append("select ").append(request.isDistinct() ? "distinct " : "");
for (int i = 0; i < properties.size(); ++i) {
sb.append(replaceDtoClassWithPoClass(request, properties.get(i).getValue()));
if (i == properties.size() - 1) {
sb.append(" ");
} else {
sb.append(",");
}
}
}
return sb.toString();
}
/**
* 做member of查询时,返回对应的实体名
* @param dtoName member of 属性名
* @return 实体名
*/
private String getEntityShortName(SearchRequest request, String dtoName) {
String result = "";
if (StringUtils.isNotBlank(dtoName)) {
for (SearchEntityDto searchEntity: request.getEntities()) {
// 将 DTO 类名转成 PO 类名
String dtoClassName = searchEntity.getValue();
String shortName = dtoClassName.substring(dtoClassName.lastIndexOf('.') + 1);
if (dtoName.equals(shortName)) {
Class<?> poClass = dto2PoCache.lookupEnityClazz(dtoClassName);
result = poClass.getSimpleName();
break;
}
}
} else {
result = request.getEntities().get(0).getValue();
result = result.substring(result.lastIndexOf('.') + 1);
}
return result;
}
/**
* 判断查询请求中是否包含集合查询
*/
private boolean hasMemberOf(SearchRequest request) {
for (SearchConditionDto scd: request.getConditions()) {
if (isMemberOfProperty(scd.getProperty().getValue())) {
return true;
}
}
return false;
}
/**
* 判断属性是否为集合查询
* @param property 属性名
* @return true是集合查询,false不是集合查询
*/
private boolean isMemberOfProperty(String property) {
return property.startsWith("com_wisdom_") || property.indexOf(".com_wisdom_") > 0;
}
/**
* 判断查询实体中是否包含 memberEntityClass
* @param request 查询请求
* @param memberEntityClass 查询实体
* @param entityList 查询实体列表
* @return true包含,false不包含
*/
private boolean hasEntityClass(SearchRequest request, String memberEntityClass, List<String> entityList) {
for (SearchEntityDto sed: request.getEntities()) {
if (sed.getValue().equals(memberEntityClass)) {
return true;
}
}
for (String s: entityList) {
if (s.equals(memberEntityClass)) {
return true;
}
}
return false;
}
/**
* 处理根据集合内数据查找的请求,将相关实体加入请求中
*/
private void handleMemberOf(SearchRequest request, StringBuilder sb) {
List<String> entityList = new ArrayList<String>();
for (SearchConditionDto scd: request.getConditions()) {
if (isMemberOfProperty(scd.getProperty().getValue())) {
String property = scd.getProperty().getValue();
int iPoint = property.indexOf('.');
if (iPoint > 0) {
property = property.substring(iPoint + 1);
}
property = property.replaceAll("_", ".");
int p = 0;
if (property.indexOf('[')>0) {
p = property.substring(0,property.indexOf('[')).lastIndexOf('.');
} else {
p = property.lastIndexOf('.');
}
String memberEntityClass = property.substring(0, p);//关联实体全限定名
if (!hasEntityClass(request, memberEntityClass, entityList)) {
entityList.add(memberEntityClass);
}
}
}
for (String s: entityList) {
String shortName = s.substring(s.lastIndexOf('.') + 1);
sb.append(",").append(s).append(" ").append(shortName);
}
}
/**
* 处理根据集合内数据查找的请求
*/
private void handleMemberOf(SearchRequest request, StringBuilder sb, String dtoProperty, String operator, String value) {
String property = dtoProperty;
int iPoint = property.indexOf('.');
String dtoName = "";
if (iPoint>=0) {
dtoName = property.substring(0, iPoint);
property = property.substring(iPoint + 1);
}
String entityName = getEntityShortName(request, dtoName);//实体名
property = property.replaceAll("_", ".");
int p = 0;
if (property.indexOf('[')>0) {
p = property.substring(0,property.indexOf('[')).lastIndexOf('.');
} else {
p = property.lastIndexOf('.');
}
String memberEntityClass = property.substring(0, p);//关联实体全限定名
String memberEntityClassName = memberEntityClass.substring(memberEntityClass.lastIndexOf('.') + 1);
property = property.substring(p+1, property.length());
if (operator.equalsIgnoreCase(SearchConditionDto.R_IN)
|| operator.equalsIgnoreCase(SearchConditionDto.R_NOT_IN)) {
if (value != null && !value.startsWith("(")) {//如果没加括号,则加上
value = "(" + value + ")";
}
operator = operator.equalsIgnoreCase(SearchConditionDto.R_IN) ? " in " : " not in ";
}
String memberEntityProperty = "id";
if (dtoProperty.indexOf('[') > 0 && dtoProperty.indexOf(']')>0) {
memberEntityProperty = dtoProperty.substring(dtoProperty.indexOf('[') + 1, dtoProperty.indexOf(']'));
//去年property中的[*]
property = property.substring(0, property.indexOf('['));
}
sb.append(memberEntityClassName).append(" in elements(").append(entityName).append('.')
.append(property).append(") and ").append(memberEntityClassName)
.append(".").append(memberEntityProperty).append(" ").append(operator).append(value);
}
private boolean isLeftBracket(SearchConditionDto c) {
return SearchConditionDto.B_LB.equals(c.getLeftBracket().getValue())
&& "".equals(c.getOperater().getValue())
&& "".equals(c.getProperty().getValue());
}
private boolean isRightBracket(SearchConditionDto c) {
return SearchConditionDto.B_RB.equals(c.getRightBracket().getValue())
&& "".equals(c.getOperater().getValue())
&& "".equals(c.getProperty().getValue());
}
/**
* resolve dynamic search where clause
* @return where clause or ""
*/
private String resolveWhereClause(SearchRequest request,
SearchResponse response) {
// condition resolver
StringBuilder sb = new StringBuilder("");
List<SearchConditionDto> conditions = request.getConditions();
if (null == conditions || conditions.size() < 1) {
// no condition restriction
} else {
// compute condition clause
sb.append("where ");
for (int i = 0; i < conditions.size(); ++i) {
SearchConditionDto c = conditions.get(i);
String relation = c.getRelation().getValue();
relation = "".equals(relation) ? (i < conditions.size()-1 ? SearchConditionDto.O_AND : relation) : relation;
String property = null;
// 判断是否含有member of语句
boolean isMemberOf = isMemberOfProperty(c.getProperty().getValue());
if (isMemberOf) {
property = c.getProperty().getValue();
} else {
property = replaceDtoClassWithPoClass(request, c.getProperty().getValue());
}
String operator = c.getOperater().getValue();
sb.append(c.getLeftBracket().getValue());
if (!SearchConditionDto.R_IS_NULL.equalsIgnoreCase(operator)
&& !SearchConditionDto.R_IS_NOT_NULL.equalsIgnoreCase(operator)
&& !isMemberOf ){ // 对is null,is not null, member of 特殊处理
sb.append(property).append(" ");
}
{
// 完善运算符具体逻辑功能
String value = replaceProperty(request, c.getValue().getValue());
//对boolean特殊处理
if ("true".equalsIgnoreCase(value)) {
value = "1";
} else if ("false".equalsIgnoreCase(value)) {
value = "0";
}
if (isMemberOf) {//member of,如 PartnerDto.com_wisdom_partner_model_PartnerEntity_equipmentTypeParams
handleMemberOf(request, sb, property, operator, value);
} else if (operator.equalsIgnoreCase(SearchConditionDto.R_LIKE)) {
value = value.replace("'", "%");
String str = operator.replace("{$0}", "'" + value + "'");
sb.append(str);
}
// (not) in
else if (operator.equalsIgnoreCase(SearchConditionDto.R_IN)
|| operator.equalsIgnoreCase(SearchConditionDto.R_NOT_IN)) {
if (value != null && !value.startsWith("(")) {//如果没加括号,则加上
value = "(" + value + ")";
}
String str = operator.replace("{$0}", value);
sb.append(str + " ");
}
// (not) between ... and ...
else if (operator.equalsIgnoreCase(SearchConditionDto.R_BETWEEN)
|| operator.equalsIgnoreCase(SearchConditionDto.R_NOT_BETWEEN)) {
String[] strs = value.split(",");
String str = operator.replace("{$0}", strs[0]);
str = operator.replace("${1}", strs[1]);
sb.append(str + " ");
} else if (SearchConditionDto.R_IS_NULL.equalsIgnoreCase(operator)
|| SearchConditionDto.R_IS_NOT_NULL.equalsIgnoreCase(operator)) { //is null / is not null
int pos = property.lastIndexOf('.');
if (property.indexOf('.') != pos) {//如果是MenuEntity.role.roleCode,则转换成MenuEntity.role
property = property.substring(0, pos);
}
sb.append(property).append(" ");
sb.append(operator + " ");
} else { // 直接使用运算符
if ("".equals(operator) && value == null) {//没有操作符号,是括号或者是 AND/OR
value = "";
}
sb.append(operator + " ").append(value + " ");
}
}
// 只有括号时,relation为空则保留空值, 如果下一条是个右括号,则不加and
if (isLeftBracket(c)
|| (i < conditions.size() - 1 && isRightBracket(conditions.get(i + 1)))) {
// TODO relation = "";
}
sb.append(c.getRightBracket().getValue()).append(" ")
.append(relation).append(" ");
}
}
String result = sb.toString();
boolean terminated = false;
String backStr = new String(result);
while (!terminated) {
result = result.replaceAll("[ ]+", " ");
result = result.replaceAll(" [ and ]+ ", " and ");
result = result.replaceAll(" [ or ]+ ", " or ");
result = result.replaceAll(" and or ", " or ");
result = result.replaceAll(" and[ ]*\\)", " )");
result = result.replaceAll(" or[ ]*\\)", " )");
result = result.replaceAll(" \\([ ]*or", " (");
result = result.replaceAll(" \\([ ]*and", " (");
result = result.replaceAll(" \\([ ]*\\)", "");
// recompute
terminated = result.equals(backStr);
backStr = new String(result);
}
logger.info("rebuild where clause string = " + result);
return result;
}
/**
* resolve dynamic search group clause
* @return group clause or ""
*/
private String resolveGroupClause(SearchRequest request,
SearchResponse response) {
// group resolver
StringBuilder sb = new StringBuilder("");
List<SearchGroupDto> groups = request.getGroups();
if (null == groups || groups.size() < 1) {
// no group requirement
} else {
// append group info for hql
sb.append("group by ");
for (int i = 0; i < groups.size(); ++i) {
sb.append(replaceDtoClassWithPoClass(request, groups.get(i).getValue()));
if (i == groups.size() - 1) {
sb.append(" ");
} else {
sb.append(",");
}
}
}
return sb.toString();
}
/**
* resolve dynamic search having clause
* @return having clause or ""
*/
private String resolveHavingClause(SearchRequest request,
SearchResponse response) {
// having resolver
StringBuilder sb = new StringBuilder("");
List<SearchHavingDto> havings = request.getHavings();
if (null == havings || havings.size() < 1) {
// no having requirement
} else {
// append having restriction
// and group key word must be provided, not check grammer here
sb.append("having ");
for (int i = 0; i < havings.size(); ++i) {
SearchConditionDto c = havings.get(i);
String relation = c.getRelation().getValue();
relation = "".equals(relation) ? (i < havings.size()-1 ? SearchConditionDto.O_AND : relation) : relation;
sb.append(c.getLeftBracket().getValue())
.append(replaceDtoClassWithPoClass(request, c.getProperty().getValue()))
.append(c.getOperater().getValue())
.append(replaceDtoClassWithPoClass(request, c.getValue().getValue()))
.append(c.getRightBracket().getValue()).append(" ")
.append(relation).append(" ");
}
}
return sb.toString();
}
/**
* resolve dynamic search order clause
* @return order clause or ""
*/
private String resolveOrderClause(SearchRequest request,
SearchResponse response) {
// order resolver
StringBuilder sb = new StringBuilder("");
List<SearchOrderDto> orders = request.getOrders();
if (null == orders || orders.size() < 1) {
// no order info provided
} else {
// append order
sb.append("order by ");
for (int i = 0; i < orders.size(); ++i) {
sb.append(replaceDtoClassWithPoClass(request, orders.get(i).getValue()));
sb.append(" ");
sb.append(orders.get(i).getOrder());
if (i == orders.size() - 1) {
sb.append(" ");
} else {
sb.append(",");
}
}
}
return sb.toString();
}
}