poi填充word,动态生成表格+LibreOffice转成pdf

2023-01-02 00:00:00 表格 填充 转成

需求:

从数据库中查询体检卡的调拨记录,生成word,转成pdf,返回给前端,客户可以选择打印或者下载

这里使用poi把数据转成word,在使用LibreOffice把word转成pdf

至于为什么不直接制作pdf模板,是因为公司不想花钱买模板软件,所以选择的这个方案

效果图:

《poi填充word,动态生成表格+LibreOffice转成pdf》

 

1.poi填充wrod工具的类:实现动态生成表格+文本替换

import org.apache.poi.xwpf.usermodel.*;
import org.apache.xmlbeans.XmlCursor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;
import org.springframework.context.annotation.Configuration;

import java.io.*;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;


/**
 * poi生成word  并且动态生成表格
 * 参数1:word模板路径"D:\\ok\\体检卡出库单.docx"                                  templatePath
 * 参数2:文本替换map,key是word字段,value是替换的值                                 param
 * 参数3,动态表格的list数据                                                        list
 * 参数4:textList,中文表头集合list                                                textList
 * 参数5:word输出的位置+文件名                                                        outPath
 */
@Configuration
public class PoiDocUtils {

    public static void toDoc(String templatePath ,Map<String,String>param, List<Map<String, String>> list, List<String>textList,String outPath ) {

        InputStream in = null;
        OutputStream out = null;
        try {
            in = new FileInputStream(templatePath);
            XWPFDocument doc = new XWPFDocument(in);

            List<XWPFParagraph> allXWPFParagraphs = doc.getParagraphs();

            for (XWPFParagraph xwpfParagraph : allXWPFParagraphs) {
                List<XWPFRun> runs = xwpfParagraph.getRuns();
                for (XWPFRun run : runs) {
                    String text = run.getText(0);
                    if (text != null && text != "") {

                        //指定位置开始创建表格 用able作为标记
                        if (text.equals("able")) {

                            //动态集合格式封装成list<map>  这里定义map的key集合
                            //把要转成表格的list数据的key取出来 集成在一个表头list中
                            List<String> keyList = new ArrayList<String>();
                            Map<String, String> map = list.get(0);
                            Set<Map.Entry<String, String>> entries = map.entrySet();
                            for (Map.Entry<String, String> entry : entries) {
                                String key = entry.getKey();
                                keyList.add(key);
                            }


                            //表的行数
                            int rows = list.size();


                            //表的列数
                            int cols = textList.size();

                            XmlCursor cursor = xwpfParagraph.getCTP().newCursor();
                            XWPFTable tableOne = doc.insertNewTbl(cursor);


                            //样式控制
                            CTTbl ttbl = tableOne.getCTTbl();
                            CTTblPr tblPr = ttbl.getTblPr() == null ? ttbl.addNewTblPr() : ttbl.getTblPr();
                            CTTblWidth tblWidth = tblPr.isSetTblW() ? tblPr.getTblW() : tblPr.addNewTblW();
                            CTJc cTJc = tblPr.addNewJc();
                            cTJc.setVal(STJc.Enum.forString("center"));//表格居中
                            tblWidth.setW(new BigInteger("9000"));//每个表格宽度
                            tblWidth.setType(STTblWidth.DXA);


                            //表格的表头创建,去上边textList表头集合的字段
                            XWPFTableRow tableRowTitle = tableOne.getRow(0);

                            tableRowTitle.getCell(0).setText(textList.get(0));

                            for (int i = 1; i < textList.size(); i++) {
                                tableRowTitle.addNewTableCell().setText(textList.get(i));
                            }


                            for (Map<String, String> cardMap : list) {
                                //遍历list 得到要导出的每一行表格数据,数据结构是map

                                XWPFTableRow createRow = tableOne.createRow();

                                for (int i = 0; i < keyList.size(); i++) {
                                    String s = cardMap.get(keyList.get(i));
                                    createRow.getCell(i).setText(s);
                                }


                            }
                            run.setText("", 0);
                        } else {
                            for (Map.Entry<String, String> entry : param.entrySet()) {
                                String key = entry.getKey();
                                int i = text.indexOf(key);
                                if (text.indexOf(key) != -1) {
                                    text = text.replace(key, entry.getValue());
                                    run.setText(text, 0);
                                }
                            }
                        }
                    }
                }
            }

            out = new FileOutputStream(outPath);
            // 输出
            doc.write(out);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.close();
                }
                if (in != null) {
                    in.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

2.LibreOffice工具类实现word转pdf

import org.springframework.context.annotation.Configuration;

import java.io.IOException;

/**
 * office文件转pdf工具类
 */
@Configuration
public class LibreOfficePDFUtils {

    /**
     * 利用libreOffice将office文档转换成pdf
     * @param inputFile  doc文件全路径 :  文件夹+文件名
     * @param pdfFile    保存输出的文件夹名
     * @return
     */
    public static boolean convert2PDF(String inputFile, String pdfFile){
        String command;
        boolean flag;
        String osName = System.getProperty("os.name");
        System.out.println(osName);
        if (osName.contains("Windows")) {
            command = "cmd /c start soffice --headless --invisible --convert-to pdf:writer_pdf_Export " + inputFile + " --outdir " + pdfFile;
        }else {
            command = "libreoffice --headless --invisible --convert-to pdf:writer_pdf_Export " + inputFile + " --outdir " + pdfFile;
        }
        flag = executeCommand(command);
        return flag;
    }


    /**
     * 执行command指令
     * @param command
     * @return
     */
    public static boolean executeCommand(String command) {

        Process process;// Process可以控制该子进程的执行或获取该子进程的信息
        try {

            process = Runtime.getRuntime().exec(command);// exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。
            // 下面两个可以获取输入输出流
//            InputStream errorStream = process.getErrorStream();
//            InputStream inputStream = process.getInputStream();
        } catch (IOException e) {
            return false;
        }
        int exitStatus = 0;
        try {
            exitStatus = process.waitFor();// 等待子进程完成再往下执行,返回值是子线程执行完毕的返回值,返回0表示正常结束
            System.out.println(exitStatus);
            // 第二种接受返回值的方法
            int i = process.exitValue(); // 接收执行完毕的返回值
        } catch (InterruptedException e) {

            return false;
        }
        if (exitStatus != 0) {

        } else {

        }
        process.destroy(); // 销毁子进程
        return true;
    }

3.文件存储的服务器地址

application-dev.yml设置

file:
  docPath: D:/pdfData/

@Component
@ConfigurationProperties(prefix="file")
@Data
public class FileUploadConfig {
 
    //库存管理调拨记录的doc存储路径
    private String docPath;

}

4.代码实例

controller

    /**
     * 库存管理-打印调拨记录
     * @return
     */
    @PostMapping("/printAllocationRecord")
    public void printAllocationRecord(@RequestParam Long allocationRecordId ,HttpServletRequest request,HttpServletResponse response){

        try {
            //Long allocationRecordId = purchaseStockAllocationVO.getAllocationRecordId();
            reservationPhysicalCardMakeService.printAllocationRecord(allocationRecordId,request,response);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * 库存管理-打印调拨记录
     * @param allocationRecordId
     * @return
     */
    void printAllocationRecord(Long allocationRecordId, HttpServletRequest request,HttpServletResponse response);






    /**
     * 库存管理-打印调拨记录
     *
     * @param allocationRecordId
     * @return
     */
    @Override
    public void printAllocationRecord(Long allocationRecordId, HttpServletRequest request, HttpServletResponse response) {

        //根据前端的id查询数据库
        QueryWrapper<PurchaseAllocationRecord> purchaseAllocationRecordQueryWrapper = new QueryWrapper<>();
        purchaseAllocationRecordQueryWrapper.eq("par.id", allocationRecordId);

        //得到需要导出的结果
        List<StorageManageVO> result = purchaseAllocationRecordMapper.getResultList(purchaseAllocationRecordQueryWrapper);


        //初始化序号0,因为数据库没有这个序号字段,导出的pdf表格需要序号
        AtomicReference<Integer> number = new AtomicReference<>(0);

        //处理数据,得到word表格中的数据.list里是map
        List<Map<String, String>> list = result.stream().map(storageManageVO -> {

            //体检卡类型(0电子卡 1纸质卡)
            String physicalExaminationCardType = storageManageVO.getPhysicalExaminationCardType();

            if ("0".equals(physicalExaminationCardType)) {
                physicalExaminationCardType = "电子体检卡";

            } else {
                physicalExaminationCardType = "纸质体检卡";
            }

            //制卡方式(0:规则制卡 1:导入制卡)
            String makeCardWay = storageManageVO.getMakeCardWay();
            if ("0".equals(makeCardWay)) {
                makeCardWay = "规则制卡";

            } else {
                makeCardWay = "导入制卡";
            }

            Map<String, String> map = new LinkedHashMap<>();
            map.put("number", number.toString());
            map.put("physicalExaminationCardNo", storageManageVO.getPhysicalExaminationCardNo());
            map.put("productName", storageManageVO.getProductName());
            map.put("physicalExaminationYear", storageManageVO.getPhysicalExaminationYear());
            map.put("physicalExaminationCardType", physicalExaminationCardType);
            map.put("makeCardWay", makeCardWay);


            number.getAndSet(number.get() + 1);
            return map;
        }).collect(Collectors.toList());


        //读取word模板的绝对路径
        String templatePath = this.getClass().getClassLoader().getResource("templates/diaobodan.docx").getPath();

        //设置word中的文本替换集合
        Map<String, String> param = new HashMap<>();
        param.put("inAllocationName", result.get(0).getInAllocationName());
        param.put("outAllocationName", result.get(0).getOutAllocationName());
        param.put("createUser", result.get(0).getCreateUser());
        param.put("allocationCount", result.get(0).getAllocationCount().toString());
        param.put("createTime", result.get(0).getCreateTime());

        //设置中文表头数据
        List<String> textList = new ArrayList<String>();
        textList.add("序号");
        textList.add("体检卡号");
        textList.add("产品名称");
        textList.add("体检年度");
        textList.add("体检卡类型");
        textList.add("制卡方式");

        //服务器存储的文件夹地址  wind :D:/pdfData/
        String docPath = fileUploadConfig.getDocPath();

        //文件名 = 当前时间+uuid:4566-2342-22ee-4432,去掉横杠
        String fileName = LocalDate.now()+"-"+ UUID.randomUUID().toString().replaceAll("-", "");

        //doc保存全路径:   文件夹位置+文件名
        String docUrl = docPath + fileName + ".docx";

        //使用poi工具类,生成doc,第一个参数word模板的绝对路径,第二个参数,文本替换集合,第三个参数:word表格中的数据,第四个参数中文表头集合,第四个参数doc保存的全路径
        PoiDocUtils.toDoc(templatePath, param, list, textList, docUrl);

        System.out.println("doc生成完成");

        //利用libreOffice将office文档转换成pdf 参数一doc文件全路径 ;  参数二要保存的文件夹
        boolean b = LibreOfficePDFUtils.convert2PDF(docUrl, docPath);

        if (!b){
            throw new RuntimeException("doc转换pdf失败,LibreOffice异常");

        }else {


            //pdf保存全路径
            String pdfUrl = docPath + fileName + ".pdf";


            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            // ---------------把pdf转成流给前端,可以实现下载和打印---------------------------

            //把pdf文件的全路径转成file文件
            File pdfFile = new File(pdfUrl);

            //获取pdf文件的全路径
            String pdfSource = pdfFile.getPath();

            OutputStream outputStream = null;
            try {
                FileInputStream hFile = new FileInputStream(pdfSource); // 以byte流的方式打开文件
                int i = hFile.available(); // 得到文件大小
                byte data[] = new byte[i];
                hFile.read(data); // 读数据
                hFile.close();
                response.reset();
                response.resetBuffer();
                response.setContentType("application/pdf;charset-UTF-8"); // 设置返回的文件类型
                String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
                String name = URLEncoder.encode(time+".pdf","UTF-8");
                response.setCharacterEncoding("UTF-8");
                response.setHeader("Content-disposition", "attachment;filename=" +name);
                outputStream = response.getOutputStream(); // 得到向客户端输出二进制数据的对象
                outputStream.write(data); // 输出数据
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                try {
                    outputStream.flush();
                    outputStream.close();
                } catch (Exception ex) {
                }
            }
        }
        }

5.word模板

《poi填充word,动态生成表格+LibreOffice转成pdf》

 

    原文作者:ytqucheng
    原文地址: https://blog.csdn.net/quccc11/article/details/125124098
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。

相关文章