动态sql解析
parent
680e4b9343
commit
e5f001cd9e
|
@ -13,7 +13,9 @@ import java.lang.annotation.*;
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
@Documented
|
@Documented
|
||||||
public @interface MethodRuleNo {
|
public @interface MethodRuleNo {
|
||||||
int value();
|
int value() default 0;
|
||||||
|
|
||||||
|
String name() default "";
|
||||||
|
|
||||||
String desc();
|
String desc();
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,6 +320,7 @@ public class ResultMapper {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getInt(i + 1));
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getInt(i + 1));
|
||||||
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getInt(i + 1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ("FLOAT".equalsIgnoreCase(columnType) || "DOUBLE".equalsIgnoreCase(columnType) || "DECIMAL".equalsIgnoreCase(columnType)) {
|
if ("FLOAT".equalsIgnoreCase(columnType) || "DOUBLE".equalsIgnoreCase(columnType) || "DECIMAL".equalsIgnoreCase(columnType)) {
|
||||||
|
@ -328,6 +329,7 @@ public class ResultMapper {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getFloat(i + 1));
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getFloat(i + 1));
|
||||||
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getFloat(i + 1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (enable) {
|
if (enable) {
|
||||||
|
@ -335,6 +337,7 @@ public class ResultMapper {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getString(i + 1));
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getString(i + 1));
|
||||||
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getString(i + 1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
|
@ -447,6 +450,7 @@ public class ResultMapper {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getInt(i + 1));
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getInt(i + 1));
|
||||||
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getInt(i + 1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if ("FLOAT".equalsIgnoreCase(columnType) || "DOUBLE".equalsIgnoreCase(columnType) || "DECIMAL".equalsIgnoreCase(columnType)) {
|
if ("FLOAT".equalsIgnoreCase(columnType) || "DOUBLE".equalsIgnoreCase(columnType) || "DECIMAL".equalsIgnoreCase(columnType)) {
|
||||||
|
@ -455,6 +459,7 @@ public class ResultMapper {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getFloat(i + 1));
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getFloat(i + 1));
|
||||||
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getFloat(i + 1));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (method.isAnnotationPresent(Associations.class)) {
|
if (method.isAnnotationPresent(Associations.class)) {
|
||||||
|
@ -484,6 +489,7 @@ public class ResultMapper {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getString(i + 1));
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toLowerCase(), rs.getString(i + 1));
|
||||||
|
((Map<? super Object, ? super Object>) o).put(columnName[i].toUpperCase(), rs.getString(i + 1));
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
@ -514,11 +520,9 @@ public class ResultMapper {
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Util.getLogger().info("获取对象:" + o.toString());
|
// Util.getLogger().info("获取对象:" + o.toString());
|
||||||
BeanInfo beanInfo = Introspector.getBeanInfo(o.getClass(), Object.class);
|
BeanInfo beanInfo = Introspector.getBeanInfo(o.getClass(), Object.class);
|
||||||
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
|
PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
|
||||||
|
|
||||||
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
|
for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
|
||||||
Class<?> propertyType = propertyDescriptor.getPropertyType();
|
Class<?> propertyType = propertyDescriptor.getPropertyType();
|
||||||
Object value = null;
|
Object value = null;
|
||||||
|
|
|
@ -24,282 +24,299 @@ import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
|
||||||
public class SqlHandler {
|
public class SqlHandler {
|
||||||
|
|
||||||
List<Object> sqlArgs = new ArrayList<>();
|
List<Object> sqlArgs = new ArrayList<>();
|
||||||
|
|
||||||
List<List> batchSqlArgs = new ArrayList<>();
|
List<List> batchSqlArgs = new ArrayList<>();
|
||||||
|
|
||||||
|
|
||||||
List<Object> batchSqlArgsList = new ArrayList();
|
List<Object> batchSqlArgsList = new ArrayList();
|
||||||
|
|
||||||
|
|
||||||
private Object batchObj = null;
|
private final Object batchObj = null;
|
||||||
|
|
||||||
public PrepSqlResultImpl handler(String sql, boolean custom, Method method, Object[] args) {
|
public PrepSqlResultImpl handler(String sql, boolean custom, Method method, Object[] args) {
|
||||||
String findSql = findSql(sql, custom, method, args);
|
String findSql = findSql(sql, custom, method, args);
|
||||||
Map<String, Object> methodArgNameMap = buildMethodArgNameMap(method, args);
|
Map<String, Object> methodArgNameMap = buildMethodArgNameMap(method, args);
|
||||||
// 处理基本类型以及包装类
|
// 处理基本类型以及包装类
|
||||||
String parse;
|
String parse;
|
||||||
if (methodArgNameMap.size() == 0) {
|
if (methodArgNameMap.size() == 0) {
|
||||||
return new PrepSqlResultImpl(findSql, sqlArgs);
|
return new PrepSqlResultImpl(findSql, sqlArgs);
|
||||||
}
|
}
|
||||||
if (methodArgNameMap.size() == 1) {
|
if (methodArgNameMap.size() == 1) {
|
||||||
Optional<Object> first = methodArgNameMap.values().stream().findFirst();
|
Optional<Object> first = methodArgNameMap.values().stream().findFirst();
|
||||||
parse = parse(findSql, first.orElse(null));
|
parse = parse(findSql, first.orElse(null));
|
||||||
} else {
|
} else {
|
||||||
parse = parse(findSql, methodArgNameMap);
|
parse = parse(findSql, methodArgNameMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new PrepSqlResultImpl(parse, sqlArgs);
|
return new PrepSqlResultImpl(parse, sqlArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parseBatch(String findSql, Object o) {
|
private String parseBatch(String findSql, Object o) {
|
||||||
String parse = "";
|
String parse = "";
|
||||||
if (!batchSqlArgsList.isEmpty()) {
|
if (!batchSqlArgsList.isEmpty()) {
|
||||||
for (Object o1 : batchSqlArgsList) {
|
for (Object o1 : batchSqlArgsList) {
|
||||||
Map<String, Object> map = new HashMap<>(8);
|
Map<String, Object> map = new HashMap<>(8);
|
||||||
map.put("item", o1);
|
map.put("item", o1);
|
||||||
map.putAll((Map<String, Object>) o);
|
map.putAll((Map<String, Object>) o);
|
||||||
parse = parse(findSql, map);
|
parse = parse(findSql, map);
|
||||||
List<Object> tempArgs = new ArrayList<>();
|
List<Object> tempArgs = new ArrayList<>();
|
||||||
tempArgs.addAll(sqlArgs);
|
tempArgs.addAll(sqlArgs);
|
||||||
batchSqlArgs.add(tempArgs);
|
batchSqlArgs.add(tempArgs);
|
||||||
sqlArgs.clear();
|
sqlArgs.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ("".equals(parse)) {
|
if ("".equals(parse)) {
|
||||||
parse = findSql;
|
parse = findSql;
|
||||||
}
|
}
|
||||||
return parse;
|
return parse;
|
||||||
}
|
}
|
||||||
|
|
||||||
public BatchSqlResultImpl handlerBatch(String sql, boolean custom, Method method, Object[] args) {
|
public BatchSqlResultImpl handlerBatch(String sql, boolean custom, Method method, Object[] args) {
|
||||||
String findSql = findSql(sql, custom, method, args);
|
String findSql = findSql(sql, custom, method, args);
|
||||||
Map<String, Object> methodArgNameMap = buildMethodArgNameMap(method, args);
|
Map<String, Object> methodArgNameMap = buildMethodArgNameMap(method, args);
|
||||||
// 处理基本类型以及包装类
|
// 处理基本类型以及包装类
|
||||||
String parse;
|
String parse;
|
||||||
if (methodArgNameMap.size() == 0) {
|
if (methodArgNameMap.size() == 0) {
|
||||||
Object o = batchSqlArgsList.get(0);
|
Object o = batchSqlArgsList.get(0);
|
||||||
if (o instanceof List) {
|
if (o instanceof List) {
|
||||||
return new BatchSqlResultImpl(findSql, batchSqlArgs);
|
return new BatchSqlResultImpl(findSql, batchSqlArgs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
parse = parseBatch(findSql, methodArgNameMap);
|
parse = parseBatch(findSql, methodArgNameMap);
|
||||||
return new BatchSqlResultImpl(parse, batchSqlArgs);
|
return new BatchSqlResultImpl(parse, batchSqlArgs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private String findSql(String sql, boolean custom, Method method, Object[] args) {
|
private String findSql(String sql, boolean custom, Method method, Object[] args) {
|
||||||
String parsing = sql;
|
String parsing = sql;
|
||||||
if (custom) {
|
if (custom) {
|
||||||
// 自定义
|
// 自定义
|
||||||
Parameter[] parameters = method.getParameters();
|
Parameter[] parameters = method.getParameters();
|
||||||
try {
|
try {
|
||||||
if (parameters.length == 0) {
|
if (parameters.length == 0) {
|
||||||
throw new BindingException("cant not find sql parameter! this parameters is nothing!");
|
throw new BindingException("cant not find sql parameter! this parameters is nothing!");
|
||||||
}
|
}
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
throw new BindingException("cant not find sql parameter! this parameters is nothing!");
|
throw new BindingException("cant not find sql parameter! this parameters is nothing!");
|
||||||
}
|
}
|
||||||
for (int i = 0; i < parameters.length; i++) {
|
for (int i = 0; i < parameters.length; i++) {
|
||||||
Parameter parameter = parameters[i];
|
Parameter parameter = parameters[i];
|
||||||
Object arg = args[i];
|
Object arg = args[i];
|
||||||
Class<?> type = parameter.getType();
|
Class<?> type = parameter.getType();
|
||||||
SqlString sqlAnnotation = parameter.getAnnotation(SqlString.class);
|
SqlString sqlAnnotation = parameter.getAnnotation(SqlString.class);
|
||||||
if (sqlAnnotation != null && type.equals(String.class)) {
|
if (sqlAnnotation != null && type.equals(String.class)) {
|
||||||
try {
|
try {
|
||||||
parsing = arg.toString();
|
parsing = arg.toString();
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
throw new BindingException("sql String param is null!");
|
throw new BindingException("sql String param is null!");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return parsing;
|
return parsing;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Map<String, Object> buildMethodArgNameMap(Method method, Object[] args) {
|
private Map<String, Object> buildMethodArgNameMap(Method method, Object[] args) {
|
||||||
Parameter[] parameters = method.getParameters();
|
Parameter[] parameters = method.getParameters();
|
||||||
Map<String, Object> params = new HashMap<>();
|
Map<String, Object> params = new HashMap<>();
|
||||||
// 参数处理
|
// 参数处理
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < parameters.length; i++) {
|
for (int i = 0; i < parameters.length; i++) {
|
||||||
Parameter parameter = parameters[i];
|
Parameter parameter = parameters[i];
|
||||||
Object arg = args[i];
|
Object arg = args[i];
|
||||||
String name = parameter.getName();
|
String name = parameter.getName();
|
||||||
Class<?> type = parameter.getType();
|
Class<?> type = parameter.getType();
|
||||||
SqlString sqlAnnotation = parameter.getAnnotation(SqlString.class);
|
SqlString sqlAnnotation = parameter.getAnnotation(SqlString.class);
|
||||||
ParamMapper paramAnnotation = parameter.getAnnotation(ParamMapper.class);
|
ParamMapper paramAnnotation = parameter.getAnnotation(ParamMapper.class);
|
||||||
if (sqlAnnotation != null && type.equals(String.class)) {
|
if (sqlAnnotation != null && type.equals(String.class)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (paramAnnotation != null) {
|
if (paramAnnotation != null) {
|
||||||
params.put(paramAnnotation.value(), arg);
|
params.put(paramAnnotation.value(), arg);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
BatchSqlArgs batchSqlArgs = parameter.getAnnotation(BatchSqlArgs.class);
|
BatchSqlArgs batchSqlArgs = parameter.getAnnotation(BatchSqlArgs.class);
|
||||||
if (batchSqlArgs != null) {
|
if (batchSqlArgs != null) {
|
||||||
try {
|
try {
|
||||||
this.batchSqlArgsList = (List<Object>) arg;
|
this.batchSqlArgsList = (List<Object>) arg;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new BindingException("can not parse batchSqlArgs for " + parameter.getName() + ", param index is " + i);
|
throw new BindingException("can not parse batchSqlArgs for " + parameter.getName() + ", param index is " + i);
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
params.put(name, arg);
|
params.put(name, arg);
|
||||||
}
|
}
|
||||||
} catch (NullPointerException e) {
|
} catch (NullPointerException e) {
|
||||||
throw new BindingException("cant not find sql parameter! this parameters is nothing!");
|
throw new BindingException("cant not find sql parameter! this parameters is nothing!");
|
||||||
}
|
}
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String parse(String sql, Object arg) {
|
private String parse(String sql, Object arg) {
|
||||||
String parseSql = sql;
|
String parseSql = sql;
|
||||||
String pattern = "\\$t\\{\\s*(?<regx>(?<field>\\w+)(\\.?(?<other>\\S+))*)\\s*}";
|
String pattern = "\\$t\\{\\s*(?<regx>(?<field>\\w+)(\\.?(?<other>\\S+))*)\\s*}";
|
||||||
Pattern compile = Pattern.compile(pattern);
|
Pattern compile = Pattern.compile(pattern);
|
||||||
Matcher matcher = compile.matcher(parseSql);
|
Matcher matcher = compile.matcher(parseSql);
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String regx = matcher.group("regx");
|
String regx = matcher.group("regx");
|
||||||
String field = matcher.group("field");
|
String field = matcher.group("field");
|
||||||
String other = matcher.group("other");
|
String other = matcher.group("other");
|
||||||
Object value = getValueByRegx(regx, field, other, arg, true);
|
Object value = getValueByRegx(regx, field, other, arg, true);
|
||||||
parseSql = parseSql.replaceFirst(pattern, value.toString());
|
parseSql = parseSql.replaceFirst(pattern, value.toString());
|
||||||
}
|
}
|
||||||
pattern = "\\$\\{\\s*(?<regx>(?<field>\\w+)(\\.?(?<other>\\S+))*)\\s*}";
|
pattern = "\\$split\\{\\s*(?<regx>(?<field>\\w+)(\\.?(?<other>\\S+))*)\\s*}";
|
||||||
compile = Pattern.compile(pattern);
|
compile = Pattern.compile(pattern);
|
||||||
matcher = compile.matcher(parseSql);
|
matcher = compile.matcher(parseSql);
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String regx = matcher.group("regx");
|
String regx = matcher.group("regx");
|
||||||
String field = matcher.group("field");
|
String field = matcher.group("field");
|
||||||
String other = matcher.group("other");
|
String other = matcher.group("other");
|
||||||
Object value = getValueByRegx(regx, field, other, arg, false);
|
Object value = getValueByRegx(regx, field, other, arg, true);
|
||||||
parseSql = parseSql.replaceFirst(pattern, value.toString());
|
String replacement = value.toString();
|
||||||
}
|
String[] split = replacement.split(",");
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (String s : split) {
|
||||||
|
sb.append("'").append(s).append("',");
|
||||||
|
}
|
||||||
|
sb.deleteCharAt(sb.length() - 1);
|
||||||
|
parseSql = parseSql.replaceFirst(pattern, sb.toString());
|
||||||
|
}
|
||||||
|
pattern = "\\$\\{\\s*(?<regx>(?<field>\\w+)(\\.?(?<other>\\S+))*)\\s*}";
|
||||||
|
compile = Pattern.compile(pattern);
|
||||||
|
matcher = compile.matcher(parseSql);
|
||||||
|
while (matcher.find()) {
|
||||||
|
String regx = matcher.group("regx");
|
||||||
|
String field = matcher.group("field");
|
||||||
|
String other = matcher.group("other");
|
||||||
|
Object value = getValueByRegx(regx, field, other, arg, false);
|
||||||
|
parseSql = parseSql.replaceFirst(pattern, value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
// pattern = "#\\{\\s*(?<regx>(?<field>\\w+)(\\.?(?<other>\\S+))*)\\s*}";
|
// pattern = "#\\{\\s*(?<regx>(?<field>\\w+)(\\.?(?<other>\\S+))*)\\s*}";
|
||||||
pattern = "#\\{\\s*(?<regx>(?<field>\\w+)\\.*(?<other>\\w+)*)\\s*}";
|
pattern = "#\\{\\s*(?<regx>(?<field>\\w+)\\.*(?<other>\\w+)*)\\s*}";
|
||||||
compile = Pattern.compile(pattern);
|
compile = Pattern.compile(pattern);
|
||||||
matcher = compile.matcher(parseSql);
|
matcher = compile.matcher(parseSql);
|
||||||
while (matcher.find()) {
|
while (matcher.find()) {
|
||||||
String regx = matcher.group("regx");
|
String regx = matcher.group("regx");
|
||||||
String field = matcher.group("field");
|
String field = matcher.group("field");
|
||||||
String other = matcher.group("other");
|
String other = matcher.group("other");
|
||||||
Object value = getValueByRegx(regx, field, other, arg, true);
|
Object value = getValueByRegx(regx, field, other, arg, true);
|
||||||
parseSql = parseSql.replaceFirst(pattern, "?");
|
parseSql = parseSql.replaceFirst(pattern, "?");
|
||||||
sqlArgs.add(value);
|
sqlArgs.add(value);
|
||||||
}
|
}
|
||||||
return parseSql;
|
return parseSql;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object getValueByRegx(String regx, String field, String other, Object arg, boolean isEscape) {
|
private Object getValueByRegx(String regx, String field, String other, Object arg, boolean isEscape) {
|
||||||
if (!regx.contains(".")) {
|
if (!regx.contains(".")) {
|
||||||
return valueHandler(arg, field, isEscape);
|
return valueHandler(arg, field, isEscape);
|
||||||
}
|
}
|
||||||
String pattern = "(?<field>\\w+)\\.*(?<other>(\\S+)*)";
|
String pattern = "(?<field>\\w+)\\.*(?<other>(\\S+)*)";
|
||||||
Pattern compile = Pattern.compile(pattern);
|
Pattern compile = Pattern.compile(pattern);
|
||||||
Matcher matcher = compile.matcher(other);
|
Matcher matcher = compile.matcher(other);
|
||||||
Object o = valueHandler(arg, field, isEscape);
|
Object o = valueHandler(arg, field, isEscape);
|
||||||
if (matcher.find()) {
|
if (matcher.find()) {
|
||||||
String innerField = matcher.group("field");
|
String innerField = matcher.group("field");
|
||||||
String innerOther = matcher.group("other");
|
String innerOther = matcher.group("other");
|
||||||
return getValueByRegx(other, innerField, innerOther, o, isEscape);
|
return getValueByRegx(other, innerField, innerOther, o, isEscape);
|
||||||
}
|
}
|
||||||
// return getValueByRegx(other,)
|
// return getValueByRegx(other,)
|
||||||
throw new BindingException("Unable to find value " + other);
|
throw new BindingException("Unable to find value " + other);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private Object valueHandler(Object arg, String key, boolean isEscape) {
|
private Object valueHandler(Object arg, String key, boolean isEscape) {
|
||||||
if (arg == null) {
|
if (arg == null) {
|
||||||
return null;
|
return null;
|
||||||
// throw new CustomerException(String.format("sql参数{%s} 为null,请检查!",key));
|
// throw new CustomerException(String.format("sql参数{%s} 为null,请检查!",key));
|
||||||
}
|
}
|
||||||
if (arg instanceof Number) {
|
if (arg instanceof Number) {
|
||||||
// 处理数字类型
|
// 处理数字类型
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
if (arg instanceof Boolean) {
|
if (arg instanceof Boolean) {
|
||||||
// 处理布尔类型
|
// 处理布尔类型
|
||||||
return arg;
|
return arg;
|
||||||
}
|
}
|
||||||
if (arg instanceof Character || arg instanceof String) {
|
if (arg instanceof Character || arg instanceof String) {
|
||||||
// 处理字符类型
|
// 处理字符类型
|
||||||
if (isEscape) {
|
if (isEscape) {
|
||||||
return arg;
|
return arg;
|
||||||
} else {
|
} else {
|
||||||
return "'" + arg + "'";
|
return "'" + arg + "'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (arg.getClass().isArray()) {
|
if (arg.getClass().isArray()) {
|
||||||
// throw new TypeNonsupportException("A value is expected, but a set is received!");
|
// throw new TypeNonsupportException("A value is expected, but a set is received!");
|
||||||
return StringUtils.join((Object[]) arg, ",");
|
return StringUtils.join((Object[]) arg, ",");
|
||||||
}
|
}
|
||||||
// 判断参数类型
|
// 判断参数类型
|
||||||
if (arg instanceof Collection) {
|
if (arg instanceof Collection) {
|
||||||
// list
|
// list
|
||||||
// throw new TypeNonsupportException("A value is expected, but a set is received!");
|
// throw new TypeNonsupportException("A value is expected, but a set is received!");
|
||||||
return StringUtils.join((Collection<?>) arg, ",");
|
return StringUtils.join((Collection<?>) arg, ",");
|
||||||
}
|
}
|
||||||
if (arg instanceof Map) {
|
if (arg instanceof Map) {
|
||||||
// map
|
// map
|
||||||
if (!((Map<?, ?>) arg).containsKey(key)) {
|
if (!((Map<?, ?>) arg).containsKey(key)) {
|
||||||
throw new ParseSqlException("Failed to find {" + key + "} related field after parsing exception!");
|
throw new ParseSqlException("Failed to find {" + key + "} related field after parsing exception!");
|
||||||
}
|
}
|
||||||
Object o = ((Map<?, ?>) arg).get(key);
|
Object o = ((Map<?, ?>) arg).get(key);
|
||||||
if (null == o) {
|
if (null == o) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
if (o instanceof Character || o instanceof String) {
|
if (o instanceof Character || o instanceof String) {
|
||||||
// 处理字符类型
|
// 处理字符类型
|
||||||
if (isEscape) {
|
if (isEscape) {
|
||||||
return o;
|
return o;
|
||||||
} else {
|
} else {
|
||||||
return "'" + o + "'";
|
return "'" + o + "'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (o instanceof Collection) {
|
if (o instanceof Collection) {
|
||||||
return valueHandler(o, key, isEscape);
|
return valueHandler(o, key, isEscape);
|
||||||
}
|
}
|
||||||
if (o.getClass().isArray()) {
|
if (o.getClass().isArray()) {
|
||||||
return valueHandler(o, key, isEscape);
|
return valueHandler(o, key, isEscape);
|
||||||
}
|
}
|
||||||
if (o instanceof Number) {
|
if (o instanceof Number) {
|
||||||
// 处理数字类型
|
// 处理数字类型
|
||||||
return valueHandler(o, key, isEscape);
|
return valueHandler(o, key, isEscape);
|
||||||
}
|
}
|
||||||
if (o instanceof Boolean) {
|
if (o instanceof Boolean) {
|
||||||
// 处理布尔类型
|
// 处理布尔类型
|
||||||
return valueHandler(o, key, isEscape);
|
return valueHandler(o, key, isEscape);
|
||||||
}
|
}
|
||||||
if (o instanceof Character || o instanceof String) {
|
if (o instanceof Character || o instanceof String) {
|
||||||
// 处理字符类型
|
// 处理字符类型
|
||||||
return valueHandler(o, key, isEscape);
|
return valueHandler(o, key, isEscape);
|
||||||
}
|
}
|
||||||
return o;
|
return o;
|
||||||
}
|
}
|
||||||
String methodName = "get" + key.substring(0, 1).toUpperCase() + key.substring(1);
|
String methodName = "get" + key.substring(0, 1).toUpperCase() + key.substring(1);
|
||||||
// 当做javaBean处理
|
// 当做javaBean处理
|
||||||
try {
|
try {
|
||||||
|
|
||||||
Method method = arg.getClass().getMethod(methodName);
|
Method method = arg.getClass().getMethod(methodName);
|
||||||
Object invoke = method.invoke(arg);
|
Object invoke = method.invoke(arg);
|
||||||
if (invoke instanceof Character || invoke instanceof String) {
|
if (invoke instanceof Character || invoke instanceof String) {
|
||||||
// 处理字符类型
|
// 处理字符类型
|
||||||
if (isEscape) {
|
if (isEscape) {
|
||||||
return invoke;
|
return invoke;
|
||||||
} else {
|
} else {
|
||||||
return "'" + invoke + "'";
|
return "'" + invoke + "'";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return invoke;
|
return invoke;
|
||||||
} catch (NoSuchMethodException e) {
|
} catch (NoSuchMethodException e) {
|
||||||
// e.printStackTrace();
|
// e.printStackTrace();
|
||||||
throw new MethodNotFindException(methodName + " is not find!");
|
throw new MethodNotFindException(methodName + " is not find!");
|
||||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
throw new RuntimeException(e.toString());
|
throw new RuntimeException(e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
package com.api.test.aiyh.controller;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import weaver.workflow.msg.MsgPushUtil;
|
||||||
|
import weaver.workflow.msg.entity.MsgEntity;
|
||||||
|
import weaver.workflow.msg.entity.MsgOperateType;
|
||||||
|
import weaver.workflow.request.RequestOperationMsgManager;
|
||||||
|
|
||||||
|
import javax.ws.rs.Consumes;
|
||||||
|
import javax.ws.rs.GET;
|
||||||
|
import javax.ws.rs.Path;
|
||||||
|
import javax.ws.rs.Produces;
|
||||||
|
import javax.ws.rs.core.MediaType;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>ceshi </h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/1 14:32</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@Path("/aiyh/test/req-msg")
|
||||||
|
public class RequestMsgNotifiyController {
|
||||||
|
|
||||||
|
@GET
|
||||||
|
@Path("/test-msg")
|
||||||
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
public String testMsg() {
|
||||||
|
RequestOperationMsgManager manager = new RequestOperationMsgManager();
|
||||||
|
List<MsgEntity> operateMsg = manager.getOperateMsg("1213", MsgOperateType.OTHER);
|
||||||
|
operateMsg.get(2).getCurrentOperatorIdMap().put("111", "2700");
|
||||||
|
operateMsg.get(2).getUserId().add("111");
|
||||||
|
System.out.println(JSON.toJSONString(operateMsg));
|
||||||
|
new MsgPushUtil().pushMsg(operateMsg);
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
|
@ -41,7 +41,7 @@ public class HrmLoinTipController {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Path("/get/message")
|
@Path("/message/read")
|
||||||
@GET
|
@GET
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
|
|
|
@ -54,10 +54,16 @@ public interface HrmLoinTipMapper {
|
||||||
* @return 是否更新成功
|
* @return 是否更新成功
|
||||||
*/
|
*/
|
||||||
@Insert("insert into cus_fielddata (scope, scopeid, id, $t{showStatusField})\n" +
|
@Insert("insert into cus_fielddata (scope, scopeid, id, $t{showStatusField})\n" +
|
||||||
"values ('HrmCustomFieldByInfoType',-1,#{userId},0)")
|
"values ('HrmCustomFieldByInfoType',-1,#{userId},1)")
|
||||||
boolean insertStatus(@ParamMapper("showStatusField") String showStatusField,
|
boolean insertStatus(@ParamMapper("showStatusField") String showStatusField,
|
||||||
@ParamMapper("userId") Integer userId);
|
@ParamMapper("userId") Integer userId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>查询是否存在数据</h2>
|
||||||
|
*
|
||||||
|
* @param userId 用户ID
|
||||||
|
* @return 数据id
|
||||||
|
*/
|
||||||
@Select("select SEQORDER from cus_fielddata where scope = 'HrmCustomFieldByInfoType'\n" +
|
@Select("select SEQORDER from cus_fielddata where scope = 'HrmCustomFieldByInfoType'\n" +
|
||||||
" and scopeid = -1 and id = #{userId}")
|
" and scopeid = -1 and id = #{userId}")
|
||||||
Integer getMessageStatusId(@ParamMapper("userId") Integer userId);
|
Integer getMessageStatusId(@ParamMapper("userId") Integer userId);
|
||||||
|
|
|
@ -49,6 +49,8 @@ public class HrmLoinTipService {
|
||||||
Integer userId = null;
|
Integer userId = null;
|
||||||
if (Objects.isNull(user)) {
|
if (Objects.isNull(user)) {
|
||||||
userId = mapper.getUserIdByAccount(userAccount);
|
userId = mapper.getUserIdByAccount(userAccount);
|
||||||
|
} else {
|
||||||
|
userId = user.getUID();
|
||||||
}
|
}
|
||||||
String showStatusField = Util.getCusConfigValue("LOGIN_BEFORE_SHOW_MESSAGE_FIELD");
|
String showStatusField = Util.getCusConfigValue("LOGIN_BEFORE_SHOW_MESSAGE_FIELD");
|
||||||
Assert.notEmpty(showStatusField, "can not query config by only mark [LOGIN_BEFORE_SHOW_MESSAGE_FIELD](登录前显示消息状态字段_人员卡片自定义字段基本信息字段) on table [uf_cus_dev_config]");
|
Assert.notEmpty(showStatusField, "can not query config by only mark [LOGIN_BEFORE_SHOW_MESSAGE_FIELD](登录前显示消息状态字段_人员卡片自定义字段基本信息字段) on table [uf_cus_dev_config]");
|
||||||
|
|
|
@ -10,10 +10,10 @@ import weaver.youhong.ai.haripijiu.action.sapdocking.config.dto.SapVoucher;
|
||||||
import weaver.youhong.ai.haripijiu.action.sapdocking.config.dto.VoucherItem;
|
import weaver.youhong.ai.haripijiu.action.sapdocking.config.dto.VoucherItem;
|
||||||
import weaver.youhong.ai.haripijiu.action.sapdocking.config.service.SapConfigService;
|
import weaver.youhong.ai.haripijiu.action.sapdocking.config.service.SapConfigService;
|
||||||
|
|
||||||
import java.io.BufferedWriter;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
|
@ -94,13 +94,18 @@ public class VoucherPayableService {
|
||||||
logger.info("凭证数据:" + voucherHeadStr);
|
logger.info("凭证数据:" + voucherHeadStr);
|
||||||
String filePath = getFilePath();
|
String filePath = getFilePath();
|
||||||
try {
|
try {
|
||||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
|
// BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
|
||||||
Files.newOutputStream(Paths.get(filePath))
|
// Files.newOutputStream(Paths.get(filePath))
|
||||||
));
|
// ));
|
||||||
writer.write(voucherHeadStr);
|
OutputStreamWriter out = new OutputStreamWriter(
|
||||||
writer.write(voucherDetailStr);
|
Files.newOutputStream(Paths.get(filePath)), StandardCharsets.UTF_8);
|
||||||
writer.flush();
|
out.write(voucherHeadStr);
|
||||||
writer.close();
|
out.write(voucherDetailStr);
|
||||||
|
out.close();
|
||||||
|
// writer.write(voucherHeadStr);
|
||||||
|
// writer.write(voucherDetailStr);
|
||||||
|
// writer.flush();
|
||||||
|
// writer.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CustomerException(Util.logStr("can not writer file [{}]", filePath));
|
throw new CustomerException(Util.logStr("can not writer file [{}]", filePath));
|
||||||
}
|
}
|
||||||
|
@ -141,13 +146,16 @@ public class VoucherPayableService {
|
||||||
logger.info("凭证数据:" + voucherHaredStr);
|
logger.info("凭证数据:" + voucherHaredStr);
|
||||||
String filePath = getFilePath();
|
String filePath = getFilePath();
|
||||||
try {
|
try {
|
||||||
|
OutputStreamWriter out = new OutputStreamWriter(
|
||||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
|
Files.newOutputStream(Paths.get(filePath)), StandardCharsets.UTF_8);
|
||||||
Files.newOutputStream(Paths.get(filePath))
|
out.write(voucherHaredStr);
|
||||||
));
|
out.close();
|
||||||
writer.write(voucherHaredStr);
|
// BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
|
||||||
writer.flush();
|
// Files.newOutputStream(Paths.get(filePath))
|
||||||
writer.close();
|
// ));
|
||||||
|
// writer.write(voucherHaredStr);
|
||||||
|
// writer.flush();
|
||||||
|
// writer.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CustomerException(Util.logStr("can not writer receipt voucher file [{}]", filePath));
|
throw new CustomerException(Util.logStr("can not writer receipt voucher file [{}]", filePath));
|
||||||
}
|
}
|
||||||
|
@ -181,12 +189,16 @@ public class VoucherPayableService {
|
||||||
logger.info("凭证数据:" + voucherHeadStr);
|
logger.info("凭证数据:" + voucherHeadStr);
|
||||||
String filePath = getFilePath();
|
String filePath = getFilePath();
|
||||||
try {
|
try {
|
||||||
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
|
// BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(
|
||||||
Files.newOutputStream(Paths.get(filePath))
|
// Files.newOutputStream(Paths.get(filePath))
|
||||||
));
|
// ));
|
||||||
writer.write(voucherHeadStr);
|
OutputStreamWriter out = new OutputStreamWriter(
|
||||||
writer.flush();
|
Files.newOutputStream(Paths.get(filePath)), StandardCharsets.UTF_8);
|
||||||
writer.close();
|
out.write(voucherHeadStr);
|
||||||
|
// writer.write(voucherHeadStr);
|
||||||
|
// writer.flush();
|
||||||
|
// writer.close();
|
||||||
|
out.close();
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new CustomerException(Util.logStr("can not writer payment voucher file [{}]", filePath));
|
throw new CustomerException(Util.logStr("can not writer payment voucher file [{}]", filePath));
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.apache.log4j.Logger;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
@ -30,7 +31,7 @@ public class SmbjUtil {
|
||||||
* @param localFilePath 本地文件绝对路径
|
* @param localFilePath 本地文件绝对路径
|
||||||
*/
|
*/
|
||||||
public void smbPut(String remoteUrl, String localFilePath, String userName, String pwd, String fileName) {
|
public void smbPut(String remoteUrl, String localFilePath, String userName, String pwd, String fileName) {
|
||||||
InputStream in = null;
|
BufferedReader br = null;
|
||||||
OutputStream out = null;
|
OutputStream out = null;
|
||||||
try {
|
try {
|
||||||
File localFile = new File(localFilePath);
|
File localFile = new File(localFilePath);
|
||||||
|
@ -40,18 +41,39 @@ public class SmbjUtil {
|
||||||
// 这里推荐使用这种方式进行用户名密码的校验,在url中拼接,如果需要特殊字符可能无法转换
|
// 这里推荐使用这种方式进行用户名密码的校验,在url中拼接,如果需要特殊字符可能无法转换
|
||||||
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(null, userName, pwd);
|
NtlmPasswordAuthentication auth = new NtlmPasswordAuthentication(null, userName, pwd);
|
||||||
SmbFile remoteFile = new SmbFile(remoteUrl + "/" + fileName, auth);
|
SmbFile remoteFile = new SmbFile(remoteUrl + "/" + fileName, auth);
|
||||||
in = new BufferedInputStream(Files.newInputStream(localFile.toPath()));
|
// in = new BufferedInputStream(Files.newInputStream(localFile.toPath()));
|
||||||
|
String uploadSapFileCharset = Util.getCusConfigValueNullOrEmpty("UPLOAD_SAP_FILE_CHARSET", "UTF-8");
|
||||||
|
br = new BufferedReader(new InputStreamReader(Files.newInputStream(localFile.toPath()), Charset.forName(uploadSapFileCharset)));
|
||||||
out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile));
|
out = new BufferedOutputStream(new SmbFileOutputStream(remoteFile));
|
||||||
byte[] buffer = new byte[1024];
|
while (br.ready()) {
|
||||||
while (in.read(buffer) != -1) {
|
String line = br.readLine();
|
||||||
out.write(buffer);
|
out.write(line.getBytes(Charset.forName(uploadSapFileCharset)));
|
||||||
buffer = new byte[1024];
|
out.write("\n".getBytes());
|
||||||
}
|
}
|
||||||
|
// byte[] buffer = new byte[1024];
|
||||||
|
// while (in.read(buffer) != -1) {
|
||||||
|
// out.write(buffer);
|
||||||
|
// buffer = new byte[1024];
|
||||||
|
// }
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("提交文件到 共享目录失败!\n" + Util.getErrString(e));
|
log.error("提交文件到 共享目录失败!\n" + Util.getErrString(e));
|
||||||
throw new CustomerException("提交文件到 共享目录失败");
|
throw new CustomerException("提交文件到 共享目录失败");
|
||||||
} finally {
|
} finally {
|
||||||
closeStream(in, out);
|
closeStream(br, out);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void closeStream(BufferedReader in, OutputStream out) {
|
||||||
|
try {
|
||||||
|
if (!Objects.isNull(out)) {
|
||||||
|
out.close();
|
||||||
|
}
|
||||||
|
if (!Objects.isNull(in)) {
|
||||||
|
in.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.error("流关闭失败!\n" + Util.getErrString(e));
|
||||||
|
throw new CustomerException("流关闭失败");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,223 @@
|
||||||
|
package weaver.youhong.ai.pcn.actioin.ccworkflow;
|
||||||
|
|
||||||
|
import aiyh.utils.Util;
|
||||||
|
import aiyh.utils.action.SafeCusBaseAction;
|
||||||
|
import aiyh.utils.annotation.ActionDesc;
|
||||||
|
import aiyh.utils.annotation.PrintParamMark;
|
||||||
|
import aiyh.utils.annotation.RequiredMark;
|
||||||
|
import aiyh.utils.excention.CustomerException;
|
||||||
|
import com.cloudstore.dev.api.bean.MessageType;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import weaver.hrm.User;
|
||||||
|
import weaver.soa.workflow.request.RequestInfo;
|
||||||
|
import weaver.workflow.msg.MsgPushUtil;
|
||||||
|
import weaver.workflow.msg.entity.MsgEntity;
|
||||||
|
import weaver.workflow.msg.entity.MsgNoticeType;
|
||||||
|
import weaver.workflow.request.RequestManager;
|
||||||
|
import weaver.youhong.ai.pcn.actioin.ccworkflow.mapper.CCWorkflowMapper;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>抄送流程</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/1 15:33</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@ActionDesc(value = "抄送流程到指定人员", author = "youhong.ai")
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class CCWorkflowAction extends SafeCusBaseAction {
|
||||||
|
|
||||||
|
private final CCWorkflowMapper mapper = Util.getMapper(CCWorkflowMapper.class);
|
||||||
|
|
||||||
|
@PrintParamMark
|
||||||
|
@RequiredMark("抄送人所在明细表编号,1-明细1 ; 2-明细2")
|
||||||
|
private String detailNo;
|
||||||
|
|
||||||
|
@PrintParamMark
|
||||||
|
@RequiredMark("抄送人所在字段字段名")
|
||||||
|
private String ccResourceField;
|
||||||
|
|
||||||
|
@PrintParamMark
|
||||||
|
@RequiredMark("一级部门负责人字段名")
|
||||||
|
private String firstLevelDepResponsibleField;
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void doSubmit(String requestId, String billTable, int workflowId, User user, RequestInfo requestInfo) {
|
||||||
|
List<Map<String, Object>> detailDateList = super.getDetailTableObjValueByDetailNo(Integer.parseInt(detailNo) - 1, requestInfo);
|
||||||
|
List<String> ccUserList = new ArrayList<>();
|
||||||
|
for (Map<String, Object> detailRow : detailDateList) {
|
||||||
|
if (String.valueOf(user.getUID()).equals(detailRow.get(firstLevelDepResponsibleField))) {
|
||||||
|
ccUserList.add(Util.null2String(detailRow.get(ccResourceField)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (ccUserList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ccUserList = ccUserList.stream().distinct().filter(item -> !"".equals(item)).collect(Collectors.toList());
|
||||||
|
if (ccUserList.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String requestTitle = mapper.selectRequestTitle(requestId);
|
||||||
|
String workflowType = requestInfo.getRequestManager().getWorkflowtype();
|
||||||
|
int nodeId = requestInfo.getRequestManager().getNodeid();
|
||||||
|
/* ******************* 插入流程操作者以及抄送日志 ******************* */
|
||||||
|
insertCurrentOperator(ccUserList, requestId, nodeId, String.valueOf(workflowId), workflowType, requestInfo);
|
||||||
|
Map<String, String> currentOperatorIdMap = this.createCurrentOperatorIdMap(ccUserList, nodeId, requestId);
|
||||||
|
/* ******************* 发送消息 ******************* */
|
||||||
|
Set<String> ccUserIds = new HashSet<>(ccUserList);
|
||||||
|
sendMsg(requestInfo, currentOperatorIdMap, ccUserIds, requestTitle);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>插入节点操作人</h2>
|
||||||
|
*
|
||||||
|
* @param ccUerList 抄送用户列表
|
||||||
|
* @param requestId 请求id
|
||||||
|
* @param nodId 节点id
|
||||||
|
* @param workflowId 流程id
|
||||||
|
* @param workflowType 流程类型
|
||||||
|
* @param requestInfo 请求信息
|
||||||
|
*/
|
||||||
|
private void insertCurrentOperator(List<String> ccUerList, String requestId,
|
||||||
|
Integer nodId,
|
||||||
|
String workflowId,
|
||||||
|
String workflowType, RequestInfo requestInfo) {
|
||||||
|
Map<String, Object> currentOperator = mapper.selectCurrentOperator(requestId, nodId);
|
||||||
|
Integer groupDetailId = 163;
|
||||||
|
Integer showOrder = 1;
|
||||||
|
Integer groupId = 0;
|
||||||
|
if (Objects.isNull(currentOperator) || currentOperator.isEmpty()) {
|
||||||
|
Object groupDetailIdObj = currentOperator.get("groupDetailId");
|
||||||
|
Object showOrderObj = currentOperator.get("showOrder");
|
||||||
|
Object groupIdObj = currentOperator.get("groupId");
|
||||||
|
groupDetailId = Util.getIntValue(Util.null2String(groupDetailIdObj), 163);
|
||||||
|
showOrder = Util.getIntValue(Util.null2String(showOrderObj), 1);
|
||||||
|
groupId = Util.getIntValue(Util.null2String(groupIdObj), 0);
|
||||||
|
}
|
||||||
|
List<Map<String, Object>> batchList = new ArrayList<>();
|
||||||
|
for (String userId : ccUerList) {
|
||||||
|
Map<String, Object> updateMap = new HashMap<>();
|
||||||
|
updateMap.put("REQUESTID", requestId);
|
||||||
|
updateMap.put("USERID", userId);
|
||||||
|
updateMap.put("GROUPID", ++groupId);
|
||||||
|
updateMap.put("WORKFLOWID", workflowId);
|
||||||
|
updateMap.put("WORKFLOWTYPE", workflowType);
|
||||||
|
updateMap.put("USERTYPE", 0);
|
||||||
|
updateMap.put("AGENTORBYAGENTID", -1);
|
||||||
|
updateMap.put("AGENTTYPE", 0);
|
||||||
|
updateMap.put("SHOWORDER", ++showOrder);
|
||||||
|
updateMap.put("RECEIVEDATE", Util.getTime("yyyy-MM-dd"));
|
||||||
|
updateMap.put("RECEIVETIME", Util.getTime("HH:mm:dd"));
|
||||||
|
updateMap.put("VIEWTYPE", 0);
|
||||||
|
updateMap.put("ISCOMPLETE", 0);
|
||||||
|
updateMap.put("ISLASTTIMES", 1);
|
||||||
|
updateMap.put("GROUPDETAILID", ++groupDetailId);
|
||||||
|
updateMap.put("NEEDWFBACK", "1");
|
||||||
|
updateMap.put("isremark", 8);
|
||||||
|
updateMap.put("preisremark", 8);
|
||||||
|
batchList.add(updateMap);
|
||||||
|
}
|
||||||
|
String sql = builderSql(batchList.get(0));
|
||||||
|
boolean flag = mapper.insertCurrentOperator(sql, batchList);
|
||||||
|
if (!flag) {
|
||||||
|
throw new CustomerException("流程抄送失败!");
|
||||||
|
}
|
||||||
|
/* ******************* 插入操纵日志 ******************* */
|
||||||
|
String userName = ccUerList.stream()
|
||||||
|
.map(id -> new User(Integer.parseInt(id)))
|
||||||
|
.map(User::getUsername)
|
||||||
|
.collect(Collectors.joining(","));
|
||||||
|
boolean insertLog = mapper.insertOperatorLog(requestId, workflowId, nodId, Util.getTime("yyyy-MM-dd"),
|
||||||
|
Util.getTime("HH:mm:dd"), requestInfo.getHostid(), userName, Util.join(ccUerList, ","),
|
||||||
|
requestInfo.getRequestManager().getUser().getUID());
|
||||||
|
|
||||||
|
if (!insertLog) {
|
||||||
|
log.error("更新流程抄送日志失败!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>构建sql</h2>
|
||||||
|
*
|
||||||
|
* @param map 更新sql
|
||||||
|
* @return 构建后的sql
|
||||||
|
*/
|
||||||
|
private String builderSql(Map<String, Object> map) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
StringBuilder valueSb = new StringBuilder();
|
||||||
|
valueSb.append(" (");
|
||||||
|
sb.append("insert into workflow_currentoperator (");
|
||||||
|
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||||
|
sb.append(entry.getKey()).append(",");
|
||||||
|
valueSb.append("#{item.").append(entry.getKey()).append("},");
|
||||||
|
}
|
||||||
|
sb.deleteCharAt(sb.length() - 1);
|
||||||
|
valueSb.deleteCharAt(sb.length() - 1);
|
||||||
|
sb.append(" values ").append(valueSb);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>获取抄送人员的当前节点操作者的id映射关系</h2>
|
||||||
|
*
|
||||||
|
* @param ccUserList 抄送人员列表
|
||||||
|
* @param node 当前节点id
|
||||||
|
* @param requestId 流程请求id
|
||||||
|
* @return 整理后的数据
|
||||||
|
*/
|
||||||
|
private Map<String, String> createCurrentOperatorIdMap(List<String> ccUserList, int node, String requestId) {
|
||||||
|
Map<String, String> result = new HashMap<>(ccUserList.size());
|
||||||
|
ccUserList.forEach(item -> result.put(item, mapper.selectCurrentOperatorId(item, node, requestId)));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>发送提示信息</h2>
|
||||||
|
*
|
||||||
|
* @param requestInfo 请求信息
|
||||||
|
* @param currentOperatorIdMap 操作者记录id和用户ID映射关系
|
||||||
|
* @param ccUserIds 抄送用户列表
|
||||||
|
* @param requestTitle 流程明晨
|
||||||
|
*/
|
||||||
|
private void sendMsg(RequestInfo requestInfo, Map<String, String> currentOperatorIdMap, Set<String> ccUserIds, String requestTitle) {
|
||||||
|
|
||||||
|
RequestManager requestManager = requestInfo.getRequestManager();
|
||||||
|
MsgEntity msgEntity = new MsgEntity();
|
||||||
|
// 流程抄送
|
||||||
|
msgEntity.setMsgType(MessageType.WF_COPY);
|
||||||
|
// 提醒类型为抄送
|
||||||
|
msgEntity.setNoticeType(MsgNoticeType.CC);
|
||||||
|
// 流程创建日期
|
||||||
|
msgEntity.setCreateDate(requestManager.getCreatedate());
|
||||||
|
// 流程创建时间
|
||||||
|
msgEntity.setCreateTime(requestManager.getCreatetime());
|
||||||
|
// 流程创建人
|
||||||
|
msgEntity.setCreator(requestInfo.getCreatorid());
|
||||||
|
// 流程当前操作者map userId -> workflow_currentoperator.id
|
||||||
|
msgEntity.setCurrentOperatorIdMap(currentOperatorIdMap);
|
||||||
|
// 当前时间 yyyy-MM-dd HH:mm:ss
|
||||||
|
msgEntity.setDate(Util.getTime("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
// 流程requestId
|
||||||
|
msgEntity.setDetailId(requestInfo.getRequestid());
|
||||||
|
// 流程标题
|
||||||
|
msgEntity.setDetailName(requestTitle);
|
||||||
|
// 流程标题
|
||||||
|
msgEntity.setDetailTitle(requestTitle);
|
||||||
|
// 当前操作者id
|
||||||
|
msgEntity.setOperatorId(String.valueOf(requestManager.getUser().getUID()));
|
||||||
|
// 接受时间
|
||||||
|
msgEntity.setReceiveDate(Util.getTime("yyyy-MM-dd HH:mm:ss"));
|
||||||
|
// 抄送用户id
|
||||||
|
msgEntity.setUserId(ccUserIds);
|
||||||
|
new MsgPushUtil().pushMsg(Collections.singletonList(msgEntity));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,95 @@
|
||||||
|
package weaver.youhong.ai.pcn.actioin.ccworkflow.mapper;
|
||||||
|
|
||||||
|
import aiyh.utils.annotation.recordset.*;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1></h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/1 16:43</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@SqlMapper
|
||||||
|
public interface CCWorkflowMapper {
|
||||||
|
/**
|
||||||
|
* <h2>查询流程名称</h2>
|
||||||
|
*
|
||||||
|
* @param requestId 流程请求id
|
||||||
|
* @return 流程名称
|
||||||
|
*/
|
||||||
|
@Select("select REQUESTNAME from workflow_requestbase where REQUESTID = #{requestId}")
|
||||||
|
String selectRequestTitle(String requestId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>查询当前节点操作人数据</h2>
|
||||||
|
*
|
||||||
|
* @param requestId 请求id
|
||||||
|
* @param nodeId 节点id
|
||||||
|
* @return 查询数据
|
||||||
|
*/
|
||||||
|
@Select("select GROUPID group_id,SHOWORDER showOrder,GROUPDETAILID groupDetailId from workflow_currentoperator where requestid = #{requestId} order by id desc limit 1")
|
||||||
|
Map<String, Object> selectCurrentOperator(
|
||||||
|
@ParamMapper("requestId") String requestId,
|
||||||
|
@ParamMapper("nodId") Integer nodeId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>批量插入流程当前操作人</h2>
|
||||||
|
*
|
||||||
|
* @param sql 批量插入sql
|
||||||
|
* @param batchList 批量数据
|
||||||
|
* @return 是否更新成功
|
||||||
|
*/
|
||||||
|
@BatchInsert(custom = true)
|
||||||
|
boolean insertCurrentOperator(@SqlString String sql, @BatchSqlArgs List<Map<String, Object>> batchList);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>插入流程操作日志记录</h2>
|
||||||
|
*
|
||||||
|
* @param requestId 请求id
|
||||||
|
* @param workflowId 流程id
|
||||||
|
* @param nodeId 节点id
|
||||||
|
* @param operateDate 操作日期
|
||||||
|
* @param operateTime 操作时间
|
||||||
|
* @param clientIp 客户端ip
|
||||||
|
* @param userName 用户名称
|
||||||
|
* @param userId 用户id
|
||||||
|
* @param operator 操作者
|
||||||
|
* @return 插入标识
|
||||||
|
*/
|
||||||
|
@Insert("INSERT INTO workflow_requestlog\n" +
|
||||||
|
" (REQUESTID, WORKFLOWID, NODEID, LOGTYPE, OPERATEDATE, OPERATETIME, OPERATOR,\n" +
|
||||||
|
" clientip, OPERATORTYPE, SHOWORDER, AGENTORBYAGENTID, AGENTTYPE,\n" +
|
||||||
|
" REQUESTLOGID, OPERATORDEPT, RECEIVEDPERSONS, ISMOBILE, SPEECHATTACHMENT,\n" +
|
||||||
|
" RECEIVEDPERSONIDS, speechattachmente9, operatorSub, operatorJob, seclevel)\n" +
|
||||||
|
"VALUES (#{requestId}, #{workflowId}, #{nodeId}, 't', #{operateDate}, #{operateTime}, " +
|
||||||
|
" #{operator}, #{clientIp},\n" +
|
||||||
|
" 0, -1, -1, '0',\n" +
|
||||||
|
" 0, 0, #{userName}, 'd', 0, #{userId}, '0', 0, 0, '30')")
|
||||||
|
boolean insertOperatorLog(@ParamMapper("requestId") String requestId,
|
||||||
|
@ParamMapper("workflowId") String workflowId,
|
||||||
|
@ParamMapper("nodeId") int nodeId,
|
||||||
|
@ParamMapper("operateDate") String operateDate,
|
||||||
|
@ParamMapper("operateTime") String operateTime,
|
||||||
|
@ParamMapper("clientIp") String clientIp,
|
||||||
|
@ParamMapper("userName") String userName,
|
||||||
|
@ParamMapper("userId") String userId,
|
||||||
|
@ParamMapper("operator") int operator);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>查询流程操作者的记录id</h2>
|
||||||
|
*
|
||||||
|
* @param item 用户id
|
||||||
|
* @param node 节点id
|
||||||
|
* @param requestId 请求id
|
||||||
|
* @return 记录id
|
||||||
|
*/
|
||||||
|
@Select("select id from workflow_currentoperator where requestid = #{requestId} " +
|
||||||
|
"and userid = #{userId} and NODEID = #{nodeId} order by id desc limit 1")
|
||||||
|
String selectCurrentOperatorId(
|
||||||
|
@ParamMapper("userId") String item,
|
||||||
|
@ParamMapper("nodeId") int node,
|
||||||
|
@ParamMapper("requestId") String requestId);
|
||||||
|
}
|
|
@ -55,6 +55,11 @@ public class WorkflowConditionsSetValueAction extends SafeCusBaseAction {
|
||||||
try {
|
try {
|
||||||
Map<String, Object> workflowData = new HashMap<>(16);
|
Map<String, Object> workflowData = new HashMap<>(16);
|
||||||
Map<String, Object> workflowMainData = super.getObjMainTableValue(requestInfo);
|
Map<String, Object> workflowMainData = super.getObjMainTableValue(requestInfo);
|
||||||
|
workflowData.put("main", workflowMainData);
|
||||||
|
workflowData.put("_user_", user);
|
||||||
|
workflowData.put("_workflowId_", workflowId);
|
||||||
|
workflowData.put("_requestId_", requestId);
|
||||||
|
workflowData.put("_billTable_", billTable);
|
||||||
ConditionsSetValueConfigMain conditionsSetValueConfigMain = service.getConditionConfigMain(onlyMark);
|
ConditionsSetValueConfigMain conditionsSetValueConfigMain = service.getConditionConfigMain(onlyMark);
|
||||||
if (Strings.isNullOrEmpty(detailNo)) {
|
if (Strings.isNullOrEmpty(detailNo)) {
|
||||||
/* ******************* 数据修改主表 ******************* */
|
/* ******************* 数据修改主表 ******************* */
|
||||||
|
@ -64,11 +69,6 @@ public class WorkflowConditionsSetValueAction extends SafeCusBaseAction {
|
||||||
}
|
}
|
||||||
/* ******************* 明细表 ******************* */
|
/* ******************* 明细表 ******************* */
|
||||||
List<Map<String, Object>> detailData = super.getDetailTableObjValueByDetailNo(Integer.parseInt(detailNo) - 1, requestInfo);
|
List<Map<String, Object>> detailData = super.getDetailTableObjValueByDetailNo(Integer.parseInt(detailNo) - 1, requestInfo);
|
||||||
workflowData.put("main", workflowMainData);
|
|
||||||
workflowData.put("_user_", user);
|
|
||||||
workflowData.put("_workflowId_", workflowId);
|
|
||||||
workflowData.put("_requestId_", requestId);
|
|
||||||
workflowData.put("_billTable_", billTable);
|
|
||||||
workflowData.put("_detailTable_", billTable + "_dt" + detailNo);
|
workflowData.put("_detailTable_", billTable + "_dt" + detailNo);
|
||||||
List<UpdateDetailRowDto> main = new ArrayList<>();
|
List<UpdateDetailRowDto> main = new ArrayList<>();
|
||||||
List<UpdateDetailRowDto> detail = new ArrayList<>();
|
List<UpdateDetailRowDto> detail = new ArrayList<>();
|
||||||
|
|
|
@ -71,6 +71,17 @@ public interface WorkflowConditionsSetValueMapper {
|
||||||
@Select(custom = true)
|
@Select(custom = true)
|
||||||
String selectCustomerSql(@SqlString String sql, Map<String, Object> workflowData);
|
String selectCustomerSql(@SqlString String sql, Map<String, Object> workflowData);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h2>查询自定义sql</h2>
|
||||||
|
*
|
||||||
|
* @param sql 自定义sql
|
||||||
|
* @param workflowData 流程数据
|
||||||
|
* @return 查询结果
|
||||||
|
*/
|
||||||
|
@Select(custom = true)
|
||||||
|
List<String> selectCustomerSqlList(@SqlString String sql, Map<String, Object> workflowData);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <h2>更新流程表单数据</h2>
|
* <h2>更新流程表单数据</h2>
|
||||||
*
|
*
|
||||||
|
|
|
@ -84,7 +84,7 @@ public class WorkflowConditionsSetValueService {
|
||||||
* @param detailNo 明细号
|
* @param detailNo 明细号
|
||||||
*/
|
*/
|
||||||
public void updateWorkflowDetailData(List<UpdateDetailRowDto> updateDetailRowDtoList, String billTable, String detailNo) {
|
public void updateWorkflowDetailData(List<UpdateDetailRowDto> updateDetailRowDtoList, String billTable, String detailNo) {
|
||||||
if (updateDetailRowDtoList.isEmpty()) {
|
if (Objects.isNull(updateDetailRowDtoList) || updateDetailRowDtoList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
UpdateDetailRowDto updateDetailRow = updateDetailRowDtoList.get(0);
|
UpdateDetailRowDto updateDetailRow = updateDetailRowDtoList.get(0);
|
||||||
|
@ -141,7 +141,7 @@ public class WorkflowConditionsSetValueService {
|
||||||
* @param requestId 当前请求ID
|
* @param requestId 当前请求ID
|
||||||
*/
|
*/
|
||||||
public void updateWorkflowData(Map<String, Object> conditionData, String billTable, String requestId) {
|
public void updateWorkflowData(Map<String, Object> conditionData, String billTable, String requestId) {
|
||||||
if (conditionData.isEmpty()) {
|
if (Objects.isNull(conditionData) || conditionData.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
StringBuilder sb = new StringBuilder("update ");
|
StringBuilder sb = new StringBuilder("update ");
|
||||||
|
|
|
@ -11,7 +11,9 @@ import weaver.youhong.ai.pcn.actioin.conditionssetvalue.mapper.WorkflowCondition
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.function.BiFunction;
|
import java.util.function.BiFunction;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -73,5 +75,14 @@ public class ValueSetRulesTreatment {
|
||||||
return mapper.selectCustomerSql(conditionItem.getCustomerSetValue(), workflowData);
|
return mapper.selectCustomerSql(conditionItem.getCustomerSetValue(), workflowData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@MethodRuleNo(value = 3, desc = "自定义sql值join(',')")
|
||||||
|
private Object customerSqlJoin(ConditionItem conditionItem, Map<String, Object> workflowData) {
|
||||||
|
List<String> list = mapper.selectCustomerSqlList(conditionItem.getCustomerSetValue(), workflowData);
|
||||||
|
if (Objects.isNull(list) || list.isEmpty()) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return Util.join(list, ",");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package youhong.ai.mymapper;
|
||||||
|
|
||||||
|
import basetest.BaseTest;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
|
import org.junit.Test;
|
||||||
|
import youhong.ai.mymapper.command.entity.SqlDefinition;
|
||||||
|
import youhong.ai.mymapper.util.ParseSqlUtil;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>测试</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/1 21:49</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class ParseSqlTest extends BaseTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test() {
|
||||||
|
String sql = "select $t{table} into set field = #{field} from table :my-where{\n" +
|
||||||
|
"\t:my-for:item=\"item\":index=\"index\":collection=\"ids\":open=\"\":separator=\"\":close=\"\":nullable{\n" +
|
||||||
|
"\t\tand $t{index} = #{item}\n" +
|
||||||
|
"\t}\n" +
|
||||||
|
"} order by abase = #{order} $t{desc}";
|
||||||
|
ParseSqlUtil parseSqlUtil = new ParseSqlUtil();
|
||||||
|
Map<String, Object> param = new HashMap<>();
|
||||||
|
param.put("ids", Arrays.asList("var1", "var2", "var3"));
|
||||||
|
param.put("table", "hhhtable");
|
||||||
|
param.put("field", "field");
|
||||||
|
param.put("order", "order");
|
||||||
|
param.put("desc", "desc_va");
|
||||||
|
SqlDefinition parse = parseSqlUtil.parse(sql, param);
|
||||||
|
System.out.println(JSON.toJSONString(parse));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testLoadClass() {
|
||||||
|
System.out.println(Arrays.asList("1", "2", "3", "4"));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
package youhong.ai.mymapper.command;
|
||||||
|
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import youhong.ai.mymapper.command.constant.CommandConsTant;
|
||||||
|
import youhong.ai.mymapper.command.entity.SqlCommandDefinition;
|
||||||
|
import youhong.ai.mymapper.command.properties.AbstractCommandProperties;
|
||||||
|
import youhong.ai.mymapper.util.ParseSqlUtil;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>指令执行器</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 16:58</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class CommandExecutor {
|
||||||
|
|
||||||
|
|
||||||
|
public String executor(SqlCommandDefinition commandDefinition) {
|
||||||
|
ParseSqlUtil parseSqlUtil = new ParseSqlUtil();
|
||||||
|
ISqlCommand actuator = commandDefinition.getActuator();
|
||||||
|
String commandType = commandDefinition.getCommandType();
|
||||||
|
AbstractCommandProperties properties = commandDefinition.getProperties();
|
||||||
|
if (CommandConsTant.WHERE.equals(commandType)) {
|
||||||
|
String commandContent = commandDefinition.getCommandContent();
|
||||||
|
String parse = parseSqlUtil.parse(commandContent);
|
||||||
|
String sql = parseSqlUtil.parseStatement(parse);
|
||||||
|
if (StringUtils.isNotBlank(sql)) {
|
||||||
|
String trim = sql.trim();
|
||||||
|
if (trim.toUpperCase().startsWith("AND ")) {
|
||||||
|
trim = trim.substring(3);
|
||||||
|
}
|
||||||
|
if (trim.toUpperCase().startsWith("OR ")) {
|
||||||
|
trim = trim.substring(2);
|
||||||
|
}
|
||||||
|
sql = " where " + trim;
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String parseString = actuator.execute(properties);
|
||||||
|
String sql = parseSqlUtil.parseStatement(parseString);
|
||||||
|
return sql;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package youhong.ai.mymapper.command;
|
||||||
|
|
||||||
|
import youhong.ai.mymapper.command.properties.AbstractCommandProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>sql 指令解析接口</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 09:40</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public interface ISqlCommand {
|
||||||
|
|
||||||
|
String execute(AbstractCommandProperties commandProperties);
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
package youhong.ai.mymapper.command.annotation;
|
||||||
|
|
||||||
|
import java.lang.annotation.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>sql指令</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 10:33</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@Target(ElementType.TYPE)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@Documented
|
||||||
|
public @interface SqlCommand {
|
||||||
|
String value();
|
||||||
|
}
|
|
@ -0,0 +1,158 @@
|
||||||
|
package youhong.ai.mymapper.command.commandImpl;
|
||||||
|
|
||||||
|
import aiyh.utils.Util;
|
||||||
|
import aiyh.utils.excention.CustomerException;
|
||||||
|
import org.apache.commons.lang.StringUtils;
|
||||||
|
import weaver.common.util.string.StringUtil;
|
||||||
|
import youhong.ai.mymapper.command.ISqlCommand;
|
||||||
|
import youhong.ai.mymapper.command.annotation.SqlCommand;
|
||||||
|
import youhong.ai.mymapper.command.constant.CommandConsTant;
|
||||||
|
import youhong.ai.mymapper.command.properties.AbstractCommandProperties;
|
||||||
|
import youhong.ai.mymapper.command.properties.MyForProperties;
|
||||||
|
import youhong.ai.mymapper.util.ParamValueUtil;
|
||||||
|
import youhong.ai.mymapper.util.ParseSqlUtil;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>for指令</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/1 23:16</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SqlCommand(CommandConsTant.FOR)
|
||||||
|
public class MyForCommand implements ISqlCommand {
|
||||||
|
private final ParseSqlUtil parseSqlUtil = new ParseSqlUtil();
|
||||||
|
|
||||||
|
private final Map<String, BiFunction<Object, Object, Object>> functionMap = new HashMap<>();
|
||||||
|
|
||||||
|
{
|
||||||
|
functionMap.put("split", (source, split) -> StringUtils.split(String.valueOf(source), String.valueOf(split)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(AbstractCommandProperties commandProperties) {
|
||||||
|
Map<String, Object> params = ParseSqlUtil.PARSE_PARAM_LOCALE.get();
|
||||||
|
MyForProperties properties = (MyForProperties) commandProperties;
|
||||||
|
String collection = properties.getCollection();
|
||||||
|
if (StringUtil.isNullOrEmpty(collection)) {
|
||||||
|
throw new NullPointerException("collection attribute is can not to be null or empty! ");
|
||||||
|
}
|
||||||
|
boolean valueFunInvoke = false;
|
||||||
|
String funName = "";
|
||||||
|
if (collection.endsWith(")")) {
|
||||||
|
char[] chars = collection.toCharArray();
|
||||||
|
funName = findInvokeFun(chars);
|
||||||
|
collection = collection.replace("." + funName, "");
|
||||||
|
valueFunInvoke = true;
|
||||||
|
}
|
||||||
|
Object value = ParamValueUtil.getValueByKeyStr(collection, params);
|
||||||
|
if (Objects.isNull(value)) {
|
||||||
|
if (properties.getNullable()) {
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
throw new NullPointerException("collection value is null: " + collection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (valueFunInvoke) {
|
||||||
|
if (value instanceof String) {
|
||||||
|
value = invokeFun(value, funName);
|
||||||
|
if (value.getClass().isArray()) {
|
||||||
|
Object[] valueArr = (Object[]) value;
|
||||||
|
List<Object> collect = Arrays.stream(valueArr).collect(Collectors.toList());
|
||||||
|
return listCommand(collect, properties);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (value instanceof List) {
|
||||||
|
return listCommand(value, properties);
|
||||||
|
}
|
||||||
|
if (value instanceof Map) {
|
||||||
|
return mapCommand(value, properties);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object invokeFun(Object value, String funName) {
|
||||||
|
String name = funName.substring(0, funName.indexOf("("));
|
||||||
|
String arg = funName.substring(funName.indexOf("\"") + 1, funName.lastIndexOf("\""));
|
||||||
|
if (!functionMap.containsKey(name)) {
|
||||||
|
throw new CustomerException("Unsupported method calls, no method:" + name);
|
||||||
|
}
|
||||||
|
return functionMap.get(name).apply(Util.null2String(value), arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String findInvokeFun(char[] chars) {
|
||||||
|
StringBuilder invokeFun = new StringBuilder();
|
||||||
|
boolean hasFun = false;
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
if (c == '.') {
|
||||||
|
while (true) {
|
||||||
|
i++;
|
||||||
|
if (i >= chars.length) {
|
||||||
|
invokeFun.delete(0, invokeFun.length());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
c = chars[i];
|
||||||
|
invokeFun.append(c);
|
||||||
|
if (c == '(') {
|
||||||
|
hasFun = true;
|
||||||
|
}
|
||||||
|
if (c == ')' && i == chars.length - 1) {
|
||||||
|
return invokeFun.toString();
|
||||||
|
}
|
||||||
|
if (c == '.' && !hasFun) {
|
||||||
|
invokeFun.delete(0, invokeFun.length());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return invokeFun.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String listCommand(Object value,
|
||||||
|
MyForProperties properties) {
|
||||||
|
List<Object> list = (List<Object>) value;
|
||||||
|
String itemName = properties.getItem();
|
||||||
|
if (StringUtil.isNullOrEmpty(itemName)) {
|
||||||
|
itemName = "item";
|
||||||
|
}
|
||||||
|
String indexName = properties.getIndex();
|
||||||
|
if (StringUtil.isNullOrEmpty(indexName)) {
|
||||||
|
indexName = "index";
|
||||||
|
}
|
||||||
|
if (list.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
|
String open = properties.getOpen();
|
||||||
|
String close = properties.getClose();
|
||||||
|
String separator = properties.getSeparator();
|
||||||
|
sqlBuilder.append(open);
|
||||||
|
for (int i = 0; i < list.size(); i++) {
|
||||||
|
Map<String, Object> tempParam = new HashMap<>();
|
||||||
|
Object item = list.get(i);
|
||||||
|
tempParam.put(itemName, item);
|
||||||
|
tempParam.put(indexName, i);
|
||||||
|
ParseSqlUtil.PARSE_TEMP_PARAM_LOCALE.set(tempParam);
|
||||||
|
String parse = parseSqlUtil.parse(properties.getCommandContent());
|
||||||
|
sqlBuilder.append(" ").append(parse);
|
||||||
|
if (i <= list.size()) {
|
||||||
|
sqlBuilder.append(separator);
|
||||||
|
}
|
||||||
|
ParseSqlUtil.PARSE_TEMP_PARAM_LOCALE.remove();
|
||||||
|
}
|
||||||
|
sqlBuilder.append(close);
|
||||||
|
return sqlBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String mapCommand(Object value, MyForProperties properties) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
package youhong.ai.mymapper.command.commandImpl;
|
||||||
|
|
||||||
|
import youhong.ai.mymapper.command.ISqlCommand;
|
||||||
|
import youhong.ai.mymapper.command.annotation.SqlCommand;
|
||||||
|
import youhong.ai.mymapper.command.constant.CommandConsTant;
|
||||||
|
import youhong.ai.mymapper.command.properties.AbstractCommandProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>where指令</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/1 23:16</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
|
||||||
|
@SqlCommand(CommandConsTant.WHERE)
|
||||||
|
public class MyWhereCommand implements ISqlCommand {
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String execute(AbstractCommandProperties commandProperties) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package youhong.ai.mymapper.command.constant;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>常量</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 17:21</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class CommandConsTant {
|
||||||
|
|
||||||
|
|
||||||
|
public static final String FOR = "for";
|
||||||
|
|
||||||
|
public static final String WHERE = "where";
|
||||||
|
|
||||||
|
public final static String COMMAND_PATH = "youhong.ai.mymapper.command.commandImpl";
|
||||||
|
|
||||||
|
|
||||||
|
public final static List<Character> Skip_CHAR = Arrays.asList('\n', '\t', '\r');
|
||||||
|
|
||||||
|
public final static List<Character> TRANSLATION_CHAR = Arrays.asList(':', '{', '}');
|
||||||
|
|
||||||
|
public final static char VARIABLE_SUFFIX = '}';
|
||||||
|
|
||||||
|
public final static String TABLE_OR_FIELD_PLACEHOLDER = "$t{";
|
||||||
|
public static final String VARIABLE_SPLIT = "$split{";
|
||||||
|
|
||||||
|
public static final String VARIABLE_REPLACE = "${";
|
||||||
|
|
||||||
|
public static final String VARIABLE_PREPARED_STATEMENT = "#{";
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package youhong.ai.mymapper.command.entity;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>指令内容描述器</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/3 15:10</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@Setter
|
||||||
|
@Getter
|
||||||
|
@ToString
|
||||||
|
public class CommandContentDefinition {
|
||||||
|
private String content;
|
||||||
|
|
||||||
|
private Integer length;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
package youhong.ai.mymapper.command.entity;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
import youhong.ai.mymapper.command.ISqlCommand;
|
||||||
|
import youhong.ai.mymapper.command.properties.AbstractCommandProperties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>sql指令描述起</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 10:45</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class SqlCommandDefinition {
|
||||||
|
|
||||||
|
/** 指令解析器 */
|
||||||
|
private ISqlCommand actuator;
|
||||||
|
|
||||||
|
/** 指令参数 */
|
||||||
|
private AbstractCommandProperties properties;
|
||||||
|
|
||||||
|
/** 指令中的内容 */
|
||||||
|
private String commandContent;
|
||||||
|
|
||||||
|
/** 指令类型 */
|
||||||
|
private String commandType;
|
||||||
|
|
||||||
|
private Integer commandLength;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package youhong.ai.mymapper.command.entity;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>sql描述信息</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 20:43</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class SqlDefinition {
|
||||||
|
private String sql;
|
||||||
|
private List<Object> args;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
package youhong.ai.mymapper.command.properties;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>指令参数</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 10:47</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public abstract class AbstractCommandProperties {
|
||||||
|
|
||||||
|
private String commandContent;
|
||||||
|
private String commandType;
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package youhong.ai.mymapper.command.properties;
|
||||||
|
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>for指令的prop</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 10:43</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
public class MyForProperties extends AbstractCommandProperties {
|
||||||
|
private String item;
|
||||||
|
|
||||||
|
private String index;
|
||||||
|
|
||||||
|
private String collection;
|
||||||
|
|
||||||
|
private String open;
|
||||||
|
|
||||||
|
private String close;
|
||||||
|
|
||||||
|
|
||||||
|
private String separator;
|
||||||
|
|
||||||
|
private Boolean nullable;
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package youhong.ai.mymapper.command.properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>where指令的prop</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 10:43</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class MyWhereProperties extends AbstractCommandProperties {
|
||||||
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package youhong.ai.mymapper.util;
|
||||||
|
|
||||||
|
import aiyh.utils.annotation.MethodRuleNo;
|
||||||
|
import youhong.ai.mymapper.command.constant.CommandConsTant;
|
||||||
|
import youhong.ai.mymapper.command.properties.AbstractCommandProperties;
|
||||||
|
import youhong.ai.mymapper.command.properties.MyForProperties;
|
||||||
|
import youhong.ai.mymapper.command.properties.MyWhereProperties;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>工厂</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 14:33</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class AbstractCommandPropertiesFactory {
|
||||||
|
|
||||||
|
@MethodRuleNo(name = CommandConsTant.WHERE, desc = "where 指令参数解析")
|
||||||
|
private AbstractCommandProperties getWhereProperties(List<String> commandItemList) {
|
||||||
|
AbstractCommandProperties commandProperties = new MyWhereProperties();
|
||||||
|
for (int i = 1; i < commandItemList.size(); i++) {
|
||||||
|
String item = commandItemList.get(i);
|
||||||
|
CommandPropUtil.setValueString(commandProperties, item);
|
||||||
|
}
|
||||||
|
return commandProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
@MethodRuleNo(name = CommandConsTant.FOR, desc = "for 指令参数解析")
|
||||||
|
private AbstractCommandProperties getForProperties(List<String> commandItemList) {
|
||||||
|
AbstractCommandProperties commandProperties = new MyForProperties();
|
||||||
|
for (int i = 1; i < commandItemList.size(); i++) {
|
||||||
|
String item = commandItemList.get(i);
|
||||||
|
CommandPropUtil.setValueString(commandProperties, item);
|
||||||
|
}
|
||||||
|
return commandProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,168 @@
|
||||||
|
package youhong.ai.mymapper.util;
|
||||||
|
|
||||||
|
import aiyh.utils.Util;
|
||||||
|
import aiyh.utils.annotation.MethodRuleNo;
|
||||||
|
import aiyh.utils.excention.CustomerException;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import youhong.ai.mymapper.command.ISqlCommand;
|
||||||
|
import youhong.ai.mymapper.command.entity.CommandContentDefinition;
|
||||||
|
import youhong.ai.mymapper.command.entity.SqlCommandDefinition;
|
||||||
|
import youhong.ai.mymapper.command.properties.AbstractCommandProperties;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>指令properties封装Util</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 11:03</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class CommandPropUtil {
|
||||||
|
|
||||||
|
public static final String SPLIT_STR = "=";
|
||||||
|
private static final Map<String, Function<List<String>, AbstractCommandProperties>> CREATE_PROP_FUN = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
/* ******************* 初始化参数 ******************* */ static {
|
||||||
|
Class<AbstractCommandPropertiesFactory> valueRuleMethodClass = AbstractCommandPropertiesFactory.class;
|
||||||
|
Method[] methods = valueRuleMethodClass.getDeclaredMethods();
|
||||||
|
AbstractCommandPropertiesFactory factory = new AbstractCommandPropertiesFactory();
|
||||||
|
for (Method method : methods) {
|
||||||
|
method.setAccessible(true);
|
||||||
|
if (method.isAnnotationPresent(MethodRuleNo.class)) {
|
||||||
|
MethodRuleNo annotation = method.getAnnotation(MethodRuleNo.class);
|
||||||
|
String value = annotation.name();
|
||||||
|
CREATE_PROP_FUN.put(value, commandItemList -> {
|
||||||
|
try {
|
||||||
|
return (AbstractCommandProperties) method.invoke(factory, commandItemList);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static SqlCommandDefinition createICommandProperties(List<String> commandItemList,
|
||||||
|
CommandContentDefinition commandContent,
|
||||||
|
ISqlCommand iSqlCommand) {
|
||||||
|
String command = commandItemList.get(0);
|
||||||
|
if (!CREATE_PROP_FUN.containsKey(command)) {
|
||||||
|
throw new CustomerException("can not find command properties factory method of command: " + command);
|
||||||
|
}
|
||||||
|
AbstractCommandProperties commandProperties = CREATE_PROP_FUN.get(command).apply(commandItemList);
|
||||||
|
commandProperties.setCommandContent(commandContent.getContent());
|
||||||
|
commandProperties.setCommandType(command);
|
||||||
|
SqlCommandDefinition commandDefinition = new SqlCommandDefinition();
|
||||||
|
commandDefinition.setCommandType(command);
|
||||||
|
commandDefinition.setCommandContent(commandContent.getContent());
|
||||||
|
commandDefinition.setActuator(iSqlCommand);
|
||||||
|
commandDefinition.setProperties(commandProperties);
|
||||||
|
commandDefinition.setCommandLength(commandContent.getLength());
|
||||||
|
return commandDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> void setValueString(T t, String valurStr) {
|
||||||
|
if (Objects.isNull(t)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
valurStr = valurStr.trim();
|
||||||
|
Class<?> aClass = t.getClass();
|
||||||
|
String[] split = valurStr.split(SPLIT_STR);
|
||||||
|
if (split.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String fieldName = split[0];
|
||||||
|
Field field;
|
||||||
|
try {
|
||||||
|
field = aClass.getDeclaredField(fieldName);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
throw new CustomerException(e);
|
||||||
|
}
|
||||||
|
Method setMethod = findMethod(aClass, fieldName, field);
|
||||||
|
if (split.length == 1) {
|
||||||
|
if (Boolean.class.equals(field.getType()) ||
|
||||||
|
boolean.class.equals(field.getType())) {
|
||||||
|
try {
|
||||||
|
setMethod.invoke(t, true);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new CustomerException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (split.length == 2) {
|
||||||
|
String value = split[1];
|
||||||
|
try {
|
||||||
|
if ((value.endsWith("\"") && value.startsWith("\"")) || (value.endsWith("'") && value.startsWith("'"))) {
|
||||||
|
value = value.substring(1, value.length() - 1);
|
||||||
|
}
|
||||||
|
setMethod.invoke(t, ParseValueUtil.parse(value.trim(), field.getType()));
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new CustomerException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
StringBuilder valueBuilder = new StringBuilder();
|
||||||
|
for (int i = 1; i < split.length; i++) {
|
||||||
|
valueBuilder.append(split[i]).append("=");
|
||||||
|
}
|
||||||
|
valueBuilder.deleteCharAt(valueBuilder.length() - 1);
|
||||||
|
try {
|
||||||
|
String trim = valueBuilder.toString().trim();
|
||||||
|
if ((trim.endsWith("\"") && trim.startsWith("\"")) || (trim.endsWith("'") && trim.startsWith("'"))) {
|
||||||
|
trim = trim.substring(1, trim.length() - 1);
|
||||||
|
}
|
||||||
|
setMethod.invoke(t, ParseValueUtil.parse(trim.trim(), field.getType()));
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new CustomerException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static Method findMethod(Class<?> aClass, String fieldName, Field field) {
|
||||||
|
Method setMethod;
|
||||||
|
try {
|
||||||
|
setMethod = aClass.getDeclaredMethod("set" + Util.firstUpperCase(fieldName), field.getType());
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new CustomerException(e);
|
||||||
|
}
|
||||||
|
return setMethod;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static class ParseValueUtil {
|
||||||
|
|
||||||
|
private final static Map<Class<?>, Function<String, ?>> CONVERT_FUN = new HashMap<>();
|
||||||
|
|
||||||
|
static {
|
||||||
|
CONVERT_FUN.put(int.class, Integer::parseInt);
|
||||||
|
CONVERT_FUN.put(Integer.class, Integer::parseInt);
|
||||||
|
CONVERT_FUN.put(double.class, Double::parseDouble);
|
||||||
|
CONVERT_FUN.put(Double.class, Double::parseDouble);
|
||||||
|
CONVERT_FUN.put(float.class, Float::parseFloat);
|
||||||
|
CONVERT_FUN.put(Boolean.class, Boolean::parseBoolean);
|
||||||
|
CONVERT_FUN.put(boolean.class, Boolean::parseBoolean);
|
||||||
|
CONVERT_FUN.put(Long.class, Long::parseLong);
|
||||||
|
CONVERT_FUN.put(long.class, Long::parseLong);
|
||||||
|
CONVERT_FUN.put(String.class, value -> value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Object parse(String value, Class<?> clazz) {
|
||||||
|
if (!CONVERT_FUN.containsKey(clazz)) {
|
||||||
|
throw new CustomerException("Non-self-supporting type conversion!");
|
||||||
|
}
|
||||||
|
return CONVERT_FUN.get(clazz).apply(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
package youhong.ai.mymapper.util;
|
||||||
|
|
||||||
|
import aiyh.utils.excention.CustomerException;
|
||||||
|
import youhong.ai.mymapper.ParseSqlTest;
|
||||||
|
import youhong.ai.mymapper.command.ISqlCommand;
|
||||||
|
import youhong.ai.mymapper.command.annotation.SqlCommand;
|
||||||
|
import youhong.ai.mymapper.command.constant.CommandConsTant;
|
||||||
|
import youhong.ai.mymapper.command.entity.CommandContentDefinition;
|
||||||
|
import youhong.ai.mymapper.command.entity.SqlCommandDefinition;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>指令util</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 09:46</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class CommandUtil {
|
||||||
|
|
||||||
|
public static final Map<String, ISqlCommand> SQL_COMMAND_MAP = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
static {
|
||||||
|
registerCommand();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static SqlCommandDefinition createCommandProperties(String commandLin, CommandContentDefinition commandContent) {
|
||||||
|
char[] chars = commandLin.toCharArray();
|
||||||
|
StringBuilder commandSb = new StringBuilder();
|
||||||
|
List<String> commandItemList = new ArrayList<>();
|
||||||
|
if (commandLin.split(":").length == 1) {
|
||||||
|
commandItemList.add(commandLin);
|
||||||
|
}
|
||||||
|
int account = 0;
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
account++;
|
||||||
|
if (CommandConsTant.Skip_CHAR.contains(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\\') {
|
||||||
|
if (CommandConsTant.TRANSLATION_CHAR.contains(chars[i + 1])) {
|
||||||
|
commandSb.append(chars[i + 1]);
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
commandSb.append(c);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == ':') {
|
||||||
|
commandItemList.add(commandSb.toString());
|
||||||
|
commandSb = new StringBuilder();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
commandSb.append(c);
|
||||||
|
}
|
||||||
|
String command = commandItemList.get(0);
|
||||||
|
ISqlCommand iSqlCommand = getCommand(command);
|
||||||
|
SqlCommandDefinition sqlCommandDefinition = CommandPropUtil.createICommandProperties(commandItemList, commandContent, iSqlCommand);
|
||||||
|
sqlCommandDefinition.setCommandLength(sqlCommandDefinition.getCommandLength() + account);
|
||||||
|
return sqlCommandDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ISqlCommand getCommand(String command) {
|
||||||
|
if (SQL_COMMAND_MAP.isEmpty()) {
|
||||||
|
throw new CustomerException("can not find command: " + command);
|
||||||
|
}
|
||||||
|
if (SQL_COMMAND_MAP.containsKey(command)) {
|
||||||
|
return SQL_COMMAND_MAP.get(command);
|
||||||
|
} else {
|
||||||
|
throw new CustomerException("can not find command: " + command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void registerCommand() {
|
||||||
|
String path = Objects.requireNonNull(ParseSqlTest.class.getResource("/")).getPath();
|
||||||
|
path += CommandConsTant.COMMAND_PATH.replace(".", File.separator);
|
||||||
|
File file = new File(path);
|
||||||
|
List<String> fileNames = new ArrayList<>();
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
if (!Objects.isNull(files)) {
|
||||||
|
for (File listFile : files) {
|
||||||
|
List<String> fileNameList = findFileName(listFile, null);
|
||||||
|
if (!Objects.isNull(fileNameList)) {
|
||||||
|
fileNames.addAll(fileNameList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (String fileName : fileNames) {
|
||||||
|
Class<?> aClass = null;
|
||||||
|
try {
|
||||||
|
aClass = Class.forName(CommandConsTant.COMMAND_PATH + "." + fileName.replace(".class", ""));
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!ISqlCommand.class.isAssignableFrom(aClass)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!aClass.isAnnotationPresent(SqlCommand.class)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
SqlCommand command = aClass.getAnnotation(SqlCommand.class);
|
||||||
|
try {
|
||||||
|
SQL_COMMAND_MAP.put(command.value(), (ISqlCommand) aClass.newInstance());
|
||||||
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
|
throw new CustomerException("can not newInstance: " + aClass.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<String> findFileName(File file, String dirName) {
|
||||||
|
List<String> fileNames = new ArrayList<>();
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
File[] files = file.listFiles();
|
||||||
|
if (Objects.isNull(files)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (File innerFile : files) {
|
||||||
|
List<String> fileName = findFileName(innerFile, file.getName());
|
||||||
|
if (!Objects.isNull(fileName)) {
|
||||||
|
fileNames.addAll(fileName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fileNames.add(Objects.isNull(dirName) ? file.getName() : dirName + "." + file.getName());
|
||||||
|
}
|
||||||
|
return fileNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
package youhong.ai.mymapper.util;
|
||||||
|
|
||||||
|
import aiyh.utils.Util;
|
||||||
|
import aiyh.utils.excention.CustomerException;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>参数工具</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 17:36</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class ParamValueUtil {
|
||||||
|
|
||||||
|
public static Object getPreparedParam(Object value) {
|
||||||
|
if (Objects.isNull(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (value instanceof CharSequence || value instanceof Number) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Object getAppendParam(Object value) {
|
||||||
|
if (Objects.isNull(value)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (value instanceof CharSequence) {
|
||||||
|
return "'" + value + "'";
|
||||||
|
}
|
||||||
|
if (value instanceof Number) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (value.getClass().isArray()) {
|
||||||
|
Object[] arr = (Object[]) value;
|
||||||
|
if (arr.length >= 1) {
|
||||||
|
Object o = arr[0];
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
if (o instanceof Number) {
|
||||||
|
for (Object obj : arr) {
|
||||||
|
sb.append(obj).append(",");
|
||||||
|
}
|
||||||
|
sb.deleteCharAt(sb.length() - 1);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
if (o instanceof String || o instanceof Character) {
|
||||||
|
sb.append("'");
|
||||||
|
for (Object obj : arr) {
|
||||||
|
sb.append(Util.null2String(obj).replace("'", "''")).append("','");
|
||||||
|
}
|
||||||
|
sb.deleteCharAt(sb.length() - 2);
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Arrays.toString(arr);
|
||||||
|
}
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static Object getValueByKeyStr(String key, Object o) {
|
||||||
|
if (Objects.isNull(o) || Objects.isNull(key) || key.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (o.getClass().isPrimitive()) {
|
||||||
|
throw new CustomerException("object is primitive, Cannot get value through : " + key);
|
||||||
|
}
|
||||||
|
if (o instanceof Map) {
|
||||||
|
return mapValue(key, o);
|
||||||
|
}
|
||||||
|
if (o instanceof List) {
|
||||||
|
throw new CustomerException("object is List, Cannot get value through : " + key);
|
||||||
|
}
|
||||||
|
return beanValue(key, o);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Object mapValue(String key, Object obj) {
|
||||||
|
String[] split = key.split("\\.");
|
||||||
|
Map map = (Map) obj;
|
||||||
|
Object value = map.get(split[0]);
|
||||||
|
if (split.length > 1) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 1; i < split.length; i++) {
|
||||||
|
sb.append(split[i]).append(".");
|
||||||
|
}
|
||||||
|
sb.deleteCharAt(sb.length() - 1);
|
||||||
|
value = getValueByKeyStr(sb.toString(), value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Object beanValue(String key, Object o) {
|
||||||
|
String[] split = key.split("\\.");
|
||||||
|
Class<?> aClass = o.getClass();
|
||||||
|
Field declaredField;
|
||||||
|
try {
|
||||||
|
declaredField = aClass.getDeclaredField(split[0]);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
throw new CustomerException(e);
|
||||||
|
}
|
||||||
|
Method method;
|
||||||
|
if (Boolean.class.equals(declaredField.getType()) || boolean.class.equals(declaredField.getType())) {
|
||||||
|
try {
|
||||||
|
method = aClass.getMethod(Util.firstUpperCase("is" + split[0]));
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
try {
|
||||||
|
method = aClass.getMethod(split[0]);
|
||||||
|
} catch (NoSuchMethodException ex) {
|
||||||
|
throw new CustomerException(ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
try {
|
||||||
|
method = aClass.getMethod(Util.firstUpperCase("get" + split[0]));
|
||||||
|
} catch (NoSuchMethodException e) {
|
||||||
|
throw new CustomerException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Object value;
|
||||||
|
try {
|
||||||
|
value = method.invoke(o);
|
||||||
|
} catch (IllegalAccessException | InvocationTargetException e) {
|
||||||
|
throw new CustomerException(e);
|
||||||
|
}
|
||||||
|
if (split.length > 1) {
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
for (int i = 1; i < split.length; i++) {
|
||||||
|
sb.append(split[i]).append(".");
|
||||||
|
}
|
||||||
|
sb.deleteCharAt(sb.length() - 1);
|
||||||
|
value = getValueByKeyStr(sb.toString(), value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,325 @@
|
||||||
|
package youhong.ai.mymapper.util;
|
||||||
|
|
||||||
|
import aiyh.utils.Util;
|
||||||
|
import aiyh.utils.excention.CustomerException;
|
||||||
|
import youhong.ai.mymapper.command.CommandExecutor;
|
||||||
|
import youhong.ai.mymapper.command.constant.CommandConsTant;
|
||||||
|
import youhong.ai.mymapper.command.entity.CommandContentDefinition;
|
||||||
|
import youhong.ai.mymapper.command.entity.SqlCommandDefinition;
|
||||||
|
import youhong.ai.mymapper.command.entity.SqlDefinition;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <h1>解析sql工具</h1>
|
||||||
|
*
|
||||||
|
* <p>create: 2023/3/2 09:42</p>
|
||||||
|
*
|
||||||
|
* @author youHong.ai
|
||||||
|
*/
|
||||||
|
public class ParseSqlUtil {
|
||||||
|
|
||||||
|
private final char[] commandPrefix = new char[]{'m', 'y', '-'};
|
||||||
|
|
||||||
|
|
||||||
|
public final static ThreadLocal<Map<String, Object>> PARSE_PARAM_LOCALE = new ThreadLocal<>();
|
||||||
|
public final static ThreadLocal<Map<String, Object>> PARSE_TEMP_PARAM_LOCALE = new ThreadLocal<>();
|
||||||
|
public final static ThreadLocal<List<Object>> SQL_PARAM_LOCALE = new ThreadLocal<>();
|
||||||
|
|
||||||
|
private final CommandExecutor commandExecutor = new CommandExecutor();
|
||||||
|
|
||||||
|
public SqlDefinition parse(String sql, Map<String, Object> params) {
|
||||||
|
if (!Objects.isNull(params)) {
|
||||||
|
PARSE_PARAM_LOCALE.set(params);
|
||||||
|
SQL_PARAM_LOCALE.set(new ArrayList<>());
|
||||||
|
}
|
||||||
|
SqlDefinition sqlDefinition = new SqlDefinition();
|
||||||
|
try {
|
||||||
|
String parse = parse(sql);
|
||||||
|
sqlDefinition.setSql(parse);
|
||||||
|
} finally {
|
||||||
|
List<Object> sqlParams = null;
|
||||||
|
if (!Objects.isNull(params)) {
|
||||||
|
PARSE_PARAM_LOCALE.remove();
|
||||||
|
sqlParams = SQL_PARAM_LOCALE.get();
|
||||||
|
sqlDefinition.setArgs(sqlParams);
|
||||||
|
SQL_PARAM_LOCALE.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sqlDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String parse(String sql) {
|
||||||
|
if (Objects.isNull(sql) || sql.isEmpty()) {
|
||||||
|
throw new CustomerException("can not parse sql, sql is empty!");
|
||||||
|
}
|
||||||
|
char[] chars = sql.toCharArray();
|
||||||
|
if (!hasCommand(chars)) {
|
||||||
|
String simpleSql = simpleSql(new String(chars));
|
||||||
|
return parseStatement(simpleSql);
|
||||||
|
}
|
||||||
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
if (CommandConsTant.Skip_CHAR.contains(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (':' == c) {
|
||||||
|
boolean isCommand = checkCommand(chars, i);
|
||||||
|
if (isCommand) {
|
||||||
|
// 解析到命令,需要将命令之前的变量解析掉
|
||||||
|
String tempSql = parseStatement(sqlBuilder.toString());
|
||||||
|
sqlBuilder.delete(0, sqlBuilder.length());
|
||||||
|
sqlBuilder.append(tempSql);
|
||||||
|
i += commandPrefix.length + 1;
|
||||||
|
SqlCommandDefinition commandDefinition = parseCommand(chars, i);
|
||||||
|
sqlBuilder.append(commandDefinition.getCommandContent());
|
||||||
|
i += commandDefinition.getCommandLength();
|
||||||
|
if (i <= chars.length - 1) {
|
||||||
|
sqlBuilder.append(" ");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sqlBuilder.append(c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sqlBuilder.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
String sqlStr = parseStatement(sqlBuilder.toString());
|
||||||
|
return simpleSql(sqlStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String simpleSql(String sql) {
|
||||||
|
char[] chars = sql.toCharArray();
|
||||||
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
|
boolean eliminate = true;
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
if (CommandConsTant.Skip_CHAR.contains(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\\') {
|
||||||
|
if (i + 1 <= chars.length - 1) {
|
||||||
|
if (CommandConsTant.TRANSLATION_CHAR.contains(chars[i + 1])) {
|
||||||
|
sqlBuilder.append(chars[i + 1]);
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sqlBuilder.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == '\'' && i != chars.length - 1) {
|
||||||
|
if (chars[i - 1] != '\'' || chars[i + 1] != '\'') {
|
||||||
|
eliminate = !eliminate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (c == ' ') {
|
||||||
|
if (chars[i + 1] == ' ' && eliminate) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sqlBuilder.append(c);
|
||||||
|
|
||||||
|
}
|
||||||
|
return sqlBuilder.toString().trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean hasCommand(char[] chars) {
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
if (':' == c) {
|
||||||
|
return checkCommand(chars, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkCommand(char[] chars, int index) {
|
||||||
|
if (index + commandPrefix.length + 1 >= chars.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (char prefix : commandPrefix) {
|
||||||
|
if (prefix != chars[++index]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SqlCommandDefinition parseCommand(char[] chars, int index) {
|
||||||
|
SqlCommandDefinition commandDefinition = getCommandDefinition(chars, index);
|
||||||
|
String executor = commandExecutor.executor(commandDefinition);
|
||||||
|
commandDefinition.setCommandContent(executor);
|
||||||
|
return commandDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
private SqlCommandDefinition getCommandDefinition(char[] chars, int index) {
|
||||||
|
StringBuilder commandSb = new StringBuilder();
|
||||||
|
boolean isCommand = false;
|
||||||
|
int commandStart = -1;
|
||||||
|
for (int i = index; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
if (CommandConsTant.Skip_CHAR.contains(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\\') {
|
||||||
|
if (CommandConsTant.TRANSLATION_CHAR.contains(chars[i + 1])) {
|
||||||
|
commandSb.append(c).append(chars[i + 1]);
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ('{' == c) {
|
||||||
|
commandStart = i;
|
||||||
|
isCommand = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
commandSb.append(c);
|
||||||
|
}
|
||||||
|
if (!isCommand) {
|
||||||
|
throw new CustomerException("Command syntax error! You should have a '{' after " + new String(chars).substring(0, index));
|
||||||
|
}
|
||||||
|
CommandContentDefinition commandContent = getCommandContent(chars, commandStart);
|
||||||
|
String command = commandSb.toString().trim();
|
||||||
|
return CommandUtil.createCommandProperties(command, commandContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
private CommandContentDefinition getCommandContent(char[] chars, int index) {
|
||||||
|
int commandSyntaxCount = 0;
|
||||||
|
StringBuilder commandContent = new StringBuilder();
|
||||||
|
int account = 0;
|
||||||
|
for (int i = index; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
account++;
|
||||||
|
if (CommandConsTant.Skip_CHAR.contains(c)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (c == '\\') {
|
||||||
|
if (CommandConsTant.TRANSLATION_CHAR.contains(chars[i + 1])) {
|
||||||
|
commandContent.append(c).append(chars[i + 1]);
|
||||||
|
i += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
commandContent.append(c);
|
||||||
|
if ('{' == c) {
|
||||||
|
commandSyntaxCount++;
|
||||||
|
}
|
||||||
|
if ('}' == c) {
|
||||||
|
commandSyntaxCount--;
|
||||||
|
if (commandSyntaxCount == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (commandSyntaxCount != 0) {
|
||||||
|
if (commandSyntaxCount > 0) {
|
||||||
|
throw new CustomerException("Command syntax error! Please check that your characters '{' are not closed on after: " + new String(chars).substring(0, index));
|
||||||
|
} else {
|
||||||
|
throw new CustomerException("Command syntax error! Please check that your characters '}' not in pairs on after: " + new String(chars).substring(0, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CommandContentDefinition commandContentDefinition = new CommandContentDefinition();
|
||||||
|
commandContentDefinition.setLength(account);
|
||||||
|
String trim = commandContent.toString().trim();
|
||||||
|
if (trim.startsWith("{") && trim.endsWith("}")) {
|
||||||
|
trim = trim.substring(1, trim.length() - 1);
|
||||||
|
}
|
||||||
|
commandContentDefinition.setContent(trim);
|
||||||
|
return commandContentDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String parseStatement(String sql) {
|
||||||
|
char[] chars = sql.toCharArray();
|
||||||
|
StringBuilder sqlBuilder = new StringBuilder();
|
||||||
|
for (int i = 0; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
String variable;
|
||||||
|
if ('$' == c) {
|
||||||
|
variable = isVariable(chars, i, CommandConsTant.TABLE_OR_FIELD_PLACEHOLDER);
|
||||||
|
if (!Objects.isNull(variable)) {
|
||||||
|
i += CommandConsTant.TABLE_OR_FIELD_PLACEHOLDER.length() + variable.length();
|
||||||
|
String variableValue = Util.null2String(getVariableValue(variable));
|
||||||
|
String str = parseStatement(variableValue);
|
||||||
|
sqlBuilder.append(str);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
variable = isVariable(chars, i, CommandConsTant.VARIABLE_SPLIT);
|
||||||
|
if (!Objects.isNull(variable)) {
|
||||||
|
i += CommandConsTant.VARIABLE_SPLIT.length() + variable.length();
|
||||||
|
String value = Util.null2String(getVariableValue(variable));
|
||||||
|
String[] split = value.split(",");
|
||||||
|
for (String s : split) {
|
||||||
|
ParseSqlUtil.SQL_PARAM_LOCALE.get().add(s);
|
||||||
|
sqlBuilder.append("?,");
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
variable = isVariable(chars, i, CommandConsTant.VARIABLE_REPLACE);
|
||||||
|
if (!Objects.isNull(variable)) {
|
||||||
|
i += CommandConsTant.VARIABLE_REPLACE.length() + variable.length();
|
||||||
|
Object value = getVariableValue(variable);
|
||||||
|
sqlBuilder.append(ParamValueUtil.getAppendParam(value));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ('#' == c) {
|
||||||
|
variable = isVariable(chars, i, CommandConsTant.VARIABLE_PREPARED_STATEMENT);
|
||||||
|
if (!Objects.isNull(variable)) {
|
||||||
|
i += CommandConsTant.VARIABLE_PREPARED_STATEMENT.length() + variable.length();
|
||||||
|
Object value = getVariableValue(variable);
|
||||||
|
sqlBuilder.append("?");
|
||||||
|
ParseSqlUtil.SQL_PARAM_LOCALE.get().add(ParamValueUtil.getPreparedParam(value));
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sqlBuilder.append(c);
|
||||||
|
}
|
||||||
|
return sqlBuilder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object getVariableValue(String variable) {
|
||||||
|
variable = variable.trim();
|
||||||
|
Map<String, Object> tempMap = ParseSqlUtil.PARSE_TEMP_PARAM_LOCALE.get();
|
||||||
|
Map<String, Object> paramMap = ParseSqlUtil.PARSE_PARAM_LOCALE.get();
|
||||||
|
Object value = ParamValueUtil.getValueByKeyStr(variable, tempMap);
|
||||||
|
if (Objects.isNull(value)) {
|
||||||
|
value = ParamValueUtil.getValueByKeyStr(variable, paramMap);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String isVariable(char[] chars, int startIndex, String variablePrefix) {
|
||||||
|
char[] prefix = variablePrefix.toCharArray();
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
boolean isVariable = false;
|
||||||
|
for (int i = startIndex; i < chars.length; i++) {
|
||||||
|
char c = chars[i];
|
||||||
|
if (!isVariable) {
|
||||||
|
for (char value : prefix) {
|
||||||
|
c = chars[i];
|
||||||
|
if (value == c) {
|
||||||
|
i++;
|
||||||
|
if (i >= chars.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isVariable = true;
|
||||||
|
}
|
||||||
|
c = chars[i];
|
||||||
|
if (c == CommandConsTant.VARIABLE_SUFFIX) {
|
||||||
|
return sb.toString();
|
||||||
|
}
|
||||||
|
sb.append(c);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,8 +10,8 @@ import com.engine.hrm.service.impl.RolesMembersServiceImpl;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import weaver.hrm.User;
|
import weaver.hrm.User;
|
||||||
|
import weaver.youhong.ai.pcn.actioin.ccworkflow.CCWorkflowAction;
|
||||||
import weaver.youhong.ai.pcn.actioin.conditionssetvalue.WorkflowConditionsSetValueAction;
|
import weaver.youhong.ai.pcn.actioin.conditionssetvalue.WorkflowConditionsSetValueAction;
|
||||||
import weaver.youhong.ai.pcn.actioin.generateloginid.GenerateLoginIdAction;
|
|
||||||
import weaver.youhong.ai.pcn.actioin.generateloginid.mapper.GenerateLoginIdMapper;
|
import weaver.youhong.ai.pcn.actioin.generateloginid.mapper.GenerateLoginIdMapper;
|
||||||
import weaver.youhong.ai.pcn.schedule.addrolebyhasundering.RegisterRoleMemberByHasUnderingCronJob;
|
import weaver.youhong.ai.pcn.schedule.addrolebyhasundering.RegisterRoleMemberByHasUnderingCronJob;
|
||||||
import weaver.youhong.ai.pcn.schedule.addrolemember.RegisterRoleMemberCronJob;
|
import weaver.youhong.ai.pcn.schedule.addrolemember.RegisterRoleMemberCronJob;
|
||||||
|
@ -124,6 +124,6 @@ public class RolesTest extends BaseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void generateFile() {
|
public void generateFile() {
|
||||||
GenerateFileUtil.createActionDocument(GenerateLoginIdAction.class);
|
GenerateFileUtil.createActionDocument(CCWorkflowAction.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,8 +3,13 @@ package youhong.ai.pcn;
|
||||||
import aiyh.utils.GenerateFileUtil;
|
import aiyh.utils.GenerateFileUtil;
|
||||||
import aiyh.utils.Util;
|
import aiyh.utils.Util;
|
||||||
import basetest.BaseTest;
|
import basetest.BaseTest;
|
||||||
|
import com.alibaba.fastjson.JSON;
|
||||||
import ebu7common.youhong.ai.bean.Builder;
|
import ebu7common.youhong.ai.bean.Builder;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import weaver.workflow.msg.MsgPushUtil;
|
||||||
|
import weaver.workflow.msg.entity.MsgEntity;
|
||||||
|
import weaver.workflow.msg.entity.MsgOperateType;
|
||||||
|
import weaver.workflow.request.RequestOperationMsgManager;
|
||||||
import weaver.youhong.ai.haripijiu.action.sapdocking.config.pojo.SapConfigDetail;
|
import weaver.youhong.ai.haripijiu.action.sapdocking.config.pojo.SapConfigDetail;
|
||||||
import weaver.youhong.ai.haripijiu.action.sapdocking.config.util.ValueRuleMethod;
|
import weaver.youhong.ai.haripijiu.action.sapdocking.config.util.ValueRuleMethod;
|
||||||
import weaver.youhong.ai.haripijiu.action.sapdocking.service.VoucherPayableService;
|
import weaver.youhong.ai.haripijiu.action.sapdocking.service.VoucherPayableService;
|
||||||
|
@ -13,6 +18,7 @@ import youhong.ai.pcn.mapper.TransTestMapper;
|
||||||
import youhong.ai.pcn.pojo.Student;
|
import youhong.ai.pcn.pojo.Student;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <h1>测试</h1>
|
* <h1>测试</h1>
|
||||||
|
@ -23,60 +29,137 @@ import java.util.HashMap;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class UtilTest extends BaseTest {
|
public class UtilTest extends BaseTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test() {
|
public void test() {
|
||||||
|
|
||||||
TransTestMapper transMapper = Util.getTransMapper(TransTestMapper.class);
|
TransTestMapper transMapper = Util.getTransMapper(TransTestMapper.class);
|
||||||
Student student = Builder.builder(Student::new)
|
Student student = Builder.builder(Student::new)
|
||||||
.with(Student::setName, "王小明2")
|
.with(Student::setName, "王小明2")
|
||||||
.with(Student::setAge, 10)
|
.with(Student::setAge, 10)
|
||||||
.with(Student::setSex, 1).build();
|
.with(Student::setSex, 1).build();
|
||||||
boolean b = transMapper.insertStudent(student);
|
boolean b = transMapper.insertStudent(student);
|
||||||
System.out.println(b);
|
System.out.println(b);
|
||||||
//boolean b1 = Util.rollbackTransMapper(TransTestMapper.class);
|
// boolean b1 = Util.rollbackTransMapper(TransTestMapper.class);
|
||||||
System.out.println(Util.commitTransMapper(TransTestMapper.class));
|
System.out.println(Util.commitTransMapper(TransTestMapper.class));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test1() {
|
public void test1() {
|
||||||
System.out.println(ValueRuleMethod.VALUE_RULE_FUNCTION.get(0).apply(
|
System.out.println(ValueRuleMethod.VALUE_RULE_FUNCTION.get(0).apply(
|
||||||
Builder.builder(SapConfigDetail::new)
|
Builder.builder(SapConfigDetail::new)
|
||||||
.with(SapConfigDetail::setCustomerValue, "哈哈哈")
|
.with(SapConfigDetail::setCustomerValue, "哈哈哈")
|
||||||
.build(),new HashMap<>()));
|
.build(), new HashMap<>()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void test2(){
|
public void test2() {
|
||||||
VoucherPayableService voucherPayableService = new VoucherPayableService();
|
VoucherPayableService voucherPayableService = new VoucherPayableService();
|
||||||
System.out.println(voucherPayableService.sendSapVoucher("testVoucher", "57058", "formtable_main_20"));
|
System.out.println(voucherPayableService.sendSapVoucher("testVoucher", "57058", "formtable_main_20"));
|
||||||
System.out.println(voucherPayableService.sendReceiptVoucher("testPayment", "57058", "formtable_main_20"));
|
System.out.println(voucherPayableService.sendReceiptVoucher("testPayment", "57058", "formtable_main_20"));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
@Test
|
public void createDoc() {
|
||||||
public void createDoc(){
|
GenerateFileUtil.createActionDocument(SendEmailToExternalPersonnelAction.class);
|
||||||
GenerateFileUtil.createActionDocument(SendEmailToExternalPersonnelAction.class);
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
@Test
|
public void testSplit() {
|
||||||
public void testSplit(){
|
String str = "ReferenceNo\tPayType\tPayAccNameCN\tPayAccNameEN\tRecAccNo\tRecAccNameCN\n" +
|
||||||
String str = "ReferenceNo\tPayType\tPayAccNameCN\tPayAccNameEN\tRecAccNo\tRecAccNameCN\n" +
|
"1\t234\taldkjf\t好的 啊\t不知道\t8382\n" +
|
||||||
"1\t234\taldkjf\t好的 啊\t不知道\t8382\n" +
|
"2\t283\t阿道夫\t也还是难过\t就啊u是的呢\t802\n" +
|
||||||
"2\t283\t阿道夫\t也还是难过\t就啊u是的呢\t802\n" +
|
"3\t7738\t看剧方\t加上撒u给你\t真个吧\t736\n" +
|
||||||
"3\t7738\t看剧方\t加上撒u给你\t真个吧\t736\n" +
|
"4\t83\t就啊啥地方\t纪念活动\t你先给你\t6383";
|
||||||
"4\t83\t就啊啥地方\t纪念活动\t你先给你\t6383";
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
@Test
|
||||||
@Test
|
public void testResUtil() {
|
||||||
public void testResUtil(){
|
TransTestMapper mapper = Util.getMapper(TransTestMapper.class);
|
||||||
TransTestMapper mapper = Util.getMapper(TransTestMapper.class);
|
System.out.println(mapper.selectStudent());
|
||||||
System.out.println(mapper.selectStudent());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testC() {
|
||||||
|
String uploadSapFileCharset = Util.getCusConfigDefaultValue("UPLOAD_SAP_FILE_CHARSET", "UTF-8");
|
||||||
|
System.out.println(uploadSapFileCharset);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void tesetRem() {
|
||||||
|
// RequestRemindBiz requestRemindBiz = new RequestRemindBiz(new User(111), 200202, 44, "submit");
|
||||||
|
// Map<String, Object> params = new HashMap<>();
|
||||||
|
// params.put("requestId", 197197);
|
||||||
|
// params.put("reminder", 90); // 提醒人
|
||||||
|
// params.put("workflowId", 44);
|
||||||
|
// params.put("submitType", "submit"); // 流程提交类型
|
||||||
|
// requestRemindBiz.requestRemind(params, RemindTypeEnum.CC);
|
||||||
|
// List<Map<String, Object>> list = new ArrayList<>();
|
||||||
|
// PoppupRemindInfoUtil poppupRemindInfoUtil = new PoppupRemindInfoUtil(true);
|
||||||
|
// Map map = new HashMap();
|
||||||
|
// map.put("userid", "" + 111);
|
||||||
|
// map.put("type", "0");
|
||||||
|
// map.put("logintype", "0");
|
||||||
|
// map.put("requestid", "" + 200201);
|
||||||
|
// map.put("requestname", "" + "2023-03-03-55666993437100");
|
||||||
|
// map.put("workflowid", "" + 44);
|
||||||
|
// map.put("creater", "" + 1);
|
||||||
|
// list.add(map);
|
||||||
|
// boolean b = poppupRemindInfoUtil.insertPoppupRemindInfo(list);
|
||||||
|
// System.out.println(b);
|
||||||
|
|
||||||
|
RequestOperationMsgManager manager = new RequestOperationMsgManager();
|
||||||
|
List<MsgEntity> operateMsg = manager.getOperateMsg("1213", MsgOperateType.OTHER);
|
||||||
|
operateMsg.get(2).getCurrentOperatorIdMap().put("111", "2700");
|
||||||
|
operateMsg.get(2).getUserId().add("111");
|
||||||
|
System.out.println(JSON.toJSONString(operateMsg));
|
||||||
|
new MsgPushUtil().pushMsg(operateMsg);
|
||||||
|
|
||||||
|
|
||||||
|
// MsgEntity msgEntity = new MsgEntity();
|
||||||
|
// // 流程抄送
|
||||||
|
// msgEntity.setMsgType(MessageType.WF_COPY);
|
||||||
|
// // 提醒类型为抄送
|
||||||
|
// msgEntity.setNoticeType(MsgNoticeType.CC);
|
||||||
|
// // 流程创建日期
|
||||||
|
// msgEntity.setCreateDate();
|
||||||
|
// // 流程创建时间
|
||||||
|
// msgEntity.setCreateTime();
|
||||||
|
// // 流程创建人
|
||||||
|
// msgEntity.setCreator();
|
||||||
|
// // 流程当前操作者map userId -> workflow_currentoperator.id
|
||||||
|
// msgEntity.setCurrentOperatorIdMap();
|
||||||
|
// // 当前时间 yyyy-MM-dd HH:mm:ss
|
||||||
|
// msgEntity.setDate();
|
||||||
|
// // 流程requestId
|
||||||
|
// msgEntity.setDetailId();
|
||||||
|
// // 流程标题
|
||||||
|
// msgEntity.setDetailName();
|
||||||
|
// // 流程标题
|
||||||
|
// msgEntity.setDetailTitle();
|
||||||
|
// // 当前操作者id
|
||||||
|
// msgEntity.setOperatorId();
|
||||||
|
// // 接受时间
|
||||||
|
// msgEntity.setReceiveDate();
|
||||||
|
// // 抄送用户id
|
||||||
|
// msgEntity.setUserId();
|
||||||
|
// new MsgPushUtil().pushMsg(Collections.singletonList(msgEntity));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testChar() {
|
||||||
|
System.out.println('\n');
|
||||||
|
System.out.println('\t');
|
||||||
|
System.out.println(' ');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue