如何通过自定义支持excel导出的动态表头

介绍

本文需要阅读过前置文档如何自定义Excel导出功能,动态表头的功能在前置文档的基础上做的进一步扩展,本文未提到的部分都参考这个前置文档。

在日常的业务开发中,我们在导出的场景会遇到需要设置动态表头的场景,比如统计商品在最近1个月的销量,固定表头列为商品的名称等基础信息,动态表头列为最近一个月的日期,在导出的时候设置每个日期的销量,本文将通过此业务场景提供示例代码。

1.自定义导出任务模型

package pro.shushi.pamirs.demo.api.model;

import pro.shushi.pamirs.file.api.model.ExcelExportTask;
import pro.shushi.pamirs.meta.annotation.Model;

@Model.model(DemoItemDynamicExcelExportTask.MODEL_MODEL)
@Model(displayName = "商品-Excel动态表头导出任务")
public class DemoItemDynamicExcelExportTask extends ExcelExportTask {
    public static final String MODEL_MODEL = "demo.DemoItemDynamicExcelExportTask";

}

2.自定义导出任务处理数据的扩展点

package pro.shushi.pamirs.demo.core.excel.exportdemo.extPoint;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.core.common.FetchUtil;
import pro.shushi.pamirs.core.common.cache.MemoryIterableSearchCache;
import pro.shushi.pamirs.demo.api.model.DemoItem;
import pro.shushi.pamirs.file.api.config.FileConstant;
import pro.shushi.pamirs.file.api.context.ExcelDefinitionContext;
import pro.shushi.pamirs.file.api.enmu.ExcelTemplateTypeEnum;
import pro.shushi.pamirs.file.api.entity.EasyExcelCellDefinition;
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.ExcelFixedHeadHelper;
import pro.shushi.pamirs.file.api.util.ExcelHelper;
import pro.shushi.pamirs.file.api.util.ExcelTemplateInit;
import pro.shushi.pamirs.framework.common.entry.TreeNode;
import pro.shushi.pamirs.meta.annotation.ExtPoint;
import pro.shushi.pamirs.meta.api.CommonApiFactory;
import pro.shushi.pamirs.meta.api.core.orm.ReadApi;
import pro.shushi.pamirs.meta.api.core.orm.systems.relation.RelationReadApi;
import pro.shushi.pamirs.meta.api.dto.config.ModelConfig;
import pro.shushi.pamirs.meta.api.dto.config.ModelFieldConfig;
import pro.shushi.pamirs.meta.api.session.PamirsSession;
import pro.shushi.pamirs.meta.enmu.TtypeEnum;
import pro.shushi.pamirs.meta.util.FieldUtils;

import java.util.*;

@Component
public class DemoItemDynamicExportExtPoint extends ExcelExportSameQueryPageTemplate<DemoItem> implements ExcelTemplateInit {
    public static final String TEMPLATE_NAME ="商品动态导出";

    @Override
    public List<ExcelWorkbookDefinition> generator() {
        ExcelFixedHeadHelper excelFixedHeadHelper = ExcelHelper.fixedHeader(DemoItem.MODEL_MODEL,TEMPLATE_NAME)
                .createBlock(TEMPLATE_NAME, DemoItem.MODEL_MODEL)
                .setType(ExcelTemplateTypeEnum.EXPORT);
        return Collections.singletonList(excelFixedHeadHelper.build());
    }

    public static void buildHeader(ExcelFixedHeadHelper excelFixedHeadHelper) {
        excelFixedHeadHelper.addColumn("name","名称")
                .addColumn("cateName","类目")
                .addColumn("searchFrom","搜索来源")
                .addColumn("description","描述")
                .addColumn("itemPrice","单价")
                .addColumn("inventoryQuantity","库存");
    }

    @Override
    @ExtPoint.Implement(expression = "context.model == \"" + DemoItem.MODEL_MODEL+"\" && context.name == \"" +TEMPLATE_NAME+"\"" )
    public List<Object> fetchExportData(ExcelExportTask exportTask, ExcelDefinitionContext context) {
        List<Object> result = super.fetchExportData(exportTask,context);
        Object block = result.get(0);
        if (block instanceof ArrayList) {
            ((List<Object>) block).forEach(o -> {
                if (o instanceof DemoItem) {
                    DemoItem item = (DemoItem) o;
                    // TODO 设置动态表头部分字段的值
                    item.get_d().put("2024-09-10", "1111");
                    item.get_d().put("2024-09-11", "2222");
                }
            });
        }
        return result;
    }

    protected <DM extends ReadApi> boolean selectRelationField(DM dataManager, String model, List<TreeNode<EasyExcelCellDefinition>> fieldNodeList, Collection<?> list, Integer maxSupportLength, int currentMaxLength) {
        Set<String> hasQueryFields = new HashSet<>();
        RelationReadApi relationManagerProcessor = CommonApiFactory.getApi(RelationReadApi.class);
        ModelConfig modelConfig = PamirsSession.getContext().getModelConfig(model);
        if (modelConfig == null) {
            return true;
        }
        MemoryIterableSearchCache<String, ModelFieldConfig> modelFieldsCache = new MemoryIterableSearchCache<>(modelConfig.getModelFieldConfigList(), ModelFieldConfig::getLname);
        for (TreeNode<EasyExcelCellDefinition> fieldNode : fieldNodeList) {
            String fieldKey = fieldNode.getKey();
            TreeNode<EasyExcelCellDefinition> parentFieldNode = fieldNode.getParent();
            if (parentFieldNode != null) {
                fieldKey = fieldKey.substring(parentFieldNode.getKey().length() + 1);
                int pi = fieldKey.indexOf(FileConstant.POINT_CHARACTER);
                if (pi != -1) {
                    fieldKey = fieldKey.substring(0, pi);
                }
            }
            ModelFieldConfig modelFieldConfig = modelFieldsCache.get(fieldKey);
            if (modelFieldConfig == null) {
                continue;
//                throw new IllegalArgumentException("模板中存在无效的模型字段 model=" + model + ", field=" + fieldKey);
            }
            if (!TtypeEnum.isRelationType(modelFieldConfig.getTtype())) {
                continue;
            }
            List<Object> needQueryList = new ArrayList<>();
            for (Object item : list) {
                if (relationManagerProcessor.isNeedQueryRelation(modelFieldConfig, FieldUtils.getFieldValue(item, modelFieldConfig.getLname()))) {
                    needQueryList.add(item);
                }
            }
            if (needQueryList.isEmpty()) {
                continue;
            }
            String field, indexString;
            int li = fieldKey.indexOf("["), ri = fieldKey.indexOf("]"), index;
            if (li != -1 && ri != -1) {
                indexString = fieldKey.substring(li + 1, ri);
                index = Integer.parseInt(indexString);
                field = fieldKey.substring(0, li);
                if (!hasQueryFields.contains(field)) {
                    currentMaxLength = computeCurrentMaxLength(maxSupportLength, currentMaxLength, needQueryList.size(), FetchUtil.listFieldQuery(dataManager, needQueryList, modelFieldsCache.get(field), maxSupportLength));
                    hasQueryFields.add(field);
                }
                if (index < needQueryList.size()) {
                    Object value = needQueryList.get(index);
                    if (!selectRelationField(dataManager, modelFieldConfig.getReferences(), fieldNode.getChildren(), Collections.singletonList(value), maxSupportLength, currentMaxLength)) {
                        return false;
                    }
                }
            } else if (li == -1 && ri == -1) {
                field = fieldKey;
                if (!hasQueryFields.contains(field)) {
                    currentMaxLength = computeCurrentMaxLength(maxSupportLength, currentMaxLength, needQueryList.size(), FetchUtil.listFieldQuery(dataManager, needQueryList, modelFieldsCache.get(field), maxSupportLength));
                    if (currentMaxLength == -1) {
                        return false;
                    }
                    hasQueryFields.add(field);
                }
                boolean isCollection = fieldNode.getValue().getIsCollection();
                List<Object> childList = new ArrayList<>();
                for (Object item : needQueryList) {
                    Object relationValue = FieldUtils.getFieldValue(item, field);
                    if (relationValue == null) {
                        continue;
                    }
                    if (isCollection) {
                        childList.addAll((Collection<?>) relationValue);
                    } else {
                        childList.add(relationValue);
                    }
                }
                if (!selectRelationField(dataManager, modelFieldConfig.getReferences(), fieldNode.getChildren(), childList, maxSupportLength, currentMaxLength)) {
                    return false;
                }
            }
        }
        return true;
    }

    private int computeCurrentMaxLength(int excelMaxSupportLength, int currentMaxLength, int needQuerySize, int listFieldQuerySize) {
        int incrementalSize = listFieldQuerySize - needQuerySize;
        if (incrementalSize <= 0) {
            return currentMaxLength;
        }
        currentMaxLength += incrementalSize;
        if (currentMaxLength > excelMaxSupportLength) {
            return -1;
        }
        return currentMaxLength;
    }
}

3.自定义导出任务的action

package pro.shushi.pamirs.demo.core.action;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;
import pro.shushi.pamirs.demo.api.model.DemoItemDynamicExcelExportTask;
import pro.shushi.pamirs.demo.core.excel.exportdemo.extPoint.DemoItemDynamicExportExtPoint;
import pro.shushi.pamirs.file.api.action.AbstractExcelExportTaskAction;
import pro.shushi.pamirs.file.api.config.ExcelConstant;
import pro.shushi.pamirs.file.api.context.ExcelDefinitionContext;
import pro.shushi.pamirs.file.api.enmu.FileExpEnumerate;
import pro.shushi.pamirs.file.api.model.ExcelWorkbookDefinition;
import pro.shushi.pamirs.file.api.util.ExcelFixedHeadHelper;
import pro.shushi.pamirs.file.api.util.ExcelHelper;
import pro.shushi.pamirs.file.api.util.ExcelWorkbookDefinitionUtil;
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.api.dto.config.ModelConfig;
import pro.shushi.pamirs.meta.api.session.PamirsSession;
import pro.shushi.pamirs.meta.common.exception.PamirsException;
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(DemoItemDynamicExcelExportTask.MODEL_MODEL)
public class DemoItemDynamicExcelExportTaskAction extends AbstractExcelExportTaskAction<DemoItemDynamicExcelExportTask> {

    @Action(displayName = "导出", contextType = ActionContextTypeEnum.CONTEXT_FREE, bindingType = {ViewTypeEnum.TABLE})
    public DemoItemDynamicExcelExportTask createExportTask(DemoItemDynamicExcelExportTask data) {
        if (data.getWorkbookDefinitionId() != null) {
            ExcelWorkbookDefinition workbookDefinition = new ExcelWorkbookDefinition();
            workbookDefinition.setId(data.getWorkbookDefinitionId());
            data.setWorkbookDefinition(workbookDefinition);
        }
        super.createExportTask(data);
        return data;
    }

    protected ExcelDefinitionContext fetchExcelDefinitionContextByWorkbookDefinition(DemoItemDynamicExcelExportTask data) {
        String model = data.getModel();
        if (StringUtils.isBlank(model)) {
            throw PamirsException.construct(FileExpEnumerate.EXPORT_MODEL_IS_NULL).errThrow();
        }
        ModelConfig modelConfig = PamirsSession.getContext().getSimpleModelConfig(model);
        if (modelConfig == null) {
            throw PamirsException.construct(FileExpEnumerate.EXPORT_MODEL_NOT_EXIST).errThrow();
        }
        ExcelFixedHeadHelper fixedHeadHelper = ExcelHelper.fixedHeader(model, DemoItemDynamicExportExtPoint.TEMPLATE_NAME)
                .setDisplayName(modelConfig.getDisplayName() + ExcelConstant.EXPORT_NAME)
                .createBlock(modelConfig.getDisplayName(), model);

        // 自定义excel START
        DemoItemDynamicExportExtPoint.buildHeader(fixedHeadHelper);
        // TODO 构建动态表头 addColumn第一个参数为动态字段的名称,第二个参数为在表头中的展示值,数据处理的扩展点内需要设置对应动态字段的值
        fixedHeadHelper.addColumn("2024-09-10", "2024-09-10");
        fixedHeadHelper.addColumn("2024-09-11", "2024-09-11");
        // 自定义excel END

        ExcelWorkbookDefinition workbookDefinition = fixedHeadHelper.build();
        data.setWorkbookDefinition(workbookDefinition);
        processClearExportStyle(data);
        return ExcelWorkbookDefinitionUtil.getDefinitionContext(workbookDefinition);
    }

    /**
     * @param data
     * @return
     */
    @Function(openLevel = FunctionOpenEnum.API)
    @Function.Advanced(type = FunctionTypeEnum.QUERY)
    public DemoItemDynamicExcelExportTask construct(DemoItemDynamicExcelExportTask data) {
        data.construct();
        return data;
    }

    @Override
    protected void doExport(DemoItemDynamicExcelExportTask exportTask, ExcelDefinitionContext context) {
        if (null != exportTask.getSync() && exportTask.getSync()) {
            excelFileService.doExportSync(exportTask, context);
        } else {
            excelFileService.doExportAsync(exportTask, context);
        }
    }
}

4.导出效果预览

如何通过自定义支持excel导出的动态表头

扩展学习

根据上面的例子,我们可以看出,所有需要对表头做自定义的场景都可以通过类似办法在DemoItemDynamicExcelExportTaskAction.fetchExcelDefinitionContextByWorkbookDefinition方法内进行处理

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

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

Like (0)
nation's avatarnation数式员工
Previous 2024年9月10日 pm3:34
Next 2024年9月12日 am11:23

相关推荐

  • IWrapper、QueryWrapper和LambdaQueryWrapper使用

    条件更新updateByWrapper 通常我们在更新的时候new一个对象出来在去更新,减少更新的字段 Integer update = new DemoUser().updateByWrapper(new DemoUser().setFirstLogin(Boolean.FALSE), Pops.<DemoUser>lambdaUpdate().from(DemoUser.MODEL_MODEL).eq(IdModel::getId, userId) 使用基础模型的updateById方法更新指定字段的方法: new 一下update对象出来,更新这个对象。 WorkflowUserTask userTaskUp = new WorkflowUserTask(); userTaskUp.setId(userTask.getId()); userTaskUp.setNodeContext(json); userTaskUp.updateById(); 条件删除updateByWrapper public List<T> delete(List<T> data) { List<Long> petTypeIdList = new ArrayList(); for(T item:data){ petTypeIdList.add(item.getId()); } Models.data().deleteByWrapper(Pops.<PetType>lambdaQuery().from(PetType.MODEL_MODEL).in(PetType::getId,petTypeIdList)); return data; } 构造条件查询数据 示例1: LambdaQueryWrapper拼接查询条件 private void queryPetShops() { LambdaQueryWrapper<PetShop> query = Pops.<PetShop>lambdaQuery(); query.from(PetShop.MODEL_MODEL); query.setSortable(Boolean.FALSE); query.orderBy(true, true, PetShop::getId); List<PetShop> petShops2 = new PetShop().queryList(query); System.out.printf(petShops2.size() + ""); } 示例2: IWrapper拼接查询条件 private void queryPetShops() { IWrapper<PetShop> wrapper = Pops.<PetShop>lambdaQuery() .from(PetShop.MODEL_MODEL).eq(PetShop::getId,1L); List<PetShop> petShops4 = new PetShop().queryList(wrapper); System.out.printf(petShops4.size() + ""); } 示例3: QueryWrapper拼接查询条件 private void queryPetShops() { //使用Lambda获取字段名,防止后面改字段名漏改 String nameField = LambdaUtil.fetchFieldName(PetTalent::getName); //使用Lambda获取Clumon名,防止后面改字段名漏改 String nameColumn = PStringUtils.fieldName2Column(nameField); QueryWrapper<PetShop> wrapper2 = new QueryWrapper<PetShop>().from(PetShop.MODEL_MODEL) .eq(nameColumn, "test"); List<PetShop> petShops5 = new PetShop().queryList(wrapper2); System.out.printf(petShops5.size() + ""); } IWrapper转为LambdaQueryWrapper @Function.Advanced(type= FunctionTypeEnum.QUERY) @Function.fun(FunctionConstants.queryPage) @Function(openLevel = {FunctionOpenEnum.API}) public Pagination<PetShopProxy> queryPage(Pagination<PetShopProxy> page, IWrapper<PetShopProxy> queryWrapper) { LambdaQueryWrapper<PetShopProxy> wrapper = ((QueryWrapper<PetShopProxy>) queryWrapper).lambda(); // 非存储字段从QueryData中获取 Map<String, Object> queryData = queryWrapper.getQueryData(); if (null != queryData && !queryData.isEmpty()) { String codes = (String) queryData.get("codes"); if (org.apache.commons.lang3.StringUtils.isNotBlank(codes)) { wrapper.in(PetShopProxy::getCode, codes.split(",")); } } return new PetShopProxy().queryPage(page, wrapper); }

    2024年5月25日
    2.9K00
  • 后端:如何自定义表达式实现特殊需求?扩展内置函数表达式

    平台提供了很多的表达式,如果这些表达式不满足场景?那我们应该如何新增表达式去满足项目的需求?目前平台支持的表达式内置函数,参考 1. 扩展表达式的场景 注解@Validation的rule字段支持配置表达式校验如果需要判断入参List类型字段中的某一个参数进行NULL校验,发现平台的内置函数不支持该场景的配置,这里就可以通过平台的机制,对内置函数进行扩展。 常见的一些代码场景,如下: package pro.shushi.pamirs.demo.core.action; ……引用类 @Model.model(PetShopProxy.MODEL_MODEL) @Component public class PetShopProxyAction extends DataStatusBehavior<PetShopProxy> { @Override protected PetShopProxy fetchData(PetShopProxy data) { return data.queryById(); } @Validation(ruleWithTips = { @Validation.Rule(value = "!IS_BLANK(data.code)", error = "编码为必填项"), @Validation.Rule(value = "LEN(data.name) < 128", error = "名称过长,不能超过128位"), }) @Action(displayName = "启用") @Action.Advanced(invisible="!(activeRecord.code !== undefined && !IS_BLANK(activeRecord.code))") public PetShopProxy dataStatusEnable(PetShopProxy data){ data = super.dataStatusEnable(data); data.updateById(); return data; } ……其他代码 } 2. 新建一个自定义表达式的函数 校验入参如果是个集合对象的情况下,单个对象的某个字段如果为空,返回false的函数。 例子:新建一个CustomCollectionFunctions类 package xxx.xxx.xxx; import org.apache.commons.collections4.CollectionUtils; import org.springframework.stereotype.Component; import pro.shushi.pamirs.meta.annotation.Fun; import pro.shushi.pamirs.meta.annotation.Function; import pro.shushi.pamirs.meta.common.constants.NamespaceConstants; import pro.shushi.pamirs.meta.util.FieldUtils; import java.util.List; import static pro.shushi.pamirs.meta.enmu.FunctionCategoryEnum.COLLECTION; import static pro.shushi.pamirs.meta.enmu.FunctionLanguageEnum.JAVA; import static pro.shushi.pamirs.meta.enmu.FunctionOpenEnum.LOCAL; import static pro.shushi.pamirs.meta.enmu.FunctionSceneEnum.EXPRESSION; /** * 自定义内置函数 */ @Fun(NamespaceConstants.expression) @Component public class CustomCollectionFunctions { /** * LIST_FIELD_NULL 就是我们自定义的表达式,不能与已经存在的表达式重复!!! * * @param list * @param field * @return */ @Function.Advanced( displayName = "校验集成的参数是否为null", language = JAVA, builtin = true, category = COLLECTION ) @Function.fun("LIST_FIELD_NULL") @Function(name = "LIST_FIELD_NULL", scene = {EXPRESSION}, openLevel = LOCAL, summary = "函数示例: LIST_FIELD_NULL(list,field),函数说明: 传入一个对象集合,校验集合的字段是否为空" ) public Boolean listFieldNull(List list, String field) { if (null == list) { return false; } if (CollectionUtils.isEmpty(list)) { return false; } for (Object data : list) { Object value =…

    2024年5月30日
    3.9K00
  • Oinone连接外部数据源方案

    场景描述 在实际业务场景中,有是有这样的需求:链接外部数据进行数据的获取;通常的做法:1、【推荐】通过集成平台的数据连接器,链接外部数据源进行数据操作;2、项目代码中链接数据源,即通过程序代码操作外部数据源的数据; 本篇文章只介绍通过程序代码操作外部数据源的方式. 整体方案 Oinone管理外部数据源,即yml中配置外部数据源; 后端通过Mapper的方式进行数据操作(增/删/查/改); 调用Mapper接口的时候,指定到外部数据源; 详细步骤 1、数据源配置(application.yml), 与正常的数据源配置一样 out_ds_name(外部数据源别名): driverClassName: com.mysql.cj.jdbc.Driver type: com.alibaba.druid.pool.DruidDataSource # local环境配置调整 url: jdbc:mysql://ip(host):端口/数据库Schema?useSSL=false&allowPublicKeyRetrieval=true&useServerPrepStmts=true&cachePrepStmts=true&useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai&autoReconnect=true&allowMultiQueries=true username: 用户名 password: 命名 initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true 2、外部数据源其他配置外部数据源限制创建表结构的执行,可以通过配置指定【不创建DB,不创建数据表】 persistence: global: auto-create-database: true auto-create-table: true ds: out_ds_name(外部数据源别名): # 不创建DB auto-create-database: false # 不创建数据表 auto-create-table: false 3、后端写Mapper SQL Mapper跟使用原生mybaits/mybaits-plus写法一样,无特殊限制; Mapper和SQL写到一起,或者分开两个文件都可以 4、Mapper被Service或者Action调用1)启动的Application中@MapperScan需要扫描到对应的包。2)调用是与普通bean一样(即调用方式跟传统的方式样),唯一的区别就是加上DsHintApi,即指定Mapper所使用的数据源。 @Autowired private ScheduleItemMapper scheduleItemMapper; public saveData(Object data) { ScheduleQuery scheduleQuery = new ScheduleQuery(); //scheduleQuery.setActionName(); try (DsHintApi dsHint = DsHintApi.use(“外部数据源名称”)) { List<ScheduleItem> scheduleItems = scheduleItemMapper.selectListForSerial(scheduleQuery); // 具体业务逻辑 } } 其他参考:如何自定义sql语句:https://doc.oinone.top/backend/4759.html

    2024年5月17日
    2.4K00
  • Oinone请求路由源码分析

    通过源码分析,从页面发起请求,如果通过graphQL传输到具体action的链路,并且在这之间做了哪些隐式处理分析源码版本5.1.x 请求流程大致如下: 拦截所有指定的请求 组装成graphQL请求信息 调用graphQL执行 通过hook拦截先执行 RsqlDecodeHook:rsql解密 UserHook: 获取用户信息, 通过cookies获取用户ID,再查表获取用户信息,放到本地Local线程里 RoleHook: 角色Hook FunctionPermissionHook: 函数权限Hook ,跳过权限拦截的实现放在这一层,对应的配置 pamirs: auth: fun-filter: – namespace: user.PamirsUserTransient fun: login #登录 – namespace: top.PetShop fun: action DataPermissionHook: 数据权限hook PlaceHolderHook:占位符转化替换hook RsqlParseHook: 解释Rsql hook SingletonModelUpdateHookBefore 执行post具体内容 通过hook拦截后执行 QueryPageHook4TreeAfter: 树形Parent查询优化 FieldPermissionHook: 字段权限Hook UserQueryPageHookAfter UserQueryOneHookAfter 封装执行结果信息返回 时序图 核心源码解析 拦截所有指定的请求 /pamirs/模块名RequestController @RequestMapping( value = "/pamirs/{moduleName:^[a-zA-Z][a-zA-Z0-9_]+[a-zA-Z0-9]$}", method = RequestMethod.POST ) public String pamirsPost(@PathVariable("moduleName") String moduleName, @RequestBody PamirsClientRequestParam gql, HttpServletRequest request, HttpServletResponse response) { } DefaultRequestExecutor 构建graph请求信息,并调用graph请求 () -> execute(GraphQL::execute, param), param private <T> T execute(BiFunction<GraphQL, ExecutionInput, T> executor, PamirsRequestParam param) { // 获取GraphQL请求信息,包含grapsh schema GraphQL graphQL = buildGraphQL(param); … ExecutionInput executionInput = ExecutionInput.newExecutionInput() .query(param.getQuery()) .variables(param.getVariables().getVariables()) .dataLoaderRegistry(Spider.getDefaultExtension(DataLoaderRegistryApi.class).dataLoader()) .build(); … // 调用 GraphQL的方法execute 执行 T result = executor.apply(graphQL, executionInput); … return result; } QueryAndMutationBinder 绑定graphQL读取写入操作 public static DataFetcher<?> dataFetcher(Function function, ModelConfig modelConfig) { if (isAsync()) { if (FunctionTypeEnum.QUERY.in(function.getType())) { return AsyncDataFetcher.async(dataFetchingEnvironment -> dataFetcherAction(function, modelConfig, dataFetchingEnvironment), ExecutorServiceApi.getExecutorService()); } else { return dataFetchingEnvironment -> dataFetcherAction(function, modelConfig, dataFetchingEnvironment); } } else { return dataFetchingEnvironment -> dataFetcherAction(function, modelConfig, dataFetchingEnvironment); } } private static Object dataFetcherAction(Function function, ModelConfig modelConfig, DataFetchingEnvironment environment) { try { SessionExtendUtils.tagMainRequest(); // 使用共享的请求和响应对象 return Spider.getDefaultExtension(ActionBinderApi.class) .action(modelConfig,…

    2024年8月21日
    6.1K02
  • Oinone设计器部署参数说明

    概述 Oinone提供两种设计器部署方式,合作伙伴可以自行选择适合自己的部署方式。 Docker配置参数 环境变量 ARG_ENV:指定spring.profiles.active(默认:dev) ARG_LIFECYCLE:指定-Plifecycle(默认:INSTALL) JVM_OPTIONS:jvm参数 PROGRAM_ARGS:程序参数 JVM_OPTIONS和PROGRAM_ARGS参数说明 java [JVM_OPTIONS?] -jar boot.jar [PROGRAM_ARGS?] 端口说明 PS:以下为目前设计器镜像的全部端口,不同类型镜像的端口由于内置服务不同,使用的端口数量不同,但端口号是完全一致的。 80:前端服务端口(设计器访问入口) 8091:后端服务端口 8093:后端EIP服务端口 20880:Dubbo端口 3306:内置MySQL端口 2181:内置Zookeeper端口 6379:内置Redis端口 9876/10991:内置RocketMQ端口 9999:内置本地OSS默认端口 挂载目录说明(挂载虚拟卷) /opt/pamirs为镜像的工作目录,所有挂载目录均在该目录下。 /opt/pamirs/ext:应用配置文件目录;包含application.yml、logback.xml、license.lic等配置文件 /opt/pamirs/nginx/vhost:Nginx配置文件目录 /opt/pamirs/logs:后端服务日志目录 /opt/mq/conf/broker.conf:RocketMQ的broker配置文件 /opt/pamirs/outlib:非设计器内置包的外部加载目录(外部库),可以添加任何jar包集成到设计器中。 /opt/pamirs/dist:前端服务目录 /opt/pamirs/static:前端静态文件目录;LOCAL类型的OSS上传和下载目录; docker run启动常用参数 -e:指定环境变量 -p:指定端口映射 -v:指定挂载目录(挂载虚拟卷) docker run [OPTIONS] IMAGE [COMMAND] [ARG…] docker compose启动常用配置 services: container: image: $IMAGE container_name: $CONTAINER_NAME restart: always # docker run -e environment: KEY1: VALUE1 KEY2: VALUE2 … # docker run -p ports: – $machinePort1:$containerPort1 – $machinePort2:$containerPort2 … # docker run -v volumes: – $machinePath1:$containerPath1 – $machinePath2:$containerPath2 … docker compose常用命令 # 使用docker-compose.yaml启动 docker compose up -d # 使用docker-compose.yaml停止并删除容器 docker compose down -v # 指定配置文件启动 docker compose -f config.yaml up -d # 指定配置文件停止并删除容器 docker compose -f config.yaml down -v JAR包方式启动 下载Oinone专属启动器 oinone-boot-starter.zip 启动命令变化 # 原命令 java -jar boot.jar # 变更后命令 boot-starter java -jar boot.jar PS:更多命令可查看后端无代码设计器Jar包启动方法

    2024年11月4日
    1.8K00

Leave a Reply

Please Login to Comment