Itex 实现java 后台的pdf导出 Maven spring boot 项目

itex

查看了网上很多pdf 导出的文档,我大约了解了一下跟word 一样的先定义一个模板然后再给模板赋值的操作,但是感觉这种方法比较鸡肋,写起来也很是麻烦,后来就看到了这个pdf 强大的类库 itex

引入pom 文件

我们对Markdown编辑器进行了一些功能拓展与语法支持,除了标准的Markdown编辑器功能,我们增加了如下几点新功能,帮助你用它写博客:

		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itextpdf</artifactId>
			<version>5.5.10</version>
		</dependency>
		<dependency>
			<groupId>com.itextpdf</groupId>
			<artifactId>itext-asian</artifactId>
			<version>5.2.0</version>
		</dependency>

查看文档

https://pan.baidu.com/s/1Fd_I7yDrWB_DnDRJgDwgyQ
提取码 nv5c
这里是一个文档,可以大概看一下有的东西,然后知道都有什么内容,以后不会的可以 从百度另找资料,这个文档也是偶然来的,版本可能跟今天的不太一样,但是核心还是差不多的。

开始使用

看过文档大概都知道这个itex 是一个操作文档类似的,跟Excel 导出很相似,但是又有所不同,他的强大之处就在于能够让你自己随心所欲的定制自己想要出来的页面效果。

		// 创建document    并且指定这是一个a4 大小的纸张   边距为20
		Document document = new Document(PageSize.A4, 20, 20, 20, 20);
		// 创建document 的write 实例,也就是文件
		PdfWriter.getInstance(document, new FileOutputStream("E:\\ckwtext.pdf"));
		// 打开 document
		document.open();
		// 设置标题
		document.addTitle("an fang workSheet Info");
		// 作者
		document.addAuthor(" jicheng ");
		// 创建时间
		document.addCreationDate();
		Chunk chunk = new Chunk("Hello world", FontFactory.getFont(FontFactory.COURIER, 20, Font.ITALIC));
		document.add(MyFont.speedFont("\n"));
		document.add(chunk);
		// 表格
		PdfPTable table = new PdfPTable(3);
		// 第一行是列名
		table.setHeaderRows(1);
		// 宽度填充
		table.getDefaultCell().setHorizontalAlignment(1);

		table.addCell(new PDFParagraph("一点都不好用", 12, Font.BOLD, BaseColor.RED));
		// 设置表哥的浮动宽度, 让文字保持居中
		table.setWidthPercentage(100.0F);
		table.addCell("2");
		table.addCell("你");
		table.addCell("4");
		table.addCell("4");

		PdfPCell cell = new PdfPCell();
		cell.setBorderColorTop(BaseColor.RED);
		cell.setBorderWidthTop(0.5f);
		cell.addElement(MyFont.speedFont("测试单元格"));
		table.addCell(cell);

		document.add(table);
		document.add(MyFont.speedFont("一点都不好用", 12, Font.BOLD, BaseColor.RED));
		document.close();

这个是初步的一个入门的一个测试,这个代码运行以后可以发现会生成一个pdf 并且带有一个表格功能的。
不多说,直接上图。
在这里插入图片描述

封装 自己的help

我根据自己的需求,封装了一些比较常用的方法。我贴出来

package webmaster.webmaster.pdf;

import java.awt.Color;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.itextpdf.text.BaseColor;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPRow;
import com.itextpdf.text.pdf.PdfPTable;
import com.itextpdf.text.pdf.StringUtils;

import io.netty.util.internal.StringUtil;

/**
 * 定义中文可以在pdf 内显示出来
 * 
 * @author Administrator
 *
 */
public class PDFParagraph extends Paragraph {

	private static final long serialVersionUID = 1L;

	/**
	 * 规范的黑色字体
	 * 
	 * @param content
	 */
	public PDFParagraph(String content) {
		super(content, getChineseFont());
	}

	/**
	 * 自己定义 字体的规范
	 * 
	 * @param content
	 * @param fontSize 字体大小
	 * @param style    Font.NORMAL 规范
	 * @param color    BaseColor.RED
	 */
	public PDFParagraph(String content, Integer fontSize, Integer style, BaseColor color) {
		super(content, getChineseFont(fontSize, style, color));
	}

	/**
	 * 自己定义12px 的规范字体并且自己定义颜色
	 * 
	 * @param content
	 * @param color
	 */
	public PDFParagraph(String content, BaseColor color) {
		super(content, getChineseFont(12, Font.NORMAL, color));
	}

	private static final Font getChineseFont() {

		Font FontChinese = null;
		try {
			BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
			FontChinese = new Font(bfChinese, 12, Font.NORMAL);
		} catch (DocumentException de) {
			System.err.println(de.getMessage());
		} catch (IOException ioe) {
			System.err.println(ioe.getMessage());
		}
		return FontChinese;
	}

	private static final Font getChineseFont(Integer fontSize, Integer style, BaseColor color) {

		Font FontChinese = null;
		try {
			BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
			FontChinese = new Font(bfChinese, fontSize, style, color);
		} catch (DocumentException de) {
			System.err.println(de.getMessage());
		} catch (IOException ioe) {
			System.err.println(ioe.getMessage());
		}
		return FontChinese;
	}
}

/**
 * 快速定义字体
 * 
 * @author Administrator
 *
 */
class MyFont {
	/**
	 * 默认的字体 size 12 常规字体,黑色
	 * 
	 * @param content
	 * @return
	 */
	public static PDFParagraph speedFont(String content) {
		return new PDFParagraph(content);
	}

	/**
	 * 自己定义一段文字
	 * 
	 * @param content  文字内容
	 * @param fontSize 文字大小
	 * @param style    文字的央视 Font.NORMAL 常规
	 * @param color    文字的颜色 BaseColor.RED
	 * @return
	 */
	public static PDFParagraph speedFont(String content, Integer fontSize, Integer style, BaseColor color) {
		return new PDFParagraph(content, fontSize, style, color);
	}

	/**
	 * 设置一段常规 12 大小的字体,可以另外设置颜色
	 * 
	 * @param content
	 * @param color   BaseColor.RED
	 * @return
	 */
	public static PDFParagraph speedFont(String content, BaseColor color) {
		return new PDFParagraph(content, color);
	}

	/**
	 * 自定义一个title 类似于标题
	 * 
	 * @param content
	 * @param fontSize
	 * @param style
	 * @param color
	 * @param element  Element.ALIGN_CENTER 水平居中的意思
	 * @return
	 */
	public static PDFParagraph centerTitle(String content, Integer fontSize, Integer style, BaseColor color,
			Integer element) {
		PDFParagraph font = new PDFParagraph(content, fontSize, style, color);
		font.setAlignment(element);
		return font;
	}
}

/**
 * 快速定义一个table
 * 
 * @author Administrator
 *
 */
class MyTable {
	/**
	 * 解析list map 数据导出
	 * 
	 * @param columnWidth 列宽度,可设置多个
	 * @param list        要解析的数据
	 * @return
	 * @throws DocumentException
	 */
	public static PdfPTable initTable(float[] columnWidth, List<Map<String, Object>> list) throws DocumentException {
		PdfPTable table = new PdfPTable(columnWidth.length);
		// 设置列宽
		table.setWidths(columnWidth);
		// 第一行是列名
		table.setHeaderRows(1);
		// 宽度填充
		table.getDefaultCell().setHorizontalAlignment(1);
		// 设置表哥的浮动宽度, 让文字保持居中
		//table.setWidthPercentage(100.0F);
		// 储存列标题
		Map<String, Integer> title = new HashMap<String, Integer>();
		// 当前创建的表哥的row 获取出来
		List<PdfPRow> rows = table.getRows();
		// 设置单元格背景颜色为灰色
		// cells0[0].setBackgroundColor(BaseColor.LIGHT_GRAY);
		for (int i = 0; i < list.size(); i++) {
			Map<String, Object> map = list.get(i);
			if (i == 0) {
				int j = 0;
				// 当前是第一列,解析出来所有的列
				PdfPCell[] cell = new PdfPCell[list.get(i).size()];
				for (String key : map.keySet()) {
					// 把所有的列都存起来
					title.put(key, j);
					cell[j] = new PdfPCell(MyFont.centerTitle(key, 13, Font.BOLD, BaseColor.BLACK, Element.ALIGN_CENTER));
					cell[j].setBackgroundColor(BaseColor.LIGHT_GRAY);
					cell[j].setHorizontalAlignment(Element.ALIGN_CENTER);//水平居中
					cell[j].setVerticalAlignment(Element.ALIGN_MIDDLE);//垂直居中
					cell[j].setFixedHeight(25f);
					j++;
				}
				rows.add(new PdfPRow(cell));
			}
			// 开始添加
			PdfPCell[] cell = new PdfPCell[list.get(i).size()];
			for (String key : map.keySet()) {
				cell[title.get(key)] = new PdfPCell(MyFont.speedFont(map.get(key) == null ? "" : map.get(key).toString()));
				cell[title.get(key)].setHorizontalAlignment(Element.ALIGN_CENTER);//水平居中
				cell[title.get(key)].setVerticalAlignment(Element.ALIGN_MIDDLE);//垂直居中
				cell[title.get(key)].setFixedHeight(25f);
			}
			rows.add(new PdfPRow(cell));
		}
		System.out.println("table 生成完成");
		return table;
	}

	public static PdfPTable initTable(String topTitle, float[] columnWidth, List<Map<String, Object>> list)
			throws DocumentException {
		// 新建一个表格 列数为列宽比例的个数
		PdfPTable table = new PdfPTable(columnWidth.length);
		// 宽度填充
		table.getDefaultCell().setHorizontalAlignment(1);
		// 设置表哥的浮动宽度, 让文字保持居中
		//table.setWidthPercentage(100.0F);
		// 获取到表格的行准备操作
		List<PdfPRow> rows = table.getRows();
		// 设置表格的列宽
		table.setWidths(columnWidth);
		// 定义一个列 然后跨列 添加到table 的表头
		PdfPCell[] celltop = new PdfPCell[2];
		celltop[0] = new PdfPCell(MyFont.centerTitle(topTitle, 13, Font.BOLD, BaseColor.BLACK, Element.ALIGN_CENTER));
		celltop[0].setBackgroundColor(BaseColor.LIGHT_GRAY);
		celltop[0].setHorizontalAlignment(Element.ALIGN_CENTER);//水平居中
		celltop[0].setVerticalAlignment(Element.ALIGN_MIDDLE);//垂直居中
		celltop[0].setFixedHeight(25f);
		// 设置跨列
		celltop[0].setColspan(2);
		rows.add(new PdfPRow(celltop));
		for(Map<String,Object> map : list) {
			for(String key : map.keySet()) {
				PdfPCell[] cells = new PdfPCell[2];
				cells[0] = new PdfPCell(MyFont.centerTitle(key, 13, Font.BOLD, BaseColor.BLACK, Element.ALIGN_CENTER));
				// 设置当前单元格的背景为灰色
				cells[0].setBackgroundColor(BaseColor.LIGHT_GRAY);
				cells[1] = new PdfPCell(MyFont.speedFont(map.get(key)==null?"":map.get(key).toString()));
				cells[0].setHorizontalAlignment(Element.ALIGN_CENTER);//水平居中
				cells[0].setVerticalAlignment(Element.ALIGN_MIDDLE);//垂直居中
				cells[0].setFixedHeight(25f);
				cells[1].setHorizontalAlignment(Element.ALIGN_CENTER);//水平居中
				cells[1].setVerticalAlignment(Element.ALIGN_MIDDLE);//垂直居中
				cells[1].setFixedHeight(25f);
				rows.add(new PdfPRow(cells));
			}
		}
		return table;
	}
}

这里我做的封装主要是有 默认的字体 该有改变字体颜色的,以及解析List<Map<String,Object>> 的一些数据 生成了两种表格。适用于数据库里直接写好sql 起好别名,然后查询出来直接交给MyTable 就可以实现的,当然第二个 table 可能需要做一个小小的处理。然后才可以使用。具体的使用和修改可以自己做一些更改

然后就是我测试的方法。

public void test() throws FileNotFoundException, DocumentException {
		// 穿件document
		Document document = new Document(PageSize.A4, 20, 20, 20, 20);
		// 创建document 的write 实例,也就是文件
		PdfWriter.getInstance(document, new FileOutputStream("E:\\ckwtext.pdf"));
		// 打开 document
		document.open();
		// 设置标题
		document.addTitle("导出文件");
		// 作者
		document.addAuthor("ckw");
		// 创建时间
		document.addCreationDate();
		// 添加一个标题
		document.add(MyFont.centerTitle("工单统计", 15, Font.BOLD, BaseColor.BLACK, Element.ALIGN_CENTER));
		document.add(MyFont.centerTitle("统计人:  ckw     统计时间:  2019-1-1  ", 15, Font.BOLD, BaseColor.BLACK,Element.ALIGN_CENTER));
		document.add(MyFont.speedFont("\n"));
		List<Map<String, Object>> list = new ArrayList();
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("定海", "3");
		map.put("东区", "3");
		map.put("分局", "3");
		Map<String, Object> map2 = new HashMap<String, Object>();
		map2.put("定海", "4");
		map2.put("东区", "4");
		map2.put("分局", "4");
		list.add(map);
		list.add(map2);
		
		PdfPTable table = MyTable.initTable(new float[] {1f,1f,2f}, list);
		document.add(table);
		document.add(MyFont.speedFont("\n"));
		document.add(MyTable.initTable("巡检详情", new float[] {1f, 1f},list));
		document.add(MyFont.speedFont("\n"));
		document.close();
		System.out.println("文件添加完成");
	}

这段我执行完的方法结果是这样的。
在这里插入图片描述
可以看到这个 List 里面包含的Map 他们的key 已经自己转换成了一个 列,或者说第二种表格的 左边的列。并且带有一个一行跨列的行作为一个提示。

提供一个下载的controller

	/*
	 * private void writeResponse(HttpServletResponse response, String path)
	 * throws IOException { System.out.println(path); String name =
	 * path.substring(path.lastIndexOf(File.separator)+1,path.length());
	 * System.out.println(name); String fileName = new
	 * String(name.getBytes("GBK"), "ISO-8859-1"); // 读到流中 InputStream inStream
	 * = new FileInputStream(path);// 文件的存放路径 // 设置输出的格式 response.reset();
	 * response.setContentType("bin"); response.addHeader("Content-Disposition",
	 * "attachment; filename="+ fileName); // 循环取出流中的数据 byte[] b = new
	 * byte[1000]; int len; while ((len = inStream.read(b)) > 0)
	 * response.getOutputStream().write(b, 0, len); inStream.close(); }
	 */

	private void writeResponse(HttpServletResponse response, String path)
			throws IOException {
		System.out.println(path);
		String name = path.substring(path.lastIndexOf(File.separator) + 1,
				path.length());
		System.out.println(name);
		String fileName = new String(name.getBytes("GBK"), "ISO-8859-1");
		response.addHeader("Content-Disposition","attachment; filename="+ fileName);
		response.setContentType("application/pdf");
		FileInputStream in;
		OutputStream out;
		try {
			in = new FileInputStream(new File(path));
			out = response.getOutputStream();
			byte[] b = new byte[512];
			while ((in.read(b)) != -1) {
				out.write(b);
			}
			out.flush();
			in.close();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

添加水印

	/**
     * pdf 添加水印
     * @param inputFile 要修改的pdf 文件位置
     * @param outputFile 添加完水印后输出的新文件位置
     * @param waterMarkName 水印文字
     */
	public static void waterMark(String inputFile,
                                 String outputFile, String waterMarkName) {
        try {
            PdfReader reader = new PdfReader(inputFile);
            PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(
                    outputFile));
            BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H",   BaseFont.EMBEDDED);

            Rectangle pageRect = null;
            PdfGState gs = new PdfGState();
            //设置透明度
            gs.setFillOpacity(0.3f);
            gs.setStrokeOpacity(0.4f);
            int total = reader.getNumberOfPages() + 1;

            JLabel label = new JLabel();
            FontMetrics metrics;
            int textH = 0;
            int textW = 0;
            label.setText(waterMarkName);
            metrics = label.getFontMetrics(label.getFont());
            textH = metrics.getHeight();
            textW = metrics.stringWidth(label.getText());

            PdfContentByte under;
            for (int i = 1; i < total; i++) {
                pageRect = reader.getPageSizeWithRotation(i);
                under = stamper.getOverContent(i);
                under.saveState();
                under.setGState(gs);
                under.beginText();
                under.setFontAndSize(base, 50);
                //设置水印颜色
                //under.setColorFill(BaseColor.RED);
                under.setColorFill(new BaseColor(90, 92, 98));
                // 水印文字成30度角倾斜
                //你可以随心所欲的改你自己想要的角度
                for (int height = interval + textH; height < pageRect.getHeight();
                     height = height + textH*7) {
                    for (int width = interval + textW; width < pageRect.getWidth() + textW;
                         width = width + textW*5) {
                        under.showTextAligned(Element.ALIGN_LEFT, waterMarkName, width - textW,height - textH, 30);
                    }
                }
                // 添加水印文字
                under.endText();
            }
            //说三遍
            stamper.close();
            reader.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值