如何用java代码生成Word文档和签字以及导出pdf文件


前言

本篇文章主要本人接到的一个紧急任务,时间紧任务重,完成的比较仓促,后续还需改善。最主要是感觉之前没有怎么接触过,所以分享出来,供大家参考一下。


一、任务描述以及前期准备

1.任务描述

是将数据库中的每个表的字段导出,生成word文档,并且可以签字和导出。

2.前期准备

1.首先在Eclipse Java EE版中新建一个Dynamic Web Project,项目结构如下图所示
建立项目
需要向项目中加入freemarker的JAR文件,可以通过下面的链接获得Freemarker的最新版本:
http://freemarker.org/freemarkerdownload.html

2.然后打开word文档,建立自己所需要的模板,然后将word保存为XML这里可能出现的一个问题就是需要填入的内容放到占位符的时候可能会出现字符分离的情况,所以建议先将需要用 占 位 符 的 地 方 用 中 文 写 在 w o r d 里 然 后 保 存 为 X M L 的 格 式 再 打 开 X M L 对 需 要 用 {}占位符的地方用中文写在word里然后保存为XML的格式再打开XML对需要用 wordXMLXML{}占位符的地方进行替换,这样就避免了字符分离的情况。
在这里插入图片描述
这里我使用的一个软件foxe(按F8可以对XML进行格式化,然后再对XML进行编辑。)

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

二、编写java代码转成word文档

1.小服务代码

这里用的是Servlet(也可以是Struts2的Action、Spring MVC的Controller等)
小服务代码如下:

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;
 
	@Override
	protected 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.doc
			resp.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();	// 删除临时文件
		}
	}
 
}

2.工具类代码

工具类代码如下:

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;
	}
 
}

3.jsp页面代码

jsp页面代码如下:
jsp代码
这里不方便拿出来,就截个图吧。

三、word签名和导出pdf

1.签名

这里说明一下,签名主要是前台完成,所以js写的比较多
代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head lang="en">
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,maximum-scale=1.0,user-scalable=no" />
    <link rel="stylesheet" href="./css/mui.min.css" />
    <link rel="stylesheet" href="./css/reset.css" />
    <link rel="stylesheet" href="./css/base.css" />
    <!-- <link rel="stylesheet" href="./css/mui.picker.min.css" /> -->
    <link rel="stylesheet" href="./css/HN_Sign.css"/>
    <title>签名</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body id="qz_parents">

<div class="canvasDiv">
    <!--<div id="editing_area">-->
    <canvas width="600" height="250" id="canvasEdit"></canvas>
    <!--</div>-->
</div>

<div class="imgDiv">
    <span id="sign_show"></span>
</div>
<!--<a class="return">-->
<!--<img src="../../images/Public_icon_sign_back.png"/>-->
<!--</a>-->
<p><img class="" src="image/xzk.png"/><span>本人已知悉并认可电子签名效力等同书面形式签字</span></p>
<div class="btnDiv">
    <a id="sign_clear" class="clearBtn">清除</a>
    <button id="sign_ok" class="okBtn" disabled>确认</button>
    <button id="cancel" class="cancel">取消</button>
</div>

<script type="text/javascript" src="./js/jquery-3.2.1.min.js"></script>
<script type="text/javascript" src="./js/mui.js"></script>
<!-- <script type="text/javascript" src="../../static/js/mui.picker.min.js"></script> -->
<script type="text/javascript" src="./js/bzyd.common.js"></script>
<script type="text/javascript" src="./js/rem.js"></script>
<script type="text/javascript" src="./js/html2canvas.js"></script>
<script type="text/javascript" src="./js/HN_esign.js"></script>
<script>
  $(function() {
    //初始化动作,根据DOM的ID不同进行自定义,如果不写则内部默认取这四个
    $().esign("canvasEdit", "sign_show", "sign_clear", "sign_ok");
    $('p').width($('.canvasDiv').width());
    $('canvas').attr('height',$('.canvasDiv').height()).attr('width',$('.canvasDiv').width());
    $('p').children('img').click(function(){
      $(this).toggleClass('check');
      if($(this).hasClass('check')){
        $(this).attr('src','image/xzk.png');
        $('#sign_ok').removeAttr('disabled');
      } else{
        $(this).attr('src','image/xzk.png');
        $('#sign_ok').attr('disabled','disabled');
      }
    });
    $('#cancel').click(function(){
      window.history.go(-1);
    });

  });
</script>
</body>
</html>

2.导出pdf

导出pdf也是挺麻烦的,不解释了,上代码。。。
代码如下:

package com.sgcc.am.freemarkerwork1.util;

import java.io.BufferedWriter;  
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
 
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 javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
 
  
   
  
import freemarker.template.Configuration;  
  
import freemarker.template.Template;  
  
import freemarker.template.TemplateException;  

public class DocumentHandler {
	//Configuration存储一些全局常量和常用设置
	   private Configuration configuration = null;  
	  
	   //构造函数生成实例并设置编码
	   public DocumentHandler() {
	      configuration = new Configuration();  
	      configuration.setDefaultEncoding("utf-8");  
	   }
	  
	   
	  /**
	   * 导出word文档,导出到本地
	   * @param tempName,要使用的模板
	   * @param docName,导出文档名称
	   * @param dataMap,模板中变量数据
	   * @param outFile,输出文档路径
	   */
	   public boolean exportDoc(String tempName,Map<?, ?> dataMap,File outFile) {  
		   boolean status = false;
	  
	      // 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载,  
	      configuration.setClassForTemplateLoading(this.getClass(), "com/sgcc/am/freemarkerwork1/ftl");  
	  
	      Template t = null;  
	  
	      try{  
	         // tempName.ftl为要装载的模板  
	         t = configuration.getTemplate(tempName+".ftl");  
	         t.setEncoding("utf-8");  
	      } catch (IOException e) {
	         e.printStackTrace();  
	      }
	  
	      Writer out = null;  
	      try{  
	         out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
	         status = true;
	      }catch(Exception e1) {  
	         e1.printStackTrace();  
	      }  
	  
	      try{  
	         t.process(dataMap, out);  
	         out.close();  
	      }catch(TemplateException e){  
	         e.printStackTrace();  
	      } catch (IOException e) {  
	         e.printStackTrace();  
	      }  
	  
	      return status;
	   }  
	  
	   /**
	    * 导出word文档,响应到请求端
	    * @param tempName,要使用的模板
	    * @param docName,导出文档名称
	    * @param dataMap,模板中变量数据
	    * @param resp,HttpServletResponse
	    */
		public boolean exportDoc(String tempName, String docName, Map<?, ?> dataMap, HttpServletResponse resp) {
			boolean status = false;
			ServletOutputStream sos = null;
			InputStream fin = null;
			if (resp != null) {
				resp.reset();
			}
	 
			// 设置模本装置方法和路径,FreeMarker支持多种模板装载方法。可以重servlet,classpath,数据库装载。参数2为模板路径
			configuration.setClassForTemplateLoading(this.getClass(), "com/sgcc/am/freemarkerwork1/ftl");
	 
			Template t = null;
	 
			try {
				// tempName.ftl为要装载的模板
				t = configuration.getTemplate(tempName + ".ftl");
				t.setEncoding("utf-8");
			} catch (IOException e) {
				e.printStackTrace();
			}
	 
			// 输出文档路径及名称 ,以临时文件的形式导出服务器,再进行下载
			String name = "temp" + (int) (Math.random() * 100000) + ".doc";
			File outFile = new File(name);
	 
			Writer out = null;
			try {
				out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile), "utf-8"));
				status = true;
			} catch (Exception e1) {
				e1.printStackTrace();
			}
	 
			try {
				t.process(dataMap, out);
				out.close();
			} catch (TemplateException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}
	 
			try {
				fin = new FileInputStream(outFile);
			} catch (FileNotFoundException e) {
				e.printStackTrace();
			}
			// 文档下载
			resp.setCharacterEncoding("utf-8");
			resp.setContentType("application/msword");
			try {
				docName = new String(docName.getBytes("UTF-8"), "ISO-8859-1");
			} catch (UnsupportedEncodingException e1) {
				e1.printStackTrace();
			}
			resp.setHeader("Content-disposition", "attachment;filename=" + docName + ".doc");
			try {
				sos = resp.getOutputStream();
			} catch (IOException e) {
				e.printStackTrace();
			}
			byte[] buffer = new byte[512]; // 缓冲区
			int bytesToRead = -1;
			// 通过循环将读入的Word文件的内容输出到浏览器中
			try {
				while ((bytesToRead = fin.read(buffer)) != -1) {
					sos.write(buffer, 0, bytesToRead);
				}
			} catch (IOException e) {
				e.printStackTrace();
			} finally {
				if (fin != null)
					try {
						fin.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				if (sos != null)
					try {
						sos.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				if (outFile != null)
					outFile.delete(); // 删除临时文件
			}
	 
			return status;
		}
	

}

四、最后展示效果

上半部分
在这里插入图片描述

总结

主要是任务急,没有具体整理代码,大家仅供参考。

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值