目录
2.2、FreemarkerUtils 类的 exportMillCertificateWord 方法
2.3.2、ProWordDownloadServiceImp
一、单个模板导出
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、后端
参考单个模板导出的后端即可
结语:那年我双手插兜,不知道什么叫做对手。