org.sagacity.sqltoy.plugins.id.macro.MacroUtils Maven / Gradle / Ivy
/**
*
*/
package org.sagacity.sqltoy.plugins.id.macro;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.sagacity.sqltoy.plugins.id.macro.impl.Case;
import org.sagacity.sqltoy.plugins.id.macro.impl.DateFormat;
import org.sagacity.sqltoy.plugins.id.macro.impl.SubString;
import org.sagacity.sqltoy.utils.BeanUtil;
import org.sagacity.sqltoy.utils.StringUtil;
/**
* @project sagacity-sqltoy
* @description 宏处理工具
* @author zhongxuchen
* @version v1.0,Date:2018年5月25日
*/
public class MacroUtils {
/**
* 转换器的格式
*/
private static Pattern macroPattern = Pattern.compile("@[a-zA-Z]+[0-9]*[\\-]?[a-zA-Z]*\\([\\w\\W]*\\)");
/**
* 字符串中内嵌参数的匹配模式 update by chenrenfei 2016-8-24 完善表达式
*/
private final static Pattern paramPattern = Pattern.compile(
"(\\$|\\#)\\{\\s*\\_?[0-9a-zA-Z\u4e00-\u9fa5]+((\\.|\\_)[0-9a-zA-Z\u4e00-\u9fa5]+)*(\\[\\d*(\\,)?\\d*\\])?\\s*\\}");
private static final HashMap filters = new HashMap() {
private static final long serialVersionUID = 2445408357544337801L;
{
put("(", ")");
put("'", "'");
put("\"", "\"");
put("[", "]");
put("{", "}");
}
};
// 宏实现类
private static Map macros = new HashMap();
static {
macros.put("@df", new DateFormat());
macros.put("@day", new DateFormat());
macros.put("@case", new Case());
macros.put("@substr", new SubString());
macros.put("@substring", new SubString());
}
/**
* @todo 宏替换,默认先执行内部后执行外部
* @param hasMacroStr
* @param keyValues
* @return
*/
public static String replaceMacros(String hasMacroStr, Map keyValues) {
return replaceMacros(hasMacroStr, keyValues, null, false, macros, null);
}
/**
* @todo 递归调用解析字符串中的转换器
* @param hasMacroStr 含macro宏的字符串
* @param keyValues
* @param paramsValues
* @param isOuter(isOuter 当@abc(@do(),xxx):为true表示从最外层的macro@abce,false则会先执行@do()
* 然后再执行@abc())
* @param macros
* @param extSign 扩展标记,目前主要给@include使用,传递dialect
* @return
*/
public static String replaceMacros(String hasMacroStr, Map keyValues, Object paramsValues,
boolean isOuter, Map macros, String extSign) {
if (StringUtil.isBlank(hasMacroStr)) {
return hasMacroStr;
}
if (StringUtil.matches(hasMacroStr, macroPattern)) {
String source = hasMacroStr;
Matcher matcher = macroPattern.matcher(source);
String matchedMacro = null;
String tmpMatchedMacro = null;
int count = 0;
int macroIndex = 0;
int index = 0;
int startIndex = 0;
while (matcher.find()) {
index = matcher.start();
tmpMatchedMacro = matcher.group();
// 判断是否是转换器
if (isMacro(macros, tmpMatchedMacro, true)) {
count++;
matchedMacro = tmpMatchedMacro;
macroIndex = startIndex + index;
if (isOuter) {
break;
}
}
startIndex = startIndex + index + 1;
source = source.substring(index + 1);
matcher = macroPattern.matcher(source);
}
// 匹配不上,则表示字符串中的转换器已经全部执行被替换,返回结果终止递归
if (count == 0) {
return hasMacroStr;
}
int sysMarkIndex = StringUtil.getSymMarkIndex("(", ")", matchedMacro, 0);
// 截取宏前面部分的sql,用于宏中做一些特定关联判断(2023-8-30)
String preSql = (macroIndex > 0) ? hasMacroStr.substring(0, macroIndex) : "";
// 得到最后一个转换器中的参数
String macroParam = matchedMacro.substring(matchedMacro.indexOf("(") + 1, sysMarkIndex);
String macroName = matchedMacro.substring(0, matchedMacro.indexOf("("));
String macroStr = matchedMacro.substring(0, sysMarkIndex + 1);
// 调用转换器进行计算
AbstractMacro macro = macros.get(macroName);
String result = macro.execute(StringUtil.splitExcludeSymMark(macroParam, ",", filters), keyValues,
paramsValues, preSql, extSign);
// 最外层是转换器,则将转结果直接以对象方式返回
if (hasMacroStr.trim().equals(macroStr.trim())) {
return result;
}
String macroResult = (result == null) ? "" : result;
hasMacroStr = replaceStr(hasMacroStr, macroStr, macroResult, macroIndex);
return replaceMacros(hasMacroStr, keyValues, paramsValues, isOuter, macros, extSign);
}
return hasMacroStr;
}
/**
* @todo 判断匹配的字符串是否是转换器
* @param macros
* @param matchedStr
* @param isStart
* @return
*/
private static boolean isMacro(Map macros, String matchedStr, boolean isStart) {
int index = matchedStr.indexOf("(");
if (matchedStr.startsWith("@") && index != -1) {
if (macros.containsKey(matchedStr.substring(0, index))) {
return true;
}
}
return false;
}
private static String replaceStr(String source, String template, String target, int fromIndex) {
if (source == null) {
return null;
}
if (template == null) {
return source;
}
if (fromIndex >= source.length() - 1) {
return source;
}
int index = source.indexOf(template, fromIndex);
if (index != -1) {
source = source.substring(0, index).concat(target).concat(source.substring(index + template.length()));
}
return source;
}
/**
* @todo 替换变量参数
* @param template
* @param keyValues
* @return
*/
public static String replaceParams(String template, Map keyValues) {
if (StringUtil.isBlank(template) || keyValues == null || keyValues.isEmpty()) {
return template;
}
LinkedHashMap paramsMap = parseParams(template);
String result = template;
if (paramsMap.size() > 0) {
Map.Entry entry;
Object value;
for (Iterator> iter = paramsMap.entrySet().iterator(); iter.hasNext();) {
entry = iter.next();
value = keyValues.get(entry.getValue());
if (value != null) {
// 支持枚举类型
if (value instanceof Enum) {
value = BeanUtil.getEnumValue(value);
}
result = replaceAllStr(result, entry.getKey().toString(), value.toString());
}
}
}
return result;
}
/**
* @todo 解析模板中的参数
* @param template
* @return
*/
private static LinkedHashMap parseParams(String template) {
LinkedHashMap paramsMap = new LinkedHashMap();
Matcher m = paramPattern.matcher(template);
String group;
while (m.find()) {
group = m.group();
// key as ${name} value:name
paramsMap.put(group, group.substring(2, group.length() - 1).trim().toLowerCase());
}
return paramsMap;
}
private static String replaceAllStr(String source, String template, String target) {
if (source == null || template.equals(target)) {
return source;
}
int index = source.indexOf(template, 0);
int subLength = target.length() - template.length();
int begin = index - 1;
while (index != -1 && index >= begin) {
source = source.substring(0, index).concat(target).concat(source.substring(index + template.length()));
begin = index + subLength + 1;
index = source.indexOf(template, begin);
}
return source;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy