java实现导出pdf文件(模板+纯代码)

前言

最近做一个导出pdf功能记录下,尝试了以下两种方式,个人感觉第一种适合特定规格的数据内容,样式又比较多,严格的再加个水印,当然用第二种也能实现,就是每个样式包括水印都要自己代码实现可能会没那么快。做的时候两种方式都遇到了多行文本换行的问题,好在都解决了。第一种就是文本栏(ColumnText)循环写入,注意赋值后每次都要调用columnText.go(),将行数据输出到文档中,就可以实现换行,第二种每个单元格(PdfPCell)利用它的addElement方式,添加元素Chunk对象,循环添加换行文本就可以了。我要实现的功能模板比较简单,但是内容需要自适应高度,内容长度不确定采取第一种方式会丢失部分内容,所以用的第二种方式。

1、模板方式导出

  1. 首先制定word模板如图:

在这里插入图片描述

  1. 做好之后另存为pdf格式

在这里插入图片描述

  1. 使用Adobe Acrobat XI Pro工具编辑pdf添加表单,可以设置默认属性,字体大小等

在这里插入图片描述
在这里插入图片描述

  1. 代码实现装填参数并导出

之前需要在pom文件种引入以下jar包

  <!--pdf模板导出-->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.6</version>
        </dependency>
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

模板导出的方法代码,字体一定要设定不然不会显示中文

public static void fillTemplate(Map<String, Object> o, Map<String, Object> outLine, Map<String, Object> images, String templatePath, String filename, HttpServletResponse response) throws Exception {
		OutputStream out = null;
        PdfReader reader=null;
        ByteArrayOutputStream bos=null;
        PdfStamper stamper=null;
        try {
			//输出到浏览器
            // 设置响应头
            filename = URLEncoder.encode(filename, "UTF-8");
            response.setContentType("application/force-download");
            response.setHeader("Content-Disposition", "attachment;fileName=" + filename);
			 out = response.getOutputStream();
            // 读取pdf模板
			reader = new PdfReader(templatePath);
			bos = new ByteArrayOutputStream();
			stamper = new PdfStamper(reader, bos);
			AcroFields form = stamper.getAcroFields();
			// 文字类的内容处理
			java.util.Iterator<String> it = form.getFields().keySet().iterator();
			//文本处理
			while (it.hasNext()) {
				String name = it.next().toString();
				String oname = name.replace("${", "").replace("}", "");
				String value = o.get(oname) != null ? o.get(oname).toString() : "";
				System.out.println(oname + "=" + value);
				//使用自定义基础字体
			//	form.setFieldProperty(name, "textfont", bfChinese, null);
				//文本域自定义换行处理
				if(!oname.contains("term")&&!oname.contains("week")&&!EmptyUtil.isEmpty(outLine) && (!EmptyUtil.isEmpty(outLine.get(oname)) || !EmptyUtil.isEmpty(outLine.get("*")) )){
						// 设置字体样式
						List<AcroFields.FieldPosition> multiLinePosition = form.getFieldPositions(name);
						int page = multiLinePosition.get(0).page;
						Rectangle rectangle = multiLinePosition.get(0).position;
						PdfContentByte pdfContentByte = stamper.getOverContent(page);
						ColumnText columnText = new ColumnText(pdfContentByte);
						columnText.setSimpleColumn(rectangle);
						Font f= getFont("5");
						///t是标识多行文本的需要换行的标识符号
						if(!EmptyUtil.isEmpty(value)&&value.contains("/t")){
							//循环写入-这种可以实现文本换行
							for(String s:value.split("/t")){
								Paragraph paragraph = new Paragraph();
								paragraph.setFont(f);
								paragraph.add(new Phrase(s));
								columnText.addText(paragraph);
								columnText.addElement(paragraph);
								columnText.go();
							}
						}else{
							Paragraph paragraph = new Paragraph();
							paragraph.setFont(f);
							paragraph.add(new Phrase(value));
							columnText.addElement(paragraph);
							columnText.addText(paragraph);
							columnText.go();
						}
				}else{
					form.setField(name, value);
				}
			}
				// 图片类的内容处理 根据表单域 左下角点定位
				if(!EmptyUtil.isEmpty(images)){
					for (String key : images.keySet()) {
						String value = images.get(key).toString();
						String imgpath = value;
						if (!EmptyUtil.isEmpty(form.getFieldPositions(key))) {
							int pageNo = form.getFieldPositions(key).get(0).page;
							Rectangle signRect = form.getFieldPositions(key).get(0).position;
							float x = signRect.getLeft();
							float y = signRect.getBottom();
							// 根据路径读取图片
							Image image = Image.getInstance(imgpath);
							// 获取图片页面
							PdfContentByte under = stamper.getOverContent(pageNo);
							//图片按照表单框大小
							image.scaleAbsolute(signRect.getWidth(), signRect.getHeight());
							// 图片大小自适应
							//image.scaleToFit(signRect.getWidth(), signRect.getHeight());
							// 添加图片
							image.setAbsolutePosition(x, y);
							under.addImage(image);
						}
					}
				}
			// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
			stamper.setFormFlattening(true);
			stamper.close();
			Document doc = new Document();
			PdfCopy copy = new PdfCopy(doc, out);
			doc.open();
			int pageNum = reader.getNumberOfPages();
			for (int i = 1; i <= pageNum; i++) {
				PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), i);
				copy.addPage(importPage);
			}
			doc.close();
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
            try {
                if (out != null) {
                    out.flush();
                    out.close();
                }
                if (reader != null) {
                    reader.close();
                }
            }catch (Exception e){
                e.printStackTrace();
            }
        }
	}
	/**
	 * 根据编号 i 获取字体样式 以后可以按照需求增加
	 * @param i
	 * @return
	 */
public static Font getFont(String i) throws IOException, DocumentException {
		BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
		Font FontChinese1 ;
		switch (i){
			case "1" :FontChinese1= new Font(bfChinese, 18, Font.BOLD);
			break;
			case "2" :FontChinese1= new Font(bfChinese, 12, Font.BOLD);
			break;
			case "3" :FontChinese1= new Font(bfChinese, 8, Font.BOLD);
			break;
			case "4" :FontChinese1= new Font(bfChinese, 24, Font.NORMAL);
			break;
			case "5" :FontChinese1= new Font(bfChinese, 9, Font.NORMAL);
				break;
			case "10" :FontChinese1= new Font(bfChinese, 10, Font.NORMAL);
			break;
			case "6" :FontChinese1= new Font(bfChinese, 8, Font.NORMAL);
				break;
			default:FontChinese1=null;
		}
		return FontChinese1;

	}

业务数据封装省略了,mapData为业务数据,参数和pdf模板字段对应

          //需要填充参数的 字体样式
           Map<String,Object> outLinemap=new HashMap<>();
           outLinemap.put("*","4");
           //生成PDF文件的文件名
           String fileName="工作安排"+ UUID.randomUUID()+".pdf";
           //导出pdf文件
           String filePath = getRequest().getRealPath("/WEB-INF/classes/static/pdf/job.pdf");
           PDFUtil.fillTemplate(mapData,outLinemap,null,filePath,fileName,getResponse());

以下是效果图:

在这里插入图片描述

文本内容太多会显示不全,超出的会丢失

2、纯代码方式导出

这个就没啥繁琐步骤了直接写代码就好了

	public static void download(List<Map<String,String>> list, Map<String, String> mapData, HttpServletResponse response) throws IOException {
		Document document = new Document();
		document.setMargins(70, 70, 20, 20);
		try {
			Font content = content = getFont("10");
			PdfWriter.getInstance(document,response.getOutputStream());
			//打开生成的pdf文件
			document.open();

			//设置内容
			Paragraph paragraph = new Paragraph("一周工作安排", getFont("4"));
			paragraph.setAlignment(1);
			//引用字体
			document.add(paragraph);

			document.add(new Paragraph("\n", getFont("4")));
			Paragraph paragraph0 = new Paragraph(mapData.get("term"), content);
			paragraph0.setAlignment(Element.ALIGN_RIGHT);
			document.add(paragraph0);
             //设置每页大小
			document.setPageSize(new RectangleReadOnly(595.0F, 600.0F));

			PdfPCell cell = null;

			// 设置表格的列宽和列数
			float[] widths2 = {15f,15f,45f,30f,30f};
			PdfPTable table = new PdfPTable(widths2);
			table.setSpacingBefore(10f);
			// 设置表格宽度为100%
			table.setWidthPercentage(100.0F);
			table.setHeaderRows(1);
			table.getDefaultCell().setHorizontalAlignment(1);

			//表头
			cell = new PdfPCell(new Paragraph("星期",content));
			cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
			cell.setHorizontalAlignment(Element.ALIGN_CENTER);
			cell.setFixedHeight(50);
			table.addCell(cell);

			cell = new PdfPCell(new Paragraph("日期",content));
			cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
			cell.setHorizontalAlignment(Element.ALIGN_CENTER);
			table.addCell(cell);

			cell = new PdfPCell(new Paragraph("工作内容",content));
			cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
			cell.setHorizontalAlignment(Element.ALIGN_CENTER);
			table.addCell(cell);

			cell = new PdfPCell(new Paragraph("地点",content));
			cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
			cell.setHorizontalAlignment(Element.ALIGN_CENTER);
			table.addCell(cell);

			cell = new PdfPCell(new Paragraph("负责部门",content));
			cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
			cell.setHorizontalAlignment(Element.ALIGN_CENTER);
			table.addCell(cell);

			//遍历一周安排数据
				for (Map<String,String> data : list) {
					PdfPCell cell1 = new PdfPCell(new Paragraph(data.get("week"), content));
					PdfPCell cell2 = new PdfPCell(new Paragraph(data.get("date"), content));

					PdfPCell cell3 = new PdfPCell();
			///n为自定义换行符号-没有特殊含义		if(!EmptyUtil.isEmpty(data.get("content"))&&data.get("content").contains("/n")){
						for(String s:data.get("content").split("/n")){
							cell3.addElement(new Chunk(s,content));
						}
					}
					PdfPCell cell4 =new PdfPCell();
					if(!EmptyUtil.isEmpty(data.get("address"))&&data.get("address").contains("/n")){
						for(String s:data.get("address").split("/n")){
							cell4.addElement(new Chunk(s,content));
						}
					}
					PdfPCell cell5 =new PdfPCell();
					if(!EmptyUtil.isEmpty(data.get("dept"))&&data.get("dept").contains("/n")){
						for(String s:data.get("dept").split("/n")){
							cell5.addElement(new Chunk(s,content));
						}
					}
					//单元格对齐方式
					cell1.setHorizontalAlignment(Element.ALIGN_CENTER);
					cell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
					cell1.setFixedHeight(40);
					//单元格垂直对齐方式
					cell2.setHorizontalAlignment(Element.ALIGN_CENTER);
					cell2.setVerticalAlignment(Element.ALIGN_MIDDLE);

					cell3.setHorizontalAlignment(Element.ALIGN_CENTER);
					cell3.setVerticalAlignment(Element.ALIGN_MIDDLE);

					cell4.setHorizontalAlignment(Element.ALIGN_CENTER);
					cell4.setVerticalAlignment(Element.ALIGN_MIDDLE);

					cell5.setHorizontalAlignment(Element.ALIGN_CENTER);
					cell5.setVerticalAlignment(Element.ALIGN_MIDDLE);


					table.addCell(cell1);
					table.addCell(cell2);
					table.addCell(cell3);
					table.addCell(cell4);
					table.addCell(cell5);
				}
			PdfPCell cellLeft = new PdfPCell(new Paragraph("备注", content));
			cellLeft.setFixedHeight(40);
			cellLeft.setVerticalAlignment(Element.ALIGN_MIDDLE);
			cellLeft.setHorizontalAlignment(Element.ALIGN_CENTER);
			PdfPCell cellRight = new PdfPCell(new Paragraph(mapData.get("remark"), content));
			cellRight.setVerticalAlignment(Element.ALIGN_MIDDLE);
			cellRight.setHorizontalAlignment(Element.ALIGN_CENTER);
			cellRight.setColspan(4);
			table.addCell(cellLeft);
			table.addCell(cellRight);

//			document.add(new Paragraph("\n"));
//			document.add(new Paragraph("▋ 信息",content));
//			document.add(new Paragraph("\n"));
//
			document.add(table);

			//关闭文档
			document.close();

		} catch (DocumentException e) {
			e.printStackTrace();
		}
	}

List<Map<String,String>>outData=new ArrayList<>(); Map<String,
String> otherData = new HashMap<>(); outData和otherData 是业务数据集合

        // 设置编码格式
        response.setContentType("application/pdf;charset=UTF-8");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode(mapData.get("term"), "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
        PDFUtil.download(outData,otherData, response);

效果图

在这里插入图片描述

  • 11
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
PDF模板导出可以使用Java的iText库来实现。iText是一个开源的Java库,可以用来创建、编辑和操作PDF文档。下面是一个简单的示例代码,演示了如何使用iText来导出PDF模板: ``` import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.PdfReader; import com.itextpdf.text.pdf.PdfStamper; import java.io.FileOutputStream; import java.io.IOException; public class PdfTemplateExporter { public static void main(String[] args) throws IOException, DocumentException { // 读取PDF模板文件 PdfReader reader = new PdfReader("template.pdf"); // 创建输出文件 FileOutputStream out = new FileOutputStream("output.pdf"); // 创建PDF文档对象 Document document = new Document(); // 创建PDF输出流 PdfStamper stamper = new PdfStamper(reader, out); // 获取PDF文档的页面数 int pages = reader.getNumberOfPages(); // 遍历所有页面 for (int i = 1; i <= pages; i++) { // 获取当前页面的可编辑区域 Rectangle rect = reader.getCropBox(i); // 在可编辑区域内添加内容(这里可以添加表格、文本、图片等) // ... // 更新页面内容 stamper.getOverContent(i).setLiteral("Q\nq\n"); // 释放资源 stamper.close(); } // 关闭PDF输出流 out.close(); } } ``` 在这个示例中,我们首先读取了一个名为“template.pdf”的PDF模板文件。然后,我们创建了一个名为“output.pdf”的输出文件,并创建了一个PDF文档对象和一个PDF输出流。接下来,我们遍历了所有页面,获取了每个页面的可编辑区域,并在可编辑区域内添加了一些内容。最后,我们更新了页面内容,关闭了PDF输出流。 当你运行这个示例代码时,它将从“template.pdf文件中读取PDF模板,并在每个页面上添加一些内容。然后,它将生成一个名为“output.pdf”的新PDF文件,其中包含了我们添加的内容。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无言.默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值