1 pdf 文件生成

生成pdf有两种方法,如下:
1) 使用 wkhtmltox 工具将 html 转 pdf
优点:一次安装,永久使用。便捷,生成效果好
缺点:并不是所有 html 都能成功转成 pdf,至于为什么需要深度研究研究。

安装
去官网下载:https://wkhtmltopdf.org/downloads.html
分 windows 环境 linux 环境,各自取用适合的包。

java 直接生成pdf java后端生成pdf_ci


如果是 windows 环境,工具解压后打开 dos 窗口,cd 到工具 bin/ 目录下,执行:

wkhtmltopdf https://wkhtmltopdf.org/downloads.html E:\dir\test.pdf

命令说明: wkhtmltopdf 【html路径】【存储路径】

存储路径一定是要先存在的,否则会报错,文件名是自定义的。生成效果如下:

java 直接生成pdf java后端生成pdf_java 直接生成pdf_02


如果是 linux 环境,以 CentOS7 系统为例。

安装:rpm -ivh --nodeps wkhtmltox-0.12.5-1.centos7.x86_64.rpm

加了 --nodeps 会将缺少的依赖一起安装。

使用与在 windows 系统是一样的,它还有很多命令,需要的自己去研究啦~

这个工具还可以将 html 转成图片,有兴趣的可以去试试。

补充:
当在 linux 环境上面将 html转换成 pdf 时,如果内容是中文,可能转出来的 pdf 里面存在空白,这可能是 linux 环境上缺乏中文字体导致的。需要将 windows 的宋字字体 simsun.ttc 拷贝到在/usr/share/fonts中,然后重新执行命令生成 pdf。simsun.ttc 一般在 C:\Windows\Fonts 目录下。

2) itext 创建 pdf 文件
优点:强大的 java 插件,可以自定义生成各种样式的 pdf 、word。
缺点:需要自己使用代码进行内容填充,稍微复杂一点。

生成 pdf 需要的 maven 依赖:

<!-- itext pdf相关 -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itextpdf</artifactId>
            <version>5.5.13</version>
        </dependency>

        <!-- itext asian 字体相关 -->
        <dependency>
            <groupId>com.itextpdf</groupId>
            <artifactId>itext-asian</artifactId>
            <version>5.2.0</version>
        </dependency>

生成 pdf 核心代码示例:

Document document = new Document(PageSize.A4);

// 新建一个pdf文件
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("E:\\test\\test.pdf"));
document.open();

// 中文字体,解决中文不能显示问题
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);

// 红标题字体风格
Font redTitleFont = new Font(bfChinese, 20, Font.BOLD, BaseColor.RED);
// 红标题抬头
Paragraph redTitle = new Paragraph(serviceConfig.getOrganization(), redTitleFont);
redTitle.setAlignment(Element.ALIGN_CENTER); // 居中
document.add(redTitle); // 文档中加入红标题字段

//参数 1.线宽度 2.直线长度,是个百分百,0-100之间 3.直线颜色 4.直线位置 5.上下移动位置
document.add(new LineSeparator(4f,100, BaseColor.RED, Element.ALIGN_CENTER,-15f)); // 画线
document.add(new LineSeparator(1f,100, BaseColor.RED, Element.ALIGN_CENTER,-20f));

// 标题字体风格
Font titleFont = new Font(bfChinese, 15, Font.BOLD); 
// 标题内容
Paragraph title = new Paragraph("关于xx的分析报告", titleFont);
title.setSpacingBefore(25); // 离上一段落(标题)空的行数
title.setAlignment(Element.ALIGN_CENTER); // 设置标题格式对齐方式
document.add(title); // // 文档中加入标题字段

// 正文字体风格
Font contextFont = new Font(bfChinese, 10, Font.NORMAL); 
// 循环生成多个相同的表格
for (Person person: persons) {
    Paragraph info = new Paragraph("工作人员" + count++, contextFont);
    info.setSpacingBefore(10); // 离上一段落(标题)空的行数
    document.add(info);

    // 两列的表
    PdfPTable table = new PdfPTable(2);
    table.setWidthPercentage(100); // 宽度100%填充
    table.setSpacingBefore(10f); // 前间距
    table.setSpacingAfter(10f); // 后间距

    List<PdfPRow> listRow = table.getRows();

    // 设置列宽比例 1:3
    float[] columnWidths = {1f, 3f};
    table.setWidths(columnWidths);

    // 第1行
    PdfPCell[] cells1 = new PdfPCell[2]; // 一行两格
    PdfPRow row1 = new PdfPRow(cells1);
    cells1[0] = new PdfPCell(new Paragraph("姓名", contextFont)); // 第一个单元格
    cells1[1] = new PdfPCell(new Paragraph(person.getName(), contextFont)); // 第二个单元格

    // 第2行
    PdfPCell[] cells2 = new PdfPCell[2];
    PdfPRow row2 = new PdfPRow(cells2);
    cells2[0] = new PdfPCell(new Paragraph("性别", contextFont)); //单元格内容
    cells2[1] = new PdfPCell(new Paragraph(person.getGender(), contextFont));
    
    // 第3行
    PdfPCell[] cells3 = new PdfPCell[2];
    PdfPRow row3 = new PdfPRow(cells3);
    cells3[0] = new PdfPCell(new Paragraph("图片", contextFont)); //单元格内容
    cells3[0].setHorizontalAlignment(Element.ALIGN_LEFT); // 水平居左
    cells3[0].setVerticalAlignment(Element.ALIGN_MIDDLE); // 垂直居中

    // 填充多个图片
    String[] paths = person.getImagePath().split(","); // 图片全路径以逗号分隔的
    int column = 4; // 1行展示图片的数量
    int row;
    if (paths.length % column == 0) {
        row = paths.length / column;
    } else {
        row = paths.length / column + 1;
    }

    PdfPTable picTable = new PdfPTable(column);
    picTable.setWidthPercentage(100); // 宽度100%填充
    List<PdfPRow> rows = picTable.getRows();

    int count = 0;
    for (int i = 0; i < row; i ++) {
        PdfPCell[] cells = new PdfPCell[column];
        PdfPRow newRow = new PdfPRow(cells);
        for (int j = 0; j < column; j ++) {
            if (count < paths.length) {
                Image image = Image.getInstance(paths[count++]);
                //设置图片的宽度和高度
                image.scaleAbsolute(100, 100);
                cells[j] = new PdfPCell(image);
            }
        }
        rows.add(newRow);
    }
    cells3[1] = new PdfPCell(picTable); // 图片组成的table加入到第三行的第二格中
    
    listRow.add(row1);
    listRow.add(row2);
    listRow.add(row3);
   
    // 把表格添加到文件中
    document.add(victimTable);
}

2 下载 pdf 文件
【效果】打开浏览器发送 get 请求,浏览器自动下载。

Controller层请求接口

/**
 * 下载工具
 */
@Resource
private DownloadUtil downloadUtil;

@GetMapping("/download")
public void export(HttpServletRequest request, HttpServletResponse response) {
	String filePath = "E:\test\";
	String fileName = "test.pdf";
	downloadUtil.downloadFile(filePath, fileName, request, response);
}

DownloadUtil.java

package xxx.common.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

/**
 * 下载工具类
 *
 * @author xianhuang
 * @date 2019/03/11 10:21
 * @since 1.0
 */
@Component
public class DownloadUtil {

    /**
     * 日志记录
     */
    private static final Logger LOGGER = LoggerFactory.getLogger(DownloadUtil.class);

    /**
     * 下载文件
     * @param filePath 文件所在目录全路径
     * @param fileName 文件全名,包括后缀
     * @param request http请求
     * @param response http返回
     * @throws IOException 异常
     */
    public void downloadFile(String filePath, String fileName, HttpServletRequest request,
                             HttpServletResponse response) throws IOException {
        String fullPath = filePath + fileName;

        if (fullPath.contains("\\")) {
            fullPath.replaceAll("\\\\","\\\\\\\\");
        }

        File f = new File(fullPath);
        if (!f.exists()) {
            LOGGER.error("文件{}不存在", f.getName());
            return;
        }

        // 解决中文名称乱码问题
        final String userAgent = request.getHeader("USER-AGENT");
        if (userAgent.contains("MSIE")
                || userAgent.contains("Trident")
                || userAgent.contains("Edge")) { //IE浏览器
            fileName = URLEncoder.encode(fileName, "UTF-8");
        } else if (userAgent.contains("Mozilla")) { //google,火狐浏览器
            fileName = new String(fileName.getBytes(), "ISO8859-1");
        } else {
            fileName = URLEncoder.encode(fileName, "UTF-8"); //其他浏览器
        }

        response.setContentType("application/octet-stream");
        response.setHeader("Content-Disposition", "attchement;filename=" + fileName );

        try (FileInputStream fileInputStream = new FileInputStream(fullPath)) {
            OutputStream outputStream = response.getOutputStream();
            byte[] b = new byte[1024];
            int j;
            while ((j = fileInputStream.read(b)) > 0) {
                outputStream.write(b, 0, j);
            }
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
        }
    }
}