1. 功能

    文件导入组件,支持 Excel(03、07)、TXT、CSV 类型文件导入;支持文件导入进度查看及终止导入。导入文件是先上传到本地服务器或 ftp 服务器再进行导入的,配置中 fileman.mode=local|ftp。

  2. 参数

    参数名 参数类型 是否必须 默认值 描述
    name java.lang.String 元素 id 和 name 属性的值
    serviceName java.lang.String 执行解析后数据的类及方法,如 com.ailk.Work@doImport(String fileSerializeId,IData params),调用 com.ailk.common.util.ImpExpUtil.getImportData 获得解析后 IDataset[] 类型数据,执行完成需要设置进度ImpExpUtil.getImpExpManager().setStatus(fileSerializeId, "100", "文件导入完成!", "", "", "");
    config java.lang.String 解析 excel 的 xml 配置文件,是相对路径(如:export/examples/basic/VipcustList.xml)
    ftpSite java.lang.String 保存导入文件的 ftp 服务器,global 配置文件中配置
    filePath java.lang.String upload/import 文件在 ftp 上相对路径
    fileSize java.lang.String 30 导入文件限定大小,最大为 30M
    fileType java.lang.String excel 导入文件类型,可选 excel、txt、csv
    posX java.lang.String 0 Excel 导入空余列数
    posY java.lang.String excel 空行 excel 导入空余行数
    model java.lang.String 失败数据导出模板相对路径,模板为 Excel03 版文件, 当使用该参数时须指定config里的 isshow="false" rowNums="2" ,rowNums为模板表头的行数
    cond java.lang.String 根据区域获取页面上的数据,在开始导入时传入后台 servicename 指定方法的参数
    params java.lang.String 将该数据拼装到 url 后,传递到 servicename 指定的方法参数中
    beforeAction java.lang.String 开始导入时调用的 js 方法名,根据其返回值的 true/false 决定是否执行后续方法,js 方法的入参为该导入组件的 id
    afterAction java.lang.String 导入操作结束时调用的 js 方法名,入参为 flag:ok(导入成功)/error(导入失败),id:该导入组件的 id
    action java.lang.String 导入执行响应操作后调用的方法名,入参为 flag:cancel(取消)/fail(失败)/ok(成功)/terminate(中断),id:该导入组件的 id
  3. HTML 代码

    <div class="c_title">
    	<div class="text">客户查询</div>
    	<div class="fn">
    		<span jwcid="@Import"
    			name="importTest"
    			serviceName="com.ailk.web.servlet.impexp.ImportManager@updateStatus"
    			config="import.xml"
    			ftpSite="name1"
    			filePath="a/b/c/d"
    			fileSize="20"
    			fileType="excel"
    		/>
    	</div>
    </div>
    
  4. 配置文件说明

    由于目前的导入失败后需要增量导入失败数据,故导入功能导入功能需要支持导入数据的有效性校验,并且能够对校验失败的数据筛选保存为对应格式文件并列出错误原因提供给用户做增量导入,故实现步骤需要:

    配置导入数据对应的 xml 文件,该文件需要配置输入校验属性
    配置导入失败数据对应的导出 xml 文件,该文件必须配置 IMPORT_ERROR 列,用来显示导出错误信息,为保证原始数据,需设置 type="1",这样不会做任何的格式转换
    导入逻辑处理后获取失败的数据,将失败的数据与对应的 xml 生成 excel,提供给用户下载并做增量导入

    <?xml version="1.0" encoding="utf-8"?>
    	<!--
    		@name: column name
    		@desc: column title
    		@type: column type(1:string 2:numeric 3:datatime)
    		@align: column align(1:left 2:center 3:right)
    		@width: column width
    		@format: column format(numeric format:0.00|#.##..., datatime format:yyyy-MM-dd...)
    		@scale: scale(scale=100)
    		@nullable: option[yes|no]
    		@equsize: column equals szie
    		@minsize: column min size
    		@maxsize: column mas size
    	-->
    <workbook>
    <sheet name="busidepartimport" desc="业务部门监控1">
    		<header isshow="true" height="300">
    			<cell
    				name="DEPART_ID"
    				desc="部门编码"
    				type="1"
    				align="1"
    				width="6000"
    			/>
    			<cell
    				name="START_DATE"
    				desc="开始时间"
    				type="1"
    				align="1"
    				width="6000"
    			/>
    			<cell
    				name="END_DATE"
    				desc="截止时间"
    				type="1"
    				align="1"
    				width="6000"
    			/>
    				<cell
    				name="VALID_FLAG"
    				desc="有效标识"
    				type="1"
    				align="1"
    				width="6000"
    			/>
    		</header>
    	</sheet>
    	<sheet name="busidepartimport2" desc="业务部门监控sheet2">
    		<header isshow="true" height="300">
    			<cell
    				name="DEPART_ID"
    				desc="部门编码"
    				type="1"
    				align="1"
    				width="6000"
    			/>
    			...
    		</header>
    	</sheet>
    	<sheet name="busidepartimport3" desc="业务部门监控sheet3">
    		<header isshow="true" height="300">
    			<cell
    				name="DEPART_ID"
    				desc="部门编码"
    				type="1"
    				align="1"
    				width="6000"
    			/>
    			...
    		</header>
    	</sheet>
    </workbook>
    
  5. 具体字段说明

    字段 说明
    name 数据映射名
    desc 表格列头描述
    type 表格列类型(1:String 2: NUMERIC 3:Datatime)
    align 表格列横向排列方式(1:left 2:center 3:right)
    width 表格列宽度
    format 表格列数据格式(如果是数字,格式为 0.00,#.## 类似数据格式形式,如果为时间,格式为 yyyy-MM-dd 类似形式)
    scale 缩放比例,如将单位为分的数字表示成元,相当于缩小 100,则值为 scale=100
    nullable 是否可以不填 option[yes|no]
    equsize 输入值的定长位数限制,如 equsize="10"
    minsize 输入值的最小位数限制,如 minsize="10"
    maxsize 输入值的最大位数限制,如 maxsize="100"

    其中 name、desc、type 等是导入时做为输入校验要用到的,与 excel 单元格类型无关(建议单元格格式统一为文本),除 format 可以做为导入的格式校验,也可以做为导出的格式显示。

  6. 导入需要的配置文件

    <sheet desc="VIP 客户资料">
    	<header isshow="true" height="300">
    		<cell
    			name="USECUST_ID"
    			desc="客户标识"
    			type="2"
    			align="1"
    			width="4000"
    			nullable="no"
    			maxsize="16"
    		/>
    		<cell
    			name="USECUST_NAME"
    			desc="客户名称"
    			type="1"
    			align="1"
    			width="6000"
    			nullable="no"
    			maxsize="100"
    		/>
    		.......
    	</header>
    </sheet>
    

    说明:需要关注导入的 excel 列的输入格式,如最大输入长度,是否必填,日期、金额的格式等

  7. 导入失败的数据,需要配置的文件

    <sheet name="VIP客户资料" desc="日程信息">
    	<header isshow="true" height="300">
    		<cell
    			name="USECUST_ID"
    			desc="客户标识"
    			type="1"
    			align="1"
    			width="4000"
    			nullable="no"
    			maxsize="16"
    		/>
    		.......
    		<cell
    			name="IMPORT_ERROR"
    			desc="导入错误"
    			type="1"
    			align="1"
    			width="10000"
    		/>
    	</header>
    </sheet>
    

    说明:由于失败的数据需要和输入前的保持一致,故最好将所有列的配置设为 type="1",将所有的数据生成时不做转换都生成为文本格式,比如:如果设置了 type="3" (时间类型),并设置了 format="yyyy-MM-dd HH:mm",如果导入的数据填的是 2007-03-01,但由于指定了类型和格式,导出会将数据转换为 2007-03-01 00:00 形式,这样就丢失了数据的原有形式。

  8. Excel 读写 API

    1. 写入 excel 文件:com.ailk.common.util.parser.ExcelWriter

      /**
       * writeExcel03FromData  无模板写 Excel03
       * @param sheets xml 配置文件信息,通过 com.ailk.common.util.parser.ExcelConfig.getSheets(filePath) 获得
       * @param datasets 输入数据
       * @param posX 空列
       * @param posY 空行
       * @throws Exception
       */
      public static void writeExcel03FromData(List sheets, OutputStream output,
      		IDataset[] datasets, int posX, int posY)
      
      /**
       * writeExcel03FromData  无模板写 Excel07
       * @param sheets 配置文件信息,通过 com.ailk.common.util.parser.ExcelConfig.getSheets(filePath) 获得
       * @param datasets 输入数据
       * @param posX 空列
       * @param posY 空行
       * @throws Exception
       */
      public static void writeExcel07FromData(List sheets, OutputStream output,
      		IDataset[] datasets, int posX, int posY)
      
      /**
       * writeExcel03FromData 有模板写 Excel03
       * @param sheets 配置文件信息,通过 com.ailk.common.util.parser.ExcelConfig.getSheets(filePath) 获得
       * @param excelModel 模板文件相对路径,Excel 模板(如水印),必须为 03 版,且只有 1 个表格
       * @param datasets 输入数据
       * @param posX 空列
       * @param posY 空行
       * @throws Exception
       */
      public static void writeExcel03FromData(List sheets, OutputStream output, InputStream excelModel,
      		IDataset[] datasets, int posX, int posY)
      
      /**
       * writeExcel03FromData 有模板写 Excel07
       * @param sheets 配置文件信息,通过com.ailk.common.util.parser.ExcelConfig.getSheets(filePath) 获得
       * @param excelModel 模板文件相对路径,Excel 模板(如水印),必须为 07 版,且只有 1 个表格
       * @param datasets 输入数据
       * @param posX 空列
       * @param posY 空行
       * @throws Exception
       */
      public static void writeExcel07FromData(List sheets, OutputStream output, InputStream excelModel,
      IDataset[] datasets, int posX, int posY)
      
    2. 读取 excel 文件:com.ailk.common.util.parser.ExcelReader

      /**
       * 将 Excel(03,07) 数据转换为 IDataset[](包括多表格)
       * @param sheets 配置文件信息,通过 com.ailk.common.util.parser.ExcelConfig.getSheets(filePath) 获得
       * @param input 导入文件输入流
       * @param posX excel 空列
       * @param posY excel 空行
       * @return IDataset[]
       * @throws Exception
       */
      public static IDataset[] readExcelToData(List sheets, InputStream input, int posX, int posY)
      
  9. 模板说明

    Excel模板按版本不同分为Excel03模板和Excel07模板,后缀分别为“.xls”和“.xlsx”,需要说明的是Excel03模板必须是由微软03版Excel生成的,07模板也必须是由微软07版Excel生成,而且每个模板只能有一个表格(即sheet),多余的要删除掉;在导出生成Excel文件时,选用模板要跟生成文件的版本一致,生成03版文件选用03版模板,07版玩家选用07版模板。

    参数 serviceName 示例代码:test.ImportManager@updateStatus

    package test;
    
    import java.util.Map;
    
    import com.ailk.common.data.IData;
    import com.ailk.common.data.IDataset;
    import com.ailk.common.data.impl.DataMap;
    import com.ailk.common.data.impl.DatasetList;
    import com.ailk.common.util.Utility;
    import com.ailk.web.util.ImpExpUtil;
    
    public class ImportManager {
    	
    	public void updateStatus(String fileSerializeId,IData params) throws Exception{
    		
    		//获得解析数据
    		IDataset[] dataset = ImpExpUtil.getImportData(fileSerializeId, params);
    		IDataset[] fails = new IDataset[dataset.length];	//失败结果集
    		IDataset[] succs = new IDataset[dataset.length];	//成功结果集
    		int failcount = 0;
    		int successcount = 0;
    		//循环表格
    		for (int i=0; i<dataset.length; i++) {
    			IDataset failset = new DatasetList();
    			IDataset succset = new DatasetList();
    			//循环行
    			for(int j=0;j<dataset[i].size();j++){
    				IData data = dataset[i].getData(j);
    				//IMPORT_RESULT 验证不通过数据标志,true 为成功,false 为失败
    				if(data.get("IMPORT_RESULT")!=null && data.getBoolean("IMPORT_RESULT")){
    					succset.add(data);
    					successcount++;
    				}else{//failed data
    					failset.add(data);
    					failcount++;
    				}
    			}
    			fails[i] = failset;
    			succs[i] = succset;
    		}
    		try {
    			ImpExpUtil.getImpExpManager().setStatus(fileSerializeId, "80.00", "文件数据解析完成!", "00:00:30", "", "");
    			doImport(succs);//成功数据继续操作
    		} catch (Exception e) {
    			ImpExpUtil.getImpExpManager().setStatus(fileSerializeId, "0", "error", "", "数据入库失败!", "");
    			Utility.error(e);
    		}
    		String downloadUrl = "";
    		String resultInfo = null;
    		if(failcount>0) {//失败数据生成文件,修改后增量导入
    			String errorConfig = "importError.xml";//失败数据导出配置文件,必填,比导入配置多IMPORT_ERROR字段
    			downloadUrl = ImpExpUtil.makeErrorFile(fails, params,errorConfig);//获取失败数据下载地址
    			resultInfo = "成功导入数据 "+successcount+" 条<br /><span class='e_red'>"+failcount
    				+" 条导入失败</span>,请<a><i class='e_ico-download'></i>点击下载</a>,修改后重新上传。";
    		}else{
    			resultInfo = "成功导入数据 "+successcount+" 条,<span class='e_green'>0 条导入失败</span>";
    		}
    		ImpExpUtil.getImpExpManager().setStatus(fileSerializeId, "100", resultInfo, "", "", downloadUrl);
    	}
    	public void doImport(IDataset[] re){
    		try {
    			Thread.sleep(5000);
    		} catch (InterruptedException e) {
    			e.printStackTrace();
    		}
    		for(IDataset ds:re){
    			for(Object row:ds){
    				IData drow=(IData)row;
    				System.out.println(drow.toString());
    			}
    		}
    
    	}	
    }
    
  10. 图示

    1. 导入按钮可以独立存在,图中使用常见的模式——位于标题栏右侧。

      标题栏
    2. 导入按钮

      标题栏
      • 文件:
      • 请上传单个文件,点击“开始导入”后,开始导入。