Commit 63f98658 by inrgihc

支持对象参数

parent b668fd78
...@@ -24,6 +24,9 @@ ...@@ -24,6 +24,9 @@
- 支持接口的x-www-form-urlencoded和JSON入参格式 - 支持接口的x-www-form-urlencoded和JSON入参格式
> HTTP入参支持application/x-www-form-urlencoded及application/json等请求格式。 > HTTP入参支持application/x-www-form-urlencoded及application/json等请求格式。
- 接口入参出参支持基本、对象及对象等多种类型
> HTTP入参出参支持整型/浮点型/时间/日期/布尔/字符串/对象及对象等多种类型
- 支持自动生成在线接口文档功能 - 支持自动生成在线接口文档功能
> 基于swagger-ui提供自动生成在线接口文档功能。 > 基于swagger-ui提供自动生成在线接口文档功能。
...@@ -79,10 +82,7 @@ ...@@ -79,10 +82,7 @@
- (2) 支持接口的缓存配置功能 - (2) 支持接口的缓存配置功能
> 基于分布式缓存等构建支持接口的缓存配置功能。 > 基于分布式缓存等构建支持接口的缓存配置功能。
- (3) 接口入参支持对象及对象数组 - (3) 前端界面整体美化
> 接口入参支持对象及对象数组,方便批量插入数据及查询的排序等功能.
- (4) 前端界面整体美化
> 美化界面的交互展示,尤其是“拓扑结构”页面。 > 美化界面的交互展示,尤其是“拓扑结构”页面。
## 二、编译打包 ## 二、编译打包
......
...@@ -130,15 +130,15 @@ ...@@ -130,15 +130,15 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.baomidou</groupId> <groupId>org.mybatis</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId> <artifactId>mybatis</artifactId>
<version>3.5.4.1</version> <version>3.5.9</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>com.baomidou</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mybatis-plus-boot-starter</artifactId>
<version>5.1.47</version> <version>3.5.4.1</version>
</dependency> </dependency>
<dependency> <dependency>
......
package com.gitee.sqlrest.common.dto;
import com.gitee.sqlrest.common.enums.ParamLocationEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseParam implements Serializable {
@ApiModelProperty("ID(前端生成并使用)")
private String id;
@ApiModelProperty("参数名")
private String name;
@ApiModelProperty("参数类型")
private ParamTypeEnum type;
@ApiModelProperty("参数位置")
private ParamLocationEnum location;
@ApiModelProperty("是否为数组")
private Boolean isArray;
@ApiModelProperty("是否必填")
private Boolean required;
@ApiModelProperty("默认值")
private String defaultValue;
@ApiModelProperty("参数描述")
private String remark;
}
package com.gitee.sqlrest.common.dto; package com.gitee.sqlrest.common.dto;
import com.gitee.sqlrest.common.enums.ParamLocationEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum; import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import com.gitee.sqlrest.common.exception.CommonException;
import com.gitee.sqlrest.common.exception.ResponseErrorCode;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable; import java.util.Collections;
import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.apache.commons.lang3.StringUtils;
@Data @Data
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@ApiModel("入参信息") @ApiModel("入参信息")
public class ItemParam implements Serializable { public class ItemParam extends BaseParam {
@ApiModelProperty("参数名") @ApiModelProperty("Object类型的子元素")
private String name; private List<BaseParam> children;
@ApiModelProperty("参数位置") public boolean valid() {
private ParamLocationEnum location; if (StringUtils.isBlank(getName())) {
throw new CommonException(ResponseErrorCode.ERROR_INTERNAL_ERROR, "parameter name must is not blank");
@ApiModelProperty("参数类型") }
private ParamTypeEnum type; if (getType() == ParamTypeEnum.OBJECT) {
if (null != children && children.size() > 0) {
@ApiModelProperty("是否为数组") for (BaseParam param : children) {
private Boolean isArray; if (StringUtils.isBlank(param.getName())) {
throw new CommonException(ResponseErrorCode.ERROR_INTERNAL_ERROR, "parameter name must is not blank");
@ApiModelProperty("是否必填") }
private Boolean required; }
return true;
@ApiModelProperty("默认值") }
private String defaultValue; } else {
children = Collections.emptyList();
@ApiModelProperty("参数描述") }
private String remark;
return false;
}
} }
...@@ -4,6 +4,7 @@ import com.gitee.sqlrest.common.enums.ParamTypeEnum; ...@@ -4,6 +4,7 @@ import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable; import java.io.Serializable;
import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
...@@ -14,12 +15,21 @@ import lombok.NoArgsConstructor; ...@@ -14,12 +15,21 @@ import lombok.NoArgsConstructor;
@ApiModel("出参信息") @ApiModel("出参信息")
public class OutParam implements Serializable { public class OutParam implements Serializable {
@ApiModelProperty("ID(前端生成并使用)")
private String id;
@ApiModelProperty("参数名") @ApiModelProperty("参数名")
private String name; private String name;
@ApiModelProperty("参数类型") @ApiModelProperty("参数类型")
private ParamTypeEnum type; private ParamTypeEnum type;
@ApiModelProperty("是否为数组")
private Boolean isArray;
@ApiModelProperty("参数描述") @ApiModelProperty("参数描述")
private String remark; private String remark;
@ApiModelProperty("Object类型的子元素")
private List<OutParam> children;
} }
...@@ -2,6 +2,7 @@ package com.gitee.sqlrest.common.dto; ...@@ -2,6 +2,7 @@ package com.gitee.sqlrest.common.dto;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
...@@ -10,8 +11,17 @@ import lombok.NoArgsConstructor; ...@@ -10,8 +11,17 @@ import lombok.NoArgsConstructor;
@AllArgsConstructor @AllArgsConstructor
@NoArgsConstructor @NoArgsConstructor
@ApiModel("参数信息") @ApiModel("参数信息")
public class ParamValue extends ItemParam { public class ParamValue extends BaseParam {
@ApiModelProperty("Object类型的子元素及值")
private List<BaseParamValue> children;
@ApiModelProperty("参数值") @ApiModelProperty("参数值")
private String value; private String value;
@Data
public static class BaseParamValue extends BaseParam {
private String value;
}
} }
package com.gitee.sqlrest.common.enums; package com.gitee.sqlrest.common.enums;
import java.util.Map;
import java.util.function.Function; import java.util.function.Function;
import lombok.Getter; import lombok.Getter;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
...@@ -11,7 +12,8 @@ public enum ParamTypeEnum { ...@@ -11,7 +12,8 @@ public enum ParamTypeEnum {
STRING("字符串", "string", "", String.class, (String str) -> str), STRING("字符串", "string", "", String.class, (String str) -> str),
DATE("日期", "string", "", String.class, (String str) -> str), DATE("日期", "string", "", String.class, (String str) -> str),
TIME("时间", "string", "", String.class, (String str) -> str), TIME("时间", "string", "", String.class, (String str) -> str),
BOOLEAN("布尔", "string", "true", Boolean.class, (String str) -> Boolean.parseBoolean(str)); BOOLEAN("布尔", "string", "true", Boolean.class, (String str) -> Boolean.parseBoolean(str)),
OBJECT("对象", "object", "{}", Map.class, s -> s);
private String name; private String name;
private String jsType; private String jsType;
...@@ -26,4 +28,8 @@ public enum ParamTypeEnum { ...@@ -26,4 +28,8 @@ public enum ParamTypeEnum {
this.clazz = clazz; this.clazz = clazz;
this.converter = converter; this.converter = converter;
} }
public boolean isObject() {
return OBJECT == this;
}
} }
...@@ -2,6 +2,8 @@ package com.gitee.sqlrest.core.dto; ...@@ -2,6 +2,8 @@ package com.gitee.sqlrest.core.dto;
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty; import io.swagger.annotations.ApiModelProperty;
import java.util.LinkedList;
import java.util.List;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.Data; import lombok.Data;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
...@@ -17,4 +19,13 @@ public class SqlParamParseResponse { ...@@ -17,4 +19,13 @@ public class SqlParamParseResponse {
@ApiModelProperty("是否为数组") @ApiModelProperty("是否为数组")
private Boolean isArray; private Boolean isArray;
@ApiModelProperty("Object类型的子元素")
private List<SqlParamParseResponse> children;
public SqlParamParseResponse(String name, Boolean isArray) {
this.name = name;
this.isArray = isArray;
this.children = new LinkedList<>();
}
} }
...@@ -65,7 +65,7 @@ public class ApiExecuteService { ...@@ -65,7 +65,7 @@ public class ApiExecuteService {
List<Object> results = ApiExecutorEngineFactory List<Object> results = ApiExecutorEngineFactory
.getExecutor(config.getEngine(), dataSource, dsEntity.getType()) .getExecutor(config.getEngine(), dataSource, dsEntity.getType())
.execute(config.getContextList(), paramValues, config.getNamingStrategy()); .execute(config.getContextList(), paramValues, config.getNamingStrategy());
return ResultEntity.success(results.size() > 1 ? results : results.get(0)); return ResultEntity.success(results.size() > 1 ? results : results.stream().findAny().orElse(null));
} catch (Throwable t) { } catch (Throwable t) {
return ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, ExceptionUtil.getMessage(t)); return ResultEntity.failed(ResponseErrorCode.ERROR_INTERNAL_ERROR, ExceptionUtil.getMessage(t));
} }
...@@ -98,7 +98,7 @@ public class ApiExecuteService { ...@@ -98,7 +98,7 @@ public class ApiExecuteService {
.collect(Collectors.toList()); .collect(Collectors.toList());
if (isArray) { if (isArray) {
if (CollectionUtils.isEmpty(hv)) { if (CollectionUtils.isEmpty(hv)) {
if(required) { if (required) {
invalidArgs.add(param); invalidArgs.add(param);
} }
} else { } else {
...@@ -130,15 +130,26 @@ public class ApiExecuteService { ...@@ -130,15 +130,26 @@ public class ApiExecuteService {
List<Object> values = (paramValue instanceof List) List<Object> values = (paramValue instanceof List)
? (List) paramValue ? (List) paramValue
: Lists.newArrayList(paramValue); : Lists.newArrayList(paramValue);
List<Object> hv = values if (type.isObject()) {
.stream().map(v -> type.getConverter().apply(v.toString())) map.put(name, values);
.collect(Collectors.toList()); } else {
map.put(name, hv); List<Object> hv = values
.stream().map(v -> type.getConverter().apply(v.toString()))
.collect(Collectors.toList());
map.put(name, hv);
}
} else { } else {
Object targetValue = (paramValue instanceof List) if (type.isObject()) {
? ((List) paramValue).get(0) Map<String, Object> objectMap = (paramValue instanceof Map)
: paramValue; ? (Map<String, Object>) paramValue
map.put(name, type.getConverter().apply(targetValue.toString())); : new HashMap<>();
map.put(name, objectMap);
} else {
Object targetValue = (paramValue instanceof List)
? ((List) paramValue).get(0)
: paramValue;
map.put(name, type.getConverter().apply(targetValue.toString()));
}
} }
} }
} else { } else {
...@@ -150,7 +161,7 @@ public class ApiExecuteService { ...@@ -150,7 +161,7 @@ public class ApiExecuteService {
.collect(Collectors.toList()); .collect(Collectors.toList());
map.put(name, list); map.put(name, list);
} else { } else {
if(required) { if (required) {
invalidArgs.add(param); invalidArgs.add(param);
} }
} }
......
...@@ -6,9 +6,8 @@ import com.gitee.sqlrest.core.exec.engine.AbstractExecutorEngine; ...@@ -6,9 +6,8 @@ import com.gitee.sqlrest.core.exec.engine.AbstractExecutorEngine;
import com.gitee.sqlrest.core.util.PageSizeUtils; import com.gitee.sqlrest.core.util.PageSizeUtils;
import com.gitee.sqlrest.core.util.SqlJdbcUtils; import com.gitee.sqlrest.core.util.SqlJdbcUtils;
import com.gitee.sqlrest.persistence.entity.ApiContextEntity; import com.gitee.sqlrest.persistence.entity.ApiContextEntity;
import com.gitee.sqlrest.template.Configuration;
import com.gitee.sqlrest.template.SqlMeta; import com.gitee.sqlrest.template.SqlMeta;
import com.gitee.sqlrest.template.SqlTemplate; import com.gitee.sqlrest.template.XmlSqlTemplate;
import com.zaxxer.hikari.HikariDataSource; import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
...@@ -27,12 +26,11 @@ public class SqlExecutorService extends AbstractExecutorEngine { ...@@ -27,12 +26,11 @@ public class SqlExecutorService extends AbstractExecutorEngine {
@Override @Override
public List<Object> execute(List<ApiContextEntity> scripts, Map<String, Object> params, NamingStrategyEnum strategy) { public List<Object> execute(List<ApiContextEntity> scripts, Map<String, Object> params, NamingStrategyEnum strategy) {
List<Object> dataList = new ArrayList<>(); List<Object> dataList = new ArrayList<>();
Configuration cfg = new Configuration();
try (Connection connection = this.dataSource.getConnection()) { try (Connection connection = this.dataSource.getConnection()) {
try { try {
connection.setAutoCommit(false); connection.setAutoCommit(false);
for (ApiContextEntity sql : scripts) { for (ApiContextEntity sql : scripts) {
SqlTemplate template = cfg.getTemplate(sql.getSqlText()); XmlSqlTemplate template = new XmlSqlTemplate(sql.getSqlText());
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
int page = PageSizeUtils.getPageFromParams(params); int page = PageSizeUtils.getPageFromParams(params);
int size = PageSizeUtils.getSizeFromParams(params); int size = PageSizeUtils.getSizeFromParams(params);
......
...@@ -7,9 +7,8 @@ import com.gitee.sqlrest.core.exec.annotation.Comment; ...@@ -7,9 +7,8 @@ import com.gitee.sqlrest.core.exec.annotation.Comment;
import com.gitee.sqlrest.core.exec.annotation.Module; import com.gitee.sqlrest.core.exec.annotation.Module;
import com.gitee.sqlrest.core.util.ConvertUtils; import com.gitee.sqlrest.core.util.ConvertUtils;
import com.gitee.sqlrest.core.util.PageSizeUtils; import com.gitee.sqlrest.core.util.PageSizeUtils;
import com.gitee.sqlrest.template.Configuration;
import com.gitee.sqlrest.template.SqlMeta; import com.gitee.sqlrest.template.SqlMeta;
import com.gitee.sqlrest.template.SqlTemplate; import com.gitee.sqlrest.template.XmlSqlTemplate;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
...@@ -33,8 +32,6 @@ import org.springframework.jdbc.support.GeneratedKeyHolder; ...@@ -33,8 +32,6 @@ import org.springframework.jdbc.support.GeneratedKeyHolder;
@Module("db") @Module("db")
public class DbVarModule { public class DbVarModule {
private static Configuration cfg = new Configuration();
private JdbcTemplate jdbcTemplate; private JdbcTemplate jdbcTemplate;
private ProductTypeEnum productType; private ProductTypeEnum productType;
private Map<String, Object> params; private Map<String, Object> params;
...@@ -63,7 +60,7 @@ public class DbVarModule { ...@@ -63,7 +60,7 @@ public class DbVarModule {
@Comment("查询所有的数据列表") @Comment("查询所有的数据列表")
public List<Map<String, Object>> selectAll(@Comment("sqlOrXml") String sqlOrXml) throws SQLException { public List<Map<String, Object>> selectAll(@Comment("sqlOrXml") String sqlOrXml) throws SQLException {
log.info("Enter selectAll() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter selectAll() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); XmlSqlTemplate template = new XmlSqlTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
try { try {
...@@ -76,7 +73,7 @@ public class DbVarModule { ...@@ -76,7 +73,7 @@ public class DbVarModule {
@Comment("count所有数据的总数") @Comment("count所有数据的总数")
public Integer selectCount(@Comment("sqlOrXml") String sqlOrXml) { public Integer selectCount(@Comment("sqlOrXml") String sqlOrXml) {
log.info("Enter selectCount() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter selectCount() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); XmlSqlTemplate template = new XmlSqlTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
String countSql = String.format("select count(*) from (%s) a", sqlMeta.getSql()); String countSql = String.format("select count(*) from (%s) a", sqlMeta.getSql());
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
...@@ -90,7 +87,7 @@ public class DbVarModule { ...@@ -90,7 +87,7 @@ public class DbVarModule {
@Comment("查询单条结果,并传入变量信息,查不到返回null") @Comment("查询单条结果,并传入变量信息,查不到返回null")
public Map<String, Object> selectOne(@Comment("sqlOrXml") String sqlOrXml) { public Map<String, Object> selectOne(@Comment("sqlOrXml") String sqlOrXml) {
log.info("Enter selectOne() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter selectOne() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); XmlSqlTemplate template = new XmlSqlTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
try { try {
...@@ -118,7 +115,7 @@ public class DbVarModule { ...@@ -118,7 +115,7 @@ public class DbVarModule {
log.info("Enter page() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter page() function, SQL:{},params:{}", sqlOrXml, params);
int page = PageSizeUtils.getPageFromParams(params); int page = PageSizeUtils.getPageFromParams(params);
int size = PageSizeUtils.getSizeFromParams(params); int size = PageSizeUtils.getSizeFromParams(params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); XmlSqlTemplate template = new XmlSqlTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
String pageSql = productType.getPageSql(sqlMeta.getSql(), page, size); String pageSql = productType.getPageSql(sqlMeta.getSql(), page, size);
List<Object> parameters = sqlMeta.getParameter(); List<Object> parameters = sqlMeta.getParameter();
...@@ -127,14 +124,14 @@ public class DbVarModule { ...@@ -127,14 +124,14 @@ public class DbVarModule {
try { try {
return build(jdbcTemplate.queryForList(pageSql, parameters.toArray())); return build(jdbcTemplate.queryForList(pageSql, parameters.toArray()));
} finally { } finally {
SqlExecuteLogger.add(sqlMeta.getSql(), parameters, System.currentTimeMillis() - start); SqlExecuteLogger.add(pageSql, parameters, System.currentTimeMillis() - start);
} }
} }
@Comment("执行insert操作,返回插入主键") @Comment("执行insert操作,返回插入主键")
public Map<String, Object> insert(@Comment("sqlOrXml") String sqlOrXml) { public Map<String, Object> insert(@Comment("sqlOrXml") String sqlOrXml) {
log.info("Enter insert() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter insert() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); XmlSqlTemplate template = new XmlSqlTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
List<Object> parameters = sqlMeta.getParameter(); List<Object> parameters = sqlMeta.getParameter();
GeneratedKeyHolder keyHolder = new GeneratedKeyHolder(); GeneratedKeyHolder keyHolder = new GeneratedKeyHolder();
...@@ -156,7 +153,7 @@ public class DbVarModule { ...@@ -156,7 +153,7 @@ public class DbVarModule {
@Comment("执行update操作,返回受影响行数") @Comment("执行update操作,返回受影响行数")
public int update(@Comment("sqlOrXml") String sqlOrXml) { public int update(@Comment("sqlOrXml") String sqlOrXml) {
log.info("Enter update() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter update() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); XmlSqlTemplate template = new XmlSqlTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
List<Object> parameters = sqlMeta.getParameter(); List<Object> parameters = sqlMeta.getParameter();
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
...@@ -182,7 +179,7 @@ public class DbVarModule { ...@@ -182,7 +179,7 @@ public class DbVarModule {
@Comment("执行delete操作,返回受影响行数") @Comment("执行delete操作,返回受影响行数")
public int delete(@Comment("sqlOrXml") String sqlOrXml) { public int delete(@Comment("sqlOrXml") String sqlOrXml) {
log.info("Enter update() function, SQL:{},params:{}", sqlOrXml, params); log.info("Enter update() function, SQL:{},params:{}", sqlOrXml, params);
SqlTemplate template = cfg.getTemplate(sqlOrXml); XmlSqlTemplate template = new XmlSqlTemplate(sqlOrXml);
SqlMeta sqlMeta = template.process(params); SqlMeta sqlMeta = template.process(params);
List<Object> parameters = sqlMeta.getParameter(); List<Object> parameters = sqlMeta.getParameter();
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
......
package com.gitee.sqlrest.core.servlet; package com.gitee.sqlrest.core.servlet;
import com.gitee.sqlrest.common.consts.Constants; import com.gitee.sqlrest.common.consts.Constants;
import com.gitee.sqlrest.common.dto.BaseParam;
import com.gitee.sqlrest.common.dto.ItemParam; import com.gitee.sqlrest.common.dto.ItemParam;
import com.gitee.sqlrest.common.enums.HttpMethodEnum; import com.gitee.sqlrest.common.enums.HttpMethodEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum; import com.gitee.sqlrest.common.enums.ParamTypeEnum;
...@@ -170,10 +171,43 @@ public class ApiSwaggerService { ...@@ -170,10 +171,43 @@ public class ApiSwaggerService {
Schema schema = new Schema().type(type.getJsType()); Schema schema = new Schema().type(type.getJsType());
if (param.getIsArray()) { if (param.getIsArray()) {
ArraySchema arraySchema = new ArraySchema().items(schema); if (type.isObject()) {
objectSchema.addProperties(param.getName(), arraySchema); Schema subObjectSchema = new ObjectSchema().name(param.getName());
if (null != param.getChildren()) {
for (BaseParam baseParam : param.getChildren()) {
Schema subSchema = new Schema().type(baseParam.getType().getJsType());
if (Optional.ofNullable(baseParam.getIsArray()).orElse(false)) {
ArraySchema subArraySchema = new ArraySchema().items(subSchema);
subObjectSchema.addProperties(baseParam.getName(), subArraySchema);
} else {
subObjectSchema.addProperties(baseParam.getName(), subSchema);
}
}
}
ArraySchema arraySchema = new ArraySchema().items(subObjectSchema);
objectSchema.addProperties(param.getName(), arraySchema);
} else {
ArraySchema arraySchema = new ArraySchema().items(schema);
objectSchema.addProperties(param.getName(), arraySchema);
}
} else { } else {
objectSchema.addProperties(param.getName(), schema); if (type.isObject()) {
Schema subObjectSchema = new ObjectSchema().name(param.getName());
if (null != param.getChildren()) {
for (BaseParam baseParam : param.getChildren()) {
Schema subSchema = new Schema().type(baseParam.getType().getJsType());
if (Optional.ofNullable(baseParam.getIsArray()).orElse(false)) {
ArraySchema subArraySchema = new ArraySchema().items(subSchema);
subObjectSchema.addProperties(baseParam.getName(), subArraySchema);
} else {
subObjectSchema.addProperties(baseParam.getName(), subSchema);
}
}
}
objectSchema.addProperties(param.getName(), subObjectSchema);
} else {
objectSchema.addProperties(param.getName(), schema);
}
} }
} }
......
...@@ -7,7 +7,7 @@ import java.util.function.Function; ...@@ -7,7 +7,7 @@ import java.util.function.Function;
public class ConvertUtils { public class ConvertUtils {
public static Map<String, Object> to(Map<String, Object> row) { public static Map<String, Object> to(Map<String, Object> row) {
return row; return to(row, null);
} }
public static Map<String, Object> to(Map<String, Object> row, Function<String, String> converter) { public static Map<String, Object> to(Map<String, Object> row, Function<String, String> converter) {
......
...@@ -5,18 +5,24 @@ import com.fasterxml.jackson.databind.Module; ...@@ -5,18 +5,24 @@ import com.fasterxml.jackson.databind.Module;
import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule; import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer; import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.gitee.sqlrest.common.dto.OutParam;
import com.gitee.sqlrest.common.enums.DataTypeFormatEnum; import com.gitee.sqlrest.common.enums.DataTypeFormatEnum;
import com.gitee.sqlrest.common.enums.ParamTypeEnum; import com.gitee.sqlrest.common.enums.ParamTypeEnum;
import com.gitee.sqlrest.common.util.UuidUtils;
import com.gitee.sqlrest.core.serdes.DateTimeSerDesFactory; import com.gitee.sqlrest.core.serdes.DateTimeSerDesFactory;
import com.google.common.collect.Lists;
import java.math.BigInteger; import java.math.BigInteger;
import java.sql.Time; import java.sql.Time;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.Date; import java.util.Date;
import java.util.LinkedHashMap; import java.util.LinkedList;
import java.util.List;
import java.util.Map; import java.util.Map;
import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
public final class JacksonUtils { public final class JacksonUtils {
...@@ -48,38 +54,41 @@ public final class JacksonUtils { ...@@ -48,38 +54,41 @@ public final class JacksonUtils {
return module; return module;
} }
public static Map<String, ParamTypeEnum> parseFieldTypes(Object obj) { public static List<OutParam> parseFieldTypes(Object obj) {
Map<String, ParamTypeEnum> results = new LinkedHashMap<>(); List<OutParam> results = new LinkedList<>();
if (null == obj) { if (null == obj) {
return results; return results;
} }
if (obj instanceof Map) { if (obj instanceof Map) {
parseFieldTypes("", (Map) obj, results); parseFieldTypes(null, (Map) obj, results);
} else if (obj instanceof Collection) { } else if (obj instanceof Collection) {
Collection collection = (Collection) obj; Collection collection = (Collection) obj;
if (CollectionUtils.isEmpty(collection)) { if (CollectionUtils.isEmpty(collection)) {
return results; return results;
} }
Object item = collection.stream().findFirst().get(); for (Object item : collection) {
if (item instanceof Map) { if (item instanceof Map) {
parseFieldTypes("", (Map) item, results); parseFieldTypes(null, (Map) item, results);
} else if (item instanceof Collection) { } else if (item instanceof Collection) {
Collection subCollection = (Collection) item; Collection subCollection = (Collection) item;
if (CollectionUtils.isEmpty(subCollection)) { if (CollectionUtils.isEmpty(subCollection)) {
return results;
}
Object subItem = subCollection.stream().findFirst().get();
if (subItem instanceof Map) {
parseFieldTypes("", (Map) subItem, results);
} else if (subItem instanceof Collection) {
Collection thSubCollection = (Collection) subItem;
if (CollectionUtils.isEmpty(thSubCollection)) {
return results; return results;
} }
Object thSubItem = thSubCollection.stream().findFirst().get(); for (Object subItem : subCollection) {
if (thSubItem instanceof Map) { if (subItem instanceof Map) {
parseFieldTypes("", (Map) thSubItem, results); parseFieldTypes(null, (Map) subItem, results);
} else if (subItem instanceof Collection) {
Collection thSubCollection = (Collection) subItem;
if (CollectionUtils.isEmpty(thSubCollection)) {
return results;
}
for (Object thSubItem : thSubCollection) {
if (thSubItem instanceof Map) {
parseFieldTypes(null, (Map) thSubItem, results);
}
}
}
} }
} }
} }
...@@ -87,25 +96,35 @@ public final class JacksonUtils { ...@@ -87,25 +96,35 @@ public final class JacksonUtils {
return results; return results;
} }
private static void parseFieldTypes(String prefix, Map<String, Object> map, Map<String, ParamTypeEnum> results) { private static void parseFieldTypes(OutParam parent, Map<String, Object> map, List<OutParam> results) {
for (String name : map.keySet()) { for (String name : map.keySet()) {
Object value = map.get(name); Object value = map.get(name);
boolean isArray = (value instanceof Collection);
ParamTypeEnum typeEnum = parseValueType(value); ParamTypeEnum typeEnum = parseValueType(value);
if (null != typeEnum) { String id = UuidUtils.generateUuid();
// TODO: 暂时先忽略不支持的对象的情况 OutParam outParam = new OutParam(id, name, typeEnum, isArray, null, Lists.newArrayList());
if (StringUtils.isBlank(prefix)) { if (isArray) {
results.put(name, typeEnum); outParam.setType(parseValueType(((Collection) value).stream().findFirst().orElse(null)));
} else { }
results.put(prefix + "." + name, typeEnum); if (null == parent) {
if (results.stream().noneMatch(one -> name.equals(one.getName()))) {
results.add(outParam);
}
} else {
if (parent.getChildren().stream().noneMatch(one -> name.equals(one.getName()))) {
parent.getChildren().add(outParam);
} }
} }
String subPrefix = StringUtils.isBlank(prefix) ? name : prefix + "." + name;
if (value instanceof Map) { if (isArray) {
parseFieldTypes(subPrefix, (Map) value, results);
} else if (value instanceof Collection) {
Collection collection = (Collection) value; Collection collection = (Collection) value;
Object item = collection.stream().findFirst().get(); Object item = collection.stream().findFirst().get();
parseFieldTypes(subPrefix, (Map) item, results); ParamTypeEnum subTypeEnum = parseValueType(item);
if (null != subTypeEnum && subTypeEnum.isObject()) {
parseFieldTypes(outParam, (Map) item, results);
}
} else if (value instanceof Map) {
parseFieldTypes(outParam, (Map) value, results);
} }
} }
} }
...@@ -117,13 +136,16 @@ public final class JacksonUtils { ...@@ -117,13 +136,16 @@ public final class JacksonUtils {
return ParamTypeEnum.LONG; return ParamTypeEnum.LONG;
} else if (value instanceof Number) { } else if (value instanceof Number) {
return ParamTypeEnum.DOUBLE; return ParamTypeEnum.DOUBLE;
} else if (value instanceof Time) { } else if (value instanceof Time || value instanceof Timestamp || value instanceof LocalDateTime) {
return ParamTypeEnum.TIME; return ParamTypeEnum.TIME;
} else if (value instanceof Date) { } else if (value instanceof Date || value instanceof LocalDate) {
return ParamTypeEnum.DATE; return ParamTypeEnum.DATE;
} else if (value instanceof String) { } else if (value instanceof String) {
return ParamTypeEnum.STRING; return ParamTypeEnum.STRING;
} else if (value instanceof Map) {
return ParamTypeEnum.OBJECT;
} else { } else {
// List的情况返回null
return null; return null;
} }
} }
......
...@@ -71,7 +71,7 @@ ...@@ -71,7 +71,7 @@
</div> </div>
<el-tabs v-if="showDetail" <el-tabs v-if="showDetail"
type="border-card"> type="border-card">
<el-tab-pane label="接口文档"> <el-tab-pane label="接口定义">
<el-row class="detail-row"> <el-row class="detail-row">
<el-col :span="4"> <el-col :span="4">
<i class="el-icon-user">接口名称:</i> <i class="el-icon-user">接口名称:</i>
...@@ -102,7 +102,7 @@ ...@@ -102,7 +102,7 @@
</el-row> </el-row>
<el-row class="detail-row"> <el-row class="detail-row">
<el-col :span="4"> <el-col :span="4">
<i class="el-icon-s-check">需要认证:</i> <i class="el-icon-s-check">访问认证:</i>
</el-col> </el-col>
<el-col :span="20"> <el-col :span="20">
<el-tag size="small" <el-tag size="small"
...@@ -126,43 +126,46 @@ ...@@ -126,43 +126,46 @@
<el-table :data="interfaceDetail.inputParams" <el-table :data="interfaceDetail.inputParams"
:header-cell-style="{background:'#eef1f6',color:'#606266'}" :header-cell-style="{background:'#eef1f6',color:'#606266'}"
size="mini" size="mini"
default-expand-all
row-key="id"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
border> border>
<template slot="empty"> <template slot="empty">
<span>请求参数为空</span> <span>请求参数为空</span>
</template> </template>
<el-table-column label="参数名" <el-table-column label="参数名"
prop="name" prop="name"
min-width="25%"> min-width="40%">
</el-table-column> </el-table-column>
<el-table-column label="参数位置" <el-table-column label="参数位置"
prop="location" prop="location"
min-width="25%"> min-width="15%">
<template slot-scope="scope"> <template slot-scope="scope">
{{enumTypeLocationFormat(scope.row.location)}} {{enumTypeLocationFormat(scope.row.location)}}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="参数类型" <el-table-column label="参数类型"
prop="type" prop="type"
min-width="25%"> min-width="15%">
<template slot-scope="scope"> <template slot-scope="scope">
{{enumTypeValueFormat(scope.row.type)}} {{enumTypeValueFormat(scope.row.type)}}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="数组" <el-table-column label="数组"
min-width="25%"> min-width="15%">
<template slot-scope="scope"> <template slot-scope="scope">
{{boolTypeFormat(scope.row.isArray)}} {{boolTypeFormat(scope.row.isArray)}}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="必填" <el-table-column label="必填"
min-width="25%"> min-width="15%">
<template slot-scope="scope"> <template slot-scope="scope">
{{boolTypeFormat(scope.row.required)}} {{boolTypeFormat(scope.row.required)}}
</template> </template>
</el-table-column> </el-table-column>
<el-table-column label="默认值" <el-table-column label="默认值"
prop="defaultValue" prop="defaultValue"
min-width="25%"> min-width="20%">
<template slot-scope="scope"> <template slot-scope="scope">
{{scope.row.defaultValue}} {{scope.row.defaultValue}}
</template> </template>
...@@ -185,6 +188,9 @@ ...@@ -185,6 +188,9 @@
<el-table :data="interfaceDetail.outputParams" <el-table :data="interfaceDetail.outputParams"
:header-cell-style="{background:'#eef1f6',color:'#606266'}" :header-cell-style="{background:'#eef1f6',color:'#606266'}"
size="mini" size="mini"
default-expand-all
row-key="id"
:tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
border> border>
<template slot="empty"> <template slot="empty">
<span>响应参数为空</span> <span>响应参数为空</span>
...@@ -259,7 +265,7 @@ ...@@ -259,7 +265,7 @@
</div> </div>
</el-card> </el-card>
</template> </template>
<script> <script>
import '@/assets/sysicon/iconfont.js' import '@/assets/sysicon/iconfont.js'
...@@ -276,7 +282,8 @@ export default { ...@@ -276,7 +282,8 @@ export default {
{ name: "浮点型", value: "DOUBLE" }, { name: "浮点型", value: "DOUBLE" },
{ name: "字符串", value: "STRING" }, { name: "字符串", value: "STRING" },
{ name: "日期", value: "DATE" }, { name: "日期", value: "DATE" },
{ name: "时间", value: "TIME" } { name: "时间", value: "TIME" },
{ name: "对象", value: "OBJECT" }
], ],
leftWidth: 0, // 左边div的初始宽度 leftWidth: 0, // 左边div的初始宽度
rightWidth: 0, // 右边div的初始宽度 rightWidth: 0, // 右边div的初始宽度
...@@ -509,7 +516,7 @@ export default { ...@@ -509,7 +516,7 @@ export default {
dataSourceId: detail.datasourceId, dataSourceId: detail.datasourceId,
engine: detail.engine, engine: detail.engine,
inputParams: detail.params, inputParams: detail.params,
outputParams: detail.outputs, outputParams: detail.outputs || [],
} }
} }
}); });
...@@ -557,7 +564,7 @@ export default { ...@@ -557,7 +564,7 @@ export default {
return item.name; return item.name;
} }
} }
return returnUnknownValue(); return this.returnUnknownValue();
}, },
enumTypeValueFormat (value) { enumTypeValueFormat (value) {
for (const item of this.paramTypeList) { for (const item of this.paramTypeList) {
...@@ -565,12 +572,12 @@ export default { ...@@ -565,12 +572,12 @@ export default {
return item.name; return item.name;
} }
} }
return returnUnknownValue(); return this.returnUnknownValue();
} }
}, },
}; };
</script> </script>
<style scoped> <style scoped>
.el-card { .el-card {
width: 100%; width: 100%;
...@@ -616,6 +623,4 @@ export default { ...@@ -616,6 +623,4 @@ export default {
font-size: 13px; font-size: 13px;
padding: 2px; padding: 2px;
} }
</style>
</style>
\ No newline at end of file
<!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>SQLREST工具</title><link href=/static/css/app.8f318ec480f6f58990bbc607de49592a.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.d2c25b0f76d62e67169a.js></script><script type=text/javascript src=/static/js/vendor.6bde4750a07bb5a2f647.js></script><script type=text/javascript src=/static/js/app.5b13ca32f61140a99ff5.js></script></body></html> <!DOCTYPE html><html><head><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><title>SQLREST工具</title><link href=/static/css/app.f2a15a0e03018d8441776c4304ddc3b9.css rel=stylesheet></head><body><div id=app></div><script type=text/javascript src=/static/js/manifest.d057b7936f48fb6e72f1.js></script><script type=text/javascript src=/static/js/vendor.6bde4750a07bb5a2f647.js></script><script type=text/javascript src=/static/js/app.5b13ca32f61140a99ff5.js></script></body></html>
\ No newline at end of file \ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,f,a){for(var c,d,i,u=0,b=[];u<r.length;u++)d=r[u],t[d]&&b.push(t[d][0]),t[d]=0;for(c in f)Object.prototype.hasOwnProperty.call(f,c)&&(e[c]=f[c]);for(n&&n(r,f,a);b.length;)b.shift()();if(a)for(u=0;u<a.length;u++)i=o(o.s=a[u]);return i};var r={},t={24:0};function o(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,o),t.l=!0,t.exports}o.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,o){n=t[e]=[r,o]});n[2]=r;var f=document.getElementsByTagName("head")[0],a=document.createElement("script");a.type="text/javascript",a.charset="utf-8",a.async=!0,a.timeout=12e4,o.nc&&a.setAttribute("nonce",o.nc),a.src=o.p+"static/js/"+e+"."+{0:"e9559647b804220c4683",1:"b17200cccd46e216dcb3",2:"140338f6a5528feea1a3",3:"776d791724a8de12ff9e",4:"f8494b8dd039413f79c8",5:"8fcbb35b45285576e78f",6:"8f85de06573e2a5f9562",7:"061807fe4716131f26f8",8:"d1391c270de5a9f111c5",9:"cbdb7fa4f5180acfbb03",10:"7eeaa94fd42d34a86b92",11:"096c0f0eaf2850056b7e",12:"da6814989fe7ae4e141f",13:"4d2138ee1bee3ad573f4",14:"429592868e75adc95933",15:"3b3f0c03ff4fed9903cc",16:"9616cfe0a4f7517b0841",17:"b4bc5fa31e227bee8651",18:"5e7f065a8d031847e833",19:"3936346cb7e30aa279e2",20:"5ef9c751035ee9a08f94",21:"d8007e7169c085e13dab"}[e]+".js";var c=setTimeout(d,12e4);function d(){a.onerror=a.onload=null,clearTimeout(c);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return a.onerror=a.onload=d,f.appendChild(a),r},o.m=e,o.c=r,o.d=function(e,n,r){o.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="/",o.oe=function(e){throw console.error(e),e}}([]);
//# sourceMappingURL=manifest.d057b7936f48fb6e72f1.js.map
\ No newline at end of file
!function(e){var n=window.webpackJsonp;window.webpackJsonp=function(r,o,a){for(var f,d,i,u=0,b=[];u<r.length;u++)d=r[u],t[d]&&b.push(t[d][0]),t[d]=0;for(f in o)Object.prototype.hasOwnProperty.call(o,f)&&(e[f]=o[f]);for(n&&n(r,o,a);b.length;)b.shift()();if(a)for(u=0;u<a.length;u++)i=c(c.s=a[u]);return i};var r={},t={24:0};function c(n){if(r[n])return r[n].exports;var t=r[n]={i:n,l:!1,exports:{}};return e[n].call(t.exports,t,t.exports,c),t.l=!0,t.exports}c.e=function(e){var n=t[e];if(0===n)return new Promise(function(e){e()});if(n)return n[2];var r=new Promise(function(r,c){n=t[e]=[r,c]});n[2]=r;var o=document.getElementsByTagName("head")[0],a=document.createElement("script");a.type="text/javascript",a.charset="utf-8",a.async=!0,a.timeout=12e4,c.nc&&a.setAttribute("nonce",c.nc),a.src=c.p+"static/js/"+e+"."+{0:"32a67c5cdba64a33f31c",1:"b17200cccd46e216dcb3",2:"140338f6a5528feea1a3",3:"776d791724a8de12ff9e",4:"f8494b8dd039413f79c8",5:"8fcbb35b45285576e78f",6:"8f85de06573e2a5f9562",7:"061807fe4716131f26f8",8:"d1391c270de5a9f111c5",9:"cbdb7fa4f5180acfbb03",10:"7eeaa94fd42d34a86b92",11:"096c0f0eaf2850056b7e",12:"85287d948c440f963d32",13:"4d2138ee1bee3ad573f4",14:"429592868e75adc95933",15:"3b3f0c03ff4fed9903cc",16:"9616cfe0a4f7517b0841",17:"b4bc5fa31e227bee8651",18:"5e7f065a8d031847e833",19:"3936346cb7e30aa279e2",20:"5ef9c751035ee9a08f94",21:"d8007e7169c085e13dab"}[e]+".js";var f=setTimeout(d,12e4);function d(){a.onerror=a.onload=null,clearTimeout(f);var n=t[e];0!==n&&(n&&n[1](new Error("Loading chunk "+e+" failed.")),t[e]=void 0)}return a.onerror=a.onload=d,o.appendChild(a),r},c.m=e,c.c=r,c.d=function(e,n,r){c.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},c.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return c.d(n,"a",n),n},c.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},c.p="/",c.oe=function(e){throw console.error(e),e}}([]);
//# sourceMappingURL=manifest.d2c25b0f76d62e67169a.js.map
\ No newline at end of file
...@@ -13,14 +13,14 @@ ...@@ -13,14 +13,14 @@
<dependencies> <dependencies>
<dependency> <dependency>
<groupId>junit</groupId> <groupId>org.mybatis</groupId>
<artifactId>junit</artifactId> <artifactId>mybatis</artifactId>
<scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>ognl</groupId> <groupId>junit</groupId>
<artifactId>ognl</artifactId> <artifactId>junit</artifactId>
<scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>
......
package com.gitee.sqlrest.template;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.FutureTask;
public class Configuration {
private ConcurrentHashMap<String, FutureTask<SqlTemplate>> templateCache;
private transient boolean cacheTemplate;
private Charset charset;
public Configuration() {
this(true, Charset.defaultCharset());
}
public Configuration(boolean cacheTemplate, Charset charset) {
super();
this.cacheTemplate = cacheTemplate;
this.charset = charset;
templateCache = new ConcurrentHashMap<>();
}
public SqlTemplate getTemplate(final String content) {
if (null == content || content.isEmpty()) {
throw new IllegalArgumentException("SQL Content is Empty!");
}
if (cacheTemplate) {
FutureTask<SqlTemplate> f = templateCache.get(content);
if (f == null) {
FutureTask<SqlTemplate> ft = new FutureTask<>(() -> createTemplate(content));
f = templateCache.putIfAbsent(content, ft);
if (f == null) {
ft.run();
f = ft;
}
}
try {
return f.get();
} catch (Exception e) {
templateCache.remove(content);
throw new RuntimeException(e);
}
}
return createTemplate(content);
}
private SqlTemplate createTemplate(String content) {
SqlTemplate template = new SqlTemplate
.SqlTemplateBuilder(this, content)
.build();
return template;
}
public SqlTemplate getTemplate(InputStream in) throws IOException {
String content;
try {
content = readerContent(in);
} catch (IOException e) {
throw new IOException("Error reading template ", e);
}
return getTemplate(content);
}
public SqlTemplate getTemplate(File tplFile) throws FileNotFoundException,
IOException {
return this.getTemplate(new FileInputStream(tplFile));
}
private String readerContent(InputStream in) throws IOException {
StringBuilder sb = new StringBuilder(in.available());
InputStreamReader inputStreamReader = new InputStreamReader(
new BufferedInputStream(in), charset);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String line;
while ((line = bufferedReader.readLine()) != null) {
sb.append(line);
}
bufferedReader.close();
return sb.toString();
}
public boolean isCacheTemplate() {
return cacheTemplate;
}
public void setCacheTemplate(boolean cacheTemplate) {
this.cacheTemplate = cacheTemplate;
}
public Charset getCharset() {
return charset;
}
public void setCharset(Charset charset) {
this.charset = charset;
}
}
package com.gitee.sqlrest.template;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ognl.OgnlContext;
import ognl.OgnlException;
import ognl.OgnlRuntime;
import ognl.PropertyAccessor;
public class SqlContext {
public static final String BINDING_DATA = "_data";
static {
OgnlRuntime.setPropertyAccessor(HashMap.class, new ContextAccessor());
}
private Configuration cfg;
private Map<String, Object> binding;
private StringBuilder sql = new StringBuilder();
private List<Object> parameter;
private int uniqueNumber = 0;
public SqlContext(Configuration cfg, Object data) {
this.cfg = cfg;
binding = new HashMap<>();
parameter = new ArrayList<>();
binding.put(BINDING_DATA, data);
}
public void bind(String key, Object value) {
binding.put(key, value);
}
public void appendSql(String sqlFragment) {
sql.append(sqlFragment).append(" ");
}
public Map<String, Object> getBinding() {
return this.binding;
}
public List<Object> getParameter() {
return this.parameter;
}
public void addParameter(Object parameter) {
this.parameter.add(parameter);
}
public String getSql() {
return sql.toString();
}
public void setSql(String sql) {
this.sql = new StringBuilder(sql);
}
public int getUniqueNumber() {
return ++uniqueNumber;
}
public Configuration getConfiguration() {
return this.cfg;
}
static class ContextAccessor implements PropertyAccessor {
public Object getProperty(Map context, Object target, Object name) throws OgnlException {
Map map = (Map) target;
Object result = map.get(name);
if (result != null) {
return result;
}
Object parameterObject = map.get(BINDING_DATA);
if (parameterObject instanceof Map) {
return ((Map) parameterObject).get(name);
}
return null;
}
public void setProperty(Map context, Object target, Object name, Object value) throws OgnlException {
Map map = (Map) target;
map.put(name, value);
}
public String getSourceAccessor(OgnlContext arg0, Object arg1, Object arg2) {
return null;
}
public String getSourceSetter(OgnlContext arg0, Object arg1, Object arg2) {
return null;
}
}
}
package com.gitee.sqlrest.template;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.parsing.XNode;
import org.apache.ibatis.parsing.XPathParser;
import org.apache.ibatis.session.Configuration;
public class XmlSqlTemplate {
private static final Pattern pattern = Pattern.compile("\\([^()]*\\)|\\[[^\\[\\]]*\\]|\\{[^{}]*}");
private Configuration configuration;
private XNode root;
public XmlSqlTemplate(String xmlSql) {
configuration = new Configuration();
configuration.setMapUnderscoreToCamelCase(true);
this.root = parseXml(xmlSql);
}
private XNode parseXml(String sql) {
String xml = "<script>" + sql + "</script>";
XPathParser parser = new XPathParser(xml);
List<XNode> xNodes = parser.evalNodes("script");
if (xNodes == null || xNodes.size() <= 0) {
throw new RuntimeException("Can not find sql statement from text: " + sql);
}
if (xNodes.size() > 1) {
throw new RuntimeException("Only support one sql statement for parse");
}
return xNodes.get(0);
}
public Map<String, Boolean> getParameterNames() {
Map<String, Boolean> inputParams = new LinkedHashMap<>();
XmlScriptBuilder builder = new XmlScriptBuilder(configuration, root);
builder.parseScriptNode(inputParams);
Map<String, Boolean> names = new LinkedHashMap<>();
for (Map.Entry<String, Boolean> entry : inputParams.entrySet()) {
String name = entry.getKey();
String subName = null;
if (null == entry.getValue()) {
continue;
}
Matcher matcher = pattern.matcher(name);
while (matcher.find()) {
name = name.replaceAll(Pattern.quote(matcher.group()), "");
matcher = pattern.matcher(name);
}
int idx = name.indexOf(".");
if (idx > 0) {
subName = name;
name = name.substring(0, idx);
}
if (entry.getValue()) {
names.put(name, true);
if (null != subName) {
names.put(subName, true);
}
} else {
names.putIfAbsent(name, entry.getValue());
if (null != subName) {
names.putIfAbsent(subName, entry.getValue());
}
}
}
return names;
}
public SqlMeta process(Map<String, Object> params) {
XmlScriptBuilder builder = new XmlScriptBuilder(configuration, root);
Map<String, Boolean> inputParams = new HashMap<>();
SqlSource sqlSource = builder.parseScriptNode(inputParams);
BoundSql boundSql = sqlSource.getBoundSql(params);
List<Object> paramValues = new ArrayList<>();
for (ParameterMapping parameterMapping : boundSql.getParameterMappings()) {
String name = parameterMapping.getProperty();
Object value = boundSql.getAdditionalParameter(name);
if (null == value) {
int idx = name.indexOf(".");
if (idx > 0) {
String objName = name.substring(0, idx);
String subName = name.substring(idx + 1);
value = params.get(objName);
if (value instanceof Map) {
value = ((Map) value).get(subName);
}
} else {
value = params.get(name);
}
}
paramValues.add(value);
}
return new SqlMeta(boundSql.getSql(), paramValues);
}
}
\ No newline at end of file
package com.gitee.sqlrest.template.fragment;
import com.gitee.sqlrest.template.util.OgnlCacheUtils;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class ExpressionEvaluator {
public boolean evaluateBoolean(String expression, Object parameterObject) {
Object value = OgnlCacheUtils.getValue(expression, parameterObject);
if (value instanceof Boolean) {
return (Boolean) value;
}
if (value instanceof Number) {
return !new BigDecimal(String.valueOf(value))
.equals(BigDecimal.ZERO);
}
return value != null;
}
public Iterable<?> evaluateIterable(String expression,
Object parameterObject) {
Object value = OgnlCacheUtils.getValue(expression, parameterObject);
if (value == null) {
throw new RuntimeException("The expression '" + expression
+ "' evaluated to a null value.");
}
if (value instanceof Iterable) {
return (Iterable<?>) value;
}
if (value.getClass().isArray()) {
// the array may be primitive, so Arrays.asList() may throw
// a ClassCastException (issue 209). Do the work manually
// Curse primitives! :) (JGB)
int size = Array.getLength(value);
List<Object> answer = new ArrayList<Object>();
for (int i = 0; i < size; i++) {
Object o = Array.get(value, i);
answer.add(o);
}
return answer;
}
if (value instanceof Map) {
return ((Map) value).entrySet();
}
throw new RuntimeException("Error evaluating expression '" + expression
+ "'. Return value (" + value + ") was not iterable.");
}
}
package com.gitee.sqlrest.template.fragment;
import com.gitee.sqlrest.template.SqlContext;
import java.util.List;
import java.util.Map;
public class MixedSqlFragment implements SqlFragment {
private List<SqlFragment> contents;
public MixedSqlFragment(List<SqlFragment> contents) {
this.contents = contents;
}
public boolean apply(SqlContext context) {
for (SqlFragment sf : contents) {
sf.apply(context);
}
return true;
}
public void applyParameter(Map<String, Boolean> names) {
for(SqlFragment sf: contents) {
sf.applyParameter(names);
}
}
}
package com.gitee.sqlrest.template.fragment;
import com.gitee.sqlrest.template.SqlContext;
import java.util.Map;
public interface SqlFragment {
boolean apply(SqlContext context);
void applyParameter(Map<String, Boolean> names);
}
package com.gitee.sqlrest.template.fragment.impl;
import com.gitee.sqlrest.template.SqlContext;
import com.gitee.sqlrest.template.fragment.SqlFragment;
import java.util.List;
import java.util.Map;
public class ChooseFragment implements SqlFragment {
private SqlFragment defaultSqlFragment;
private List<SqlFragment> ifSqlFragments;
public ChooseFragment(List<SqlFragment> ifSqlFragments,
SqlFragment defaultSqlFragment) {
this.ifSqlFragments = ifSqlFragments;
this.defaultSqlFragment = defaultSqlFragment;
}
public boolean apply(SqlContext context) {
for (SqlFragment sqlNode : ifSqlFragments) {
if (sqlNode.apply(context)) {
return true;
}
}
if (defaultSqlFragment != null) {
defaultSqlFragment.apply(context);
return true;
}
return false;
}
public void applyParameter(Map<String, Boolean> names) {
for (SqlFragment sqlNode : ifSqlFragments) {
sqlNode.applyParameter(names);
}
if (defaultSqlFragment != null) {
defaultSqlFragment.applyParameter(names);
}
}
}
package com.gitee.sqlrest.template.fragment.impl;
import com.gitee.sqlrest.template.SqlContext;
import com.gitee.sqlrest.template.fragment.ExpressionEvaluator;
import com.gitee.sqlrest.template.fragment.SqlFragment;
import com.gitee.sqlrest.template.token.GenericTokenParser;
import com.gitee.sqlrest.template.token.TokenHandler;
import java.util.Map;
public class ForEachFragment implements SqlFragment {
public static final String ITEM_PREFIX = "__frch_";
private ExpressionEvaluator evaluator;
private String collectionExpression;
private SqlFragment contents;
private String open;
private String close;
private String separator;
private String item;
private String index;
public ForEachFragment(SqlFragment contents, String collectionExpression,
String index, String item, String open, String close,
String separator) {
this.contents = contents;
this.evaluator = new ExpressionEvaluator();
this.collectionExpression = collectionExpression;
this.index = index;
this.item = item;
this.open = open;
this.close = close;
this.separator = separator;
}
public boolean apply(SqlContext context) {
Map<String, Object> bindings = context.getBinding();
final Iterable<?> iterable = evaluator.evaluateIterable(
collectionExpression, bindings);
boolean first = true;
applyOpen(context);
int i = 0;
for (Object o : iterable) {
SqlContext oldContext = context;
if (first) {
context = new PrefixedContext(context, "");
} else {
if (separator != null) {
context = new PrefixedContext(context, separator);
} else {
context = new PrefixedContext(context, "");
}
}
int uniqueNumber = context.getUniqueNumber();
if (o instanceof Map.Entry) { // Issue #709
@SuppressWarnings("unchecked")
Map.Entry<Object, Object> mapEntry = (Map.Entry<Object, Object>) o;
applyIndex(context, mapEntry.getKey(), uniqueNumber);
applyItem(context, mapEntry.getValue(), uniqueNumber);
} else {
applyIndex(context, i, uniqueNumber);
applyItem(context, o, uniqueNumber);
}
contents.apply(new FilteredContext(context, index, item,
uniqueNumber));
if (first) {
first = !((PrefixedContext) context).isPrefixApplied();
}
context = oldContext;
i++;
}
applyClose(context);
return true;
}
public void applyParameter(Map<String, Boolean> names) {
names.put(this.collectionExpression, true);
}
private void applyIndex(SqlContext context, Object o, int i) {
if (index != null) {
context.bind(index, o);
context.bind(itemizeItem(index, i), o);
}
}
private void applyItem(SqlContext context, Object o, int i) {
if (item != null) {
context.bind(item, o);
context.bind(itemizeItem(item, i), o);
}
}
private void applyOpen(SqlContext context) {
if (open != null) {
context.appendSql(open);
}
}
private void applyClose(SqlContext context) {
if (close != null) {
context.appendSql(close);
}
}
private static String itemizeItem(String item, int i) {
return new StringBuilder(ITEM_PREFIX).append(item).append("_")
.append(i).toString();
}
private static class FilteredContext extends SqlContext {
private SqlContext delegate;
private int index;
private String itemIndex;
private String item;
public FilteredContext(SqlContext delegate, String itemIndex, String item,
int i) {
super(null, null);
this.delegate = delegate;
this.index = i;
this.itemIndex = itemIndex;
this.item = item;
}
@Override
public Map<String, Object> getBinding() {
return delegate.getBinding();
}
@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
}
@Override
public String getSql() {
return delegate.getSql();
}
@Override
public void appendSql(String sql) {
GenericTokenParser parser = new GenericTokenParser("#{", "}",
new TokenHandler() {
public String handleToken(String content) {
String newContent = content.replaceFirst("^\\s*"
+ item + "(?![^.,:\\s])",
itemizeItem(item, index));
if (itemIndex != null && newContent.equals(content)) {
newContent = content.replaceFirst("^\\s*"
+ itemIndex + "(?![^.,:\\s])",
itemizeItem(itemIndex, index));
}
return new StringBuilder("#{")
.append(newContent)
.append("}").toString();
}
});
delegate.appendSql(parser.parse(sql));
}
@Override
public int getUniqueNumber() {
return delegate.getUniqueNumber();
}
}
private class PrefixedContext extends SqlContext {
private SqlContext delegate;
private String prefix;
private boolean prefixApplied;
public PrefixedContext(SqlContext delegate, String prefix) {
super(null, null);
this.delegate = delegate;
this.prefix = prefix;
this.prefixApplied = false;
}
public boolean isPrefixApplied() {
return prefixApplied;
}
@Override
public Map<String, Object> getBinding() {
return delegate.getBinding();
}
@Override
public void bind(String name, Object value) {
delegate.bind(name, value);
}
@Override
public void appendSql(String sql) {
if (!prefixApplied && sql != null && sql.trim().length() > 0) {
delegate.appendSql(prefix);
prefixApplied = true;
}
delegate.appendSql(sql);
}
@Override
public String getSql() {
return delegate.getSql();
}
@Override
public int getUniqueNumber() {
return delegate.getUniqueNumber();
}
}
}
package com.gitee.sqlrest.template.fragment.impl;
import com.gitee.sqlrest.template.SqlContext;
import com.gitee.sqlrest.template.fragment.ExpressionEvaluator;
import com.gitee.sqlrest.template.fragment.SqlFragment;
import java.util.Map;
public class IfFragment implements SqlFragment {
private String test;
private SqlFragment contents;
private ExpressionEvaluator expression;
public IfFragment(SqlFragment contents, String test) {
this.expression = new ExpressionEvaluator();
this.contents = contents;
this.test = test;
}
public boolean apply(SqlContext context) {
if (expression.evaluateBoolean(test, context.getBinding())) {
this.contents.apply(context);
return true;
}
return false;
}
public void applyParameter(Map<String, Boolean> names) {
this.contents.applyParameter(names);
}
}
package com.gitee.sqlrest.template.fragment.impl;
import com.gitee.sqlrest.template.fragment.SqlFragment;
import java.util.Arrays;
import java.util.List;
/**
*
* @author Wen
*
*/
public class SetFragment extends TrimFragment {
private static List<String> suffixList = Arrays.asList(",");
public SetFragment(SqlFragment contents) {
super(contents, "SET", null, null, suffixList);
}
}
package com.gitee.sqlrest.template.fragment.impl;
import com.gitee.sqlrest.template.SqlContext;
import com.gitee.sqlrest.template.fragment.SqlFragment;
import com.gitee.sqlrest.template.token.GenericTokenParser;
import com.gitee.sqlrest.template.token.TokenHandler;
import com.gitee.sqlrest.template.util.OgnlCacheUtils;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class TextFragment implements SqlFragment {
private String sql;
public TextFragment(String sql) {
this.sql = sql;
}
public boolean apply(final SqlContext context) {
GenericTokenParser parser2 = new GenericTokenParser("${", "}",
new TokenHandler() {
public String handleToken(String content) {
Object value = OgnlCacheUtils.getValue(content,
context.getBinding());
return value == null ? "" : value.toString();
}
});
context.appendSql(parser2.parse(sql));
return true;
}
public void applyParameter(Map<String, Boolean> names) {
List<String> openTokens = Arrays.asList("${", "#{");
String closeToken = "}";
for (String openToken : openTokens) {
new GenericTokenParser(openToken, closeToken,
(name) -> {
names.putIfAbsent(name, false);
return name;
})
.parse(sql);
}
}
}
package com.gitee.sqlrest.template.fragment.impl;
import com.gitee.sqlrest.template.SqlContext;
import com.gitee.sqlrest.template.fragment.SqlFragment;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class TrimFragment implements SqlFragment {
private SqlFragment contents;
private String prefix;
private String suffix;
private List<String> prefixesToOverride;
private List<String> suffixesToOverride;
public TrimFragment(SqlFragment contents, String prefix, String suffix,
String prefixesToOverride, String suffixesToOverride) {
this(contents, prefix, suffix, prefixesToOverride == null ? null : Arrays.asList(prefixesToOverride
.split("\\|")), suffixesToOverride == null ? null : Arrays.asList(suffixesToOverride.split("\\|")));
}
public TrimFragment(SqlFragment contents, String prefix, String suffix,
List<String> prefixesToOverride, List<String> suffixesToOverride) {
this.contents = contents;
this.prefix = prefix;
this.suffix = suffix;
this.prefixesToOverride = prefixesToOverride;
this.suffixesToOverride = suffixesToOverride;
}
public boolean apply(SqlContext context) {
FilteredContent fContext = new FilteredContent(context);
contents.apply(fContext);
fContext.applyAll();
return false;
}
public void applyParameter(Map<String, Boolean> names) {
this.contents.applyParameter(names);
}
private class FilteredContent extends SqlContext {
private SqlContext delegate;
private boolean trimed = false;
private StringBuilder sql = new StringBuilder();
public FilteredContent(SqlContext delegate) {
super(null, null);
this.delegate = delegate;
}
public void applyAll() {
if (trimed) {
return;
}
sql = new StringBuilder(sql.toString().trim());
String upperSql = sql.toString().toUpperCase();
if (upperSql.length() > 0) {
applyPrefix(upperSql);
applySuffix(upperSql);
}
delegate.appendSql(sql.toString());
}
private void applySuffix(String upperSql) {
if (suffixesToOverride != null) {
for (String toRemove : suffixesToOverride) {
if (upperSql.endsWith(toRemove)) {
// sql.delete(0, toRemove.trim().length()) ;
int start = sql.length() - toRemove.length();
int end = sql.length();
sql.delete(start, end);
break;
}
}
}
if (suffix != null) {
this.appendSql(suffix);
}
}
private void applyPrefix(String upperSql) {
if (prefixesToOverride != null) {
for (String toRemove : prefixesToOverride) {
if (upperSql.startsWith(toRemove.toUpperCase())) {
sql.delete(0, toRemove.length());
break;
}
}
}
if (prefix != null) {
sql.insert(0, prefix + " ");
}
}
@Override
public void bind(String key, Object value) {
delegate.bind(key, value);
}
@Override
public void appendSql(String sqlFragement) {
sql.append(sqlFragement).append(" ");
}
@Override
public Map<String, Object> getBinding() {
return delegate.getBinding();
}
@Override
public List<Object> getParameter() {
return delegate.getParameter();
}
@Override
public void addParameter(Object parameter) {
delegate.addParameter(parameter);
}
@Override
public String getSql() {
return delegate.toString();
}
}
}
package com.gitee.sqlrest.template.fragment.impl;
import com.gitee.sqlrest.template.fragment.SqlFragment;
public class WhenFragment extends IfFragment {
public WhenFragment(SqlFragment contents, String test) {
super(contents, test);
}
}
package com.gitee.sqlrest.template.fragment.impl;
import com.gitee.sqlrest.template.fragment.SqlFragment;
import java.util.Arrays;
import java.util.List;
public class WhereFragment extends TrimFragment {
private static List<String> prefixList = Arrays
.asList("AND ", "OR ", "AND\n", "OR\n", "AND\r", "OR\r", "AND\t", "OR\t");
public WhereFragment(SqlFragment contents) {
super(contents, "WHERE", null, prefixList, null);
}
}
package com.gitee.sqlrest.template.token;
public class GenericTokenParser {
private final String openToken;
private final String closeToken;
private final TokenHandler handler;
public GenericTokenParser(String openToken, String closeToken,
TokenHandler handler) {
this.openToken = openToken;
this.closeToken = closeToken;
this.handler = handler;
}
public String parse(String text) {
StringBuilder builder = new StringBuilder();
if (text != null && text.length() > 0) {
char[] src = text.toCharArray();
int offset = 0;
int start = text.indexOf(openToken, offset);
while (start > -1) {
if (start > 0 && src[start - 1] == '\\') {
// the variable is escaped. remove the backslash.
builder.append(src, offset, start - 1).append(openToken);
offset = start + openToken.length();
} else {
int end = text.indexOf(closeToken, start);
if (end == -1) {
builder.append(src, offset, src.length - offset);
offset = src.length;
} else {
builder.append(src, offset, start - offset);
offset = start + openToken.length();
String content = new String(src, offset, end - offset);
builder.append(handler.handleToken(content));
offset = end + closeToken.length();
}
}
start = text.indexOf(openToken, offset);
}
if (offset < src.length) {
builder.append(src, offset, src.length - offset);
}
}
return builder.toString();
}
}
package com.gitee.sqlrest.template.token;
public interface TokenHandler {
String handleToken(String content);
}
package com.gitee.sqlrest.template.util;
import java.io.StringReader;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import ognl.ExpressionSyntaxException;
import ognl.Node;
import ognl.Ognl;
import ognl.OgnlException;
import ognl.OgnlParser;
import ognl.ParseException;
import ognl.TokenMgrError;
public class OgnlCacheUtils {
private static final Map<String, ognl.Node> expressionCache = new ConcurrentHashMap<>();
public static Object getValue(String expression, Object root) {
try {
return Ognl.getValue(parseExpression(expression), root);
} catch (OgnlException e) {
throw new RuntimeException("Error evaluating expression '"
+ expression + "'. Cause: " + e, e);
}
}
private static Object parseExpression(String expression)
throws OgnlException {
try {
Node node = expressionCache.get(expression);
if (node == null) {
node = new OgnlParser(new StringReader(expression))
.topLevelExpression();
expressionCache.put(expression, node);
}
return node;
} catch (ParseException e) {
throw new ExpressionSyntaxException(expression, e);
} catch (TokenMgrError e) {
throw new ExpressionSyntaxException(expression, e);
}
}
}
package com.gitee.sqlrest.template; package com.gitee.sqlrest.template;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.Test; import org.junit.Test;
public class TemplateTest { public class TemplateTest {
...@@ -8,28 +12,26 @@ public class TemplateTest { ...@@ -8,28 +12,26 @@ public class TemplateTest {
@Test @Test
public void testIf() { public void testIf() {
String content = "select * from user where <if test='id != null ' > id = #{id} </if>"; String content = "select * from user where <if test='id != null ' > id = #{id} </if>";
Configuration cfg = new Configuration(); XmlSqlTemplate parser = new XmlSqlTemplate(content);
SqlTemplate template = cfg.getTemplate(content);
System.out.println(template.getParameterNames()); System.out.println(parser.getParameterNames());
HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
map.put("id", "11"); map.put("id", "11");
SqlMeta process = template.process(map); SqlMeta process = parser.process(map);
System.out.println(process); System.out.println(process);
} }
@Test @Test
public void testWhere() { public void testWhere() {
String content = "select * from user <where> <if test='id != null ' > and id = #{id} </if> <if test=' name != null' >name =#{name}</if> </where>"; String content = "select * from user <where> <if test='id != null ' > and id = #{id} </if> <if test=' name != null' >name =#{name}</if> </where>";
Configuration cfg = new Configuration(); XmlSqlTemplate parser = new XmlSqlTemplate(content);
SqlTemplate template = cfg.getTemplate(content);
System.out.println(template.getParameterNames()); System.out.println(parser.getParameterNames());
HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
//map.put("name", "join"); //map.put("name", "join");
SqlMeta process = template.process(map); SqlMeta process = parser.process(map);
System.out.println(process); System.out.println(process);
} }
...@@ -37,15 +39,14 @@ public class TemplateTest { ...@@ -37,15 +39,14 @@ public class TemplateTest {
@Test @Test
public void testSet() { public void testSet() {
String content = "update user <set> <if test='id != null '> id = #{id} ,</if><if test='name != null '> name = #{name} ,</if> </set> "; String content = "update user <set> <if test='id != null '> id = #{id} ,</if><if test='name != null '> name = #{name} ,</if> </set> ";
Configuration cfg = new Configuration(); XmlSqlTemplate parser = new XmlSqlTemplate(content);
SqlTemplate template = cfg.getTemplate(content);
System.out.println(template.getParameterNames()); System.out.println(parser.getParameterNames());
HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
map.put("id", "123"); map.put("id", "123");
map.put("name", "join"); map.put("name", "join");
SqlMeta process = template.process(map); SqlMeta process = parser.process(map);
System.out.println(process); System.out.println(process);
} }
...@@ -53,25 +54,23 @@ public class TemplateTest { ...@@ -53,25 +54,23 @@ public class TemplateTest {
@Test @Test
public void testChoose() { public void testChoose() {
String content = "select * from user <where><choose><when test=' id!= null '> and id = #{id} </when><when test=' name!= null and name.length()>0 '> and name = #{name} </when></choose> </where>"; String content = "select * from user <where><choose><when test=' id!= null '> and id = #{id} </when><when test=' name!= null and name.length()>0 '> and name = #{name} </when></choose> </where>";
Configuration cfg = new Configuration(); XmlSqlTemplate parser = new XmlSqlTemplate(content);
SqlTemplate template = cfg.getTemplate(content);
System.out.println(template.getParameterNames()); System.out.println(parser.getParameterNames());
HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
//map.put("id", "123"); //map.put("id", "123");
map.put("name", "join"); map.put("name", "join");
SqlMeta process = template.process(map); SqlMeta process = parser.process(map);
System.out.println(process); System.out.println(process);
} }
@Test @Test
public void testForEach() { public void testForEach() {
String content = "select * from user <where> id in <foreach item=\"item\" index=\"index\" collection=\"list\" open=\"(\" separator=\",\" close=\")\"> ${item} ${index} </foreach></where>"; String content = "select * from user <where> id in <foreach item=\"item\" index=\"index\" collection=\"list\" open=\"(\" separator=\",\" close=\")\"> ${item} ${index} </foreach></where>";
Configuration cfg = new Configuration(); XmlSqlTemplate parser = new XmlSqlTemplate(content);
SqlTemplate template = cfg.getTemplate(content);
System.out.println(template.getParameterNames()); System.out.println(parser.getParameterNames());
HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
map.put("id", "123"); map.put("id", "123");
...@@ -87,7 +86,7 @@ public class TemplateTest { ...@@ -87,7 +86,7 @@ public class TemplateTest {
map2.put("11", "111"); map2.put("11", "111");
map2.put("22", "222"); map2.put("22", "222");
map.put("list", map2); map.put("list", map2);
SqlMeta process = template.process(map); SqlMeta process = parser.process(map);
System.out.println(process); System.out.println(process);
} }
...@@ -95,14 +94,13 @@ public class TemplateTest { ...@@ -95,14 +94,13 @@ public class TemplateTest {
public void testLT() { public void testLT() {
//String content = "select * from user where <if test='id != null ' > id &lt; #{id} </if>"; //String content = "select * from user where <if test='id != null ' > id &lt; #{id} </if>";
String content = "select * from user where <if test='id != null ' > id <![CDATA[ < ]]> #{id} </if>"; String content = "select * from user where <if test='id != null ' > id <![CDATA[ < ]]> #{id} </if>";
Configuration cfg = new Configuration(); XmlSqlTemplate parser = new XmlSqlTemplate(content);
SqlTemplate template = cfg.getTemplate(content);
System.out.println(template.getParameterNames()); System.out.println(parser.getParameterNames());
HashMap<String, Object> map = new HashMap<>(); HashMap<String, Object> map = new HashMap<>();
map.put("id", "11"); map.put("id", "11");
SqlMeta process = template.process(map); SqlMeta process = parser.process(map);
System.out.println(process); System.out.println(process);
} }
...@@ -120,9 +118,8 @@ public class TemplateTest { ...@@ -120,9 +118,8 @@ public class TemplateTest {
+ " AND last_name like concat('%', #{lastName}, '%')\n" + " AND last_name like concat('%', #{lastName}, '%')\n"
+ " </if>\n" + " </if>\n"
+ " </trim>"; + " </trim>";
Configuration cfg = new Configuration(); XmlSqlTemplate parser = new XmlSqlTemplate(content);
SqlTemplate template = cfg.getTemplate(content); System.out.println(parser.getParameterNames());
System.out.println(template.getParameterNames());
} }
@Test @Test
...@@ -141,9 +138,76 @@ public class TemplateTest { ...@@ -141,9 +138,76 @@ public class TemplateTest {
+ " </foreach> \n" + " </foreach> \n"
+ " </when>\n" + " </when>\n"
+ "</choose>"; + "</choose>";
Configuration cfg = new Configuration(); XmlSqlTemplate parser = new XmlSqlTemplate(content);
SqlTemplate template = cfg.getTemplate(content); System.out.println(parser.getParameterNames());
}
@Test
public void testObject() {
String xmlSql = " insert into `employees` "
+ " (emp_no,birth_date,first_name,last_name,gender,hire_date)"
+ " values "
+ "<foreach collection='records' item='record' separator=','>"
+ " ( #{record.empNo}, #{record.birthDate}, #{record.firstName}, #{record.lastName}, #{record.gender}, #{record.hireDate})"
+ "</foreach>";
XmlSqlTemplate sqlParser = new XmlSqlTemplate(xmlSql);
Map<String, Boolean> paramNames = sqlParser.getParameterNames();
System.out.println(paramNames);
Map<String, Object> record1 = new HashMap<>();
record1.put("empNo", 11);
record1.put("birthDate", new Date());
record1.put("firstName", "tom1");
record1.put("lastName", "cat1");
record1.put("gender", "F");
record1.put("hireDate", new Date());
Map<String, Object> record2 = new HashMap<>();
record2.put("empNo", 22);
record2.put("birthDate", new Date());
record2.put("firstName", "tom2");
record2.put("lastName", "cat2");
record2.put("gender", "F");
record2.put("hireDate", new Date());
List<Map<String, Object>> employees = Arrays.asList(record1, record2);
Map<String, Object> params = new HashMap<>();
params.put("records", employees);
SqlMeta sqlData = sqlParser.process(params);
System.out.println(sqlData.getSql());
System.out.println(sqlData.getParameter());
}
@Test
public void testObjFiled() {
String sql = "SELECT * from employees.departments WHERE dept_no=#{obj.deptNo}";
XmlSqlTemplate template = new XmlSqlTemplate(sql);
System.out.println(template.getParameterNames());
Map<String, Object> obj = new HashMap<>();
obj.put("deptNo", "d001");
Map<String, Object> params = new HashMap<>();
params.put("obj", obj);
SqlMeta sqlMeta = template.process(params);
System.out.println(sqlMeta);
}
@Test
public void testObjArrayField() {
String sql = "SELECT * from employees.departments WHERE dept_no in \n"
+ "<foreach open=\"(\" close=\")\" collection=\"obj.deptNo\" separator=\",\" item=\"item\" index=\"index\">"
+ "#{item}"
+ "</foreach>";
XmlSqlTemplate template = new XmlSqlTemplate(sql);
System.out.println(template.getParameterNames()); System.out.println(template.getParameterNames());
Map<String, Object> obj = new HashMap<>();
obj.put("deptNo", Arrays.asList("d001","d002"));
Map<String, Object> params = new HashMap<>();
params.put("obj", obj);
SqlMeta sqlMeta = template.process(params);
System.out.println(sqlMeta);
} }
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment