Oinone协同开发源码分析

前提

源码分析版本是 5.1.x版本

什么是协同开发模式

协同开发模式解决的是不同开发,在开发同一个模型时,不会相互影响,也不会影响到测试环境
详见:Oinone协同开发使用手册

协同开发原理

在协同模式下,本地开发的元数据,配置pamirs.data.distribution.session.ownSign参数后,元数据前缀加ownSign值,然后只存在redis缓存,不落库。其它环境无法直接访问到该数据。
测试环境,或其它环境访问,需要在url上加ownSign等于设置的,则读redis数据时,除了加载通用数据,也会合并ownSign前缀的redis数据,显示出来

注意事项

  1. 协同开发仅支持界面设计器,其他设计器均不支持
  2. 不支持权限配置
  3. 不支持工作流触发

版本支持

完整支持5.1.0及以上

功能详解

启动时操作

  1. 做元数据保护检查
  2. 配置ownSign,则key拼接为 ownSign + ':' + key
  3. 清除掉ownSign的redis缓存数据;非ownSign不用清理
  4. 计算差量数据
  5. 有差量数据,放入ownSign标识数据,并清理本地标识
  6. dubbo注册服务,group拼接group + ownSign 后进行注册

读取时操作

读本地

  1. 组装key: ownSign + ':' + key
  2. 本地缓存有数据,更新缓存本地数据,返回
  3. 本地没有数据,读redis,并插入本地缓存

读远程

dubbo注册消费者,group拼接group + ownSign 后进行泛化调用

元数据保护检查

开启数据保护模式,在启动参数里加
-PmetaProtected=pamirs

会在启动时,往redis里写入数据

private static final String META_PROTECTED_KEY = "pamirs:check:meta-protected";
private void writeMetaProtected(String metaProtected) {
    stringRedisTemplate.opsForValue().set(META_PROTECTED_KEY, metaProtected);
}

如果同时又设置 pamirs.data.distribution.session.ownSign
则会报错 在使用元数据保护模式下,不允许设置 [pamirs.distribution.session.ownSign]

处理逻辑如下

  1. 看redis是否启用保护标识的值
  2. 获取pamirs.distribution.session.ownSign配置
  3. 没有启动参数 且redis没有值,则retrun
  4. 如果有启动参数且配置了ownSign,报错 在使用元数据保护模式下,不允许设置 [pamirs.distribution.session.ownSign]
  5. 如果有启动参数且 redis没有值或启动参数设置 -P metaForceProtected,则写入redis
  6. 如果有启动参数, 且启动参数跟redis值不同,则报错[公共环境开启了元数据保护模式,本地开发环境需配置[pamirs.distribution.session.ownSign]]
  7. 如果没有启动参数且redis有值,但没有配置ownSign 报错[公共环境开启了元数据保护模式,本地开发环境需配置[pamirs.distribution.session.ownSign]]

核心代码如下
MetadataProtectedChecker

public void process(AppLifecycleCommand command, Set<String> runModules,
                        List<ModuleDefinition> installModules, List<ModuleDefinition> upgradeModules, List<ModuleDefinition> reloadModules) {
        String currentMetaProtected = stringRedisTemplate.opsForValue().get(META_PROTECTED_KEY);
        String metaProtected = getMetaProtected();
        boolean hasCurrentMetaProtected = StringUtils.isNotBlank(currentMetaProtected);
        boolean hasMetaProtected = StringUtils.isNotBlank(metaProtected);
        if (!hasCurrentMetaProtected && !hasMetaProtected) {
            return;
        }
        if (hasMetaProtected) {
            if (Spider.getDefaultExtension(SessionFillOwnSignApi.class).handleOwnSign()) {
            // 如果有启动参数且配置了ownSign
                throw new UnsupportedOperationException("在使用元数据保护模式下,不允许设置 [pamirs.distribution.session.ownSign]");
            }
            if (!hasCurrentMetaProtected || isForceProtected()) {
                writeMetaProtected(metaProtected);
            } else if (!metaProtected.equals(currentMetaProtected)) {
            // 如果有启动参数, 且启动参数跟redis值不同
                throw unsupportedLocalOperation();
            }
        } else {
            if (Spider.getDefaultExtension(SessionFillOwnSignApi.class).handleOwnSign()) {
                return;
            }
            // 没有启动参数且redis有值,但没有配置ownSign 报错
            throw unsupportedLocalOperation();
        }
    }

取ownSign方式

  1. 看header是否有ownSign这个标识
  2. header没有,则从配置里取,并放到header里
    ownSign的获取核心代码
    CdDistributionSessionFillOwnSignApi

    @Override
    public String getCdOwnSign() {
        String cdOwnSign = null;
        // 看header是否有ownSign这个标识
        Map<String, String> headers = PamirsSession.getRequestVariables().getHeaders();
        if (MapUtils.isNotEmpty(headers)) {
            cdOwnSign = headers.get(OWN_SIGN);
        }
        // 页面没有ownSign标识,则从配置里取,并放到header里
        if (StringUtils.isBlank(cdOwnSign)) {
            cdOwnSign = getConfigCdOwnSign();
            if (headers != null) {
                headers.put(OWN_SIGN, cdOwnSign);
            }
        }
        return cdOwnSign;
    }

清理redis缓存

ownSign的rediskey组装形式,会在原有key前加入ownSign值 + ":"
ownSign + ':' + key
CdDistributionSessionCacheApi

    SEPARATOR_COLON = ":";
    default String keyOwnSign(String key) {
        String cdOwnSign = SessionFillOwnSignApiHolder.get().getCdOwnSign();
        if (StringUtils.isNotBlank(cdOwnSign)) {
            key = cdOwnSign + SEPARATOR_COLON + key;
        }
        return key;
    }
  1. 如果配置ownSign设置,则进行清理工作
  2. 组装Key: ownSign + ':' + key
  3. 执行redis删除
    核心代码 CdModelL2Cache

    public void clear() {
    
        if (handleOwnSign()) {
            SessionRedisUtils.deletePattern(keyOwnSign(super.getModelDefPattern()));
            SessionRedisUtils.deletePattern(keyOwnSign(super.getModelNamePattern()));
        }
    }

数据写入缓存

以模型为例
插入缓存入口,updateMetaData

public <T extends MetaBaseModel> void updateMetaData(String model, List<T> dataList) {
        if (CollectionUtils.isEmpty(dataList)) {
            return;
        }

        // 初始化. Init要放在allMetaRefresh的判断前面
        this.init();
        if (allMetaRefresh) {
            return;
        }

        switch (model) {
            case ModuleDefinition.MODEL_MODEL:
            case UeModule.MODEL_MODEL:
                asyncExecution(model, dataList.size(), MetaUpgradeCheckApi.UPDATE_OPERATOR, () -> fillSessionModule((List<ModuleDefinition>) dataList));
                break;
            ....
        }
    }

每个model轮询处理
    private boolean fillSessionModel(List<ModelDefinition> dataList, Boolean needFunctions) {
        ....
        return reliableExecution(() -> {
            for (ModelDefinition modelDefinition : dataList) {
                doOneModel(modelDefinition, needFunctions);
            }
        }, "模型元数据[变更]");
    }

    private void doOneModel(ModelDefinition modelDefinition, Boolean needFunctions) {
        // 构造模型配置
        ModelConfig modelConfig = SessionsHelper.fetchModelConfig(modelDefinition);
        String modelModel = modelConfig.getModel();
        String modelUniqueKey = modelModel + ":" + Optional.ofNullable(modelDefinition.getModelFields()).map(List::size).orElse(0);
        try {
            if (ObjectRepeatHelper.isNotRepeat(DistributionDataSupplier.getModelRepeats(), modelUniqueKey)) {
            // 放入缓存
                modelCache.put(modelModel, modelConfig);
            }
        } catch (Exception e) {
            ....
        }

        // 全量情况下metaData.getStandAloneFunctionList()的Function不全;需要把模型的Function也进行缓存
        if (needFunctions) {
            fillSessionModelFunction(modelConfig.getFunctionList());
        }
    }

放入缓存
CdModelL2Cache

    private void cdPut(String key, ModelConfig value) {
        String modelDefCacheKey = cdModelDefCacheKey(key);
        String modelNameCacheKey = cdModelNameCacheKey(value.getName());
        byte[] bytes = MetadataSerializationHelper.serialize(value.getModelDefinition());
        SessionRedisUtils.set(modelDefCacheKey, bytes);
        SessionRedisUtils.set(modelNameCacheKey, bytes);
        //从模型设计器保存后,需要清除掉本地空的标识。后面再get的时候会从redis中获取
DistributionMetaDataLocalCache.removeModelDef(modelDefCacheKey);
        DistributionMetaDataLocalCache.removeModelDef(modelNameCacheKey);
    }

其它处理ownSign数据对象有:

CdFunctionByNameL2Cache
CdFunctionL2Cache
CdActionL2Cache
CdViewL2Cache
....

写入dubbo服务

写入dubbo链路看文章Oinone远程调用链路源码分析

  1. 在group加后缀 group = group + ownSign
  2. 调用dubbo泛化调用

核心代码DefaultRemoteRegistry

    // 泛化调用
    public void registryService(Function function) {
        String interfaceName = RegistryUtils.getRegistryInterface(function);
        String group = getGroup(function, true);
        String version = getVersion(function);
        Integer timeout = getTimeout(function);
        Integer retries = function.getRetries();
        if (log.isDebugEnabled()) {
            log.debug("register service. interfaceName: {}, group: {}, version: {}, timeout: {}, retries: {}", interfaceName, group, version, timeout, retries);
        }
        remoteRegistryComponent.registryGenericService(interfaceName, group, version, timeout, retries);
}

// group加前缀
private String getGroup(Function function, boolean usingOwnSign) {
        String group = function.getGroup();
...
        if (usingOwnSign) {
            String ownSign = Spider.getDefaultExtension(SessionFillOwnSignApi.class).getCdOwnSign();
            if (StringUtils.isNotBlank(ownSign)) {
                group = group + ownSign;
            }
        }
        return group;
    }

读缓存

  1. 如果配置ownSign参数,则走ownSign处理逻辑
  2. 组装key: cdOwnSign + SEPARATOR_COLON + key
  3. 本地有缓存,更新本地缓存,并返回
  4. 本地没有缓存,读取redis数据,后放入本地缓存,返回

CdModelL2Cache

public ModelConfig get(String key) {
        ModelConfig modelConfig;
        if (handleOwnSign()) {
            modelConfig = cdGet(key);
            if (modelConfig == null) {
                modelConfig = super.get(key);
            }
        } else {
            modelConfig = super.get(key);
        }
        return modelConfig;
    }

private ModelConfig cdGet(String key) {
        if (DistributionBaseKeyer.MODEL_MODEL_BASE_KEYS.contains(key)) {
            return CommonApiFactory.getApi(DistributionL1CacheProxy.class).getModelL1Cache().get(key);
        }
        String modelDefCacheKey = cdModelDefCacheKey(key);
        ModelDefinition modelDef = DistributionMetaDataLocalCache.getModelDef(modelDefCacheKey);
        // 本地有数据,返回,没有则放入本地缓存,再返回
        if (modelDef != null || DistributionMetaDataLocalCache.keyModelDef(modelDefCacheKey)) {
            return super.covertModelConfig(modelDef);
        }
        // 读取redis数据
        byte[] bytes = SessionRedisUtils.get(modelDefCacheKey);
        modelDef = KryoSerializer.deserialize(bytes);
        if (modelDef != null) {
            // 放入本地缓存DistributionMetaDataLocalCache.setModelDef(modelDefCacheKey, modelDef);
        }
        return super.covertModelConfig(modelDef);
    }

读dubbo服务

读取dubbo链路看文章Oinone远程调用链路源码分析
RemoteComputer.invoke()

  1. 在group加后缀 group = group + ownSign
  2. 调用dubbo泛化调用

核心代码DefaultRemoteRegistry

    public GenericService registryConsumer(Function function) {
        String interfaceName = RegistryUtils.getRegistryInterface(function);
        // 
        String group = getGroup(function, true);
        String version = getVersion(function);
        Integer timeout = getTimeout(function);
        Integer retries = function.getRetries();
        if (log.isDebugEnabled()) {
            log.debug("register consumer. interfaceName: {}, group: {}, version: {}, timeout: {}, retries: {}", interfaceName, group, version, timeout, retries);
        }
        return remoteRegistryComponent.registryGenericConsumer(interfaceName, group, version, timeout, retries);
    }

Oinone社区 作者:oinone原创文章,如若转载,请注明出处:https://doc.oinone.top/backend/17209.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

(0)
oinone的头像oinone
上一篇 2024年9月11日 am9:57
下一篇 2024年9月12日 pm6:12

相关推荐

  • 如何自定义Excel导出功能

    介绍 在平台提供的默认导出功能无法满足业务需求的时候,我们可以自定义导出功能,以满足业务中个性化的需求。 功能示例 继承平台的导出任务模型,加上需要在导出的弹窗视图需要展示的字段 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.file.api.model.ExcelExportTask; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(DemoItemExportTask.MODEL_MODEL) @Model(displayName = "商品-Excel导出任务") public class DemoItemExportTask extends ExcelExportTask { public static final String MODEL_MODEL = "demo.DemoItemExportTask"; // 自定义显示的字段 @Field.String @Field(displayName = "发布人") private String publishUserName; } 编写自定义导出弹窗视图的数据初始化方法和导出提交的action package pro.shushi.pamirs.demo.core.action; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.DemoItemExportTask; import pro.shushi.pamirs.file.api.action.ExcelExportTaskAction; import pro.shushi.pamirs.file.api.model.ExcelWorkbookDefinition; import pro.shushi.pamirs.file.api.service.ExcelFileService; import pro.shushi.pamirs.meta.annotation.Action; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum; import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum; import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; @Slf4j @Component @Model.model(DemoItemExportTask.MODEL_MODEL) public class DemoItemExcelExportTaskAction extends ExcelExportTaskAction { public DemoItemExcelExportTaskAction(ExcelFileService excelFileService) { super(excelFileService); } @Action(displayName = "导出", contextType = ActionContextTypeEnum.CONTEXT_FREE, bindingType = {ViewTypeEnum.TABLE}) public DemoItemExportTask createExportTask(DemoItemExportTask data) { if (data.getWorkbookDefinitionId() != null) { ExcelWorkbookDefinition workbookDefinition = new ExcelWorkbookDefinition(); workbookDefinition.setId(data.getWorkbookDefinitionId()); data.setWorkbookDefinition(workbookDefinition); } super.createExportTask(data); return data; } /** * @param data * @return */ @Function(openLevel = FunctionOpenEnum.API) @Function.Advanced(type = FunctionTypeEnum.QUERY) public DemoItemExportTask construct(DemoItemExportTask data) { data.construct(); return data; } } 编写导出的数据处理逻辑,此处可以拿到导出弹窗内自定义的字段提交的值,然后根据这些值处理自定义逻辑 package pro.shushi.pamirs.demo.core.excel.extPoint; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.DemoItem; import pro.shushi.pamirs.demo.api.model.DemoItemExportTask; import pro.shushi.pamirs.demo.api.model.DemoItemImportTask; import pro.shushi.pamirs.file.api.context.ExcelDefinitionContext; import pro.shushi.pamirs.file.api.enmu.ExcelTemplateTypeEnum; import pro.shushi.pamirs.file.api.extpoint.ExcelExportFetchDataExtPoint; import pro.shushi.pamirs.file.api.extpoint.impl.ExcelExportSameQueryPageTemplate; import pro.shushi.pamirs.file.api.model.ExcelExportTask; import pro.shushi.pamirs.file.api.model.ExcelWorkbookDefinition; import pro.shushi.pamirs.file.api.util.ExcelHelper; import pro.shushi.pamirs.file.api.util.ExcelTemplateInit; import pro.shushi.pamirs.meta.annotation.ExtPoint; import java.util.Collections; import java.util.List; @Component public class DemoItemExportExtPoint extends ExcelExportSameQueryPageTemplate implements ExcelTemplateInit , ExcelExportFetchDataExtPoint…

    2024年1月3日
    1.2K00
  • 【Oracle】后端部署使用Oracle数据库

    Oracle数据库配置 驱动配置 jdbc仓库 https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc8 Maven配置(11g版本可用) <ojdbc.version>23.2.0.0</ojdbc.version> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <version>${ojdbc.version}</version> </dependency> JDBC连接配置 pamirs: datasource: base: type: com.alibaba.druid.pool.DruidDataSource driverClassName: oracle.jdbc.OracleDriver url: jdbc:oracle:thin:@//127.0.0.1:1521/orcl username: YOUR_SCHEMA_NAME password: xxxxxx Oracle默认为每个用户创建了一个与当前用户名同名的模式,每个用户应该只使用该模式(DBA用户除外),因此平台使用Oracle时应该通过username处指定与该模式同名的用户名来指定模式。(Oracle多数据源时每一个数据库创建一个用户) 创建用户时用户名应全大写。 连接url配置 官方文档 https://odbc.postgresql.org/docs/config-opt.html url格式 jdbc:oracle:thin:@//ip:端口号/服务名或SID 每一个Oracle进程默认为一个Oracle数据库实例,使用服务名或sid登录该Oralce数据库实例。一个Oracle sid 对应一个数据库实例,而一个服务名可以标识多个数据库实例。远程连接时推荐使用服务名进行连接。可以在安装Oracle的机器上打开SQLPlus,用SYSTEM用户登录上去后使用SELECT SYS_CONTEXT('USERENV', 'INSTANCE_NAME') AS SID FROM DUAL;查询登录使用的sid;也可以使用SELECT VALUE AS SERVICE_NAME FROM V$PARAMETER WHERE NAME = 'service_names';查询登录使用的服务名。 其他连接参数如需配置,可自行查阅相关资料进行调优。 方言配置 pamirs方言配置 pamirs: dialect: ds: base: type: Oracle version: 11.2 major-version: 11g pamirs: type: Oracle version: 11.2 major-version: 11g plus: configuration: jdbc-type-for-null: "NULL" using-model-as-property: true using-statement-handler-dialect: true mapper: batch: useAffectRows global: table-pattern: '${table_30}' column-pattern: '${column_30}' 数据库版本 type version majorVersion 11g – 11.2.0.1.0 Oracle 11.2 11g 12c – 12.2.0.1.0 Oracle 12.2 12c PS:由于方言开发环境为Oracle Database 11g Enterprise Edition Release 11.2.0.1.0版本,其他类似版本(11.2.x)原则上不会出现太大差异,如出现其他版本无法正常支持的,可在文档下方留言。 schedule方言配置 pamirs: event: enabled: true schedule: enabled: true dialect: type: Oracle version: 11.2 major-version: 11g 其他配置 逻辑删除的值配置 pamirs: mapper: global: table-info: logic-delete-value: (CAST(SYSTIMESTAMP AS DATE) – TO_DATE('1970-01-01 08:00:00', 'YYYY-MM-DD HH24:MI:SS')) * 8640000000000 Oracle数据库用户初始化及授权 — 以下命令均使用dba账户执行 — 创建用户 ONE_TEST (用户名需全大写) 密码 123456 CREATE USER ONE_TEST IDENTIFIED BY 123456; — 解锁用户 ALTER USER ONE_TEST ACCOUNT UNLOCK; — 将用户的默认表空间设置为USERS,临时表空间设置为TEMP ALTER USER ONE_TEST DEFAULT TABLESPACE USERS; ALTER USER ONE_TEST TEMPORARY TABLESPACE TEMP; — 可以用以下命令查询某用户的表空间: SELECT…

    2025年7月10日
    40100
  • Oinone登录扩展:对接SSO(适应于4.7.8及之后的版本)

    适配版本 4.7.8及其之后的版本 概述 在企业内部,对于已有一套完整的登录系统(SSO)的情况下,通常会要求把所有的系统都对接到SSO中;本文主要讲解用Oinone开发的项目对接SSO的具体实现。 对接步骤 1、项目自定义实现UserCookieLogin,可参考示例说明: pro.shushi.pamirs.user.api.login.UserCookieLoginFree 2、对接SSO示例 对接流程说明: 1)【必须】从请求头Header或者Query中获取到token; 2)【必须】去SSO服务端验证token的有效性; 3)【可选】根据token去服务端获取用户信息;如果token可以直接反解析出用户信息,则该步骤忽略; 4)【可选】根据实际情况用户信息是否进行DB的存储; 5)【必须】验证token有效后,生成Session和Cookie(即token换cookie); 注意超时时间需要 <= SSO服务端token失效时间。 package pro.shushi.pamirs.demo.core.sso; import com.alibaba.fastjson.JSON; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import pro.shushi.pamirs.demo.core.sso.constant.HttpConstant; import pro.shushi.pamirs.demo.core.sso.constant.SessionUserTypeEnum; import pro.shushi.pamirs.demo.core.sso.model.ApiCommonTransient; import pro.shushi.pamirs.demo.core.sso.model.PermissionInfoResp; import pro.shushi.pamirs.demo.core.sso.utils.AuthenticateUtils; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.common.exception.PamirsException; import pro.shushi.pamirs.meta.common.spring.BeanDefinitionUtils; import pro.shushi.pamirs.resource.api.enmu.UserSignUpType; import pro.shushi.pamirs.user.api.cache.UserCache; import pro.shushi.pamirs.user.api.constants.UserConstant; import pro.shushi.pamirs.user.api.enmu.UserExpEnumerate; import pro.shushi.pamirs.user.api.enmu.UserLoginTypeEnum; import pro.shushi.pamirs.user.api.login.IUserLoginChecker; import pro.shushi.pamirs.user.api.login.UserCookieLogin; import pro.shushi.pamirs.user.api.login.UserCookieLoginSimple; import pro.shushi.pamirs.user.api.model.PamirsUser; import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient; import pro.shushi.pamirs.user.api.service.UserService; import pro.shushi.pamirs.user.api.utils.CookieUtil; import javax.servlet.http.HttpServletResponse; /** * * @author shushi * * 完全自定义login的过程 * 需要实现登陆部分login 以及拦截部分fetchUserIdByReq * 如果fetchUserIdByReq返回值为null的时候 将会被拦截 */ @Slf4j @Order(0) @Component public class DemoUserSSOCookieLogin extends UserCookieLogin<PamirsUser> { //刷新令牌 private static String REFRESH_TOKEN = "refreshToken"; //系统id private static String CLIENT_ID = "client-id"; //访问令牌 private static String AUTHORIZATION = "Authorization"; private IUserLoginChecker checker; @Autowired private UserService userService; @Autowired private RedisTemplate<String, String> redisTemplate; @Override public String type() { return UserLoginTypeEnum.COOKIE.value(); } @Override public PamirsUser resolveAndVerification(PamirsUserTransient user) { if (checker == null) { checker = BeanDefinitionUtils.getBean(IUserLoginChecker.class); } return checker.check4login(user); } /** * 重写登录拦截功能 * 该函数主要作用,通过三方权限校验. * @return */ // 版本升级需要修改 @Override public PamirsUserDTO fetchUserIdByReq() { String sessionId =…

    2024年4月2日
    1.9K00
  • 导入设计数据时dubbo超时导入失败

    问题描述 在本地启动导入设计数据的工程时,会出现dubbo调用超时导致设计数据无法完整导入的问题。 org.apache.dubbo.remoting.TimeoutException 产生原因 pom中的包依赖出现问题,导致没有使用正确的远程服务。 本地可能出现的异常报错堆栈信息如下: xception in thread "fixed-1-thread-10" PamirsException level: ERROR, code: 10100025, type: SYSTEM_ERROR, msg: 函数执行错误, extra:, extend: null at pro.shushi.pamirs.meta.common.exception.PamirsException$Builder.errThrow(PamirsException.java:190) at pro.shushi.pamirs.framework.faas.fun.manage.ManagementAspect.around(ManagementAspect.java:118) at sun.reflect.GeneratedMethodAccessor498.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethodWithGivenArgs(AbstractAspectJAdvice.java:644) at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:633) at org.springframework.aop.aspectj.AspectJAroundAdvice.invoke(AspectJAroundAdvice.java:70) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:95) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:749) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:691) at pro.shushi.pamirs.framework.orm.DefaultWriteApi$$EnhancerBySpringCGLIB$$b4cea2b4.createOrUpdateBatchWithResult(<generated>) at pro.shushi.pamirs.meta.base.manager.data.OriginDataManager.createOrUpdateBatchWithResult(OriginDataManager.java:161) at pro.shushi.pamirs.meta.base.manager.data.OriginDataManager.createOrUpdateBatch(OriginDataManager.java:152) at pro.shushi.pamirs.ui.designer.service.installer.UiDesignerInstaller.lambda$install$0(UiDesignerInstaller.java:42) at pro.shushi.pamirs.core.common.function.AroundRunnable.run(AroundRunnable.java:26) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: org.apache.dubbo.rpc.RpcException: Failed to invoke the method createOrUpdateBatchWithResult in the service org.apache.dubbo.rpc.service.GenericService. Tried 1 times of the providers [192.168.0.123:20880] (1/1) from the registry 127.0.0.1:2181 on the consumer 192.168.0.123 using the dubbo version 2.7.22. Last error is: Invoke remote method timeout. method: $invoke, provider: dubbo://192.168.0.123:20880/ui.designer.UiDesignerViewLayout.oio.defaultWriteApi?anyhost=true&application=pamirs-demo&application.version=1.0.0&check=false&deprecated=false&dubbo=2.0.2&dynamic=true&generic=true&group=pamirs&interface=ui.designer.UiDesignerViewLayout.oio.defaultWriteApi&metadata-type=remote&methods=*&payload=104857600&pid=69748&qos.enable=false&register.ip=192.168.0.123&release=2.7.15&remote.application=pamirs-test&retries=0&serialization=pamirs&service.name=ServiceBean:pamirs/ui.designer.UiDesignerViewLayout.oio.defaultWriteApi:1.0.0&side=consumer&sticky=false&timeout=5000&timestamp=1701136088893&version=1.0.0, cause: org.apache.dubbo.remoting.TimeoutException: Waiting server-side response timeout by scan timer. start time: 2023-11-28 10:23:05.835, end time: 2023-11-28 10:23:10.856, client elapsed: 695 ms, server elapsed: 4326 ms, timeout: 5000 ms, request: Request [id=0, version=2.0.2, twoway=true, event=false, broken=false, data=null], channel: /192.168.0.123:49449 -> /192.168.0.123:20880 at org.apache.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:110) at org.apache.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:265) at org.apache.dubbo.rpc.cluster.interceptor.ClusterInterceptor.intercept(ClusterInterceptor.java:47) at org.apache.dubbo.rpc.cluster.support.wrapper.AbstractCluster$InterceptorInvokerNode.invoke(AbstractCluster.java:92) at org.apache.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:98) at org.apache.dubbo.registry.client.migration.MigrationInvoker.invoke(MigrationInvoker.java:170) at org.apache.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:96) at org.apache.dubbo.common.bytecode.proxy0.$invoke(proxy0.java) at pro.shushi.pamirs.framework.faas.distribution.computer.RemoteComputer.compute(RemoteComputer.java:124) at pro.shushi.pamirs.framework.faas.FunEngine.run(FunEngine.java:80) at pro.shushi.pamirs.distribution.faas.remote.spi.service.RemoteFunctionHelper.run(RemoteFunctionHelper.java:68) at pro.shushi.pamirs.framework.faas.fun.manage.ManagementAspect.around(ManagementAspect.java:109) … 20 more Caused…

    2023年11月28日
    1.0K00
  • 如何自定义Excel导入功能

    介绍 在平台提供的默认导入功能无法满足业务需求的时候,我们可以自定义导入功能,以满足业务中个性化的需求。 功能示例 下面以导入文件的时候加入发布人的字段作为示例讲解。 继承平台的导入任务模型,加上需要在导入的弹窗视图需要展示的字段 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.file.api.model.ExcelImportTask; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(DemoItemImportTask.MODEL_MODEL) @Model(displayName = "商品-Excel导入任务") public class DemoItemImportTask extends ExcelImportTask { public static final String MODEL_MODEL = "demo.DemoItemImportTask"; // 自定义显示的字段 @Field.String @Field(displayName = "发布人") private String publishUserName; } 编写自定义导入弹窗视图的数据初始化方法和导入提交的action package pro.shushi.pamirs.demo.core.action; import org.springframework.stereotype.Component; import pro.shushi.pamirs.boot.base.resource.PamirsFile; import pro.shushi.pamirs.demo.api.model.DemoItemImportTask; import pro.shushi.pamirs.file.api.action.ExcelImportTaskAction; import pro.shushi.pamirs.file.api.config.FileProperties; import pro.shushi.pamirs.file.api.model.ExcelWorkbookDefinition; import pro.shushi.pamirs.file.api.service.ExcelFileService; import pro.shushi.pamirs.meta.annotation.Action; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.meta.annotation.Model; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum; import pro.shushi.pamirs.meta.enmu.FunctionOpenEnum; import pro.shushi.pamirs.meta.enmu.FunctionTypeEnum; import pro.shushi.pamirs.meta.enmu.ViewTypeEnum; @Slf4j @Component @Model.model(DemoItemImportTask.MODEL_MODEL) public class DemoItemExcelImportTaskAction extends ExcelImportTaskAction { public DemoItemExcelImportTaskAction(FileProperties fileProperties, ExcelFileService excelFileService) { super(fileProperties, excelFileService); } @Action(displayName = "导入", contextType = ActionContextTypeEnum.CONTEXT_FREE, bindingType = {ViewTypeEnum.TABLE}) public DemoItemImportTask createImportTask(DemoItemImportTask data) { if (data.getWorkbookDefinitionId() != null) { ExcelWorkbookDefinition workbookDefinition = new ExcelWorkbookDefinition(); workbookDefinition.setId(data.getWorkbookDefinitionId()); data.setWorkbookDefinition(workbookDefinition); } Object fileId = data.get_d().get("fileId"); if (fileId != null) { PamirsFile pamirsFile = new PamirsFile().queryById(Long.valueOf(fileId.toString())); data.setFile(pamirsFile); } super.createImportTask(data); return data; } /** * @param data * @return */ @Function(openLevel = FunctionOpenEnum.API) @Function.Advanced(type = FunctionTypeEnum.QUERY) public DemoItemImportTask construct(DemoItemImportTask data) { data.construct(); return data; } } 编写导入的单行数据处理逻辑,此处可以拿到导入弹窗内自定义的字段提交的值,然后根据这些值处理自定义逻辑,此处演示代码就是将导入后的商品的发布人都设置为自定义导入视图填的发布人信息 package pro.shushi.pamirs.demo.core.excel.extPoint; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import pro.shushi.pamirs.demo.api.model.DemoItem; import pro.shushi.pamirs.demo.api.model.DemoItemImportTask; import pro.shushi.pamirs.demo.api.service.DemoItemService; import pro.shushi.pamirs.file.api.context.ExcelImportContext; import pro.shushi.pamirs.file.api.extpoint.AbstractExcelImportDataExtPointImpl; import pro.shushi.pamirs.file.api.extpoint.ExcelImportDataExtPoint;…

    2023年11月22日
    1.3K00

Leave a Reply

登录后才能评论