1. 功能

    实现文件导出,目前支持导出类型为:xls、xlsx、csv、txt。
    如果后台有任务调度服务器的话,可以支持定时导出功能。
    默认情况下框架提供的处理方法仅支持单服务器、无数据库操作的用法。
    默认为本地开发模式,生产环境各模块要按需定制。

  2. 参数

    参数名 参数类型 是否必须 默认值 描述
    name java.lang.String 元素 id 和 name 属性的值
    fileType java.lang.String 用于自定义导出文件类型或指定导出组件显示的文件类型,需以 json 字符串格式列出,如:{'.xls':'.xls','.txt':'.txt'}
    fileName java.lang.String 默认导出文件名
    params java.lang.String 用户自定义传到后台的参数
    serviceName java.lang.String 用户自定义导出后台处理方法
    ftpSite java.lang.String ftp 服务配置
    model java.lang.String excel 模版路径, 当使用该参数时须指定config里的 isshow="false" rowNums="2" ,rowNums为模板表头的行数
    config java.lang.String excel 导出配置文件路径
    posX java.lang.String excel 导出默认 x 轴偏移量
    posY java.lang.String excel 导出默认 y 轴偏移量
    cond java.lang.String 根据区域获取页面上的数据,在开始导出时传入后台 servicename 指定方法的参数
    filePath java.lang.String 自定义导出文件路径
    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(中断)/loading(正在导出),id:该导出组件的 id
  3. 调用 Javascript API

    方法 window.Export_ExportName.setParams(urlParams)
    说明 通过 js 动态设置要传递到后台的参数内容
    参数 urlParams 态设置传递数据,动态设置传递数据,需为 url 格式,如:a=b&c=d
  4. 调用 Java API

    方法 beginExport(String fileSerializeId,IData params,String fileId,IDataset[] datasets)
    说明 传入需导出的数据,框架自动生成导出文件,更新导出状态,并将文件上传到FTP或本地的指定目录
    参数 fileSerializeId 框架自动生成的导出现成唯一标记
    params serviceName 中传入的参数
    fileId 文件唯一标记
    datasets 需生成到文件中的数据内容
    方法 beginExport(String fileSerializeId,IData params,String fileId,IDataset[] datasets,List cfgData)
    说明 传入需导出的数据,框架自动生成导出文件,更新导出状态,并将文件上传到FTP或本地的指定目录
    参数 fileSerializeId 框架自动生成的导出现成唯一标记
    params serviceName 中传入的参数
    fileId 文件唯一标记
    datasets 需生成到文件中的数据内容
    cfgData 配置文件自定义数据(非从配置文件中获取)
  5. 后台方法定义规则

    1. serviceName

      该参数的写法需遵循 className@MethodName,用以调用用户自定义的方法获取相应的状态,className 对应的类不能为抽象类。

      method 的形参为(String,IData),String 对应本次导入或导出的唯一标记,IData 对应前台传入的参数

    2. cancel

      用于中断当前导入或导出,用户需要在中断时执行自定义操作时可在 serviceName 定义的 class 中定义 cancel(String,IData) 方法即可,形参含义同上

  6. servlet配置

    在web.xml中增加配置:

    <servlet>
    	<servlet-name>impExp</servlet-name>
    	<servlet-class>com.ailk.web.servlet.impexp.ImpExpServlet</servlet-class>
    	<init-param>
    		<param-name>pool-size</param-name>
    		<param-value>2</param-value>
    	</init-param>
    	<load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
    	<servlet-name>impExp</servlet-name>
    	<url-pattern>/impExp</url-pattern>
    </servlet-mapping>
    

    pool-size 表示线程池的大小,默认为 1000;

  7. 在 global.properties 中增加配置

    impExp.activetime=10 以秒为单位,用以设置 ImpExpManager 中对状态的清理频率,默认为 60。

    import.export.location=/demo/impExp,设置导出的 url 路径,demo 要替换为应用的 path,impExp 对应 ImpExpServlet 配置的 servlet 名。

  8. 自定义导入导出进度的设置

    //获取当前进度
    String prefixProgress = ImpExpUtil.getImpExpManager().getProgress(fileSerializeId); 
    String curProgress = (Integer.valueOf(prefixProgress)+5)+"";
    
    //设置进度
    ImpExpUtil.getImpExpManager().setProgress(fileSerializeId, curProgress);
    //ImpExpUtil.getImpExpManager().setRemainTime(fileSerialId, remainTime);
    
    //设置当前的操作步骤
    ImpExpUtil.getImpExpManager().setStatusStep(fileSerializeId, "数据更新");
    
    //后台出错时的错误原因描述
    //ImpExpUtil.getImpExpManager().setErrorReason(fileSerializeId, errorValue);
    
    //设置下载链接
    ImpExpUtil.getImpExpManager().setDownLoadUrl(fileSerializeId, "download=1");
    
    //获取导入或导出的剩余时间
    ImpExpUtil.getImpExpManager().getRemainTime (fileSerializeId, "download=1");
    
    //获取文件下载路径
    getDownloadPath(String fileSerializeId,String fileId,String ftpSite,Map<String,String[]> params);
    

    fileSerializeId:框架生成的导入、导出唯一标记
    fileId:文件唯一标记
    ftpSite:ftp配置
    params:页面传入参数

    【注】在实际的时候过程中需要用开发人员去实现用户传入的文件名与该文件保存在服务器上的唯一文件名 fileId(该文件名由开发人员自定义生成方法)以及导出结果的页面

  9. 自定义状态管理类方法

    在集群状态下需要自定义状态管理类,自定义类需继承抽象类 com.ailk.web.servlet.impexp.AbstractImpExpManager;
    默认状态管理类为 DefaultImpExpManager,该类是将状态管理在 jvm 的内存中。需重写其中的更新状态方法,
    自定义类后需将类路径配置到 global.properties 中的 impExp.manager 属性中。

    方法 Map<String,ConcurrentHashMap<String,String>> getStatus()
    说明 获取全部被管理的状态对象
    方法 ConcurrentHashMap<String,String> getStatus(String fileSerializeId)
    说明 获取制定的导入导出状态对应的状态对象
    参数 fileSerializeId 导入或导出的唯一标记
    方法 void updateStatus(String fileSerializeId,String key,String value)
    说明 更新状态参数
    参数 fileSerializeId 导入或导出的唯一标记
    key 更新状态的 key
    value 更新状态的 value
    方法 addStatus(String fileSerializeId,ConcurrentHashMap<String,String> status)
    说明 增加新的 status 状态
    参数 fileSerializeId 导入或导出的唯一标记
    status 新增的状态类
    方法 void removeStatus(String fileSerializeId)
    说明 从状态管理类中移除指定的导入或导出的状态
    参数 fileSerializeId 导入或导出的唯一标记
    方法 void removeAllStatus()
    说明 移除全部被管理的状态
  10. 自定义导入导出处理类

    在后台实现异步或不需要进行线程管理的情况后可自定义该处理类,自定义类需集成抽象类 com.ailk.web.servlet.impexp.AbstractImpExpAction;
    默认处理类为:com.ailk.web.servlet.impexp.DefaultImpExpAction;
    可通过重写方法实现自定义需求,自定义类后需将类路径配置到 global.properties 中的 impExp.action 属性中。

    方法 void initConfig(IData config)
    说明 根据 servlet 的配置进行数据初始化
    参数 config servlet 中的配置数据
    方法 void cancelProgress(HttpServletRequest request, HttpServletResponse response)
    说明 终端导入或导出时的处理方法
    方法 String initTimer(HttpServletRequest request, HttpServletResponse response)
    说明 初始化定时任务时重写方法,可定义任务的执行耗时,开始时间,数据大小。
    方法 void callService(HttpServletRequest request,String serviceName,String fileSerializeId,IData param) throws Exception
    说明 调用组件中配置的 ServiceName 参数指定的方法
    参数 serviceName 对应组件中的 serviceName
    fileSerializeId 导入导出对应的唯一标记
    param 页面传入数据
    方法 String getProgressData(HttpServletRequest request, HttpServletResponse response,String fileSerializeId) throws IOException
    说明 页面获取当前导入导出状态
    参数 fileSerializeId 导入导出对应的唯一标记

    自定义类时可通过调用 doCancelProgress(HttpServletRequest request, HttpServletResponse response) 调用终端导入或导出的数据处理及根据 serviceName 调用 cancel 方法。
    可通过 buildProgressData(String fileSerializeId) 获取导入或导出的状态。
    可通过 buildInitTimerData(IData map,String totalSize,String startTime,String useTime) 处理定时方法的参数。
    可通过 doService(HttpServletRequest request,String serviceName,String fileSerializeId,IData param) 调用 serviceName 对应的处理方法。

  11. 文件处理类

    框架提供有普通文件写入和分步文件写入两种方式;
    其中的普通文件写入针对的是一次写入文件内容,并会操作文件导出的状态;
    分步文件写入则仅生成文件内容,不进行状态更新。

    1. 普通文件写入方法参数定义

      fileSerializeId 每次导入导出的唯一标记,从 serviceName 对应的方法的第一参数获取
      fileName 被导出文件的文件名,获取用户前台输入的文件名的方式为 从 serviceName 对应的方法的第二参数获取:paramMap.getString("fileName")
      params 与 serviceName 中的第二参数一致;
      datasets 需要生成到文件中的数据;
      iDataKeys 在非 excel 导出模式下,如无 excelCfg 和 excelCfgData 配置文件,可通过该参数设置没列对应的 key 值;
      headNames 在非 excel 导出模式下,如无 excelCfg 和 excelCfgData 配置文件,可通过该参数设置生成文件的头信息
      excelModel 生成 excel 需要使用的模版文件
      cfgData 可通过 ExcelConfig.getSheets(excelCfg) 获取解析到 xml 配置数据
      excelCfg xml 配置模版在 classes 下的位置
      token 针对 txt 导出设置的列连接符

      提供的普通文件写入方法有:

      String beginExport(String fileSerializeId,IData params,String fileName,IDataset[] datasets)
      String beginExport(String fileSerializeId,IData params,String fileName,IDataset[] datasets,List cfgData)
      String beginExport(String fileSerializeId,IData params,String fileName,IDataset[] datasets,List cfgData,String token)
      String beginExport(String fileSerializeId,IData params,String fileName,IDataset[] datasets,List cfgData,String token)
      String beginExport(String fileSerializeId,String fileName,IData params,IDataset[] datasets,Object[] iDataKeys,String[] headNames,String token)
      String beginExport(String fileSerializeId,String fileName,IData params,IDataset[] datasets,Object[] iDataKeys,String[] headNames,String excelCfg,String excelModel,String token)
      String beginExport(String fileSerializeId,String fileName,IData params,IDataset[] datasets,Object[] iDataKeys,String[] headNames,List cfgData,String excelModel,String token)
      String beginExport(String fileSerializeId,String fileName,IData params,IDataset[] datasets,Object[] iDataKeys,String[] headNames,String excelCfg,List cfgData,String excelModel,String token)
      
    2. 分步文件写入方法参数定义

      fileType 文件类型,可接受类型为 xls,xlsx,txt,csv;其中 xls 和 xlsx 没调用一次会生成一个 excel 文件,并放到与 fileId 对应的压缩包中供下载;txt、csv 采用的是数据追加方式直接生成到文件中
      datasets 需要被转化到文件中的数据集,在生成 excel 文件时可根据配置文件 excelCfgData 或 excelCfg 中配置的 sheet 格数传入对应长度的datasets,在txt,csv 中数据集仅接受长度为1
      fileId 文件唯一标记;可自定义生成方式,也可在首次调用该方法时将fileId置空,然后通过返回值获取对应的 fileId,另外也可通过框架方法获取:String fileId = ImpExpUtil.getImpExpManager().getFileAction().createFileId();
      model 生成 excel 需要使用的模版文件 当使用该参数时须指定config里的 isshow="false" rowNums="2" ,rowNums为模板表头的行数
      excelCfgData 可通过 ExcelConfig.getSheets(excelCfg) 获取解析到 xml 配置数据
      excelCfg xml 配置模版在 classes 下的位置
      iDataKeys 在非 excel 导出模式下,如无excelCfg和excelCfgData 配置文件,可通过该参数设置没列对应的 key 值
      headNames 在非 excel 导出模式下,如无excelCfg和excelCfgData 配置文件,可通过该参数设置生成文件的头信息
      pos_x 针对 excel 导出设置的 x 轴偏移量
      pos_y 针对 excel 导出设置的 y 轴偏移量
      token 针对 txt 导出设置的列连接符

      提供的分步文件写入方法有:

      String beginExportByStep(String fileType,IData params,IDataset[] datasets,String fileId ,String model,List excelCfgData)
      String beginExportByStep(String fileType,IData params,IDataset[] datasets,String fileId ,String model,String excelCfg)
      String beginExportByStep(String fileType,IData params,IDataset[] datasets,String fileId ,String model,List excelCfgData,String token)
      String beginExportByStep(String fileType,IData params,IDataset[] datasets,String fileId ,String model,String excelCfg,String token)
      String beginExportByStep(String fileType,IData params,IDataset[] datasets,String fileId ,String model,List excelCfgData,Object[] iDataKeys,String[] headNames,String token)
      String beginExportByStep(String fileType,IData params,IDataset[] datasets,String fileId ,String model,String excelCfg,Object[] iDataKeys,String[] headNames,String token)
      String beginExportByStep(String fileType,IData params,IDataset[] datasets,String fileId ,String model,List excelCfgData,String excelCfg,Object[] iDataKeys,String[] headNames,String token)
      String beginExportByStep(String fileType,IDataset[] datasets,String fileId ,String model,List excelCfgData,String excelCfg,Object[] iDataKeys,String[] headNames,int pos_x,int pos_y,String token)
      
  12. 示例

    1. HTML 代码

      <div class="c_title">
      	<div class="text">查询结果</div>
      	<div class="fn"> 
      		<span jwcid="@Export" name="testExport" params="a=b&c=中文" serviceName="com.ailk.demo.view.TestExport@testExport"
      			action="exportAction"
      			afterAction="beforeExportAction"
      			config="VipcustList.xml" fileName="中文测试" fileType="{'.txt':'.txt','.xls':'.xls','.csv':'.csv'}" 
      			model="test.xls" posX="2" posY="2" partId="QueryCond,QueryCond"/>
      	</div>
      </div>
      
    2. Java 代码

      /**
      *fileSerializeId:本次导出的全局唯一标识,可通过该参数修改导出的状态
      *param:前台传入的参数
      */
      public void testExport(String fileSerializeId,IData paramMap) throws Exception{
      	String fileName = paramMap.getString("fileName");
      	String ftpSite = paramMap.getString("ftpSite");
      	paramMap.put("test", new String[]{"test"});
      	//fileName = new String(fileName.getBytes("ISO8859-1"),"utf-8");
      	//可通过数据库或全局数据设置该 用户自定义文件名  与  全局唯一的文件名之间的对应关系,以避免出现相同路径下 文件名重复的问题
      	IVisit visit = VisitManager.getInstance().getVisit();
      	//visit.get("test");
      	IDataset[] dsArray = new DatasetList[1];
      	IDataset ds = new DatasetList();
      	IData da = new DataMap();
      	da.put("VIP_ID", "value1");
      	da.put("USECUST_NAME", "value2");
      	da.put("key3", "value3");
      	da.put("key4", "value4");
      	ds.add(da);
      	dsArray[0] = ds;
      	//List list = ExcelConfig.getSheets("/VipcustList.xml");
      	
      	ImpExpUtil.getImpExpManager().setSimpleStatus(fileSerializeId, "10", "操作成功!");
      	//Thread.currentThread().sleep(3000);
      	ImpExpUtil.beginExport(fileSerializeId,  paramMap, fileName, dsArray);
      	//ImpExpUtil.beginExport(fileSerializeId, fileName, paramMap, dsArray, null, null, ftpSite, ((String[])paramMap.get("cfgFile"))[0], null);
      	//ImpExpUtil.beginExport(fileSerializeId,fileName,paramMap,dsArray,null,null,ftpSite,null,null);
      	//IDataset[] das = ImpExpUtil.getImportData(fileSerializeId, paramMap,list);
      	//ImpExpManager.setSimpleStatus(fileSerializeId, "100", "操作成功!");
      	/**  
      	ImpExpUtil.getImpExpManager().setSimpleStatus(fileSerializeId, "40", "获取数据");
      	File file = ImpExpUtil.writeCSVFromData(ds);
      	ImpExpUtil.getImpExpManager().setSimpleStatus(fileSerializeId, "80", "生成文件");
      	
      	try {
      		FileUtil fileUtil = null;
      		if (ftpSite == null || "".equals(ftpSite)) {
      			fileUtil = new FileUtil();
      		}else{
      			fileUtil = new FileUtil(ftpSite);
      		}
      		
      		InputStream is = new FileInputStream(file);
      		
      		fileUtil.uploadFile(is,filePath);
      		is.close();
      	}catch (Exception e) {
      		Utility.error(e.getMessage());
      	}finally{
      		file.delete();
      	}
      	ImpExpUtil.getImpExpManager().getDownloadPath(fileSerializeId,fileName,ftpSite,filePath);
      	ImpExpUtil.getImpExpManager().setSimpleStatusWithUrl(fileSerializeId, "100", "上传ftp", "download=1");
      	*/
      }
      public void cancel(String fileSerializeId,IData param){
      	System.out.println("The Imp or Exp is canceled! The fileSerializeId is "+fileSerializeId);
      }