From 70ae89dd70fa5d025a4516880562f8c6ec2b1797 Mon Sep 17 00:00:00 2001 From: haha Date: Sun, 27 Apr 2025 22:36:00 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=A2=9E=E5=8A=A0dataway=E6=A1=86=E6=9E=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yanzhu-modules/yanzhu-manage/pom.xml | 11 ++ .../manage/YanZhuManageApplication.java | 4 + .../com/yanzhu/manage/hasor/HasorModule.java | 64 ++++++++ .../net/hasor/dataql/domain/DomainHelper.java | 118 ++++++++++++++ .../dataway/service/InterfaceApiFilter.java | 149 ++++++++++++++++++ .../java/net/hasor/dataway/spi/ApiInfo.java | 102 ++++++++++++ .../src/main/resources/bootstrap.yml | 22 ++- 7 files changed, 468 insertions(+), 2 deletions(-) create mode 100644 yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/hasor/HasorModule.java create mode 100644 yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataql/domain/DomainHelper.java create mode 100644 yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataway/service/InterfaceApiFilter.java create mode 100644 yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataway/spi/ApiInfo.java diff --git a/yanzhu-modules/yanzhu-manage/pom.xml b/yanzhu-modules/yanzhu-manage/pom.xml index d65b984c..0b90c692 100644 --- a/yanzhu-modules/yanzhu-manage/pom.xml +++ b/yanzhu-modules/yanzhu-manage/pom.xml @@ -179,6 +179,17 @@ sqlite-jdbc 3.41.2.2 + + + net.hasor + hasor-spring + 4.2.5 + + + net.hasor + hasor-dataway + 4.2.5 + diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/YanZhuManageApplication.java b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/YanZhuManageApplication.java index 75b7ea92..d5419ec1 100644 --- a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/YanZhuManageApplication.java +++ b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/YanZhuManageApplication.java @@ -3,6 +3,8 @@ package com.yanzhu.manage; import com.yanzhu.common.security.annotation.EnableCustomConfig; import com.yanzhu.common.security.annotation.EnableRyFeignClients; import com.yanzhu.common.swagger.annotation.EnableCustomSwagger2; +import net.hasor.spring.boot.EnableHasor; +import net.hasor.spring.boot.EnableHasorWeb; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -15,6 +17,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @EnableCustomSwagger2 @EnableRyFeignClients @SpringBootApplication +@EnableHasor() +@EnableHasorWeb() public class YanZhuManageApplication { public static void main(String[] args) diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/hasor/HasorModule.java b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/hasor/HasorModule.java new file mode 100644 index 00000000..cf8d660b --- /dev/null +++ b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/hasor/HasorModule.java @@ -0,0 +1,64 @@ +package com.yanzhu.manage.hasor; + +import net.hasor.core.ApiBinder; +import net.hasor.core.DimModule; +import net.hasor.dataql.DataQL; +import net.hasor.dataql.compiler.qil.QIL; +import net.hasor.dataway.DatawayApi; +import net.hasor.dataway.authorization.PermissionType; +import net.hasor.dataway.dal.FieldDef; +import net.hasor.dataway.service.InterfaceApiFilter; +import net.hasor.dataway.spi.ApiInfo; +import net.hasor.dataway.spi.AuthorizationChainSpi; +import net.hasor.dataway.spi.CompilerSpiListener; +import net.hasor.dataway.spi.PreExecuteChainSpi; +import net.hasor.db.JdbcModule; +import net.hasor.db.Level; +import net.hasor.spring.SpringModule; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import javax.sql.DataSource; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.Map; +import java.util.Set; + +@DimModule +@Component +public class HasorModule implements SpringModule { + @Autowired + private DataSource dataSource = null; + + public void loadModule(ApiBinder apiBinder) throws Throwable { + // .DataSource form Spring boot into Hasor + apiBinder.installModule(new JdbcModule(Level.Full, this.dataSource)); + + InterfaceApiFilter f; + apiBinder.bindSpiListener(PreExecuteChainSpi.class, (apiInfo, future) -> { + try{ + Method method = apiInfo.getClass().getMethod("getObj"); + Map obj=(Map)method.invoke(apiInfo); + Object a=obj; + }catch (Exception ex){ + + } + //String apiPath = apiInfo.getApiPath(); +// String apiMethod = apiInfo.getMethod() +// if (...) { +// // (方式1)通过 future 设置异常信息 +// future.failed(new StatusMessageException(401, "not power")); +// // (方式2)或者直接 throw 一个异常 +// throw new StatusMessageException(401, "not power"); +// } + }); + apiBinder.bindSpiListener(CompilerSpiListener.class, new CompilerSpiListener() { + @Override + public QIL compiler(ApiInfo apiInfo, String query, DataQL dataQL) throws IOException { + query = "hint FRAGMENT_SQL_QUERY_BY_PAGE = true;\nhint FRAGMENT_SQL_QUERY_BY_PAGE_NUMBER_OFFSET = 1;\n " + query; + return CompilerSpiListener.super.compiler(apiInfo, query, dataQL); + } + }); + + } +} diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataql/domain/DomainHelper.java b/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataql/domain/DomainHelper.java new file mode 100644 index 00000000..820e6b26 --- /dev/null +++ b/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataql/domain/DomainHelper.java @@ -0,0 +1,118 @@ +package net.hasor.dataql.domain; +import net.hasor.dataql.Udf; +import net.hasor.dataql.runtime.operator.OperatorUtils; +import net.hasor.utils.ArrayUtils; +import net.hasor.utils.ref.BeanMap; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.*; + +public class DomainHelper { + public static ValueModel nullDomain() { + return ValueModel.NULL; + } + + public static ListModel newList() { + return new ListModel(); + } + + public static ObjectModel newObject() { + return new ObjectModel(); + } + + public static DataModel convertTo(Object object) { + if (object instanceof DataModel) { + // 已经是 DataModel + return (DataModel) object; + } else if (object == null) { + // 基础类型:空 + return ValueModel.NULL; + } else if (OperatorUtils.isBoolean(object)) { + // 基础类型:boolean + if ((boolean) object) { + return ValueModel.TRUE; + } else { + return ValueModel.FALSE; + } + } else if (object instanceof CharSequence) { + // 基础类型:字符串 + return new ValueModel(String.valueOf(object)); + } else if (OperatorUtils.isNumber(object)) { + // 基础类型:数字 + return new ValueModel(object); + } else if (object instanceof Date) { + // 外部类型:时间 -> Long + return new ValueModel(((Date) object).getTime()); + } else if (object instanceof UUID) { + // 外部类型:UUID -> String + return new ValueModel(((UUID) object).toString()); + } else if (object.getClass().isEnum()) { + // 外部类型:枚举 -> ValueModel(字符串) + return new ValueModel(((Enum) object).name()); + } else if (object instanceof Map) { + // 外部类型:Map -> ObjectModel + Map mapData = (Map) object; + Set entrySet = mapData.entrySet(); + ObjectModel objectModel = new ObjectModel(); + for (Object entry : entrySet) { + if (entry instanceof Map.Entry) { + Object key = ((Map.Entry) entry).getKey(); + Object val = ((Map.Entry) entry).getValue(); + objectModel.put(key.toString(), convertTo(val)); + } + } + return objectModel; + } else if (object.getClass().isArray()) { + // 外部类型:数组 -> ListModel + Class componentType = object.getClass().getComponentType(); + Object[] objectArrays = null; + if (componentType.isPrimitive()) { + /** */if (Boolean.TYPE == componentType) { + objectArrays = ArrayUtils.toObject((boolean[]) object); + } else if (Byte.TYPE == componentType) { + objectArrays = ArrayUtils.toObject((byte[]) object); + } else if (Short.TYPE == componentType) { + objectArrays = ArrayUtils.toObject((short[]) object); + } else if (Integer.TYPE == componentType) { + objectArrays = ArrayUtils.toObject((int[]) object); + } else if (Long.TYPE == componentType) { + objectArrays = ArrayUtils.toObject((long[]) object); + } else if (Character.TYPE == componentType) { + objectArrays = ArrayUtils.toObject((char[]) object); + } else if (Float.TYPE == componentType) { + objectArrays = ArrayUtils.toObject((float[]) object); + } else if (Double.TYPE == componentType) { + objectArrays = ArrayUtils.toObject((double[]) object); + } else { + objectArrays = (Object[]) object; + } + } else { + objectArrays = (Object[]) object; + } + return new ListModel(Arrays.asList(objectArrays)); + } else if (object instanceof Collection) { + // 外部类型:集合 -> ListModel + return new ListModel((Collection) object); + } else if (object instanceof Udf) { + // 外部类型:UDF -> CallModel + return new UdfModel((Udf) object); + } else if (object instanceof LocalDateTime) { + LocalDateTime localDateTime=(LocalDateTime)object; + Date date = Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + return new ValueModel((date).getTime()); + } else { + // 外部类型:Bean -> ObjectModel + BeanMap beanMap = new BeanMap(object); + ObjectModel objectModel = new ObjectModel(); + for (String entryKey : beanMap.keySet()) { + if ("class".equals(entryKey)) { + //objectModel.put(entryKey, convertTo(beanMap.getBean().getClass().getName())); + } else { + objectModel.put(entryKey, convertTo(beanMap.get(entryKey))); + } + } + return objectModel; + } + } +} \ No newline at end of file diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataway/service/InterfaceApiFilter.java b/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataway/service/InterfaceApiFilter.java new file mode 100644 index 00000000..e4afa5b5 --- /dev/null +++ b/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataway/service/InterfaceApiFilter.java @@ -0,0 +1,149 @@ +package net.hasor.dataway.service; +import com.alibaba.fastjson.JSON; +import net.hasor.core.Inject; +import net.hasor.core.spi.SpiTrigger; +import net.hasor.dataway.DatawayApi; +import net.hasor.dataway.config.DatawayUtils; +import net.hasor.dataway.config.LoggerUtils; +import net.hasor.dataway.dal.ApiDataAccessLayer; +import net.hasor.dataway.dal.ApiStatusEnum; +import net.hasor.dataway.dal.EntityDef; +import net.hasor.dataway.dal.FieldDef; +import net.hasor.dataway.spi.ApiInfo; +import net.hasor.dataway.spi.CallSource; +import net.hasor.utils.StringUtils; +import net.hasor.web.Invoker; +import net.hasor.web.InvokerChain; +import net.hasor.web.InvokerConfig; +import net.hasor.web.InvokerFilter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.lang.reflect.Method; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; + +/** + * 负责处理 API 的执行 + * @author 赵永春 (zyc@hasor.net) + * @version : 2020-03-20 + */ +public class InterfaceApiFilter implements InvokerFilter { + protected static Logger logger = LoggerFactory.getLogger(InterfaceApiFilter.class); + @Inject + private ApiCallService callService; + @Inject + private SpiTrigger spiTrigger; + @Inject + private ApiDataAccessLayer dataAccessLayer; + @Inject + private CrossDomainService crossDomainService; + private final String apiBaseUri; + private final String adminBaseUri; + + public InterfaceApiFilter(String apiBaseUri, String adminBaseUri) { + this.apiBaseUri = apiBaseUri; + this.adminBaseUri = adminBaseUri; + } + + @Override + public void init(InvokerConfig config) { + config.getAppContext().justInject(this); + } + + @Override + public Object doInvoke(Invoker invoker, InvokerChain chain) throws Throwable { + HttpServletRequest httpRequest = invoker.getHttpRequest(); + String requestURI = invoker.getRequestPath(); + String httpMethod = httpRequest.getMethod().toUpperCase().trim(); + if (!requestURI.startsWith(this.apiBaseUri)) { + return chain.doNext(invoker); + } + // + // .Skip ui url + if (StringUtils.isNotBlank(this.adminBaseUri)) { + if (requestURI.startsWith(this.adminBaseUri)) { + return chain.doNext(invoker); + } + } + // + DatawayUtils.resetLocalTime(); + String mimeType = invoker.getMimeType("json"); + // + // .查询接口数据 + ApiInfo apiInfo = new ApiInfo(); + apiInfo.setCallSource(CallSource.External); + String script = null; + try { + Map object = this.dataAccessLayer.getObjectBy(EntityDef.RELEASE, FieldDef.PATH, requestURI); + if (object == null) { + throw new IllegalStateException("API is not published."); + } + ApiStatusEnum anEnum = ApiStatusEnum.typeOf(object.get(FieldDef.STATUS)); + if (anEnum != ApiStatusEnum.Published) { + throw new IllegalStateException("API is not published."); + } + String apiMethod = object.get(FieldDef.METHOD); + if (!StringUtils.equalsIgnoreCase(httpMethod, apiMethod)) { + throw new IllegalStateException("request method are not allowed."); + } + // + apiInfo.setReleaseID(object.get(FieldDef.ID)); + apiInfo.setApiID(object.get(FieldDef.API_ID)); + apiInfo.setMethod(object.get(FieldDef.METHOD)); + apiInfo.setApiPath(object.get(FieldDef.PATH)); + apiInfo.setOptionMap(JSON.parseObject(object.get(FieldDef.OPTION))); + setApiInfoObj(apiInfo,object); + script = object.get(FieldDef.SCRIPT); + } catch (Exception e) { + Object result = DatawayUtils.exceptionToResult(e).getResult(); + LoggerUtils loggerUtils = LoggerUtils.create() // + .addLog("httpMethod", httpMethod) // + .addLog("apiPath", requestURI) // + .addLog("result", result) // + .logException(e); + logger.error("requestFailed - " + loggerUtils.toJson(), e); + return DatawayUtils.responseData(this.spiTrigger, apiInfo, mimeType, invoker, result); + } + // + // .准备参数 + Map jsonParam; + if ("GET".equalsIgnoreCase(httpMethod)) { + jsonParam = new HashMap<>(); + Enumeration parameterNames = httpRequest.getParameterNames(); + while (parameterNames.hasMoreElements()) { + String paramName = parameterNames.nextElement(); + jsonParam.put(paramName + "Arrays", httpRequest.getParameterValues(paramName)); + jsonParam.put(paramName, httpRequest.getParameter(paramName)); + } + } else { + String jsonBody = invoker.getJsonBodyString(); + if (StringUtils.isNotBlank(jsonBody)) { + jsonParam = JSON.parseObject(jsonBody); + } else { + jsonParam = new HashMap<>(); + } + } + apiInfo.setParameterMap(jsonParam); + // + // .配置跨域 + this.crossDomainService.configureCross( apiInfo, invoker); + // + // .执行调用 + String finalScript = script; + Object objectMap = this.callService.doCallWithoutError(apiInfo, param -> finalScript); + return DatawayUtils.responseData(this.spiTrigger, apiInfo, mimeType, invoker, objectMap); + } + + private void setApiInfoObj(ApiInfo apiInfo, Map object) { + try{ + Method method=apiInfo.getClass().getMethod("setObj",Map.class); + method.invoke(apiInfo,object); + }catch (Exception ex){ + ex.printStackTrace();; + } + } +} \ No newline at end of file diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataway/spi/ApiInfo.java b/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataway/spi/ApiInfo.java new file mode 100644 index 00000000..47b340f1 --- /dev/null +++ b/yanzhu-modules/yanzhu-manage/src/main/java/net/hasor/dataway/spi/ApiInfo.java @@ -0,0 +1,102 @@ +package net.hasor.dataway.spi; + +import net.hasor.dataql.Hints; +import net.hasor.dataway.DatawayApi; +import net.hasor.dataway.dal.FieldDef; + +import java.util.Map; + +public class ApiInfo implements DatawayApi{ + + private CallSource callSource; + private String apiID; + private String releaseID; + private String method; + private String apiPath; + private Map parameterMap; + private Map optionMap; + private Hints prepareHint; + + public Map getObj() { + return obj; + } + + public void setObj(Map obj) { + this.obj = obj; + } + + private Map obj; + + public ApiInfo() { + } + + /** @deprecated */ + @Deprecated + public boolean isPerform() { + return CallSource.InterfaceUI == this.callSource; + } + + public CallSource getCallSource() { + return this.callSource; + } + + public void setCallSource(CallSource callSource) { + this.callSource = callSource; + } + + public String getApiID() { + return this.apiID; + } + + public void setApiID(String apiID) { + this.apiID = apiID; + } + + public String getReleaseID() { + return this.releaseID; + } + + public void setReleaseID(String releaseID) { + this.releaseID = releaseID; + } + + public String getMethod() { + return this.method; + } + + public void setMethod(String method) { + this.method = method; + } + + public String getApiPath() { + return this.apiPath; + } + + public void setApiPath(String apiPath) { + this.apiPath = apiPath; + } + + public Map getParameterMap() { + return this.parameterMap; + } + + public void setParameterMap(Map parameterMap) { + this.parameterMap = parameterMap; + } + + public Map getOptionMap() { + return this.optionMap; + } + + public void setOptionMap(Map optionMap) { + this.optionMap = optionMap; + } + + public Hints getPrepareHint() { + return this.prepareHint; + } + + public void setPrepareHint(Hints prepareHint) { + this.prepareHint = prepareHint; + } + } diff --git a/yanzhu-modules/yanzhu-manage/src/main/resources/bootstrap.yml b/yanzhu-modules/yanzhu-manage/src/main/resources/bootstrap.yml index b02b3f0d..4393a936 100644 --- a/yanzhu-modules/yanzhu-manage/src/main/resources/bootstrap.yml +++ b/yanzhu-modules/yanzhu-manage/src/main/resources/bootstrap.yml @@ -1,6 +1,11 @@ # Tomcat server: port: 9208 + servlet: + encoding: + enabled: true + charset: UTF-8 + force: true # Spring spring: @@ -15,8 +20,10 @@ spring: discovery: # 服务注册地址 server-addr: @discovery.server-addr@ + # 工作空间配置 + namespace: a113aa27-4d61-46e0-81d6-9cede0457f0d # 服务分组 - group: JiangYuQi + #group: lijun config: # 配置中心地址 server-addr: @discovery.server-addr@ @@ -31,4 +38,15 @@ logging: com.ycx.manage.mapper: DEBUG bim: - dataPath: '/Users/mac/code/bimdata/' \ No newline at end of file + dataPath: '/Users/mac/code/bimdata/' + +#http://localhost:9208/interface-ui/ +# 启用 Dataway 功能(默认不启用) +HASOR_DATAQL_DATAWAY: true +# 开启 ui 管理功能(注意生产环境必须要设置为 false,否则会造成严重的生产安全事故) +HASOR_DATAQL_DATAWAY_ADMIN: true + +# (可选)API工作路径 +HASOR_DATAQL_DATAWAY_API_URL: /api/ +# (可选)ui 的工作路径,只有开启 ui 管理功能后才有效 +HASOR_DATAQL_DATAWAY_UI_URL: /interface-ui/ \ No newline at end of file From fc8226e526479f19eb42aafa7fb8c79c7f9533e9 Mon Sep 17 00:00:00 2001 From: haha Date: Mon, 28 Apr 2025 00:03:00 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E8=80=83=E5=8B=A4?= =?UTF-8?q?=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/yanzhu/manage/hasor/HasorModule.java | 2 +- .../src/views/manage/attendance_cfg/index.vue | 604 ++++++++++-------- 2 files changed, 345 insertions(+), 261 deletions(-) diff --git a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/hasor/HasorModule.java b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/hasor/HasorModule.java index cf8d660b..48b35011 100644 --- a/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/hasor/HasorModule.java +++ b/yanzhu-modules/yanzhu-manage/src/main/java/com/yanzhu/manage/hasor/HasorModule.java @@ -55,7 +55,7 @@ public class HasorModule implements SpringModule { apiBinder.bindSpiListener(CompilerSpiListener.class, new CompilerSpiListener() { @Override public QIL compiler(ApiInfo apiInfo, String query, DataQL dataQL) throws IOException { - query = "hint FRAGMENT_SQL_QUERY_BY_PAGE = true;\nhint FRAGMENT_SQL_QUERY_BY_PAGE_NUMBER_OFFSET = 1;\n " + query; + query = "hint FRAGMENT_SQL_COLUMN_CASE=\"hump\"\n hint FRAGMENT_SQL_QUERY_BY_PAGE_NUMBER_OFFSET = 1 \n" + query; return CompilerSpiListener.super.compiler(apiInfo, query, dataQL); } }); diff --git a/yanzhu-ui-vue3/src/views/manage/attendance_cfg/index.vue b/yanzhu-ui-vue3/src/views/manage/attendance_cfg/index.vue index 2b7caffe..224d6fd6 100644 --- a/yanzhu-ui-vue3/src/views/manage/attendance_cfg/index.vue +++ b/yanzhu-ui-vue3/src/views/manage/attendance_cfg/index.vue @@ -1,40 +1,36 @@