• 根据word模板生成word、转换成pdf、打成war包


    一、word模板

    二、替换模板里的内容(创建一个WordUtils工具类)

    import org.apache.poi.xwpf.usermodel.*;

    import java.io.*;
    import java.util.Iterator;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;

    public class WordUtils {
    /**
    * 替换表格里面的变量
    * @param doc 要替换的文档
    * @param params 参数
    */
    public static void replaceInTable(XWPFDocument doc, Map<String, Object> params) {
    Iterator<XWPFTable> iterator = doc.getTablesIterator();
    XWPFTable table;
    List<XWPFTableRow> rows;
    List<XWPFTableCell> cells;
    List<XWPFParagraph> paragraphs = doc.getParagraphs();
    for (XWPFParagraph paragraph : paragraphs) {
    List<XWPFRun> runs = paragraph.getRuns();
    for (XWPFRun run : runs) {
    run.setText(changeValue(run.toString(), params),0);
    }
    }
    while (iterator.hasNext()) {
    table = iterator.next();
    rows = table.getRows();
          // 删除行
          //table.removeRow(3);
                for (XWPFTableRow row : rows) {
    cells = row.getTableCells();
    for (XWPFTableCell cell : cells) {
    List<XWPFParagraph> paras = cell.getParagraphs();
    for (XWPFParagraph paragraph : paras) {
    List<XWPFRun> runs = paragraph.getRuns();
    for (XWPFRun run : runs) {
    run.setText(changeValue(run.toString(), params),0);
    }
    }
    }
    }
        mergeCellsVertically(table, 0, 1,2);
        mergeCellsVertically(table, 3, 1,2);
            }
    }

    /**
    * 匹配传入信息集合与模板
    * @param value 模板需要替换的区域
    * @param textMap 传入信息集合
    * @return 模板需要替换区域信息集合对应值
    */
    private static String changeValue(String value, Map<String, Object> textMap){
    Set<Map.Entry<String, Object>> textSets = textMap.entrySet();
    for (Map.Entry<String, Object> textSet : textSets) {
    //匹配模板与替换值 格式${key}
    String key = "${"+textSet.getKey()+"}";
    if(value.indexOf(key)!= -1){
    value = textSet.getValue().toString();
    }
    }
    return value;
    }

    /**
    * 关闭输入流
    * @param is
    */
    public static void close(InputStream is) {
    if (is != null) {
    try {
    is.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }

    /**
    * 关闭输出流
    * @param os
    */
    public static void close(OutputStream os) {
    if (os != null) {
    try {
    os.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }


    }

    三、实现类   reportService

    /**   convertPath路径D:/template/convert   

    Map<String, Object> params       例:params.put("name", "张三");   // 与模板里设置的变量一致

    **/

    private ResponseEntity<byte[]> templateWrite(String filePath, Map<String, Object> params, int n) throws IOException {

             String convertPath = path + File.separator + "template" + File.separator + "convert";

        File dir = new File(convertPath);
    if (!dir.exists()) {
    dir.mkdir();
    }
    String docxFilePath = convertPath + File.separator + "tb" + n + ".docx";
    String pdfFilePath = convertPath + File.separator + "pdf" + File.separator + "tb" + n + ".pdf";
    InputStream is = new FileInputStream(filePath);
    XWPFDocument doc = new XWPFDocument(is);
    // 替换表格里面的变量
    WordUtils.replaceInTable(doc, params);

    OutputStream os = new FileOutputStream(docxFilePath);
    doc.write(os);
    WordUtils.close(os);
    WordUtils.close(is);
    os.flush();
    os.close();

    return this.convertToPdf(docxFilePath, pdfFilePath);
    }
    private ResponseEntity<byte[]> convertToPdf(String docxFilePath, String pdfFilePath) throws IOException {
    // word转pdf
    String targetPath = path + File.separator + "template" + File.separator + "convert" + File.separator + "pdf";
    LibreofficeUtils.wordConverterToPdf(docxFilePath, targetPath, osName);

    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_PDF);
    headers.setContentDispositionFormData("attachment", "tb.pdf");
      //输入docx
       //headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    //headers.setContentDispositionFormData("attachment", "tb.docx");

    ResponseEntity<byte[]> returnFile = new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(new File(pdfFilePath)), headers, HttpStatus.OK);

    deleteFile(new File(path + File.separator + "template" + File.separator + "convert" ));

    return returnFile;
    }

     四、controller类

    @RequestMapping(value = "/download-pdf", method = RequestMethod.GET)
    public ResponseEntity<byte[]> downloadPDF(HttpServletResponse response, ExamReportDTO examReport) throws Exception {
    return reportService.exportPDF(response, examReport);
    }

     五、pom.xml    (第一次word转Pdf用的是poi,4.1.2版本太高,所以转换报错,需要降低版本)

    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <!--<version>4.1.2</version>-->
    <version>3.12</version>
    </dependency>

    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <!--<version>4.1.2</version>-->
    <version>3.12</version>
    </dependency>

    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <!-- <version>4.1.2</version>-->
    <version>3.12</version>
    </dependency>

    <dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-scratchpad</artifactId>
    <!--<version>4.1.2</version>-->
    <version>3.12</version>
    </dependency>

    <!-- https://mvnrepository.com/artifact/org.apache.xmlbeans/xmlbeans -->
    <dependency>
    <groupId>org.apache.xmlbeans</groupId>
    <artifactId>xmlbeans</artifactId>
    <version>3.1.0</version>
    </dependency>

    <dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
    <version>1.0.6</version>
    </dependency>

    <dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itextpdf</artifactId>
    <version>5.5.11</version>
    </dependency>

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

    <dependency>
    <groupId>fr.opensagres.xdocreport</groupId>
    <artifactId>org.odftoolkit.odfdom.converter.pdf</artifactId>
    <version>1.0.6</version>
    </dependency>

    <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
    </dependency>

     六、最终实现此需求经历的过程

    1、先使用的itext,根据pdf模板,填写区域值,直接生成pdf文件,无需转换。

    难点:需要安装Adobe Acrobat DC,按照如下步骤,设计表单的域值。

    Pdf模板准备好后,可以自行百度,查询itext如何根据pdf模板,填充内容

    结果:最终没有选择这个方式,主要是因为,生成的pdf时,域值框,背景色是蓝色,没有多余时间研究如何变成白色,所以放弃了。

     

     

     2、使用poi   实现word转换pdf 

    service类     

    InputStream docxInputStream = new FileInputStream(docxFilePath);
    XWPFDocument document = new XWPFDocument(docxInputStream);
    OutputStream out = new FileOutputStream(pdfFilePath);

    PdfOptions options = PdfOptions.create();
    document.createNumbering();
    PdfConverter.getInstance().convert(document, out, options); // 需要注意,此类只能用低版本的Poi,所以把原来的4.1.2版本降为了3.12
    docxInputStream.close();
    out.close();

    结果:此方式有不足,word有复选框或者和合并单元格这种复杂样式时,转换后的Pdf格式错乱,所以放弃此方法

    3、使用libreoffice

    需要安装liberoffice ,并配置path环境变量   

    安装完后,可以从过cmd,来测试是否可行

     pdf 包路径     .docx文件路径   

     1)创建LibreofficeUtils工具类 

    import java.io.BufferedReader;
    import java.io.File;
    import java.io.IOException;
    import java.io.InputStreamReader;

    public class LibreofficeUtils {

    public static boolean wordConverterToPdf(String docxPath,String targetPath, String osName) throws IOException {
    File file = new File(docxPath);
    try {
    String command = "";
    if (osName.contains("Windows")) {
    command = "soffice --convert-to pdf -outdir " + targetPath + " " + docxPath;
    } else {
    command = "doc2pdf --output=" + targetPath + File.separator + file.getName().replaceAll(".(?i)docx", ".pdf") + " " + docxPath;
    }
    String result = executeCommand(command);
    if (result.equals("") || result.contains("writer_pdf_Export")) {
    return true;
    }
    } catch (Exception e) {
    e.printStackTrace();
    throw e;
    }
    return false;
    }

    private static String executeCommand(String command) {
    StringBuffer output = new StringBuffer();
    Process p;
    InputStreamReader inputStreamReader = null;
    BufferedReader reader = null;
    try {
    p = Runtime.getRuntime().exec(command);
    p.waitFor();
    inputStreamReader = new InputStreamReader(p.getInputStream(), "UTF-8");
    reader = new BufferedReader(inputStreamReader);
    String line = "";
    while ((line = reader.readLine()) != null) {
    output.append(line + " ");
    }
    } catch (IOException e) {
    e.printStackTrace();
    } catch (InterruptedException e) {
    e.printStackTrace();
    } finally {
    try {
    if (reader != null) {
    reader.close();
    }
    if (inputStreamReader != null) {
    inputStreamReader.close();
    }
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    System.out.println(output.toString());
    return output.toString();
    }
    }

    2) service 类

     // word转pdf
    String targetPath = path + File.separator + "template" + File.separator + "convert" + File.separator + "pdf";
    LibreofficeUtils.wordConverterToPdf(docxFilePath, targetPath, osName);

    3)用到的jar包
    <dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.4</version>
    </dependency>
    结果:经过多种方法尝试,此方法可行


    七、补充下,把pdf打成zip包代码实现

    service实现类:
        /**
    * 多文件打成zip包
    *
    * @param path 如:D:
    */
    private void pdfToZip(String path) {
    // String convertPath = path + File.separator + "template" + File.separator + "convert" + File.separator + "pdf";
    String convertPath = path + File.separator + "template" + File.separator + "convert";
    File dir = new File(convertPath);
    if (dir.isDirectory()) {
    List<File> file = new ArrayList<>();
    File[] files = dir.listFiles();
    File zipFile = new File(convertPath + File.separator + "tianbao.zip");
    for (int i = 0; i < files.length; i++) {
    File f = files[i];
    String fileName = f.getName();
    String suffix = fileName.substring(fileName.lastIndexOf("."));
    // if (suffix.equals(".pdf")) {
    if (suffix.equals(".docx")) {
    file.add(f);
    }
    }
    ZipUtils.toZip(file, zipFile);
    }
    }

    // 打包完zip后,输出
    String convertPath = path + File.separator + "template" + File.separator + "convert";
    // String zipPath = convertPath + File.separator + "pdf" + File.separator;
    String zipPath = convertPath + File.separator;
    HttpHeaders headers = new HttpHeaders();
    headers.setContentDispositionFormData("attachment", "tb.zip");
    ResponseEntity<byte[]> returnFile = new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(new File(zipPath + "tb.zip")), headers, HttpStatus.OK);
            // 删除文件
    deleteFile(new File(convertPath));
          retrun returnFile;


    private void deleteFile(File file) {
    if (file.isDirectory()) {
    File[] files = file.listFiles();
    for (int i = 0; i < files.length; i++) {
    deleteFile(files[i]);
    }
    }
    file.delete();
    }


    import org.springframework.boot.container.core.log.ZKLogger;
    import org.springframework.boot.container.core.log.ZKLoggerFactory;

    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.util.List;
    import java.util.zip.ZipEntry;
    import java.util.zip.ZipOutputStream;

    public class ZipUtils {
    private static final ZKLogger logger = ZKLoggerFactory.getLogger(ZipUtils.class);

    /**
    * 把文件集合打成zip压缩包
    * @param srcFiles 压缩文件集合
    * @param zipFile zip文件名
    * @throws RuntimeException 异常
    */
    public static void toZip(List<File> srcFiles, File zipFile) throws RuntimeException {
    long start = System.currentTimeMillis();
    if(zipFile == null){
    logger.error("压缩包文件名为空!");
    return;
    }
    if(!zipFile.getName().endsWith(".zip")){
    logger.error("压缩包文件名异常,zipFile={}", zipFile.getPath());
    return;
    }
    ZipOutputStream zos = null;
    FileOutputStream out = null;
    try {
    out = new FileOutputStream(zipFile);
    zos = new ZipOutputStream(out);
    for (File srcFile : srcFiles) {
    byte[] buf = new byte[10*1024];
    zos.putNextEntry(new ZipEntry(srcFile.getName()));
    int len;
    FileInputStream in = new FileInputStream(srcFile);
    while ((len = in.read(buf)) != -1) {
    zos.write(buf, 0, len);
    }
    //zos.setComment("我是注释");
    in.close();
    }
    zos.closeEntry();
    long end = System.currentTimeMillis();
    logger.info("压缩完成,耗时:" + (end - start) + " ms");
    } catch (Exception e) {
    logger.error("ZipUtil toZip exception, ", e);
    throw new RuntimeException("zipFile error from ZipUtils", e);
    } finally {
    if (zos != null) {
    try {
    zos.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    if (out != null) {
    try {
    out.close();
    } catch (IOException e) {
    e.printStackTrace();
    }
    }
    }
    }
    }


    由于需求变更,WordUtils里添加合并单元格功能:
    /**
    * word跨行并单元格
    * @param table 表格
    * @param col 合并行所在列
    * @param fromRow 开始行
    * @param toRow 结束行
    */
    public static void mergeCellsVertically(XWPFTable table, int col, int fromRow, int toRow) {
    for (int rowIndex = fromRow; rowIndex <= toRow; rowIndex++) {
    XWPFTableCell cell = table.getRow(rowIndex).getCell(col);
    if ( rowIndex == fromRow ) {
    cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
    } else {
    cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
    }
    }
    }








  • 相关阅读:
    Android通讯录查询篇ContactsContract.Data
    startActivityForResult 用法
    Android 开发 – 使用菜单
    屏幕旋转 转
    动态更改屏幕方向LANDSCAPE与PORTRAIT 转
    .使用ContactsContract API
    主题:android之XmlResourceParser类使用实例 转
    Android使用AttributeSet自定义控件的方法 转
    EmbossMaskFilter BlurMaskFilter
    字典转换成实体列表
  • 原文地址:https://www.cnblogs.com/ssk913/p/14025781.html
Copyright © 2020-2023  润新知