700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Java Web项目中使用Freemarker生成Word文档

Java Web项目中使用Freemarker生成Word文档

时间:2024-04-26 18:41:44

相关推荐

Java Web项目中使用Freemarker生成Word文档

Web项目中生成Word文档的操作屡见不鲜,基于Java的解决方案也是很多的,包括使用Jacob、Apache POI、Java2Word、iText等各种方式,其实在从Office 开始,就可以将Office文档转换成XML文件,这样只要将需要填入的内容放上${}占位符,就可以使用像Freemarker这样的模板引擎将出现占位符的地方替换成真实数据,这种方式较之其他的方案要更为简单。

下面举一个简单的例子,比如在Web页面中填写个人简历,然后点击保存下载到本地,效果图如下所示。

打开下载的Word文件

首先在Eclipse Java EE版中新建一个Dynamic Web Project,项目结构如下图所示

需要向项目中加入freemarker的JAR文件,可以通过下面的链接获得Freemarker的最新版本:

/freemarkerdownload.html

模板文件resume.ftl是如何生成的呢,其实非常简单,将需要的Word文档做好之后,选择另存为XML文件,另存之后建议用Editplus、Notepad++、Sublime等工具打开查看一下,因为有的时候你写的占位符可能会被拆开,这样Freemarker就无法处理了。

打开XML文件看看吧,如果刚才你写的${title}、${name}被xml文件给拆散了,修改一下XML文件就OK了。

修改过后另存为resume.ftl模板文件,如下所示:

接下来就是Servlet(也可以是Struts2的Action、Spring MVC的Controller等)和工具类WordGenerator的编写以及页面test.jsp的制作了,代码如下所示:

小服务的代码:

[java]view plain copy print ? packagecom.lovo.servlet;importjava.io.File;importjava.io.FileInputStream;importjava.io.IOException;importjava.io.InputStream;importjava.util.Enumeration;importjava.util.HashMap;importjava.util.Map;importjavax.servlet.ServletException;importjavax.servlet.ServletOutputStream;importjavax.servlet.annotation.WebServlet;importjavax.servlet.http.HttpServlet;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importcom.lovo.util.WordGenerator;/***ServletimplementationclassMyServlet*/@WebServlet("/saveDocServlet")publicclassMyServletextendsHttpServlet{privatestaticfinallongserialVersionUID=1L;@Overrideprotectedvoidservice(HttpServletRequestreq,HttpServletResponseresp)throwsServletException,IOException{req.setCharacterEncoding("utf-8");Map<String,Object>map=newHashMap<String,Object>();Enumeration<String>paramNames=req.getParameterNames();//通过循环将表单参数放入键值对映射中while(paramNames.hasMoreElements()){Stringkey=paramNames.nextElement();Stringvalue=req.getParameter(key);map.put(key,value);}//提示:在调用工具类生成Word文档之前应当检查所有字段是否完整//否则Freemarker的模板殷勤在处理时可能会因为找不到值而报错这里暂时忽略这个步骤了Filefile=null;InputStreamfin=null;ServletOutputStreamout=null;try{//调用工具类WordGenerator的createDoc方法生成Word文档file=WordGenerator.createDoc(map,"resume");fin=newFileInputStream(file);resp.setCharacterEncoding("utf-8");resp.setContentType("application/msword");//设置浏览器以下载的方式处理该文件默认名为resume.docresp.addHeader("Content-Disposition","attachment;filename=resume.doc");out=resp.getOutputStream();byte[]buffer=newbyte[512];//缓冲区intbytesToRead=-1;//通过循环将读入的Word文件的内容输出到浏览器中while((bytesToRead=fin.read(buffer))!=-1){out.write(buffer,0,bytesToRead);}}finally{if(fin!=null)fin.close();if(out!=null)out.close();if(file!=null)file.delete();//删除临时文件}}}

package com.lovo.servlet;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.InputStream;import java.util.Enumeration;import java.util.HashMap;import java.util.Map;import javax.servlet.ServletException;import javax.servlet.ServletOutputStream;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.lovo.util.WordGenerator;/*** Servlet implementation class MyServlet*/@WebServlet("/saveDocServlet")public class MyServlet extends HttpServlet {private static final long serialVersionUID = 1L;@Overrideprotected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {req.setCharacterEncoding("utf-8");Map<String, Object> map = new HashMap<String, Object>();Enumeration<String> paramNames = req.getParameterNames();// 通过循环将表单参数放入键值对映射中while(paramNames.hasMoreElements()) {String key = paramNames.nextElement();String value = req.getParameter(key);map.put(key, value);}// 提示:在调用工具类生成Word文档之前应当检查所有字段是否完整// 否则Freemarker的模板殷勤在处理时可能会因为找不到值而报错 这里暂时忽略这个步骤了File file = null;InputStream fin = null;ServletOutputStream out = null;try {// 调用工具类WordGenerator的createDoc方法生成Word文档file = WordGenerator.createDoc(map, "resume");fin = new FileInputStream(file);resp.setCharacterEncoding("utf-8");resp.setContentType("application/msword");// 设置浏览器以下载的方式处理该文件默认名为resume.docresp.addHeader("Content-Disposition", "attachment;filename=resume.doc");out = resp.getOutputStream();byte[] buffer = new byte[512];// 缓冲区int bytesToRead = -1;// 通过循环将读入的Word文件的内容输出到浏览器中while((bytesToRead = fin.read(buffer)) != -1) {out.write(buffer, 0, bytesToRead);}} finally {if(fin != null) fin.close();if(out != null) out.close();if(file != null) file.delete();// 删除临时文件}}}

工具类的代码:

[java]view plain copy print ? packagecom.lovo.util;importjava.io.File;importjava.io.FileOutputStream;importjava.io.IOException;importjava.io.OutputStreamWriter;importjava.io.Writer;importjava.util.HashMap;importjava.util.Map;importfreemarker.template.Configuration;importfreemarker.template.Template;publicclassWordGenerator{privatestaticConfigurationconfiguration=null;privatestaticMap<String,Template>allTemplates=null;static{configuration=newConfiguration();configuration.setDefaultEncoding("utf-8");configuration.setClassForTemplateLoading(WordGenerator.class,"/com/lovo/ftl");allTemplates=newHashMap<>();//Java7钻石语法try{allTemplates.put("resume",configuration.getTemplate("resume.ftl"));}catch(IOExceptione){e.printStackTrace();thrownewRuntimeException(e);}}privateWordGenerator(){thrownewAssertionError();}publicstaticFilecreateDoc(Map<?,?>dataMap,Stringtype){Stringname="temp"+(int)(Math.random()*100000)+".doc";Filef=newFile(name);Templatet=allTemplates.get(type);try{//这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开Writerw=newOutputStreamWriter(newFileOutputStream(f),"utf-8");t.process(dataMap,w);w.close();}catch(Exceptionex){ex.printStackTrace();thrownewRuntimeException(ex);}returnf;}}

package com.lovo.util;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStreamWriter;import java.io.Writer;import java.util.HashMap;import java.util.Map;import freemarker.template.Configuration;import freemarker.template.Template;public class WordGenerator {private static Configuration configuration = null;private static Map<String, Template> allTemplates = null;static {configuration = new Configuration();configuration.setDefaultEncoding("utf-8");configuration.setClassForTemplateLoading(WordGenerator.class, "/com/lovo/ftl");allTemplates = new HashMap<>();// Java 7 钻石语法try {allTemplates.put("resume", configuration.getTemplate("resume.ftl"));} catch (IOException e) {e.printStackTrace();throw new RuntimeException(e);}}private WordGenerator() {throw new AssertionError();}public static File createDoc(Map<?, ?> dataMap, String type) {String name = "temp" + (int) (Math.random() * 100000) + ".doc";File f = new File(name);Template t = allTemplates.get(type);try {// 这个地方不能使用FileWriter因为需要指定编码类型否则生成的Word文档会因为有无法识别的编码而无法打开Writer w = new OutputStreamWriter(new FileOutputStream(f), "utf-8");t.process(dataMap, w);w.close();} catch (Exception ex) {ex.printStackTrace();throw new RuntimeException(ex);}return f;}}

JSP页面的代码:

[html]view plain copy print ? <%@pagepageEncoding="UTF-8"%><!DOCTYPEhtml><html><head><metacharset="UTF-8"/><title>Document</title><styletype="text/css">*{font-family:"微软雅黑";}.textField{border:none;border-bottom:1pxsolidgray;text-align:center;}#file{border:1pxsolidblack;width:80%;margin:0auto;}h1input{font-size:72px;}tdtextarea{font-size:14px;}.key{width:125px;font-size:20px;}</style></head><body><formaction="saveDocServlet"method="post"><divid="file"align="center"><h1><inputtype="text"name="title"class="textField"value="我的简历"/></h1><hr/><table><tr><tdclass="key">姓名:</td><td><inputtype="text"name="name"class="textField"/></td><tdclass="key">性别:</td><td><inputtype="radio"name="gender"value="男"checked/>男<inputtype="radio"name="gender"value="女"/>女</td></tr><tr><tdclass="key">联系电话:</td><td><inputtype="text"name="tel"class="textField"/></td><tdclass="key">家庭住址:</td><td><inputtype="text"name="address"class="textField"/></td></tr><tr><tdcolspan="4"class="key">个人简介:</td></tr><tr><tdcolspan="4"><textarearows="10"cols="100"name="content"></textarea></td></tr></table></div><divalign="center"style="margin-top:15px;"><inputtype="submit"value="保存Word文档"/></div></form></body></html>

<%@ page pageEncoding="UTF-8"%><!DOCTYPE html><html><head><meta charset="UTF-8" /><title>Document</title><style type="text/css">* { font-family: "微软雅黑"; }.textField { border:none; border-bottom: 1px solid gray; text-align: center; }#file { border:1px solid black; width: 80%; margin:0 auto; }h1 input{ font-size:72px; }td textarea { font-size: 14px; }.key { width:125px; font-size:20px; }</style></head><body><form action="saveDocServlet" method="post"><div id="file" align="center"><h1><input type="text" name="title" class="textField" value="我的简历"/></h1><hr/><table><tr><td class="key">姓名:</td><td><input type="text" name="name" class="textField"/></td><td class="key">性别:</td><td><input type="radio" name="gender" value="男" checked/>男<input type="radio" name="gender" value="女" />女</td></tr><tr><td class="key">联系电话:</td><td><input type="text" name="tel" class="textField"/></td><td class="key">家庭住址:</td><td><input type="text" name="address" class="textField"/></td></tr><tr><td colspan="4" class="key">个人简介:</td></tr><tr><td colspan="4"><textarea rows="10" cols="100" name="content"></textarea></td></tr></table></div><div align="center" style="margin-top:15px;"><input type="submit" value="保存Word文档" /></div></form></body></html>

说明:小服务是使用注解进行配置的,因此你的服务器需要支持Servlet 3规范,我使用的服务器是Tomcat 7.0.52。如果你的服务器不支持Servlet 3规范那就使用web.xml来配置你的小服务吧,其他地方没有不同。如果你不熟悉Servlet 3规范的新特性,可以阅读CSDN上另一篇文章,链接如下所示:

/zhongweijian/article/details/8279650

此外,如果你希望在Word文档中插入图片,可以把Word另存为的XML文件中代表图片的那个很长的字符串(BASE64编码的字符串)换成一个占位符,在将要插入Word文档的图片对象转换成BASE64编码的字符串,用该字符串替换掉占位符就可以了,示意图和代码如下所示:

将图片转换成BASE64字符串的代码如下所示:

[java]view plain copy print ? publicstaticStringgetImageString(Stringfilename)throwsIOException{InputStreamin=null;byte[]data=null;try{in=newFileInputStream(filename);data=newbyte[in.available()];in.read(data);in.close();}catch(IOExceptione){throwe;}finally{if(in!=null)in.close();}BASE64Encoderencoder=newBASE64Encoder();returndata!=null?encoder.encode(data):"";}

public static String getImageString(String filename) throws IOException {InputStream in = null;byte[] data = null;try {in = new FileInputStream(filename);data = new byte[in.available()];in.read(data);in.close();} catch (IOException e) {throw e;} finally {if(in != null) in.close();}BASE64Encoder encoder = new BASE64Encoder();return data != null ? encoder.encode(data) : "";}

注意:这里使用的BASE64Encoder类在sun.misc包下,rt.jar中有这个类,但是却无法直接使用,需要修改访问权限,在Eclipse中可以这样修改。

在项目上点右键选择Properties菜单项进入如下图所示的界面:

这样设置后就可以使用BASE64Encoder类了,在项目中调用getImageString方法指定要插入的图片的完整文件名(带路径的文件名),该方法返回的字符串就是将图片处理成BASE64编码后的字符串。但愿你按照上面的步骤一次成功!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。