第一步导包
<!--pdf生成工具类-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.4.2</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.4.1</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.29</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf</artifactId>
<version>9.1.18</version>
</dependency>
然后是写一个 ftl文件,具体写法请百度,还有font文件,如图
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: SimSun;
}
section {
display: block;
margin: 20px 10px;
}
.title {
text-align: center;
}
.preface p {
line-height: 30px;
}
.preface p.content {
text-indent: 2em;
}
section>table {
table-layout: fixed;
width: 100%;
margin: 20px 0px;
text-align: center;
word-wrap: break-word;
}
</style>
</head>
<body>
<!-- 标题 start -->
<section class="title">
<h2>报价数据</h2>
</section>
<!-- 标题 end -->
<!-- 汇总统计信息 start -->
<section class="count-info">
<table border="1" cellspacing="0">
<#list data as ai>
<tr>
<#list ai as ad>
<#if ad??>
<#if ad?is_number>
<td>${ad}</td>
<#else>
<#if ad?is_string && ad !="null/null" && ad !="null">
<td>${ad}</td>
<#else>
<td> </td>
</#if>
</#if>
<#else>
<td> </td>
</#if>
</#list>
</tr>
</#list>
</table>
</section>
</body>
</html>
然后是controller代码
@Controller
@RequestMapping("pdf")
public class PdfController extends BaseController {
@Autowired
private PdfService pdfService;
final int interval = -5;
@RequestMapping("/public/checkData/{orderNum}")
public void quotationStand(@PathVariable String orderNum) {
try {
Map<String, Object> stringObjectMap = pdfService.quotationStand(orderNum);
System.out.println(stringObjectMap);
} catch (Exception e) {
e.printStackTrace();
}
}
@RequestMapping("/public/export/quotationStand/{orderNum}")
public void quotationStand(@PathVariable String orderNum, HttpServletResponse response) throws Exception {
ByteArrayOutputStream baos = null;
OutputStream out = null;
try {
// stringObjectMap 是业务逻辑代码。主要是数据查询,我就不粘贴出来了
Map<String, Object> stringObjectMap = pdfService.quotationStand(orderNum);
baos = PDFTemplateUtil.createPDF(stringObjectMap, "quotationTemplate.ftl");
// 设置响应消息头,告诉浏览器当前响应是一个下载文件
//加载示例文档、
ByteArrayInputStream swapStream = new ByteArrayInputStream(baos.toByteArray());
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
String str = "XXXXXXXX";
waterMark(swapStream, byteArrayOutputStream, str);
response.setContentType("application/x-msdownload");
// 告诉浏览器,当前响应数据要求用户干预保存到文件中,以及文件名是什么 如果文件名有中文,必须URL编码
String fileName = URLEncoder.encode("报价快照.pdf", "UTF-8");
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
baos = byteArrayOutputStream;
out = response.getOutputStream();
baos.writeTo(out);
baos.close();
} catch (Exception e) {
logger.error(e.getMessage(), e);
e.printStackTrace();
throw new Exception("导出失败:" + e.getMessage());
} finally {
if (baos != null) {
baos.close();
}
if (out != null) {
out.close();
}
}
}
/**
* 加水印
*
* @param inputFile
* @param outputFile
* @param waterMarkName
*/
private void waterMark(InputStream inputFile, OutputStream outputFile, String waterMarkName) {
try {
PdfReader reader = new PdfReader(inputFile);
PdfStamper stamper = new PdfStamper(reader, outputFile);
BaseFont base = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.EMBEDDED);
Rectangle pageRect = null;
PdfGState gs = new PdfGState();
gs.setFillOpacity(0.2f);
gs.setStrokeOpacity(0.2f);
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, 20);
// 水印文字成30度角倾斜
//你可以随心所欲的改你自己想要的角度
for (int height = interval + textH; height < pageRect.getHeight();
height = height + textH * 10) {
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();
}
}
}
还有service代码
package com.ruoyi.portal.util;
import java.io.*;
import java.util.Locale;
import java.util.Map;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.springframework.beans.factory.annotation.Value;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.pdf.BaseFont;
import freemarker.template.Configuration;
import freemarker.template.Template;
public class PDFTemplateUtil {
/**
* 通过模板导出pdf文件
*
* @param data 数据
* @param templateFileName 模板文件名
* @throws Exception
*/
public static ByteArrayOutputStream createPDF(Map<String, Object> data, String templateFileName) throws Exception {
// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例
Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 指定FreeMarker模板文件的位置
cfg.setClassForTemplateLoading(PDFTemplateUtil.class, "/templates");
ITextRenderer renderer = new ITextRenderer();
OutputStream out = new ByteArrayOutputStream();
try {
// 设置 css中 的字体样式(暂时仅支持宋体和黑体) 必须,不然中文不显示
renderer.getFontResolver().addFont("/templates/font/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
// 设置模板的编码格式
cfg.setEncoding(Locale.CHINA, "UTF-8");
// 获取模板文件
Template template = cfg.getTemplate(templateFileName, "UTF-8");
StringWriter writer = new StringWriter();
// 将数据输出到html中
template.process(data, writer);
writer.flush();
String html = writer.toString();
// 把html代码传入渲染器中
renderer.setDocumentFromString(html);
// 设置模板中的图片路径 (这里的images在resources目录下) 模板中img标签src路径需要相对路径加图片名 如<img src="images/xh.jpg"/>
// String url = PDFTemplateUtil.class.getClassLoader().getResource("/images").toURI().toString();
String url = "./";
renderer.getSharedContext().setBaseURL(url);
renderer.layout();
renderer.createPDF(out, false);
renderer.finishPDF();
out.flush();
return (ByteArrayOutputStream) out;
} finally {
if (out != null) {
out.close();
}
}
}
/**
* 通过模板导出pdf文件
*
* @param data 数据
* @param templateFileName 模板文件名
* @throws Exception
*/
public static ByteArrayOutputStream createPDFByByte(Map<String, Object> data, String templateFileName) throws Exception {
// 创建一个FreeMarker实例, 负责管理FreeMarker模板的Configuration实例
Configuration cfg = new Configuration(Configuration.DEFAULT_INCOMPATIBLE_IMPROVEMENTS);
// 指定FreeMarker模板文件的位置
cfg.setClassForTemplateLoading(PDFTemplateUtil.class, "/templates");
Document document = new Document(new RectangleReadOnly(824F, 595F));
OutputStream out = new ByteArrayOutputStream();
PdfWriter mPdfWriter = PdfWriter.getInstance(document, out);
document.open();
try {
// 设置模板的编码格式
cfg.setEncoding(Locale.CHINA, "UTF-8");
// 获取模板文件
Template template = cfg.getTemplate(templateFileName, "UTF-8");
StringWriter writer = new StringWriter();
// 将数据输出到html中
template.process(data, writer);
writer.flush();
String html = writer.toString();
ByteArrayInputStream bin = new ByteArrayInputStream(html.getBytes());
XMLWorkerHelper.getInstance().parseXHtml(mPdfWriter, document, bin, null, new ChinaFontProvide());
document.close();
return (ByteArrayOutputStream) out;
} finally {
if (out != null) {
out.close();
}
}
}
public static final class ChinaFontProvide implements FontProvider {
@Override
public boolean isRegistered(String s) {
return false;
}
@Override
public Font getFont(String arg0, String arg1, boolean arg2, float arg3, int arg4, BaseColor arg5) {
com.itextpdf.text.pdf.BaseFont bfChinese = null;
try {
bfChinese = com.itextpdf.text.pdf.BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", com.itextpdf.text.pdf.BaseFont.NOT_EMBEDDED);
} catch (Exception e) {
e.printStackTrace();
}
Font FontChinese = new Font(bfChinese, 12, Font.NORMAL);
return FontChinese;
}
}
}