Java HTML导出PDF (二)

时间:2021-05-01 06:41:50

转自:http://huangronaldo.iteye.com/blog/1555917

对于java中如何从html中直接导出pdf,有很多的开源代码,这里个人用itext转。

首先需要的包有:core-renderer-1.0.jar

core-renderer-R8pre1.jar

core-renderer.jar

iText-2.0.8.jar

jtidy-4aug2000r7-dev.jar

Tidy.jar

iTextAsian.jar

java代码的话就比较简单了。具体是先用Tidy将html转换为xhtml,将xhtml转换为其它各种格式的。虽然在转化到pdf时也是用的iText。代码如下:

Java代码   Java HTML导出PDF (二)
  1. //struts1.x中  
Java代码   Java HTML导出PDF (二)
  1. else if("Html2Pdf".equalsIgnoreCase(action)){  
  2.     exportPdfFile("http://localhost:8080/jsp/test.jsp");  
  3.     return null;  
  4. }  
  5.   
  6. // 导出pdf add by huangt 2012.6.1  
  7.     public File exportPdfFile(String urlStr) throws BaseException {  
  8.         // String outputFile = this.fileRoot + "/" +  
  9.         // ServiceConstants.DIR_PUBINFO_EXPORT + "/" + getFileName() + ".pdf";  
  10.         String outputFile = "d:/test3.pdf";  
  11.         OutputStream os;  
  12.         try {  
  13.             os = new FileOutputStream(outputFile);  
  14.   
  15.             ITextRenderer renderer = new ITextRenderer();  
  16.   
  17.             String str = getHtmlFile(urlStr);  
  18.             renderer.setDocumentFromString(str);  
  19.             ITextFontResolver fontResolver = renderer.getFontResolver();  
  20.               
  21.             fontResolver.addFont("C:/WINDOWS/Fonts/SimSun.ttc",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);// 宋体字  
  22.             fontResolver.addFont("C:/WINDOWS/Fonts/Arial.ttf",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);// 宋体字  
  23.             renderer.layout();  
  24.   
  25.             renderer.createPDF(os);  
  26.   
  27.             System.out.println("转换成功!");  
  28.             os.flush();  
  29.             os.close();  
  30.             return new File(outputFile);  
  31.         } catch (FileNotFoundException e) {  
  32.             // logger.error("不存在文件!" + e.getMessage());  
  33.             throw new BaseException(e);  
  34.         } catch (DocumentException e) {  
  35.             // logger.error("生成pdf时出错了!" + e.getMessage());  
  36.             throw new BaseException(e);  
  37.         } catch (IOException e) {  
  38.             // logger.error("pdf出错了!" + e.getMessage());  
  39.             throw new BaseException(e);  
  40.         }  
  41.   
  42.     }  
  43.   
  44.     // 读取页面内容 add by huangt 2012.6.1  
  45.     public String getHtmlFile(String urlStr) throws BaseException {  
  46.         URL url;  
  47.         try {  
  48.             if (urlStr.indexOf("?") != -1) {  
  49.                 urlStr = urlStr + "&locale="  
  50.                         + LocaleContextHolder.getLocale().toString();  
  51.             } else {  
  52.                 urlStr = urlStr + "?locale="  
  53.                         + LocaleContextHolder.getLocale().toString();  
  54.             }  
  55.             url = new URL(urlStr);  
  56.   
  57.             URLConnection uc = url.openConnection();  
  58.             InputStream is = uc.getInputStream();  
  59.               
  60.             Tidy tidy = new Tidy();  
  61.   
  62.             OutputStream os2 = new ByteArrayOutputStream();  
  63.             tidy.setXHTML(true); // 设定输出为xhtml(还可以输出为xml)  
  64.             tidy.setCharEncoding(Configuration.UTF8); // 设定编码以正常转换中文  
  65.             tidy.setTidyMark(false); // 不设置它会在输出的文件中给加条meta信息  
  66.             tidy.setXmlPi(true); // 让它加上<?xml version="1.0"?>  
  67.             tidy.setIndentContent(true); // 缩进,可以省略,只是让格式看起来漂亮一些  
  68.             tidy.parse(is, os2);  
  69.   
  70.             is.close();  
  71.   
  72.             // 解决乱码 --将转换后的输出流重新读取改变编码  
  73.             String temp;  
  74.             StringBuffer sb = new StringBuffer();  
  75.             BufferedReader in = new BufferedReader(new InputStreamReader(  
  76.                     new ByteArrayInputStream(  
  77.                             ((ByteArrayOutputStream) os2).toByteArray()),  
  78.                     "utf-8"));  
  79.             while ((temp = in.readLine()) != null) {  
  80.                 sb.append(temp);  
  81.             }  
  82.   
  83.             return sb.toString();  
  84.         } catch (IOException e) {  
  85.             // logger.error("读取客户端网页文本信息时出错了" + e.getMessage());  
  86.             throw new BaseException(e);  
  87.         }  
  88.   
  89.     }  

 

为了解决包的问题,加上Maven <!-- pdf导出 -->

Xml代码   Java HTML导出PDF (二)
  1. <dependency>  
  2.     <groupId>com.lowagie</groupId>  
  3.     <artifactId>itext</artifactId>  
  4.     <version>2.1.7</version>  
  5. </dependency>  
  6. <dependency>  
  7.     <groupId>org.xhtmlrenderer.flyingsaucer</groupId>  
  8.     <artifactId>pdf-renderer</artifactId>  
  9.     <version>1.0</version>  
  10. </dependency>  
  11. <dependency>  
  12.     <groupId>jtidy</groupId>  
  13.     <artifactId>jtidy</artifactId>  
  14.     <version>4aug2000r7-dev</version>  
  15.     <type>jar</type>  
  16.     <scope>compile</scope>  
  17. </dependency>  
  18. <dependency>  
  19.     <groupId>net.sf.barcode4j</groupId>  
  20.     <artifactId>barcode4j-light</artifactId>  
  21.     <version>2.0</version>  
  22. </dependency>  
  23. <dependency>  
  24.     <groupId>avalon-framework</groupId>  
  25.     <artifactId>avalon-framework-impl</artifactId>  
  26.     <version>4.2.0</version>  
  27. </dependency>  
  28. <!-- pdf -->  
 

另外附上 稍微复杂的PDFUtils.java文件,由于没时间就不做整理解释了!

package com.iris.egrant.utils.pdf;

import java.awt.Color;
import java.awt.Font;
import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang.ObjectUtils;
import org.krysalis.barcode4j.impl.code128.Code128Bean;
import org.krysalis.barcode4j.output.bitmap.BitmapCanvasProvider;
import org.krysalis.barcode4j.tools.UnitConv;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;
import org.w3c.tidy.Configuration;
import org.w3c.tidy.Tidy;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;

import com.iris.egrant.exception.ServiceException;
import com.iris.egrant.file.utils.FileUtils;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.FontFactory;
import com.lowagie.text.Image;
import com.lowagie.text.PageSize;
import com.lowagie.text.Paragraph;
import com.lowagie.text.Phrase;
import com.lowagie.text.Rectangle;
import com.lowagie.text.pdf.BaseFont;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PRTokeniser;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfImportedPage;
import com.lowagie.text.pdf.PdfReader;
import com.lowagie.text.pdf.PdfStamper;
import com.lowagie.text.pdf.PdfWriter;

@Component
public class PDFUtil {

	@Value("${fontDir}")
	private String fontFileRootDir; // 字体文件路径
	private final String SIMSUN = "SimSun.ttc"; // 字体-宋体
	private final String SIMHEI = "SimHei.ttf"; // 字体-黑体
	private final String ARIAL = "Arial.ttf"; // 字体-Arial
	private final String ARIAL_B = "ArialBd.ttf"; // 字体-Arial 粗体
	private final String TIMES = "Times.ttf"; // 字体-Arial
	private final String TIMES_B = "TimesBd.ttf"; // 字体-Arial 粗体
	private final String ARIAL_I = "ArialI.ttf"; // 字体-Arial
	private final String SONGT = "SongT.ttf"; // 字体-Arial
	private final String JDHEI = "JDHei.ttf"; // 字体-经典黑体加粗
	private final String MSHEI = "MSHei.ttf"; // 字体-Arial

	private static final String UTF8 = "UTF-8"; // 编码-UTF-8

	// private static final String BARCODE_PATH = "rpt_barcode"; // 用于查找条形码的路径和文件
	private static final String PDF_SUFFIX_NAME = "pdf"; // PDF后缀名(文件类型)
	private static final String PIC_SUFFIX_NAME = "jpg"; // PDF后缀名(文件类型)
	@Value("${pdfDir}")
	private String pdfFileRootDir;// 生成PDF文件的路径

	private static final Color WATERMARK_FONT_COLOR = Color.LIGHT_GRAY; // 水印字体默认颜色
	private static final int WATERMARK_FONT_SIZE = 60; // 水印默认字体大小
	private static final int ROTATION = 45; // 水印旋转角度
	private static final String PAGETYPE = "pageType"; // 页码类型
	private static final String HEADERLEFT = "headerLeft"; // 页眉位置:左 一般为图片
	private static final String HEADERCENTER = "headerCenter"; // 页眉位置:中
	private static final String HEADERRIGHT = "headerRight"; // 页眉位置:右
	private static final String FOOTERLEFT = "footerLeft"; // 页脚位置:中
	private static final String FOOTERCENTER = "footerCenter";// 页脚位置:中
	private static final String FOOTERRIGHT = "footerRight";// 页脚位置:右
	private static final int HEADER_Y = 35;
	private static final int HEADER_LINE_Y = 40;
	private static final int HEADER_LINE_X = 60;

	/**
	 * 生成申报书条形码.
	 * 
	 * @time:2012.6.13
	 * @author huangt
	 * @param code
	 */
	public String createBarCode(String code) throws Exception {

		try {
			// Create the barcode bean
			Code128Bean bean = new Code128Bean();
			final int dpi = 100;
			// Configure the barcode generator
			bean.setModuleWidth(UnitConv.in2mm(1.0f / dpi)); // makes the narrow
			bean.doQuietZone(false);
			// Open output file
			File filePath = new File(pdfFileRootDir);
			// 判断文件夹是否存在,如果不存在则创建文件夹
			if (!filePath.exists()) {
				filePath.mkdirs();
			}
			String fileName = getTempName(pdfFileRootDir, PIC_SUFFIX_NAME);
			File outputFile = new File(fileName);
			OutputStream out = new FileOutputStream(outputFile);
			try {
				// Set up the canvas provider for monochrome JPEG output
				BitmapCanvasProvider canvas = new BitmapCanvasProvider(out, "image/jpeg", dpi,
						BufferedImage.TYPE_BYTE_BINARY, false, 0);
				// Generate the barcode
				bean.generateBarcode(canvas, code);
				// Signal end of generation
				canvas.finish();
			} finally {
				out.close();
			}
			return fileName;

		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * 在pdf文件中添加水印.
	 * 
	 * @author huangt
	 * @time 2012.7.13
	 * @param outputFile
	 *            水印输出文件
	 * @param waterMarkName
	 *            水印名字
	 * @param rotation
	 *            旋转角度
	 */

	public void waterMark(String outputFile, String waterMarkName, int fontSize) throws Exception {
		waterMark(outputFile, waterMarkName, ROTATION, WATERMARK_FONT_COLOR, fontSize, true); // 默认角度为45,默认颜色为浅灰色
	}

	public void waterMark(String outputFile, String waterMarkName, int fontSize, boolean isNoFirst) throws Exception {
		waterMark(outputFile, waterMarkName, ROTATION, WATERMARK_FONT_COLOR, fontSize, isNoFirst); // 默认角度为45,默认颜色为浅灰色
	}

	public void waterMark(String outputFile, String waterMarkName) throws Exception {
		waterMark(outputFile, waterMarkName, true); // 默认角度为45,默认颜色为浅灰色
	}

	public void waterMark(String outputFile, String waterMarkName, Color color) throws Exception {
		waterMark(outputFile, waterMarkName, ROTATION, color, WATERMARK_FONT_SIZE, true); // 默认角度为45
	}

	public void waterMark(String outputFile, String waterMarkName, float rotation) throws Exception {
		waterMark(outputFile, waterMarkName, rotation, WATERMARK_FONT_COLOR, WATERMARK_FONT_SIZE, true); // 默认颜色为浅灰色
	}

	public void waterMark(String outputFile, String waterMarkName, boolean isNoFirst) throws Exception {
		waterMark(outputFile, waterMarkName, ROTATION, WATERMARK_FONT_COLOR, WATERMARK_FONT_SIZE, isNoFirst); // 默认角度为45,默认颜色为浅灰色
	}

	public void waterMark(String outputFile, String waterMarkName, float rotation, Color color, int fontSize,
			boolean isNoFirst) throws Exception {

		int total = 0;
		String tempPdf = getTempName(pdfFileRootDir, PDF_SUFFIX_NAME);
		FileUtils.copyFile(outputFile, tempPdf); // 复制一个临时文件
		PdfReader reader = new PdfReader(tempPdf);
		PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(outputFile));
		total = reader.getNumberOfPages() + 1;
		PdfContentByte under;
		com.lowagie.text.Font font = FontFactory.getFont(buildAbsoluteFilePath("FONT") + ARIAL, BaseFont.IDENTITY_H,
				BaseFont.NOT_EMBEDDED, WATERMARK_FONT_SIZE, Font.PLAIN, color);
		for (int i = 1; i < total; i++) {
			if (isNoFirst && i == 1) {
				continue;
			}
			Rectangle pageSize = reader.getPageSize(i);
			under = stamper.getUnderContent(i);
			under.beginText();
			// 添加水印
			ColumnText.showTextAligned(under, Element.ALIGN_CENTER, new Phrase(waterMarkName, font),
					pageSize.getWidth() / 2, pageSize.getHeight() / 2, rotation);
			under.endText();
		}

		stamper.close();
		// 删除临时文件
		deleteFile(tempPdf);// 删除临时文件
	}

	/**
	 * 
	 * 拼接PDF (可根据所在的页码插入).
	 * 
	 * @author huangt
	 * @time:2012.6.15
	 * 
	 * */
	@SuppressWarnings("unused")
	private String mosaicPdf(String subfile, String outputFile, Integer index) throws Exception {

		String outputFileCopy = getTempName(pdfFileRootDir, PDF_SUFFIX_NAME);
		FileUtils.copyFile(outputFile, outputFileCopy); // 复制一个临时文件
		String tempFile = getTempName(pdfFileRootDir, PDF_SUFFIX_NAME);
		Document document = new Document();
		// 建立一个书写器(Writer)与document对象关联,通过书写器(Writer)可以将文档写入到磁盘中。
		PdfWriter.getInstance(document, new FileOutputStream(tempFile));
		document.open();
		Paragraph chunk = new Paragraph(" ");
		document.add(chunk);
		document.close();
		PdfReader reader = new PdfReader(outputFileCopy);
		PdfReader reader2 = new PdfReader(subfile);
		PdfReader reader3 = new PdfReader(tempFile);

		PdfStamper stamper = new PdfStamper(reader3, new FileOutputStream(outputFile));
		try {
			int total = reader.getNumberOfPages();
			int total2 = reader2.getNumberOfPages();

			PdfContentByte under;

			// 从现有的别的pdf合并过来
			for (int i = 1; i < total + total2; i++) {
				stamper.insertPage(i, PageSize.A4);
				under = stamper.getUnderContent(i);
				if (i > index && i < index + total2) { // 根据index页码在PDF中插入需要插入的PDF
					under.addTemplate(stamper.getImportedPage(reader2, i - index), 1, 0, 0, 1, 0, 0);
				} else {
					if (i >= index + total2) {
						under.addTemplate(stamper.getImportedPage(reader, i - total2), 1, 0, 0, 1, 0, 0);
					} else {
						under.addTemplate(stamper.getImportedPage(reader, i), 1, 0, 0, 1, 0, 0);
					}
				}
			}

		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			stamper.close();
			deleteFile(tempFile); // 删除临时文件
			deleteFile(outputFileCopy);
		}
		return null;
	}

	/**
	 * 
	 * 合并PDF.
	 * 
	 * @author huangt
	 * @time:2012.6.15
	 * @param list
	 *            需要合并的PDF路径
	 * @param fileName
	 *            合并生成的PDF文件名
	 * */
	public String mosaicPdf(List<String> list, String fileName) throws Exception {

		if (list != null && list.size() > 0) {
			String savePath = getFileName(pdfFileRootDir, fileName, PDF_SUFFIX_NAME);
			Document document = new Document(new PdfReader(list.get(0)).getPageSize(1));
			PdfCopy copy = new PdfCopy(document, new FileOutputStream(savePath));
			document.open();
			for (int i = 0; i < list.size(); i++) {
				PdfReader reader = new PdfReader(list.get(i));
				int n = reader.getNumberOfPages();
				for (int j = 1; j <= n; j++) {
					document.newPage();
					PdfImportedPage page = copy.getImportedPage(reader, j);
					copy.addPage(page);
				}
			}
			document.close();
			/*
			 * String savePath = getFileName(pdfFileRootDir, fileName, PDF_SUFFIX_NAME); PdfReader reader = new
			 * PdfReader(list.get(0)); PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(savePath)); int
			 * total = reader.getNumberOfPages(); PdfContentByte under; int count = 0; for (String str : list) {
			 * PdfReader reader2 = new PdfReader(str); int total2 = reader2.getNumberOfPages() + 1; count = count +
			 * total2; for (int i = 1; i < total2; i++) { stamper.insertPage(count + i, PageSize.A4); under =
			 * stamper.getUnderContent(count + i); under.addTemplate(stamper.getImportedPage(reader2, i), 1, 0, 0, 1, 0,
			 * 0); } } stamper.close();
			 */
			for (String str : list) {
				if (str.indexOf("pdf/") != -1) {
					deleteFile(str);
				}
			}
			return savePath;

		} else {
			return null;
		}

	}

	/**
	 * 
	 * 设置页眉和页脚.
	 * 
	 * @author huangt
	 * @throws IOException
	 * @param pdfFile
	 *            需要设置页眉页码的pdf文件
	 * @param header
	 *            页眉内容
	 * @param isHomePage
	 *            是否首页显示页码
	 * @time:2012.6.15
	 * 
	 * */
	public void setPDFHeader(String pdfFile, Map<String, Object> header) throws IOException {
		setPDFHeader(pdfFile, header, 0, true, false); // 默认首页不显示页码
	}

	public void setPDFHeader(String pdfFile, Map<String, Object> header, boolean isNoHomePage, boolean isNoLastPape)
			throws IOException {
		setPDFHeader(pdfFile, header, 0, isNoHomePage, isNoLastPape); // 默认首页不显示页码
	}

	/**
	 * 设置页眉和页脚.
	 * 
	 * @param pdfFile
	 *            需要设置页眉页码的pdf文件
	 * @param header
	 *            页眉页脚内容
	 * @param isNoHomePage
	 *            首页是否不显示页码
	 * @param isNoLastPape
	 *            尾页是否不显示页码
	 * @throws IOException
	 */
	public void setPDFHeader(String pdfFile, Map<String, Object> header, Integer fundPages, boolean isNoHomePage,
			boolean isNoLastPape) throws IOException {
		int total = 0;
		String tempPdf = getTempName(pdfFileRootDir, PDF_SUFFIX_NAME);
		try {
			FileUtils.copyFile(pdfFile, tempPdf); // 复制一个临时文件
			PdfReader reader = new PdfReader(tempPdf);
			PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(pdfFile));
			total = reader.getNumberOfPages();
			PdfContentByte under;
			BaseFont bf = BaseFont.createFont(buildAbsoluteFilePath("FONT") + SIMHEI, BaseFont.IDENTITY_H,
					BaseFont.NOT_EMBEDDED);
			BaseFont bfArial = BaseFont.createFont(buildAbsoluteFilePath("FONT") + SONGT, BaseFont.IDENTITY_H,
					BaseFont.NOT_EMBEDDED);
			int totalNum = total; // 总页码数
			if (fundPages != null) {
				totalNum = totalNum - fundPages;
			} else {
				fundPages = 0;
			}
			if (isNoLastPape) { // 末页是否要页码,true 为不需要页码,则总页码减1
				totalNum = totalNum - 1;
			}
			if (isNoHomePage) { // 首页是否要页码,true 为不需要页码,则总页码减1
				totalNum = totalNum - 1;
			}
			String pageType = ObjectUtils.toString(header.get(PAGETYPE));
			if (pageType == null || "".equals(pageType)) {
				pageType = " 第 @current@ 页  共 @total@ 页 ";
			}
			for (int i = 1; i <= total; i++) {
				// 增加内容
				Rectangle pageSize = reader.getPageSize(i);
				under = stamper.getUnderContent(i);
				under.beginText();
				if (i == 1) { // 设置版本号
					if (header.containsKey("version")) {
						under.setFontAndSize(bfArial, 10);
						under.showTextAlignedKerned(Element.ALIGN_CENTER, ObjectUtils.toString(header.get("version")),
								pageSize.getWidth() - HEADER_LINE_X - HEADER_LINE_X, HEADER_Y, 0);
					}
				}
				under.setFontAndSize(bfArial, 9);
				if (isNoHomePage) { // 判断首页是否要页码
					if (i > 1) { //
						if ((i - 1) <= totalNum) {
							under.showTextAlignedKerned(Element.ALIGN_CENTER,
									pageType.replace("@current@", (i - 1) + "").replace("@total@", totalNum + ""),
									pageSize.getWidth() / 2, HEADER_Y, 0);
						} else if (!isNoLastPape) {
							under.showTextAlignedKerned(
									Element.ALIGN_CENTER,
									pageType.replace("@current@", (i - 1 - totalNum) + "").replace("@total@",
											fundPages + ""), pageSize.getWidth() / 2, HEADER_Y, 0);
						}
					}

				} else {
					if (i <= totalNum) {
						under.showTextAlignedKerned(Element.ALIGN_CENTER, pageType.replace("@current@", i + "")
								.replace("@total@", totalNum + ""), pageSize.getWidth() / 2, HEADER_Y, 0);
					} else if (!isNoHomePage) {
						under.showTextAlignedKerned(Element.ALIGN_CENTER,
								pageType.replace("@current@", (i - totalNum) + "").replace("@total@", fundPages + ""),
								pageSize.getWidth() / 2, HEADER_Y, 0);
					}
				}
				// 设置页眉(由于本人不知道itext能不能支持对已存在pdf修改,只能暂时用这种方法 :huangt注)
				if (i > 1 && i < total) {
					under.setFontAndSize(bf, 10);
					setHeaderByMap(under, pageSize, header, true, true);
					under.saveState();
					under.setLineWidth(0.5f);
					under.moveTo(50, pageSize.getHeight() - HEADER_LINE_Y);
					under.lineTo(pageSize.getWidth() - 50, pageSize.getHeight() - HEADER_LINE_Y);
					under.stroke();
					under.restoreState();
				} else {
					under.setFontAndSize(bf, 10);
					if (i == total) {
						if (isNoLastPape) { // 如果最后一页没有页面的话
							setHeaderByMap(under, pageSize, header, false, true);
						} else {
							setHeaderByMap(under, pageSize, header, true, true);
						}
						under.saveState();
						under.setLineWidth(0.5f);
						under.moveTo(HEADER_LINE_X, pageSize.getHeight() - HEADER_LINE_Y);
						under.lineTo(pageSize.getWidth() - HEADER_LINE_X, pageSize.getHeight() - HEADER_LINE_Y);

					} else if (i == 1) {
						setHeaderByMap(under, pageSize, header, false, false);
						under.saveState();
					}
					under.stroke();
					under.restoreState();
				}
				under.endText();
			}
			stamper.close();

		} catch (Exception e) {
			e.printStackTrace();
		}
		// 删除临时文件
		deleteFile(tempPdf);
	}

	/**
	 * 根据页眉页脚入参(位置,类型:用以@开头)设置页眉页脚.
	 * 
	 * @throws IOException
	 * @throws MalformedURLException
	 * @throws DocumentException
	 * 
	 * */
	public void setHeaderByMap(PdfContentByte under, Rectangle pageSize, Map<String, Object> header, boolean isFoot,
			boolean isHeard) throws Exception {
		if (isHeard) {
			String headerLeft = ObjectUtils.toString(header.get(HEADERLEFT));
			String headerCenter = ObjectUtils.toString(header.get(HEADERCENTER));
			String headerRight = ObjectUtils.toString(header.get(HEADERRIGHT));

			// 页眉左边
			if (isPath4Header(headerLeft)) {
				setHeaderByImage(under, pageSize, HEADER_LINE_X, pageSize.getHeight() - HEADER_Y,
						getImagePath(headerLeft));
			} else {
				under.showTextAlignedKerned(Element.ALIGN_LEFT, headerLeft, HEADER_LINE_X, pageSize.getHeight()
						- HEADER_Y, 0);
			}
			// 页眉中间
			if (isPath4Header(headerCenter)) {
				setHeaderByImage(under, pageSize, pageSize.getWidth() / 2, pageSize.getHeight() - HEADER_Y,
						getImagePath(headerCenter));
			} else {
				under.showTextAlignedKerned(Element.ALIGN_CENTER, headerCenter, pageSize.getWidth() / 2,
						pageSize.getHeight() - HEADER_Y, 0);
			}
			// 页眉右边
			if (isPath4Header(headerRight)) {
				setHeaderByImage(under, pageSize, pageSize.getWidth() - HEADER_LINE_X, pageSize.getHeight() - HEADER_Y,
						getImagePath(headerRight), true);
			} else {
				under.showTextAlignedKerned(Element.ALIGN_RIGHT, headerRight, pageSize.getWidth() - HEADER_LINE_X,
						pageSize.getHeight() - HEADER_Y, 0);
			}

		}
		if (isFoot) {
			String footerLeft = ObjectUtils.toString(header.get(FOOTERLEFT));
			String footerCenter = ObjectUtils.toString(header.get(FOOTERCENTER));
			String footerRight = ObjectUtils.toString(header.get(FOOTERRIGHT));

			// 页脚左边
			if (isPath4Header(footerLeft)) {
				setHeaderByImage(under, pageSize, HEADER_LINE_X, HEADER_Y, getImagePath(footerLeft));
			} else {
				under.showTextAlignedKerned(Element.ALIGN_LEFT, footerLeft, HEADER_LINE_X, HEADER_Y, 0);
			}
			// 页脚中间
			if (isPath4Header(footerCenter)) {
				setHeaderByImage(under, pageSize, pageSize.getWidth() / 2, HEADER_Y, getImagePath(footerCenter));
			} else {
				under.showTextAlignedKerned(Element.ALIGN_CENTER, footerCenter, pageSize.getWidth() / 2, HEADER_Y, 0);
			}
			// 页脚右边
			if (isPath4Header(footerRight)) {
				setHeaderByImage(under, pageSize, pageSize.getWidth() - HEADER_LINE_X, HEADER_Y,
						getImagePath(footerRight), true);
			} else {
				under.showTextAlignedKerned(Element.ALIGN_RIGHT, footerRight, pageSize.getWidth() - HEADER_LINE_X,
						HEADER_Y, 0);
			}
		}

	}

	public void setHeaderByImage(PdfContentByte under, Rectangle pageSize, float x, float y, String imagePath)
			throws Exception {
		if (imagePath != null && !"".equals(imagePath)) {
			Image image = Image.getInstance(imagePath);
			image.setAbsolutePosition(x, y);
			under.addImage(image);
		}
	}

	public void setHeaderByImage(PdfContentByte under, Rectangle pageSize, float x, float y, String imagePath,
			boolean isRight) throws Exception { // 右边的图片需要减去图片的宽度
		if (imagePath != null && !"".equals(imagePath)) {
			Image image = Image.getInstance(imagePath);
			if (isRight) {
				image.setAbsolutePosition(x - image.getWidth(), y);
			} else {
				image.setAbsolutePosition(x, y);
			}
			under.addImage(image);
		}
	}

	/**
	 * 页眉页脚插入图时,判断是否是图片路径,并返回图片的路径(因为传过来的值是以@开头的为路径).
	 * 
	 * */
	public boolean isPath4Header(String headerStr) {
		if (headerStr.startsWith("@")) {

			return true;
		}
		return false;
	}

	public String getImagePath(String headerStr) {
		return headerStr.substring(1);
	}

	/**
	 * 生成PDF.
	 * 
	 * @param urlStr
	 *            要生成PDF的页面URL
	 * @param map
	 *            页面需要用到的参数
	 * @return
	 * @throws Exception
	 */
	public String exportPdfFile(String urlStr, Map<String, Object> map) throws Exception {

		String outputFile = getTempName(pdfFileRootDir, PDF_SUFFIX_NAME);
		File filePath = new File(pdfFileRootDir);

		// urlStr = URLDecoder.decode(urlStr, "UTF-8");
		if (!filePath.exists()) {
			filePath.mkdirs();
		}
		OutputStream os;
		try {

			os = new FileOutputStream(outputFile);

			ITextRenderer renderer = new ITextRenderer();
			String str = getHtmlFile(urlStr, map);
			// renderer.setDocument(new File(str));
			renderer.setDocumentFromString(str);
			ITextFontResolver fontResolver = renderer.getFontResolver();
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + SIMSUN, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // 字体包
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + SIMHEI, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // 黑体
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + ARIAL, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // Arail
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + ARIAL_B, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // Arail
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + ARIAL_I, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // Arail
			// Times New Roman
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + TIMES, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
			// Times New Roman
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + TIMES_B, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + JDHEI, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
			fontResolver.addFont(buildAbsoluteFilePath("FONT") + MSHEI, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

			renderer.layout();
			renderer.createPDF(os);
			os.flush();
			os.close();

			// 返回生成PDF文件的路径和名字 ,以保存数据库
			return outputFile;
		} catch (FileNotFoundException e) {
			// logger.error("不存在文件!" + e.getMessage());
			throw new ServiceException(e);
		} catch (DocumentException e) {
			// logger.error("生成pdf时出错了!" + e.getMessage());
			throw new ServiceException(e);
		} catch (IOException e) {
			// logger.error("pdf出错了!" + e.getMessage());
			throw new ServiceException(e);
		}

	}

	// 读取页面内容 add by huangt 2012.6.1
	public static String getHtmlFile(String urlStr, Map<String, Object> map) throws ServiceException {
		URL url;
		try {
			if (urlStr.indexOf("?") != -1) {
				urlStr = urlStr + "&locale=" + LocaleContextHolder.getLocale().toString();
			} else {
				urlStr = urlStr + "?locale=" + LocaleContextHolder.getLocale().toString();
			}
			url = new URL(urlStr);

			// URLConnection uc = url.openConnection();
			// uc.addRequestProperty("xmlData", xmlData);
			HttpURLConnection urlConn = (HttpURLConnection) url.openConnection();
			// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在http正文内,因此需要设为true,
			// 默认情况下是false;
			urlConn.setDoOutput(true);
			// 设置是否从httpUrlConnection读入,默认情况下是true;
			urlConn.setDoInput(true);
			// Post 请求不能使用缓存
			urlConn.setUseCaches(false);
			// 设定传送的内容类型是可序列化的java对象
			// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
			// 设定请求的方法为"POST",默认是GET
			urlConn.setRequestMethod("POST");

			// 连接,上面对urlConn的所有配置必须要在connect之前完成,
			urlConn.connect();
			// 此处getOutputStream会隐含的进行connect (即:如同调用上面的connect()方法,
			// 所以在开发中不调用上述的connect()也可以)。

			OutputStream os = urlConn.getOutputStream();
			String param = new String();
			String xmlData = URLEncoder.encode(map.get("xmlData").toString(), "UTF-8");
			if (map.containsKey("barCodePath")) {
				param = "xmlData=" + xmlData + "&jspUrl=" + map.get("jspUrl").toString() + "&barCodePath="
						+ map.get("barCodePath"); // 传参
			} else {
				param = "xmlData=" + xmlData + "&jspUrl=" + map.get("jspUrl").toString(); // 传参
			}
			os.write(param.getBytes());
			InputStream is = urlConn.getInputStream();

			Tidy tidy = new Tidy();

			OutputStream os2 = new ByteArrayOutputStream();
			tidy.setXHTML(true); // 设定输出为xhtml(还可以输出为xml)
			tidy.setCharEncoding(Configuration.UTF8); // 设定编码以正常转换中文
			tidy.setTidyMark(false); // 不设置它会在输出的文件中给加条meta信息
			tidy.setXmlPi(true); // 让它加上<?xml version="1.0"?>
			tidy.setIndentContent(true); // 缩进,可以省略,只是让格式看起来漂亮一些
			tidy.parse(is, os2);

			is.close();

			// 解决乱码 --将转换后的输出流重新读取改变编码
			String temp;
			StringBuffer sb = new StringBuffer();
			BufferedReader in = new BufferedReader(new InputStreamReader(new ByteArrayInputStream(
					((ByteArrayOutputStream) os2).toByteArray()), UTF8));
			while ((temp = in.readLine()) != null) {
				sb.append(temp);
			}

			return sb.toString();
		} catch (IOException e) {
			// logger.error("读取客户端网页文本信息时出错了" + e.getMessage());
			throw new ServiceException(e);
		}

	}

	/**
	 * 
	 * 根据特殊字符查找所在页码.
	 * 
	 * @author huangt
	 * @throws IOException
	 * @time:2012.7.6
	 * 
	 * */
	public static int findStringForPageNum(String fileName, String pageString) throws Exception {
		// String PAGESTRING = "#$%@*";
		PdfReader reader = new PdfReader(fileName);
		int pageNum = 0;
		int total = reader.getNumberOfPages();
		String pageStringUnicode = toUnicode(pageString);
		for (int i = 1; i < total; i++) {
			byte[] streamBytes = reader.getPageContent(i);
			PRTokeniser tokenizer = new PRTokeniser(streamBytes);
			StringBuffer sb = new StringBuffer();
			while (tokenizer.nextToken()) {
				if (tokenizer.getTokenType() == PRTokeniser.TK_STRING) {
					String temp;
					System.out.println(tokenizer.getStringValue());
					byte[] b = tokenizer.getStringValue().getBytes("ISO-8859-1");
					for (int j = 0; j < b.length; j++) {
						temp = Integer.toHexString(0xFF & b[j]);
						if (temp.length() < 2) {
							sb.append(0);
						}
						sb.append(temp);
					}
				}
			}
			if (sb.toString().indexOf(pageStringUnicode) > 0) {
				pageNum = i;
				break;
			}
		}
		return pageNum;
	}

	/**
	 * 删除临时文件 fileName:如果传入文件名,即不生成序列化的临时文件名.
	 * */
	public static void deleteFile(String fileName) {
		File file = new File(fileName);
		file.delete();
	}

	/**
	 * 生成序列化的临时文件名 fileDir:文件路径 type:文件类型,如jpg pdf 等 fileName:如果传入文件名,即不生成序列化的临时文件名.
	 * */
	public static String getTempName(String fileDir, String type) {
		String fileStr = fileDir + UUID.randomUUID().toString() + "." + type;
		return fileStr;
	}

	/**
	 * 生成文件名 fileDir:文件路径 type:文件类型,如jpg pdf 等 fileName:如果传入文件名,即不生成序列化的临时文件名.
	 * */
	public static String getFileName(String fileDir, String fileName, String type) {
		String fileStr = fileDir + fileName + "." + type;
		return fileStr;
	}

	public static void parsePdf(String src) throws IOException {
		PdfReader reader = new PdfReader(src);
		byte[] streamBytes = reader.getPageContent(1);
		PRTokeniser tokenizer = new PRTokeniser(streamBytes);
		while (tokenizer.nextToken()) {
			if (tokenizer.getTokenType() == PRTokeniser.TK_STRING) {
				StringBuffer sb = new StringBuffer();
				String sTemp;
				for (int i = 0; i < tokenizer.getStringValue().getBytes("Unicode").length; i++) {
					sTemp = Integer.toHexString(0xFF & tokenizer.getStringValue().getBytes("Unicode")[i]);
					if (sTemp.length() < 2) {
						sb.append(0);
					}
					sb.append(sTemp);
				}
				System.out.println(sb.toString());
			}
		}
	}

	public static String toUnicode(String s) throws Exception {

		byte[] bytes = s.getBytes("Unicode");
		String str;
		StringBuffer sb = new StringBuffer();
		for (int j = 2; j < bytes.length; j++) {
			str = Integer.toHexString(0xFF & bytes[j]);
			if (str.length() < 2) {
				sb.append(0);
			}
			sb.append(str);
		}
		return sb.toString();
	}

	private String buildAbsoluteFilePath(String type) {
		String apath = "";

		if ("PDF".equalsIgnoreCase(type)) {

			apath = pdfFileRootDir;
		}
		if ("FONT".equalsIgnoreCase(type)) {
			apath = fontFileRootDir;
		}
		// if (!apath.endsWith(File.separator)) {
		// apath += File.separator;
		// }
		return apath;
	}

}