如何自定义Excel导入功能

介绍

在平台提供的默认导入功能无法满足业务需求的时候,我们可以自定义导入功能,以满足业务中个性化的需求。

功能示例

下面以导入文件的时候加入发布人的字段作为示例讲解。

  1. 继承平台的导入任务模型,加上需要在导入的弹窗视图需要展示的字段
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;
}
  1. 编写自定义导入弹窗视图的数据初始化方法和导入提交的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;
    }

}
  1. 编写导入的单行数据处理逻辑,此处可以拿到导入弹窗内自定义的字段提交的值,然后根据这些值处理自定义逻辑,此处演示代码就是将导入后的商品的发布人都设置为自定义导入视图填的发布人信息
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;
import pro.shushi.pamirs.file.api.model.ExcelImportTask;
import pro.shushi.pamirs.meta.annotation.Ext;
import pro.shushi.pamirs.meta.annotation.ExtPoint;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.common.exception.PamirsException;

import java.util.Optional;

@Slf4j
@Component
@Ext(ExcelImportTask.class)
public class DemoItemImportExtPoint extends AbstractExcelImportDataExtPointImpl<DemoItem> implements ExcelImportDataExtPoint<DemoItem> {

    @Autowired
    private DemoItemService demoItemService;

    @Override
    @ExtPoint.Implement(expression = "importContext.definitionContext.model == \"" + DemoItem.MODEL_MODEL + "\"")
    public Boolean importData(ExcelImportContext importContext, DemoItem data) {
        ExcelImportTask importTask = importContext.getImportTask();
        try {
            DemoItemImportTask hrExcelImportTask = new DemoItemImportTask().queryById(importTask.getId());

            String publishUserName = Optional.ofNullable(hrExcelImportTask).map(DemoItemImportTask::getPublishUserName).orElse(null);
            // 个性化字段设置到模型数据中
            data.setPublishUserName(publishUserName);

            demoItemService.create(data);
        } catch(PamirsException e) {
            log.error("导入异常", e);
        } catch (Exception e) {
            log.error("导入异常", e);
        }
        return Boolean.TRUE;
    }
}
  1. 编写导入的视图xml
<view type="FORM" title="导入" name="import_dialog" widget="form" model="demo.DemoItemImportTask" width="small">
    <template slot="form" cols="1">
        <field data="model" invisible="true"/>
        <field data="publishUserName"/>
        <field data="workbookDefinition" widget="Select" label="导入模板" required="true"
               domain="model == ${activeRecord.model} and dataStatus == 'ENABLED' and type =in= ('IMPORT_EXPORT','IMPORT')"/>
        <field data="file" widget="Upload" label="上传文件" required="true"/>
    </template>
    <template slot="footer">
        <action name="$$internal_DownloadImportWorkbook" label="下载模板" type="PRIMARY"/>
        <action name="createImportTask" label="导入" type="PRIMARY" validateForm="true" closeDialog="true" refreshData="true"/>
    </template>
</view>
  1. 初始化导入的动作
package pro.shushi.pamirs.demo.core.init;

import org.springframework.stereotype.Component;
import pro.shushi.pamirs.boot.base.enmu.ActionTargetEnum;
import pro.shushi.pamirs.boot.common.api.command.AppLifecycleCommand;
import pro.shushi.pamirs.boot.common.api.init.LifecycleCompletedAllInit;
import pro.shushi.pamirs.boot.common.extend.MetaDataEditor;
import pro.shushi.pamirs.core.common.InitializationUtil;
import pro.shushi.pamirs.demo.api.DemoModule;
import pro.shushi.pamirs.demo.api.model.DemoItem;
import pro.shushi.pamirs.demo.api.model.DemoItemImportTask;
import pro.shushi.pamirs.file.api.init.FileExportAndImportViewActionInit;
import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j;
import pro.shushi.pamirs.meta.api.dto.meta.Meta;
import pro.shushi.pamirs.meta.domain.module.ModuleDefinition;
import pro.shushi.pamirs.meta.enmu.ActionContextTypeEnum;
import pro.shushi.pamirs.meta.enmu.ViewTypeEnum;

import java.util.HashMap;
import java.util.Map;

@Slf4j
@Component
public class DemoModuleAppInstall implements MetaDataEditor, LifecycleCompletedAllInit {

    @Override
    public void edit(AppLifecycleCommand command, Map<String, Meta> metaMap) {
        InitializationUtil util = InitializationUtil.get(metaMap, DemoModule.MODULE_MODULE, DemoModule.MODULE_NAME);

        util.createViewAction("demoItemImportAction", "商品导入", DemoItem.MODEL_MODEL,
                InitializationUtil.getOptions(ViewTypeEnum.TABLE,ViewTypeEnum.GALLERY), DemoItemImportTask.MODEL_MODEL, ViewTypeEnum.FORM,
                ActionContextTypeEnum.CONTEXT_FREE, ActionTargetEnum.DIALOG, FileExportAndImportViewActionInit.DEFAULT_IMPORT_VIEW_NAME, "", _va->{
            Map<String, Object> context = new HashMap<>();
            context.put("model", "'" + DemoItem.MODEL_MODEL + "'");
            _va.setContext(context);
        });
    }

    @Override
    public void process(AppLifecycleCommand command, Map<String, ModuleDefinition> runModuleMap) {
    }
}
  1. 导入功能完成,我们看导入弹窗页面的截图 WX20231122-042634@2x

本文来自投稿,不代表Oinone社区立场,如若转载,请注明出处:https://doc.oinone.top/backend/4716.html

Like (1)
nation's avatarnation数式员工
Previous 2023年11月21日 pm6:12
Next 2023年11月23日

相关推荐

  • 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.apache.commons.lang3.StringUtils; 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.SSOConstant; 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.utils.AuthenticateUtils; import pro.shushi.pamirs.demo.core.sso.model.PermissionInfoResp; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO; import pro.shushi.pamirs.meta.api.dto.protocol.PamirsRequestVariables; 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.meta.common.util.UUIDUtil; 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.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.concurrent.TimeUnit; /** * * @author wangxian * * 完全自定义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 createSessionId(HttpServletRequest request, PamirsUser idModel) { return UUIDUtil.getUUIDNumberString(); } @Override public String type() { return UserLoginTypeEnum.COOKIE.value(); } @Override public PamirsUser resolveAndVerification(PamirsUserTransient user) { if (checker == null) { checker =…

    2023年11月24日
    2.0K00
  • JSON转换工具类

    JSON转换工具类 JSON转对象 pro.shushi.pamirs.meta.util.JsonUtils JSON转模型 pro.shushi.pamirs.framework.orm.json.PamirsDataUtils

    2023年11月1日
    2.6K00
  • 【MSSQL】后端部署使用MSSQL数据库(SQLServer)

    MSSQL数据库配置 驱动配置 Maven配置(2017版本可用) <mssql.version>9.4.0.jre8</mssql.version> <dependency> <groupId>com.microsoft.sqlserver</groupId> <artifactId>mssql-jdbc</artifactId> <version>${mssql.version}</version> </dependency> 离线驱动下载 mssql-jdbc-7.4.1.jre8.jarmssql-jdbc-9.4.0.jre8.jarmssql-jdbc-12.2.0.jre8.jar JDBC连接配置 pamirs: datasource: base: type: com.alibaba.druid.pool.DruidDataSource driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver url: jdbc:sqlserver://127.0.0.1:1433;DatabaseName=base username: xxxxxx password: xxxxxx initialSize: 5 maxActive: 200 minIdle: 5 maxWait: 60000 timeBetweenEvictionRunsMillis: 60000 testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true asyncInit: true 连接url配置 暂无官方资料 url格式 jdbc:sqlserver://${host}:${port};DatabaseName=${database} 在jdbc连接配置时,${database}必须配置,不可缺省。 其他连接参数如需配置,可自行查阅相关资料进行调优。 方言配置 pamirs方言配置 pamirs: dialect: ds: base: type: MSSQL version: 2017 major-version: 2017 pamirs: type: MSSQL version: 2017 major-version: 2017 数据库版本 type version majorVersion 2017 MSSQL 2017 2017 PS:由于方言开发环境为2017版本,其他类似版本原则上不会出现太大差异,如出现其他版本无法正常支持的,可在文档下方留言。 schedule方言配置 pamirs: event: enabled: true schedule: enabled: true dialect: type: MSSQL version: 2017 major-version: 2017 type version majorVersion MSSQL 2017 2017 PS:由于schedule的方言在多个版本中并无明显差异,目前仅提供一种方言配置。 其他配置 逻辑删除的值配置 pamirs: mapper: global: table-info: logic-delete-value: CAST(DATEDIFF(S, CAST('1970-01-01 00:00:00' AS DATETIME), GETUTCDATE()) AS BIGINT) * 1000000 + DATEPART(NS, SYSUTCDATETIME()) / 100 MSSQL数据库用户初始化及授权 — init root user (user name can be modified by oneself) CREATE LOGIN [root] WITH PASSWORD = 'password'; — if using mssql database, this authorization is required. ALTER SERVER ROLE [sysadmin] ADD MEMBER [root];

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

    平台提供了很多的表达式,如果这些表达式不满足场景?那我们应该如何新增表达式去满足项目的需求?目前平台支持的表达式内置函数,参考 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
  • 字段类型之关系描述的特殊场景(常量关联)

    场景概述 【字段类型之关系与引用】一文中已经描述了各种关系字段的常规写法,还有一些特殊场景如:关系映射中存在常量,或者M2M中间表是大于两个字段构成。 场景描述 1、PetTalent模型增加talentType字段2、PetItem与PetTalent的多对多关系增加talentType(达人类型),3、PetItemRelPetTalent中间表维护petItemId、petTalentId以及talentType,PetDogItem和PetCatItem分别重写petTalents字段,关系中增加常量描述。示意图如下: 实际操作步骤 Step1 新增 TalentTypeEnum package pro.shushi.pamirs.demo.api.enumeration; import pro.shushi.pamirs.meta.annotation.Dict; import pro.shushi.pamirs.meta.common.enmu.BaseEnum; @Dict(dictionary = TalentTypeEnum.DICTIONARY,displayName = "达人类型") public class TalentTypeEnum extends BaseEnum<TalentTypeEnum,Integer> { public static final String DICTIONARY ="demo.TalentTypeEnum"; public final static TalentTypeEnum DOG =create("DOG",1,"狗达人","狗达人"); public final static TalentTypeEnum CAT =create("CAT",2,"猫达人","猫达人"); } Step2 PetTalent模型增加talentType字段 package pro.shushi.pamirs.demo.api.model; import pro.shushi.pamirs.demo.api.enumeration.TalentTypeEnum; import pro.shushi.pamirs.meta.annotation.Field; import pro.shushi.pamirs.meta.annotation.Model; @Model.model(PetTalent.MODEL_MODEL) @Model(displayName = "宠物达人",summary="宠物达人",labelFields ={"name"}) public class PetTalent extends AbstractDemoIdModel{ public static final String MODEL_MODEL="demo.PetTalent"; @Field(displayName = "达人") private String name; @Field(displayName = "达人类型") private TalentTypeEnum talentType; } Step3 修改PetItem的petTalents字段,在关系描述中增加talentType(达人类型) @Field.many2many(relationFields = {"petItemId"},referenceFields = {"petTalentId","talentType"},through = PetItemRelPetTalent.MODEL_MODEL ) @Field.Relation(relationFields = {"id"}, referenceFields = {"id","talentType"}) @Field(displayName = "推荐达人",summary = "推荐该商品的达人们") private List<PetTalent> petTalents; Step4 PetDogItem增加petTalents字段,重写父类PetItem的关系描述 talentType配置为常量,填入枚举的值 增加domain描述用户页面选择的时候自动过滤出特定类型的达人,RSQL用枚举的name @Field(displayName = "推荐达人") @Field.many2many( through = "PetItemRelPetTalent", relationFields = {"petItemId"}, referenceFields = {"petTalentId","talentType"} ) @Field.Relation(relationFields = {"id"}, referenceFields = {"id", "#1#"}, domain = " talentType == DOG") private List<PetTalent> petTalents; Step5 PetCatItem增加petTalents字段,重写父类PetItem的关系描述 talentType配置为常量,填入枚举的值 增加domain描述用户页面选择的时候自动过滤出特定类型的达人,RSQL用枚举的name @Field(displayName = "推荐达人") @Field.many2many( through = "PetItemRelPetTalent", relationFields = {"petItemId"}, referenceFields = {"petTalentId","talentType"} ) @Field.Relation(relationFields = {"id"}, referenceFields = {"id", "#2#"}, domain = " talentType == CAT") private List<PetTalent> petTalents; Step6 PetCatItem增加petTalents字段,many2one关系示例 talentType配置为常量,填入枚举的值 增加domain描述用户页面选择的时候自动过滤出特定类型的达人,RSQL用枚举的name @Model.model(PetPet.MODEL_MODEL) @Model(displayName…

    2024年5月25日
    2.3K00

Leave a Reply

Please Login to Comment