Bootstrap

FreeMarker导出Excel

Java使用FreeMarker模板引擎导出Excel

导出Excel的方式有许多,例如,使用POI自定义单元格,EasyPOI封装的各种导出等等。但是对应一些复杂的Excel,使用FreeMarker模板引擎导出Excel可能更为方便。废话不多说了,上源码:
1,设计模板
将需要替换的数据,如果是单个属性值,使用${属性值},如果是集合list,使用 ${list.属性值},如下图:
在这里插入图片描述
2,转为XML
填好之后另存为 XML电子表格,如下图:
在这里插入图片描述
3,修改模板
将模板放到项目下或者固定路径下,这个根据项目的要求,如果需要对里面的数据判断赋值可以使用 ${属性值!“”},如下图:
在这里插入图片描述
4,编写代码

  • 服务端代码
public void export(@RequestBody Map<String, Object> map, HttpServletRequest request, HttpServletResponse response) {
        Map<String, Object> rmap = null;
        Map<String, Object> cmap = null;
        Map<String, Object> data = new HashMap<>();
        // 配置模板属性
        Template t = null;
        Configuration configuration = new Configuration(new Version("2.3.0"));
        configuration.setDefaultEncoding("UTF-8");
        String time = new SimpleDateFormat("yyyyMMddHHmmssSSS").format(new Date());
        //导出的文件名
        String fileName = "D:\\template\\bxd_" + time + ".xls";
        Writer out = null;
        try {
            request.setCharacterEncoding("UTF-8");
            configuration.setDirectoryForTemplateLoading(new File(request.getRealPath("/") + "/template/"));
            //获取模板文件
            t = configuration.getTemplate("bxd_template.xml");
            // 查询数据
            Xs_bxd xs_bxd = bxdService.getById(id);
            if (xs_bxd != null) {
                data.put("ccr", xs_bxd.getBusTraveller());
                data.put("bm", xs_bxd.getDepartment());
                data.put("zw", xs_bxd.getDuty());
                data.put("cxsj", dateToTimeStrFormat(xs_bxd.getLeaveTime()));
                data.put("fhsj", dateToTimeStrFormat(xs_bxd.getRevolveTime()));
                data.put("dlr", xs_bxd.getDeputy());
                data.put("ptry", xs_bxd.getEscort());
                data.put("ccsy", xs_bxd.getBusinessMatters());
                data.put("ccdd", xs_bxd.getPlaceBusiness());
                data.put("yjjp", xs_bxd.getFlightTicket());
                data.put("jtgj", xs_bxd.getVehicle());
                data.put("yjlf", xs_bxd.getAdvanceTravel());
            }
            List<Xs_bxd_mx> xs_bxd_mxs = bxdMxService.getExportBxdList(id);
            data.put("list", xs_bxd_mxs);
            out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fileName), "utf-8"));
            // 将填充数据填入模板文件并输出到目标文件
            t.process(data, out);
            WordUtil.download(response, new File(fileName));
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
  • WordUtil.download()方法的代码
public synchronized static void download(HttpServletResponse response, File file) {
        BufferedInputStream bis = null;
        BufferedOutputStream bos = null;
        try {
            response.setContentType("application/octet-stream");
            // 下载文件能正常显示中文
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
            bis = new BufferedInputStream(new FileInputStream(file));
            bos = new BufferedOutputStream(response.getOutputStream());
            byte[] buff = new byte[10240];
            int bytesRead;
            while (-1 != (bytesRead = bis.read(buff, 0, buff.length))) {
                bos.write(buff, 0, bytesRead);
            }
            bis.close();
            bos.close();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            //这里为测试代码,可以自行封装
            String fileName = "D:\\test.docx";
            File f = new File(fileName);
            if (f.exists()) {
                f.delete();
            }
        }
    }
  • 前端代码
    这里前端使用了Vue和iView的组件,使用Ajax进行请求
// 导出当前的数据
 export(e) {
     let that = this;
     that.$Modal.confirm({
         title: "确认导出",
         content: "确认导出该条数据吗?",
         onOk: () => {
             // 原生ajax
             let xhr = new XMLHttpRequest();
             //post方式请求后台的路径
             xhr.open('post', '../bxd/export.do', true);
             //导出的Excel是二进制数据类型,因此设置为blob
             xhr.responseType = 'blob';
             //请求头(key,value),请求头能够设置多个key-value对
             xhr.setRequestHeader('Content-Type', 'application/json;charset=utf-8');
             //返回成功,导出的Excel文件
             xhr.onload = function () {
                 if (this.status == 200) {
                     let blob = this.response;
                     let a = document.createElement('a');
                     let url = window.URL.createObjectURL(blob);
                     a.href = url;
                     //设置文件名称
                     a.download = e.busTraveller + "报销单(" + that.formatDate(new Date(), 'yyyy-MM-dd') + ").xls";
                     a.click();
                 } else {
                     that.$Spin.hide();
                 }
             }
             //请求的参数,json格式,后台要用json格式接收
             xhr.send(JSON.stringify({
                 "id": e.id
             }));
         }
     })
 },

遇到的问题:导出的Excel使用WPS可以打开,使用Office打开可能出现以下提示信息:
在这里插入图片描述
XML模板里面搜一下 ExpandedRowCount,修改模板这里的值为固定值或者修改为动态的值(${data?size + 10},这里+10不是一定的,多少都行),或者大于当前的行(列)数,
在这里插入图片描述

;