导入导出二开常见问题
**1.二开时,如何将继承导入插件BatchImportPlugin中的部分数据或标识,传递至表单插件中,以供类似beforeImport的方法获取?**
答:可在BatchImportPlugin的插件中,调用导入上下文对象ImportContext(ctx)中插入数据,后续通过方法入参中的option对象即可获取。
**2.当需要同时导入多个业务对象时,如何二开实现?**
答:可按如下方案实现:
方案一:上传多个Excel模板,每个模板均符合对应业务对象的导入模板要求。
优点:代码开发量小,可复用现有的导入相关的二开逻辑;
缺点:该方式实际是将多次导入过程在二开代码中整合成一次,可调整的逻辑较小。
步骤:
①构建一个文件上传入口,可上传一个或多个Excel文件。
②监听步骤①的上传事件(表单插件中监听upload事件),收集上传完成的Excel文件。
③可参考标准产品kd.bos.form.plugin.impt.ImportService#startImport的写法,启动导入相关的两个线程(入参url即为Excel的文件服务器地址,调用一次启动一个单据的导入任务,多个单据启动多次,BatchImportPlugin可为业务单据的导入插件(即BatchImportPlugin子类))
```java
/**
* 设置导入页面显示
*
* @param rc rc
* @param ctx ctx
* @param startArgs startArgs
* @return BatchImportPlugin
*/
@Override
public BatchImportPlugin setContext(RequestContext rc, ImportContext ctx, List<String> startArgs) {
try {
Field view = ctx.getClass().getDeclaredField("view");
ReflectionUtils.makeAccessible(view);
try {
IFormView formView = (FormView) view.get(ctx);
formView.setVisible(false, "radiofield", "radiofield1");
} catch (IllegalAccessException e) {
LOGGER.error(e.getMessage());
}
} catch (NoSuchFieldException e) {
LOGGER.error(e.getMessage());
}
return super.setContext(rc, ctx, startArgs);
}
```
方案二:构建一个包含多个业务对象字段的整合型单据(假设多个单据间存在一对一,一对多关系,则可按照分录等格式构建),配置标准导入操作。
优点:相较于方案一更加灵活
缺点:不执行各单据原有的导入相关逻辑;
步骤:
①配置多个业务对象的整合型单据实体
②该单据配置标准导入操作
③该单据配置导入插件(BatchImportPlugin),并重写其save方法,在save方法中,完成对数据的分离及各实际库表的持久化。
**3.当业务需要导入非标准模板的数据时,如何二开实现?**
参照问题5中方案一的实现,并且重写其导入插件的“resolveExcel”方法,构造与标准产品一致的JSON格式数据。
代码可以参考:
```java
//伪代码,仅供参考,请勿复制
public void statlmport(String ogld,String sevicehppld, String checkRightApid,String billFornd,String listlame, String url,String importpiugin){
RequestContext rc = RequestContext.qet();
string readoriginalNumstring = System.getProperty( "import.readoriginalNum", Boolean.tostring(false));
Boslean readOriginalNum = Boolean.parseBoolean(readoriginaNumString);
Importcontext ctx =(new Imortontext(this.getView(), logId, seviceAppId, checkrightappId, listMame,billFomld,"save",url,"", false ,"", null,null, "", null, read0riginalNum))
.addOption("importtype","new")
.addOption("KeyFields", null)
.addOption("ForUpdateMultiLangFields",false)
.addOption("OverrideEntry",false)
.addOption("SetNuLL",true)
.addOption("splitSubEntries", false);
IImportDataPlugin plugin = (IImportDataPlugin)TypesContainer.createInstance(importPlugin);
BatchImportplugin batchPlugin = ((BatchImportpludin)pluin).setContext(rc, ctx,Arnays.aslist("resolveExcel", "importData");
thregdPool.submit(batchplugin);
threadPool.submit(batchplugin);
```
**4.当业务需要将引出的Excel文件做一些格式的调整时,如何二开实现?**
答:可以重写列表导出插件中的afterExportFile方法,该方法中,二开可以获取即将下载的文件流,拿到文件流后,可以使用POI提供的相关类进行文件格式、数据的修改调整。可参考如下代码:
```java
/**@author rd_agbyte_yang
*
* 示例代码实现功能:
* 1.修改按列表导出的文件名为【实体名称】+列表.xlsx
* 2.修改前三行的第一列为红色字体
*
*/
public class TestExportListPlugin extends AbstractListPlugin {
@Override
public void beforeExportFile(BeforeExportFileEvent e) {
// 示例:将引出文件名重置为主实体名称+“引出列表”
e.setFileName(e.getMainEntityType().getDisplayName() + "引出列表.xlsx");
}
@Override
public void afterExportFile(ExportFileEvent e) {
File file = e.getFile();
if (file != null) {
// 示例:修改前三行的第一列为红色字体
try (FileInputStream fis = new FileInputStream(file);) {
Workbook wb = new XSSFWorkbook(fis);
Sheet sheet = wb.getSheetAt(0);
// 修改背景颜色(示例写死,自行修改)
for (int i = 0; i < 3; i++) {
CellStyle cs = wb.createCellStyle();
cs.setFillForegroundColor(IndexedColors.RED.getIndex());
cs.setFillPattern(FillPatternType.SOLID_FOREGROUND);
sheet.getRow(i).getCell(1).setCellStyle(cs);
}
// 保存
FileOutputStream out = new FileOutputStream(file);
wb.write(out);
wb.close();
out.close();
} catch (Throwable ex) {
ex.printStackTrace();
}
}
}
}
```
**5.当业务需要将导出的Excel文件做一些格式的调整时,且数据量较大时(问题7方式可能在大数据量下导致OOM),如何二开实现?**
问题7的解决方案较为简单,可以适用于大部分数据量小的导出场景,当数据量较大时,POI的方法
```java
Workbook wb = new XSSFWorkbook(fis);
```
可能存在性能问题,占用较大内存空间,产生OOM问题,此时需要另外的方式进行处理,建议参考如下伪代码进行处理
```java
//伪代码 MySheetHandler更多细节可参考
kd.bos.form.plugin.impt.BatchImportFailedSheetHandler#handleRow
//伪代码,请勿复制
public void afterExportFile(ExportFileEvent e) {
File file = e.getFile();
if (file != null) {
new ExcelReader().read(in, new SheetHandler() {
@Override
public void handleRow(ParsedRow row) {
/**
*入参为Excel的每行数据,根据业务场景处理,也可参考
*kd.bos.form.plugin.impt.BatchImportFailedSheetHandler#handleRow
*/
dealWithRowData(row);
}
}, true);
}
}
```
**6.导入模板中的基础资料,需要手动输入编码,可能存在错误输入(如空格)或客户认为输入编码较为繁琐,如何二开实现基础资料如下拉选项字段一样,可以下拉选择基础资料值?**
可参考链接:https://vip.kingdee.com/knowledge/specialDetail/228886918686445824?category=449142108704634112&id=327109527931751680&productLineId=29
**7.客户现场不想使用苍穹标准的导入模板,二开如何实现导入客户的模板?**
可参考如下demo,自行处理解析数据的逻辑:
```java
public class TestBatchImportPlugin extends BatchImportPlugin {
@Override
protected void resolveExcel() {
FileService service = FileServiceFactory.getAttachmentFileService();
ExcelReader reader = new ExcelReader();
//此为历史设计,当前导入文件路径集合中有且仅有一条数据
Set<String> allUrls = ctx.getAllUrls();
List<String> urlList = new ArrayList<>(allUrls);
String importExcelFileUrl = urlList.get(0);
try (InputStream in = service.getInputStream(importExcelFileUrl)) {
MainEntityType mainEntityType = buildMainEntityType(null);
if (mainEntityType instanceof QueryEntityType) {
mainEntityType = ((QueryEntityType) mainEntityType).getMainEntityType();
}
// MySheetHandler为用户自定义的excel解析器
reader.read(in, new MySheetHandler(ctx, mainEntityType, importExcelFileUrl));
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
ctx.setResolveComplete(importExcelFileUrl);
}
}
/**
* 可以自定义保存,比如直接入库等,还可以在保存后做额外的逻辑
*/
@Override
protected ApiResult save(List<ImportBillData> rowdatas, ImportLogger logger) {
ApiResult result = super.save(rowdatas, logger);
if (result.getSuccess()) {
// TODO 额外的逻辑,比如级联更新别的实体的数据,触发另外的操作等等
}
return result;
}
}
class MySheetHandler extends SheetHandler {
private int startRowNum = 0;
private int currRowNum = 0;
private ImportEntityMapping entityMapping;
private Map<Integer, String> nameRow;
private ImportContext ctx;
private MainEntityType mainEntityType;
private String importExcelFileUrl;
private LinkedBlockingQueue<ImportBillData> dataQueue;
public MySheetHandler(ImportContext ctx, MainEntityType mainEntityType, String importExcelFileUrl) {
this.ctx = ctx;
this.mainEntityType = mainEntityType;
this.importExcelFileUrl = importExcelFileUrl;
this.dataQueue = ctx.getDataQueue(importExcelFileUrl);
this.importExcelFileUrl = importExcelFileUrl;
}
@Override
public void handleRow(ParsedRow currentRow) {
JSONObject jsonData = new JSONObject();
currRowNum = currentRow.getRowNum();
//假设字段标识行在第三行
if (currRowNum == 2) {
nameRow = currentRow.getData();
}
if (currRowNum == 3) {
//注意 此处会根据标识构建一个映射对象,如不适用该对象,请自行构建
//包含的主要信息为Map<String, ColInfo> cols;列数据格式
entityMapping = ImportEntityMapping.create(mainEntityType, nameRow, currentRow.getData());
}
//假设数据行从Excel第五行开始
if (currRowNum >= 4) {
Map<Integer, String> rowData = currentRow.getData();
for (Map.Entry<Integer, String> integerStringEntry : rowData.entrySet()) {
/**
* 示例代码,根据实际数据解析构建成JSON格式
*/
jsonData.put("keyField1",integerStringEntry.getValue());
}
}
addBillData(new ImportBillData(jsonData, startRowNum, currRowNum,entityMapping));
}
private void addBillData(ImportBillData billData) {
try {
if (!dataQueue.offer(billData, 10, TimeUnit.MINUTES)) {
throw new KDBizException("解析超时");
}
} catch (Throwable e) {
throw new KDBizException("解析存在未知异常");
}
}
}
}
```
导入导出二开常见问题
**1.二开时,如何将继承导入插件BatchImportPlugin中的部分数据或标识,传递至表单插件中,以供类似beforeImport的方法获取?**答:可在Bat...
点击下载文档
本文2024-09-23 00:36:10发表“云苍穹知识”栏目。
本文链接:https://wenku.my7c.com/article/kingdee-cangqiong-140524.html
您需要登录后才可以发表评论, 登录登录 或者 注册
最新文档
热门文章