# 引入插件开发

## 使用场景

用户打开引入起始页，准备引入参数（引入类型、匹配字段、数据文件），点击开始引入后，系统打开引入进度界面并启动两个线程分别执行“引入插件”的解析和保存方法，两个线程并发执行，通过缓存池共享单据数据。

引入插件基类会提供如下方法：

```java
public class BatchImportPlugin implements Callable<Object>, IImportDataPlugin {
	protected ImportContext ctx;					// 引入上下文，包括文件url，数据缓存池等相关参数
	protected MainEntityType mainEntityType;			// 默认逻辑，如果为空，会重新构造
	
	/**获取待引入的实体key 
	 * @return
	 */
	public String getBillFormId()
	
	/**覆盖引入的匹配字段备选项 
	 * @return
	 */
	public List<ComboItem> getOverrideFieldsConfig()
	
	/**覆盖引入匹配字段的缺省值 
	 * @return
	 */
	public String getDefaultKeyFields()
	
	/**缺省引入模式，新增、覆盖、覆盖并新增 
	 * @return
	 */
	public String getDefaultImportType()
	
	/**锁定的控件列表 
	 * @return
	 */
	public List<String> getDefaultLockUIs()
	
	/**缺省的保存逻辑 
	 * @param rowdatas
	 * @param logger
	 * @return
	 */
	protected ApiResult save(List<ImportBillData> rowdatas, ImportLogger logger) 

/**引入的批量数据大小 
	 * @return
	 */
	protected int getBatchImportSize()

	/**是否强制批处理 
	 * @return 
* true，如果多列中不够一批将等待；
* false 不管队列中有多少数据，当前批次能取到多少就返回，不超过getBatchImportSize()设置的批量最大值
	 */
	protected boolean isForceBatch() 
	
	/**构建Web API保存操作实例，用于转换Json并保存单 
	 * @return
	 */
	protected AbstractOperateWebApi getSaveWebApi()

	/**根据数据动态构造实体类型 
	 * @param billdata
	 * @return
	 */
	protected MainEntityType buildMainEntityType(JSONObject billdata) 
	
	/**解析excel数据后压入缓存队列  */
	protected void resolveExcel()
	
	/**从缓存队列分批取数，调用Save()方法保存, 如果有数据失败会生成错误数据文件 */
	protected void importData() throws Throwable
	
	/**帮助方法：将操作结果转成引入结果 
	 * @param saveResult
	 * @return
	 */
	protected ApiResult convertApiResult(OperationResult saveResult)
	
	/**根据表单标识和模板数据构造引出的实体类型 ，下载引出模板时将根据该实体生成字段列
	 * @param billFormId   实体表单标识
* @param templateData 模板数据
	 * @return
	 */
	@Override
	public MainEntityType getExportMainEntityType(String billFormId, DynamicObject templateData)
}

```

## 开发步骤

首先，创建一个插件类，继承`kd.bos.form.plugin.impt.BatchImportPlugin`插件类；然后根据需要重写上面提到的方法（具体详情参看插件类的方法注释）；最后将引入插件挂载到引入操作的操作参数里面。

![](images\clip_image002.jpg)

## 问题答疑

### 如何在标准引入保存数据前，微调数据？

有时候，我们不需要干预标准引入过程，也不想处理原始数据的转换，那我们可以通过表单插件微调即将要保存入库的最终数据。

首先，创建一个表单插件类（单据继承AbstractBillPlugin，基础资料继承AbstractBasePlugin），然后重写方法，其中InitImportDataEventArgs可以拿到引入配置参数和原始数据，ImportDataEventArgs参数里面会原始数据和基础资料缓存，BeforeImportDataEventArgs可以取到原始数据之外还可以取消本单引入。

 

```java
// 引入前初始化
public void initImportData(InitImportDataEventArgs e)

// 原始数据填充model前事件
public void beforeImportData(BeforeImportDataEventArgs e)

// 原始数据填充model后，保存前事件，我们可以从model获取/修改当前已经转换好的数// 据，也可以添加/移除/修正基础资料缓存，提高下一条数据引入的查询和命中效率
public void afterImportData(ImportDataEventArgs e)

//下面是几个事件参数提供的方法：
/**
 * 引入初始化事件参数
 */
public class InitImportDataEventArgs extends EventObject {
    /**
	 * 所有待引入的源数据包
	 * @return
	 */
    public List<Map<String, Object>> getSourceDataList() 
}

/**
 * 引入填充数据前事件参数
 */
public class BeforeImportDataEventArgs extends ImportDataEventArgs {
	/**
	 * 是否取消本单引入
	 * @return
	 */
	public void setCancel(boolean cancel)
	
	/**
	 * 取消本单引入的原因说明
	 * @return
	 */
	public void setCancelMessage(String cancelMessage)
	
	/**
	 * 指定是否触发afterImportData事件、执行实体服务规则。默认是触发的，可以指定不触发，提升性能
	 * @param fireAfterImportData
	 */
	public void setFireAfterImportData(boolean fireAfterImportData) 
}

/**
 * 引入填充数据后保存前事件参数
 */
public class ImportDataEventArgs extends EventObject {
	/**获取表单关联的原始数据
	 */
	public Map<String, Object> getSourceData() 
	
	/**获取公共的基础资料缓存
	 */
	public Map<BasedataItem, Object> getBasedataPks() 
}

 
```

### 引入插件中如何增加日志，生成到错误数据文件中？

```java
@Override
protected ApiResult save(List<ImportBillData> rowdatas, ImportLogger logger) {
	Iterator<ImportBillData> it = rowdatas.iterator();
	while(it.hasNext()){
		ImportBillData data = it.next();
		// 返回校验信息
		String validMsg = validBillData(data);
		if(StringUtils.isNotBlank(validMsg)){
			// 有校验提示，校验不通过，记录日志，移除数据
			logger.log(data.getStartIndex(), validMsg).fail();
			it.remove();
		}
	}
// 调用缺省方法保存合法的数据
	return super.save(rowdatas, logger);
}

```

## 历史变更对比

|   | BatchImportPlugin | IImportPlugin | IImportServicePlugin |
| --- | --- | --- | --- |
| 类型 | 类 | 接口 | 接口 |
| 缺省实现 | 缺省实现 | 无 | 无 |
| 定制引入界面 | 支持 | 不支持 | 不支持 |
| 固定分批 | 支持 | 不支持 | 不支持 |
| 动态生成动态对象 | 支持 | 不支持 | 不支持 |
| 定制下载模板 | 支持 | 不支持 | 不支持 |
| 和表单插件共享基础资料缓存 | 支持 | 不支持 | 不支持 |
| 整个引入任务共享上下文 | 支持 | 不支持 | 不支持 |
| 自定义解析excel | 支持 | 支持，但是不友好，重写后会导致自定义保存失效 | 支持，但是不友好，重写后会导致自定义保存失效 |
| 自定义保存 | 支持 | 支持 | 支持 |
| 其他 | 无引入前、引入后事件 | 引入前、引入后事件 | 引入前、引入后事件 |