Word导出(FreeMarker)

本文介绍了在一个财务管理应用中,如何通过Java后端与前端的配合,实现单个模板和按公司分类多个模板的导出功能,包括view.jsp页面的事件处理,ProWordDownloadAction的逻辑处理,以及ftl模板的使用和数据填充。
摘要由CSDN通过智能技术生成

目录

一、单个模板导出

1、前端

1.1、view.jsp

2、 后端

2.1、ProWordDownloadAction

2.2、FreemarkerUtils 类的 exportMillCertificateWord 方法

2.3、拼接的 map 数据 

2.3.1、IProWordDownloadService 

2.3.2、ProWordDownloadServiceImp 

 2.4、ftl文件

二、多个模板导出(按照公司分类)

1、前端

1.1、view.jsp

1.2、classbutton.jsp 

1.3、selectTemplate.jsp 

2、后端 


一、单个模板导出

1、前端

1.1、view.jsp

<c:if test="${ contractManageFksqbForm.docStatus=='30' || contractManageFksqbForm.docStatus=='20' }">
    <ui:button order="2" text="报销单导出" onclick="downloadDoc()">
    </ui:button>
</c:if>

 οnclick="downloadDoc()" 对应下面的函数

function downloadDoc() {
    var url = "/pro/word/proWordDownload.do?method=downloadWord&fdId=${param.fdId}&type=zfjs";
    Com_OpenWindow('${LUI_ContextPath}' + url, '_blank');
}

首先需要在详情页添加一个按钮,点击按钮调用后端的方法 并且打开一个新的页面

Com_OpenWindow 表示打开一个新的页面

2、 后端

2.1、ProWordDownloadAction

String type = request.getParameter("type");
String fileName = "";
String ftlName = "";
Map<String, Object> dataMap = new HashMap<>();

if ("jbcsq".equals(type)) {
    fileName = "加班餐结算单.doc";
    ftlName = "加班餐结算.ftl";
    dataMap = getServiceImp(request).getDataMap27(request);
}

FreemarkerUtils.exportMillCertificateWord(request, response, dataMap, fileName, ftlName);

注:根据前端传过来的 type 进行判断走到对应的代码 

fileName:导出的 word 名称

ftlName:ftl 模板名称对应 template 目录下的文件

dataMap:拼接的导出需要的 map 数据

那这个FreemarkerUtils 的 exportMillCertificateWord 方法究竟是怎么导出一个word 的呢,以及这个 dataMap 的数据是如何进行封装的呢? 让我们接着往下看

2.2、FreemarkerUtils 类的 exportMillCertificateWord 方法

public static void exportMillCertificateWord(HttpServletRequest request, HttpServletResponse response,
                                             Map dataMap, String fileName, String ftlName) {
    File file = null;
    InputStream in = null;
    ServletOutputStream out = null;
    try {
        file = createWord(dataMap, ftlName);
        in = new FileInputStream(file);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/msword");
        // 设置浏览器以下载的方式,处理该文件名
        response.setHeader("Content-Disposition", "attachment;fileName=" +
                ProWordUtil.encodeFileName(request, fileName));
        out = response.getOutputStream();
        byte[] buffer = new byte[512];
        int bytesToRead;
        // 通过循环将读入的Word文件的内容输出到浏览器中
        while((bytesToRead = in.read(buffer)) != -1) {
            out.write(buffer, 0, bytesToRead);
        }
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        IoUtil.close(in);
        IoUtil.close(out);
        if (file != null) {
            file.delete();
        }
    }
}

 首先调用 createWord 方法把拼接好的 map 和 ftl 模板文件传过去

让我们接着往下看看这个 createWord 方法是怎么做的

public static File createWord(Map dataMap, String templateName) {
    String name = "temp" + (int) (Math.random() * 100000) +".doc";
    File file = new File(name);
    Writer writer = null;
    try {
        configuration.setClassForTemplateLoading(FreemarkerUtils.class, "/com/landray/kmss/pro/word/template/");
        Template template = configuration.getTemplate(templateName, "UTF-8");
        writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file), StandardCharsets.UTF_8));
        template.process(dataMap, writer);
    } catch (IOException | TemplateException e) {
        throw new RuntimeException(e);
    } finally {
        IoUtil.close(writer);
    }
    return file;
}

该方法会返回一个 file ,接收后再该 file 写出去就行了

2.3、拼接的 map 数据 

2.3.1、IProWordDownloadService 
Map<String, Object> getDataMap27(HttpServletRequest request) throws Exception;
2.3.2、ProWordDownloadServiceImp 
@Override
    public Map<String, Object> getDataMap27(HttpServletRequest request) throws Exception {
        Map<String, Object> dataMap = new HashMap<>();
        String fdId = request.getParameter("fdId");
        ICostApplyJbcsqService costApplyJbcsqService = (ICostApplyJbcsqService) SpringBeanUtil.getBean("costApplyJbcsqService");
        CostApplyJbcsq costApplyJbcsq = (CostApplyJbcsq) costApplyJbcsqService.findByPrimaryKey(fdId, null, true);
        if (costApplyJbcsq != null) {
            dataMap.put("Sqdh", costApplyJbcsq.getDocNumber() == null ? "" : costApplyJbcsq.getDocNumber());
            dataMap.put("Ycsj", costApplyJbcsq.getFdDateMeal() == null ? "" : DateUtil.convertDateToString(costApplyJbcsq.getFdDateMeal(), "yyyy年MM月dd日"));
            dataMap.put("Ycbz", costApplyJbcsq.getFdYcbz() == null ? "" : costApplyJbcsq.getFdYcbz() + "元/人");
            dataMap.put("Ycrs", costApplyJbcsq.getFdYcrs() == null ? "" : costApplyJbcsq.getFdYcrs());
            dataMap.put("Ycje", costApplyJbcsq.getFdSqje() == null ? "" : costApplyJbcsq.getFdSqje());
            dataMap.put("Ycsy", costApplyJbcsq.getFdBz() == null ? "" : costApplyJbcsq.getFdBz());

            //申请部门
            SysOrgElement docDept = costApplyJbcsq.getDocDept();
            String sqbm = "";
            if (docDept != null) {
                if (docDept.getFdParent() != null) {
                    sqbm += docDept.getFdParent().getFdName() + "_";
                }
                sqbm += docDept.getFdName();
            }
            dataMap.put("Sqbm", sqbm);

            List<LbpmAuditNote> lbpmAuditNoteList = getLbpmAuditNoteService().findByModelId(fdId, new RequestContext());
            for (LbpmAuditNote lbpmAuditNote : lbpmAuditNoteList) {
                String base64Str = "";
                if (lbpmAuditNote.getFdHandler() != null) {
                    List<SysAttMain> attMainList = FreemarkerUtils.getPicAttBySignature(lbpmAuditNote.getFdHandler());
                    if (!ArrayUtil.isEmpty(attMainList) && getSysAttMainService().getInputStream(attMainList.get(0)) != null) {
                        base64Str = Base64.encode(getSysAttMainService().getInputStream(attMainList.get(0)));
                    }
                }
                if ("起草节点".equals(lbpmAuditNote.getFdFactNodeName()) && "drafter_submit".equals(lbpmAuditNote.getFdActionKey())) {
                    dataMap.put("Sqr", lbpmAuditNote.getHandlerName());
                } else if ("部门负责人".equals(lbpmAuditNote.getFdFactNodeName()) && "handler_pass".equals(lbpmAuditNote.getFdActionKey())) {
                    dataMap.put("Yj", lbpmAuditNote.getFdAuditNote());
                    dataMap.put("Bmfzr", base64Str);
                } else if ("部门负责人/分管领导".equals(lbpmAuditNote.getFdFactNodeName()) && "handler_pass".equals(lbpmAuditNote.getFdActionKey())) {
                    dataMap.put("Yj", lbpmAuditNote.getFdAuditNote());
                    dataMap.put("Bmfzr", base64Str);
                } else if ("分公司领导".equals(lbpmAuditNote.getFdFactNodeName()) && "handler_pass".equals(lbpmAuditNote.getFdActionKey())) {
                    dataMap.put("Yj", lbpmAuditNote.getFdAuditNote());
                    dataMap.put("Bmfzr", base64Str);
                }
            }
        }
        return dataMap;
    }

通过 map 拼接 ftl 模板需要的数据

 2.4、ftl文件

注:整理好模板后,模板后的字段需要使用占位符占用, 签名的文件图片大小为 1 ✖ 2.4,将 word 文档另存为 xml 文件后将后缀改为 ftl 即可

<#list bmfzrList as item>
<w:binData
        w:name="${"wordml://03000002"+item_index+".jpg"}">${item}</w:binData>
<v:shape id="_x0000_i1026" type="#_x0000_t75" alt=""
         style="width:67.8pt;height:28.2pt" o:preferrelative="f">
    <v:imagedata src="${"wordml://03000002"+item_index+".jpg"}"
                 o:href="../../AppData/Local/Temp/ksohtml11684/wps2.png"/>
    <o:lock v:ext="edit" aspectratio="f"/>
</v:shape>
</#list>

 注意事项:1、ftl 模板找到对应的取值的地方使用 ${} 取值

2、需要使用判断的地方还可以使用 <#if>标签进行判断

3、同一个位置需要存储多个图片的(List或者Set集合)可以参照如上代码("${"wordml://03000002"+item_index+".jpg"}">${item}),03000002不能跟同一个模板中的重复,使用 <#list bmfzrList as item> 标签读取集合中的数据

二、多个模板导出(按照公司分类)

1、前端

1.1、view.jsp

<c:if test="${ contractManageFksqbForm.docStatus=='30'}">
    <c:import url="classbutton.jsp" charEncoding="UTF-8">
        <c:param name="fdId" value="${param.fdId}"/>
    </c:import>
</c:if>

url 指定的是对应目录下的文件 ,导入该文件到此文件中

1.2、classbutton.jsp 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ include file="/resource/jsp/common.jsp" %>
<ui:button text="支付(结算)申请导出" onclick="updateInfo()" order="2" parentId="toolbar"/>
<script>
    function updateInfo() {
        seajs.use(['sys/ui/js/dialog'], function (dialog) {
            var url = "/contract/manage/contract_manage_fksqb/selectTemplate.jsp?fdId=${param.fdId}&fdCategory=${docTemplateName}";
            dialog.iframe(url, "选择导出模板", null, {width: 500, height: 400});
        });
    }
</script>

url 对应点击导出按钮后弹出的页面,携带的参数为 fdId (主键)和 fdCategory (公司)

${docTemplateName} 的取值为对应模块下的 Action 中的 loadActionForm 方法所指定

/**
     * 根据http请求,获取model,将model转化为form并返回。<br>
     * URL中必须包含fdId参数,该参数为记录id。<br>
     * 若获取model不成功,则抛出errors.norecord的错误信息。
     *
     * @param form
     * @param request
     * @return form对象
     * @throws Exception
     */
    protected void loadActionForm(ActionMapping mapping, ActionForm form,
                                  HttpServletRequest request, HttpServletResponse response)
            throws Exception {
        form.reset(mapping, request);
        IExtendForm rtnForm = null;
        String id = request.getParameter("fdId");
        if (!StringUtil.isNull(id)) {
            IBaseModel model = getServiceImp(request).findByPrimaryKey(id,
                    null, true);
            if (model != null){
                rtnForm = getServiceImp(request).convertModelToForm(
                        (IExtendForm) form, model, new RequestContext(request));
                UserOperHelper.logFind(model);
                ContractManageFksqb contractManageFksqb = (ContractManageFksqb) model;
                ContractManageZfTemplate parentTemplate = contractManageFksqb.getDocTemplate();
                String fdName = parentTemplate.getFdParent()==null?parentTemplate.getFdName():((ContractManageZfTemplate)parentTemplate.getFdParent()).getFdName();
                request.setAttribute("docTemplateName",fdName);
            }
        }
        if (rtnForm == null) {
            throw new NoRecordException();
        }
        request.setAttribute(getFormName(rtnForm, request), rtnForm);
    }

1.3、selectTemplate.jsp 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<html>
<head>
    <style>
        .category-list {
            width: 100%;
            height: 300px;
            padding: 0;
            margin: 0;
            text-align: center;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
        }

        .category-list ul {
            list-style-type: none;
            padding: 0;
            margin: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
        }

        .category-list li {
            margin: 10px;
        }
    </style>
</head>
<script>
    var basePath = "${pageContext.request.contextPath}";
    // 获取地址栏的完整URL
    var url = window.location.href;
    // 获取地址栏的参数部分
    var params = window.location.search;

    // 获取指定参数的值
    function getParameterByName(name) {
        name = name.replace(/[\[\]]/g, "\\$&");
        var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
            results = regex.exec(params);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, " "));
    }

    function downloadDoc(fdTemplateId) {

        var tableName = document.getElementById("ul").children[fdTemplateId].querySelector("span").innerText;
        var fdId = getParameterByName('fdId');
        var url = basePath + "/pro/word/proWordDownload.do?method=downloadWord&fdId=" + fdId + "&&type=zfjssp&&tableName=" + tableName;
        window.open(url, '_blank');

    }

    window.onload = function () {
        var category = getParameterByName('fdCategory');
        var li = "";
        if (category == "山东水设") {
            li = '<li><span>山东省水利勘测设计院有限公司(院本部)</span> <button onclick="downloadDoc(' + 0 + ')">选择</button></li>' +
                '<li><span>山东省水利勘测设计院有限公司(院内分公司)</span> <button onclick="downloadDoc(' + 1 + ')">选择</button></li>';
        } else if (category == "监理公司") {
            li = '<li><span>山东省水利工程建设监理有限公司</span> <button onclick="downloadDoc(' + 0 + ')">选择</button></li>';
        } else if (category == "试验公司") {
            li = '<li><span>山东省水利工程试验中心有限公司</span> <button onclick="downloadDoc(' + 0 + ')">选择</button></li>';
        } else if (category == "大禹集团") {
            li = '<li><span>山东大禹水务建设集团有限公司(大禹及其分公司)</span> <button onclick="downloadDoc(' + 0 + ')">选择</button></li>' +
                '<li><span>山东省水利水电建筑工程承包有限公司(承包公司)</span> <button onclick="downloadDoc(' + 1 + ')">选择</button></li>' +
                '<li><span>山东大禹水务建设集团有限公司(大禹其他子公司)</span> <button onclick="downloadDoc(' + 2 + ')">选择</button></li>';
        } else if (category == "水设分公司") {
            li = '<li><span>山东省水利勘测设计院有限公司分公司</span> <button onclick="downloadDoc(' + 0 + ')">选择</button></li>';
        }
        document.getElementById("ul").innerHTML = li;

    }
</script>
<body>

<div class="category-list">
    <ul id="ul">

    </ul>
</div>
</body>
</html>

根据传入的公司进行判断弹出对应的模板 

2、后端 

参考单个模板导出的后端即可

结语:那年我双手插兜,不知道什么叫做对手。 

  • 13
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值