通过xml方式根据word模板导出word

原创 2016年06月02日 10:14:24

1 . 实现代码

package com.base.pf.common.util;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.axis.encoding.Base64;

import com.base.pf.base.util.PropertiesMgr;
import com.base.pf.base.util.StringUtils;

/**
 * 导出WORD
 * 
 * @author ZHEN.L
 * @date 2014.09.23
 * @date 2014.11.05
 * 
 */
public class WordUtils {

	/**
	 * 转换PDF格式
	 */
	public static final String WORD_2_PDF = "Word.pdf";

	/**
	 * word导出标记
	 */
	public static final String WORD_EXP_TAG = "Word.exp";

	/**
	 * word导出值
	 */
	public static final String WORD_EXP_TAG_VALUE = "word";

	/**
	 * 模板名称标记
	 */
	public static final String WORD_TEMPLATE_NAME = "Word.fileName";

	/**
	 * 模板名称标记
	 */
	public static final String WORD_FILE_NAME = "fileName";

	/**
	 * 模板名称标记:动态字段
	 */
	public static final String WORD_FILE_NAME_FIELD = "FieldfileName";

	// 模板路径
	protected static final String WORD_TEMPLATE_PATH = "\\page\\project\\template_word\\";

	/**
	 * word中换行:需要将word中\r\n转回为以下字符串 <w:spacing w:line="240" w:line-rule="auto"
	 * /> 240为单倍行距,360为1.5倍行距
	 */
	protected static final String LINE_FEED = "</w:t></w:r></w:p><w:p wsp:rsidR=\"004C3B63\" wsp:rsidRDefault=\"004C3B63\" wsp:rsidP=\"00302FB9\"><w:pPr><w:spacing w:line=\"340\" w:line-rule=\"auto\" /><w:rPr><w:rFonts w:ascii=\"宋体\" w:h-ansi=\"宋体\"/><wx:font wx:val=\"宋体\"/><w:sz w:val=\"24\"/></w:rPr></w:pPr><w:r><w:rPr><w:rFonts w:ascii=\"宋体\" w:h-ansi=\"宋体\" w:hint=\"fareast\"/><wx:font wx:val=\"宋体\"/><w:sz w:val=\"24\"/></w:rPr><w:t>    ";

	protected static final String PDF_PATH = PropertiesMgr
			.getValue("exp_word_pdf_path") + "/";

	/**
	 * 导出word
	 * 
	 * @param response
	 */
	public synchronized static String exp(HttpServletRequest request,
			HttpServletResponse response, Object obj) {
		String xml = "";
		String PDF = request.getParameter(WORD_2_PDF);
		Map map = BeanToMapUtils.convertBean(obj);
		String templatePath = request.getServletContext().getRealPath("/")
				+ WORD_TEMPLATE_PATH;
		String templateName = request.getParameter(WORD_TEMPLATE_NAME);
		// 模板名称,程序中获取,通过DTO传递过来
		if (map.get("templateName") != null) {
			templateName = String.valueOf(map.get("templateName"));
		}
		File file = new File(templatePath + templateName);
		String fileName = request.getParameter(WORD_FILE_NAME);
		String fieldFileName = request.getParameter(WORD_FILE_NAME_FIELD);
		if (!file.exists()) {
			throw new NullPointerException("模板不存在!");
		}
		OutputStream os = null;
		BufferedReader br = null;
		try {
			br = new BufferedReader(new InputStreamReader(new FileInputStream(
					file), "UTF-8"));
			String buf = null;
			while ((buf = br.readLine()) != null) {
				xml += buf;
			}
			// ContactDtoT dto = new ContactDtoT();
			// if (!(obj instanceof Map))
			// BeanUtils.copyProperties(obj, dto);
			if (!StringUtils.isEmpty(fieldFileName)) {
				String temp = String.valueOf(map.get(fieldFileName));
				if (!StringUtils.isEmpty(temp)) {
					fileName = temp.trim() + fileName;
				}
			}
			xml = replace(xml, map);
			if (!"word".equalsIgnoreCase(PDF)) {
				File pdfFile = new File(PDF_PATH);
				if (!pdfFile.exists()) {
					pdfFile.mkdirs();
				}
				OutputStream localOs = new FileOutputStream(new File(PDF_PATH
						+ fileName + ".doc"));
				localOs.write(xml.getBytes("UTF-8"));
				PDFUtils.download(request, response, PDF_PATH + fileName
						+ ".doc");
				return null;
			}
			response.setContentType("application/msword,charset=UTF-8");
			response.setHeader("Content-disposition", "attachment;filename="
					+ URLEncoder.encode(fileName + ".doc", "UTF-8"));
			os = response.getOutputStream();
			os.write(xml.getBytes("UTF-8"));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			close(br, os);
		}
		return null;
	}

	// 将文件,转换成BASE64
	protected static String getBASE64(String path) {
		// path = "d:/1.jpg";
		String base64 = "";
		File file = new File(path);
		FileInputStream fis = null;
		ByteArrayOutputStream bos = null;
		try {
			fis = new FileInputStream(file);
			bos = new ByteArrayOutputStream(1000);
			byte[] bytes = new byte[1024];
			while ((fis.read(bytes)) != -1) {
				bos.write(bytes);
			}
			base64 = Base64.encode(bos.toByteArray());
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			close(fis, bos);
		}
		return base64;
	}

	// 替换xml中字符
	protected static String replace(String xml, Map map) {
		Integer pWidth = 0, pHeight = 0; // 印章高度、宽度
		Set set = map.keySet();
		int photoIndex = 0; // 图片序号标记
		Iterator its = set.iterator();
		String key, value, tagKey, photoXml; // 图片部分XML
		while (its.hasNext()) {
			try {
				key = StringUtils.withSpaceReplaceNull(its.next());
				tagKey = "${" + key + "}";
				value = StringUtils.withSpaceReplaceNull(map.get(key));
				if (key.startsWith("photo_")) {
					photoIndex++;
					ImageDto imageDto = readImageInfo(value);
					// 设计思想: 首先将XML中图片标记${key}替换为word图片对应的XML;
					// 第二,将${photo_tag}图片(电子印章)替换为对应的${key}值,再将${key}替换为base64,
					// 公司公章:大部分长度4.2cm,个别长度3.8
					if ("photo_superName".equalsIgnoreCase(key)
							|| "photo_super".equalsIgnoreCase(key)) {
						// 图片位置
						String pict_position_left = StringUtils
								.withSpaceReplaceNull(map
										.get("pict_position_left"));
						String pict_position_top = StringUtils
								.withSpaceReplaceNull(map
										.get("pict_position_top"));
						pict_position_left = "".equals(pict_position_left) ? "0"
								: pict_position_left;
						pict_position_top = "".equals(pict_position_top) ? "-47"
								: pict_position_top;
						photoXml = IMG_UP.replace("${pict_index}", // 替换图片序列号
								String.valueOf(photoIndex));
						photoXml = photoXml.replace("${pict_position_left}",
								pict_position_left); // 替换图片左侧位置
						photoXml = photoXml.replace("${pict_position_top}",
								pict_position_top); // 替换图片上部位置
						// 像素和厘米之间的换算是需要知道图片的分辨率的。通常设计网页的时候,图片的分辨率一般都是用72dpi的,
						// 即72像素/英寸,由于1英寸= 2.54厘米,所以在设计网页的时候,一般1厘米约为28像素
						imageDto.getWidth();
						photoXml = photoXml.replace("${pict_width}",
								getpWidth(key, null, imageDto.getWidth())); // 替换图片宽度
						photoXml = photoXml.replace("${pict_height}",
								getpHeight(key, null, imageDto.getHeight())); // 替换图片高度

						photoXml = photoXml.replace("${pict_tag}", tagKey);
						xml = xml.replace(tagKey, photoXml);
						// 个人签章:个人签名(高1.8cm,宽待定)、执业资格章(高3cm,宽4.5cm)
					} else if ("photo_engineer".equalsIgnoreCase(key)
							|| "photo_chief".equalsIgnoreCase(key)) {
						String pict_position_left = StringUtils
								.withSpaceReplaceNull(map
										.get("pict_position_left_personal"));
						String pict_position_top = StringUtils
								.withSpaceReplaceNull(map
										.get("pict_position_top_personal"));
						pict_position_top = "".equals(pict_position_top) ? "0"
								: pict_position_top;
						pict_position_left = "".equals(pict_position_left) ? "0"
								: pict_position_left;
						photoXml = IMG_UP.replace("${pict_index}",
								String.valueOf(photoIndex));
						photoXml = photoXml.replace("${pict_position_left}",
								pict_position_left); // 替换图片左侧位置
						photoXml = photoXml.replace("${pict_position_top}",
								pict_position_top); // 替换图片上部位置
						photoXml = photoXml.replace(
								"${pict_width}",
								getpWidth(key, map.get("personalSealType"),
										imageDto.getWidth())); // 替换图片宽度
						photoXml = photoXml.replace(
								"${pict_height}",
								getpHeight(key, map.get("personalSealType"),
										imageDto.getHeight())); // 替换图片高度
						photoXml = photoXml.replace("${pict_tag}", tagKey);
						xml = xml.replace(tagKey, photoXml);
					}
					xml = xml.replace(tagKey, imageDto.getBase64());
				} else {
					value = value.replace("\r\n", LINE_FEED);
					xml = xml.replace(tagKey, value);
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		String date = new SimpleDateFormat("yyyy 年  MM 月 dd 日")
				.format(new Date());
		xml = xml.replace("${date}", date);
		xml = xml.replace("${photo_}", "");
		xml = xml.replace("${photo_superName}", "");
		xml = xml.replace("${photo_super}", "");
		xml = xml.replace("${photo_engineer}", "");
		xml = xml.replace("${photo_chief}", "");
		return xml;
	}

	// 获取印章宽度: 个人签名:高度1.8cm;个人执业资格:高度3cm,宽度:4.5cm; 公司公章:最大4.2cm
	private static String getpWidth(String pType, Object sealPeronal,
			double width) {
		double pWidth = 100;
		String sealPeronalType = String.valueOf(sealPeronal);
		// 公章
		if ("photo_superName".equalsIgnoreCase(pType)
				|| "photo_super".equalsIgnoreCase(pType)) {
			pWidth = width > 119 ? 119 : width;
			// 个人签章:执业资格
		} else if ("photo_engineer".equalsIgnoreCase(pType)
				&& "1001".equals(sealPeronalType)) {
			pWidth = width > 126 ? 126 : width;
			// 个人签章:签名
		} else if ("photo_engineer".equalsIgnoreCase(pType)) {
			pWidth = width > 195 ? 195 : width;
			// 个人签章:执业资格
		} else if ("photo_chief".equalsIgnoreCase(pType)
				&& "1001".equals(sealPeronalType)) {
			pWidth = width > 126 ? 126 : width;
			// 个人签章:签名
		} else if ("photo_chief".equalsIgnoreCase(pType)) {
			pWidth = width > 202 ? 202 : width;
		}
		return String.valueOf(pWidth);
	}

	// 获取印章宽度: 个人签名:高度1.8cm;个人执业资格:高度3cm,宽度:4.5cm; 公司公章:最大4.2cm
	private static String getpHeight(String pType, Object sealPeronal,
			double height) {
		double pHeight = 100;
		String sealPeronalType = String.valueOf(sealPeronal);
		// 公章
		if ("photo_superName".equalsIgnoreCase(pType)
				|| "photo_super".equalsIgnoreCase(pType)) {
			pHeight = height > 119 ? 119 : height;
			// 个人签章:执业资格
		} else if ("photo_engineer".equalsIgnoreCase(pType)
				&& "1001".equals(sealPeronalType)) {
			pHeight = height > 84 ? 84 : height;
			// 个人签章:签名
		} else if ("photo_chief".equalsIgnoreCase(pType)
				&& "1001".equals(sealPeronalType)) {
			pHeight = height > 84 ? 84 : height;
		} else if ("photo_engineer".equalsIgnoreCase(pType)
				|| "photo_chief".equalsIgnoreCase(pType)) {
			pHeight = height > 50.4 ? 50.4 : height;
		}
		return String.valueOf(pHeight);
	}

	/**
	 * 读取图片信息
	 * 
	 * @date 2014.10.22
	 * @param path
	 */
	protected static ImageDto readImageInfo(String path) {
		// path = "d:/b3.jpg";
		if (StringUtils.isEmpty(path)) {
			throw new NullPointerException("图片路径为空!");
		}
		File file = new File(path);
		if (!file.exists()) {
			throw new NullPointerException("图片不存在,路径为:" + path);
		}
		ImageDto dto = null;
		BufferedImage bi = null;
		ByteArrayOutputStream bos = null;
		FileInputStream fis = null;
		try {
			dto = new ImageDto();
			fis = new FileInputStream(file);
			bos = new ByteArrayOutputStream(1000);
			byte[] bytes = new byte[1024];
			while ((fis.read(bytes)) != -1) {
				bos.write(bytes);
			}
			bi = ImageIO.read(file);
			dto.setWidth(bi.getWidth());
			dto.setHeight(bi.getHeight());
			dto.setBase64(Base64.encode(bos.toByteArray()));
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			if (fis != null) {
				try {
					fis.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			if (bos != null) {
				try {
					bos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
		return dto;
	}

	// 关闭IO
	protected static void close(BufferedReader br, OutputStream os) {
		if (br != null) {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (os != null) {
			try {
				os.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				os.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	// 关闭IO
	protected static void close(FileInputStream fis, ByteArrayOutputStream bos) {
		if (fis != null) {
			try {
				fis.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		if (bos != null) {
			try {
				bos.flush();
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				bos.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 签名:在文字的右侧
	 */
	protected static final String IMG_RIGHT = ""
			+ " <w:pict> "
			+ " 	<v:shapetype id=\"_x0000_t75\" coordsize=\"21600,21600\" o:spt=\"75\" "
			+ " 		o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\"> "
			+ " 		<v:stroke joinstyle=\"miter\" /> "
			+ " 		<v:formulas> "
			+ " 			<v:f eqn=\"if lineDrawn pixelLineWidth 0\" /> "
			+ " 			<v:f eqn=\"sum @0 1 0\" /> "
			+ " 			<v:f eqn=\"sum 0 0 @1\" /> "
			+ " 			<v:f eqn=\"prod @2 1 2\" /> "
			+ " 			<v:f eqn=\"prod @3 21600 pixelWidth\" /> "
			+ " 			<v:f eqn=\"prod @3 21600 pixelHeight\" /> "
			+ " 			<v:f eqn=\"sum @0 0 1\" /> "
			+ " 			<v:f eqn=\"prod @6 1 2\" /> "
			+ " 			<v:f eqn=\"prod @7 21600 pixelWidth\" /> "
			+ " 			<v:f eqn=\"sum @8 21600 0\" /> "
			+ " 			<v:f eqn=\"prod @7 21600 pixelHeight\" /> "
			+ " 			<v:f eqn=\"sum @10 21600 0\" /> "
			+ " 		</v:formulas> "
			+ " 		<v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\" /> "
			+ " 		<o:lock v:ext=\"edit\" aspectratio=\"t\" /> "
			+ " 	</v:shapetype> "
			+ " 	<w:binData w:name=\"wordml://03000002.png\" xml:space=\"preserve\">${photo_tag}</w:binData> "
			+ " 	<v:shape id=\"图片 1\" o:spid=\"_x0000_i1025\" type=\"#_x0000_t75\" "
			+ " 		style=\"margin-top:10pt;width:106.5pt;height:48pt;z-index:1;visibility:visible;mso-wrap-style:square\"> "
			+ " 		<v:imagedata src=\"wordml://03000002.png\" o:title=\"\" /> "
			+ " 	</v:shape> " + " </w:pict> ";

	/**
	 * 位置:在图片的上方
	 * 
	 */
	protected static final String IMG_UP = ""
			+ " <w:pict> "
			+ " 	<v:shapetype id=\"_x0000_t75\" coordsize=\"21600,21600\" o:spt=\"75\" "
			+ " 		o:preferrelative=\"t\" path=\"m@4@5l@4@11@9@11@9@5xe\" filled=\"f\" stroked=\"f\"> "
			+ " 		<v:stroke joinstyle=\"miter\" /> "
			+ " 		<v:formulas> "
			+ " 			<v:f eqn=\"if lineDrawn pixelLineWidth 0\" /> "
			+ " 			<v:f eqn=\"sum @0 1 0\" /> "
			+ " 			<v:f eqn=\"sum 0 0 @1\" /> "
			+ " 			<v:f eqn=\"prod @2 1 2\" /> "
			+ " 			<v:f eqn=\"prod @3 21600 pixelWidth\" /> "
			+ " 			<v:f eqn=\"prod @3 21600 pixelHeight\" /> "
			+ " 			<v:f eqn=\"sum @0 0 1\" /> "
			+ " 			<v:f eqn=\"prod @6 1 2\" /> "
			+ " 			<v:f eqn=\"prod @7 21600 pixelWidth\" /> "
			+ " 			<v:f eqn=\"sum @8 21600 0\" /> "
			+ " 			<v:f eqn=\"prod @7 21600 pixelHeight\" /> "
			+ " 			<v:f eqn=\"sum @10 21600 0\" /> "
			+ " 		</v:formulas> "
			+ " 		<v:path o:extrusionok=\"f\" gradientshapeok=\"t\" o:connecttype=\"rect\" /> "
			+ " 		<o:lock v:ext=\"edit\" aspectratio=\"t\" /> "
			+ " 	</v:shapetype> "
			+ " 	<w:binData w:name=\"wordml://0300000${pict_index}.png\" xml:space=\"preserve\">${pict_tag}</w:binData> "
			+ " 	<v:shape id=\"图片 3\" o:spid=\"_x0000_s1026\" type=\"#_x0000_t75\" "
			+ " 		style=\"position:absolute;left:0;text-align:left;margin-left:${pict_position_left}pt;margin-top:${pict_position_top}pt;width:${pict_width}pt;height:${pict_height}pt;z-index:1;visibility:visible;mso-wrap-style:square;mso-width-percent:0;mso-height-percent:0;mso-wrap-distance-left:9pt;mso-wrap-distance-top:0;mso-wrap-distance-right:9pt;mso-wrap-distance-bottom:0;mso-position-horizontal:absolute;mso-position-horizontal-relative:text;mso-position-vertical:absolute;mso-position-vertical-relative:text;mso-width-percent:0;mso-height-percent:0;mso-width-relative:margin;mso-height-relative:margin\"> "
			+ " 		<v:imagedata src=\"wordml://0300000${pict_index}.png\" o:title=\"\" /> "
			+ " 	</v:shape> " + " </w:pict> ";

}

2. 在具体需要导出的功能的查询单条记录的方法中加入代码

	// 导出word
		if (WordUtils.WORD_EXP_TAG_VALUE.equals(request
				.getParameter(WordUtils.WORD_EXP_TAG))) {
			WordUtils.exp(request, response, dto);
			return null;
		}

3. 导出页面
<!-- 导出WORD -->
<div><form id="WordForm" name="WordForm" method="post" action="query.do"> <!-- 查询路径 -->
	<input type="hidden" name="<%=WordUtils.WORD_EXP_TAG %>" value="<%=WordUtils.WORD_EXP_TAG_VALUE %>"/><!-- 用于判断是否为导出功能,无需修改 -->
	<input type="hidden" name="<%=WordUtils.WORD_TEMPLATE_NAME %>" value="start.xml"/> <!-- 模板名称:模板放在page/project/template_word下 -->
	<input type="hidden" name="<%=WordUtils.WORD_FILE_NAME %>" value="开工令"/> <!-- 导出的WORD名称(注:系统会自动为名称后加上当前日期) -->
	<input type="hidden" name="id" id="id"/>
	<input type="hidden" name="handleType" id="handleType" value="<%=IEnginerringStartConstant.HANDLE_BROWSE%>"/>
</form></div>

4. 导出js

	// 导出
	EnginerringStartHandle.exp = function(){
		var id = $("#modifyId").val();
		if(!id){
			$.messager.alert('提示',"请先保存数据",'info');
			return;
		}
		$("#id").val(id);
		$.messager.progress({
	        msg:'正在处理,请等待...'
	    });
		$("#WordForm").submit();
		setTimeout("$.messager.progress('close')",6000);
	};


版权声明:本文为博主原创文章,未经博主允许不得转载。

Word模板导出

一、步骤: 1.在Word中建立书签; 2.编写C#代码:  (1) 数据准备 [html] view plain copy /// summary>          //...

Delphi7高级应用开发随书源码

  • 2003年04月30日 00:00
  • 676KB
  • 下载

FreeMaker+Xml导出word(含图片)

最近在做一个简报导出的功能,要求导出word格式,上网找了很多资料,ka

WordXML格式初步分析

前言 Office2003以上,Word可以以XML文本格式存储,这样就可以使用外部程序创建Word文件,而不需要使用Word的对象。也能够自由的打开分析Word文件,或者发布到自己的Web页面,或...

通过一个word模板来生成新的word并且填充内容

关于用Java编写生成word文档,动态添加数据到word文档的一些心得,经过翻阅了无数的有用的和无用的资料以后,总算找到了一种靠谱的方法 1.概述 经过反反复复的查阅资料,总算找到了一个靠谱的生...

根据模板生成word文档下载

需求:根据数据库已有字段,填入写好的word并下载 工具 :freemark   一种方便生成word的引擎,内置好大量基础方法 思路: 一.将数据库数据按需求(根据id,根据name......)提...

使用 poi 根据 word 模板生成 word 文件

本例子是一个 maven 项目,要引入 poi 的依赖片段如下: org.apache.poi poi 3.13 ...

xml方式导出word优缺点:

xml方式导出word优缺点: 优点:          1、代码量少,样式、内容容易控制,打印不变形,符合office标准;          2、支持Linux平台,不要求安装o...

XML导出word

XML导出word类 新建一个word文档,如图 在相应单元格中插入书签 将word文档另存为xml文档 后台代码: ExportWordML expwordml = ne...

在java 用xml模板通过freemarker生成word文档

先贴一段代码,这是根据网上的代码稍作修改后可以直接运行 需要下载freemarker.jar maven的项目直接引用 org.freemarker freemarker 2.3.23 ...
  • jr_soft
  • jr_soft
  • 2016年07月20日 14:54
  • 1242
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:通过xml方式根据word模板导出word
举报原因:
原因补充:

(最多只允许输入30个字)