Eap功能介绍 导出

 

导出所涉及到的技能点

  • servlet规范
  • 面向接口编程
  • 面向bean编程
  • http协议的了解
  • spring aop
  • @Value注解的使用
  • spring spel表达式引擎
  • poi第三方依赖的api使用
  • groovy 安全占位符(?.)

导出是一个很常见的功能,基本上每个后台管理的项目都会用到.

导出功能的实现一般会有三种方式的实现.

  1. 硬编码每个业务+poi代码,就是每个业务代码如果要有导出的需求,会有实施手动写代码与代码进行死耦合.
  2. 将导出部分的代码进行封装,每个业务调用公共类,实施写少量的代码进行硬编码.
  3. eap实现了导出部分的代码不需要写的地步,只需要写一些配置参数,eg: 导出文件名 文件头等等.

eap,进行导出,只需要在一个特定的表添加一行导出配置

INSERT INTO `t_system_system_export` (
  `id`,
  `content`,  ##excel导出正文的字段申明
  `file_name`,  ##excel导出的文件名
  `title`,  ## excel的表头
  `url`,  ## 请求的uri
  `data`  ## 数据的位置
) 
VALUES
  (
    '3',
    '#root.id;#root.name;@exportG.yesNo(#root?.enabled);#root?.createdDate',
    '角色列表',
    '编号;角色名;状态;创建日期',
    '/system/role/index.sp',
    '#root[page]?.result'
  ) ;

这是一个角色表的导出配置. 导出后的结果大概是下面的样子

编号 角色名 状态 创建时间
3 超级管理员 2017-02-02 12:00:00

然后在前台表单页面添加一个导出的按钮,导出这个功能就ok了.

以下开始介绍功能实现细节

浏览器发起一个请求,查询当前角色为正常的列表,这个请求的url可以是这样的
http://127.0.0.1:8085/system/role/index.sp?enabled=1
,
如果要将这页导出,只需要在请求后面追加一个请求参数.最终的url是
http://127.0.0.1:8085/system/role/index.sp?enabled=1&export=excel
 ↓
导出拦截器aop策略拦截所有带注解@RequestMapping的方法.同样会拦截到此请求.
 ↓
判断是否是导出请求,如果带export参数,根据请求的uri到库里查询对应的url是`system/role/index.sp`  的记录.
 ↓
这里预留了接口申明,ExportHelper,根据export=excel进行excel的实现类调用,以后可以添加csv的实现.
 ↓
ExportHelper exportHelper = new ExcelExportHelper();
 ↓
由于下载文件的特殊性,修改http response的MIME 申明application/vnd.ms-excel,使浏览器弹出下载确认框.添加文件名报文头,由于http协议的原因,需要将中文文件名转换为iso-8859-1编码.
 ↓
修改page的分页信息,进行库里数据循环批量查询
 ↓
执行被拦截的方法ProceedingJoinPoint.proceed(argNew) 返回结果ModelAndView.
 ↓
根据导出配置的data字段配置,从ModelAndView 取出数据集集合,根据字段的配置定义,取出对应的数据(spel),调用exportHelper.write()将数据写入到poi对象中.如果查到数据库里还有未导出的数据,再循环进行查询导出.
 ↓
将poi对象中的数据写入response流中.再flush一下,导出流程就结束了

所需要做的仅仅只是在数据库添加一行配置.需要掌握spel表达式.

比如,有的字段在库里存的是1234,但是显示的时候是不同的状态码. 比如角色的状态码 ,在库里 0 无效 1 有效 但是导出的时候不能是0和1 要进行必要的转换.

@exportG.yesNo(#root?.enabled)

这里@符号是调用spring bean进行处理看一下source code

@Component("exportG")
public class ExportTrasform {
    @Value("${application.name:#{null}}")
    public String APPLICATION_NAME;
    @Autowired
    private DefaultService defaultService;

    public static String nothing(String value) {
        return value;
    }

    public static String param(String value, String paramName) {
        return QUtil.tran(value, paramName);
    }

    public static String yesNoontrary(String value) {
        return "0".equals(value) ? "是" : "否";
    }

    public static String yesNo(String value) {
        return "0".equals(value) ? "否" : "是";
    }
}

html改造

在集成eap进行开发时,所需要的只需要拉一个导出组件到合适的位置.进行几个属性值的填充.开发框架会维护剩下的一切.

如果不使用页面编辑器,需要在页面添加一个按钮,绑定事件

$(".export").click(function () {
    //找到导出按钮的所有form祖先里的第一个form祖先
    var fm = $(this).closest("form");
    if (!fm) return ;
    var target = fm.attr("target");
    var _action =  fm.attr("action");
    if (!_action) return;
    var action = _action


    if (action.indexOf('?')>-1)
        action += "&";
    else
        action +="?";
    action += "export=excel";
    //修改target 新标签页打开
    fm.attr("target","_blank");
    fm.attr("action",action);
    fm.submit();

    setTimeout(function () {
        if (target)
            fm.attr("target",target);//之前修改了target属性,再修改回去
        else
            fm.removeAttr("target");

        fm.attr("action",_action);
    },100);

});

限制

  1. 表单元素里不能有input 的name为export,避免冲突
  2. 导出支持同步ModelAndView,暂时不支持异步的ajax,即添加@ReponseBody的方法,没有做兼容
  3. 导出按钮必须包含在form表单元素里面
  4. 跨行跨列不在考虑的范围内