Java html转pdf批量生成打包zip浏览器下载到客户端

最近项目要改做一个需求,需求内容就是做一个批量导出的pdf功能,没接触过,所以在网上搜了很多内容,也碰到很多坑,现在自己总结一下,方便以后项目碰到。

1、首先maven依赖选择 刚开是用的是flying-saucer-pdf,但是其中碰到的问题是其中的getBBox问题,原生jar包会存在getBBox(I)问题,因为该依赖会下载flying-saucer-pdf,flying-saucer-core,还有自带的itext2.1.7jar包,导致报错,后来选择flying-saucer-pdf-itext5。

2、因为客户端访问服务器的时候,如果你选择了文件夹导出,那么会导出在服务器端,而客户端不行,尤其是java的图形化界面JFileChooser,该控件慎重使用。所以后来把原来的开发改掉,现在使用生成pdf然后打包成zip下载。

3、HTML内部中文与参数中文之间会出很大问题

4、图片问题

5、中文包问题iTextAsian问题 路径与iTextpdf包不同步

最后经过一周的努力终于把整个的过程完成了,现在贴一个小demo。

MAVEN依赖

          <dependency>
             <groupId>org.xhtmlrenderer</groupId>
             <artifactId>flying-saucer-pdf-itext5</artifactId>
            <version>9.1.6</version>
        </dependency>
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
            <version>2.3.23</version>
        </dependency>

其中还有到了ant.jar,iText-2.0.8.jar,iTextAsian.jar

https://download.csdn.net/download/u012832579/10652048 下载链接
主代码

    @RequestMapping(value = "pdfExport",method =  RequestMethod.GET)
    public void pdfExport(@RequestParam(value = "ids") String ids,Model model,HttpServletRequest request,HttpServletResponse response) throws IOException, DocumentException{

        String filePath = customerTaskService.getWorkUrl() + "xwjys/src/main/Webapp/extjs/zip";
        //删除zip包
        File file=new File(filePath+ "/file.zip");
        if(file.exists()){
            file.delete(); 
        }

        String path = customerTaskService.getWorkUrl().replace('/', '\\') +"xwjys\\src\\main\\Webapp\\extjs\\zip\\file";
        //删除本地zip以及残余pdf
        customerTaskService.delAllFile(path); //删除完里面所有内容
        String[] idss = ids.split(",");
        System.out.println("生成本地pdf");
        for(String id:idss){
            Model models = getModel(Long.valueOf(id),model);
            customerTaskService.pdfExport(models,filePath,id);
        }
        System.out.println("打包zip进行下载");
        customerTaskService.zipDowload(filePath, request, response);
        System.out.println("下载成功");
    }

以下代码对应主代码方法调用
获取本地路径

    //获取项目绝对路径
    public String getWorkUrl(){
        String t=Thread.currentThread().getContextClassLoader().getResource("").getPath(); 
        int num=t.indexOf(".metadata");
        return t.substring(1,num);
    }

删除上次生成的pdf

    public  boolean delAllFile(String path) {
        boolean flag = false;
        File file = new File(path);
        if (!file.exists()) {
          return flag;
        }
        if (!file.isDirectory()) {
          return flag;
        }
        String[] tempList = file.list();
        File temp = null;
        for (int i = 0; i < tempList.length; i++) {
           if (path.endsWith(File.separator)) {
              temp = new File(path + tempList[i]);
           } else {
               temp = new File(path + File.separator + tempList[i]);
           }
           if (temp.isFile()) {
              temp.delete();
           }
           if (temp.isDirectory()) {
              delAllFile(path + "/" + tempList[i]);//先删除文件夹里面的文件
              flag = true;
           }
        }
        return flag;
      }

HTML是一个模板,内容由自己的数据来填
生成pdf的内容 主要是看自己需要什么,用model来 存、html来取 将数据放在url中,看类型取,在html中用el表达式取 比如这个界面用${grcode.xxx}

 model.addAttribute("qrcode", url);

比如你也可以把model换成date,然后HTML中用${name}来获取中文

Map<String,Object> data = new HashMap<String,Object>();
data.put("name","小红");

生成pdf 方法 pdfExport

    public void pdfExport(Model model,String filePath,String id)throws IOException {
        //模板
        String HTML = "template_freemarker_fs.html";
        //名称
        String resource = filePath + "/file/" + id +".pdf";
        String content = freeMarkerRender(model, HTML);
        this.createPdf(content, resource);
    }

合并数据以及模板

    public String freeMarkerRender(Model data, String htmlTmp) {
        Writer out = new StringWriter();
        try {
            // 获取模板,并设置编码方式
            Configuration freemarkerCfg = new Configuration();
            String workUrl = getWorkUrl().replace('/', '\\');
            freemarkerCfg.setDirectoryForTemplateLoading(new File(workUrl+"xwjys\\src\\main\\webapp\\extjs\\templates"));
            freemarkerCfg.setDefaultEncoding("UTF-8");
            freemarkerCfg.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
            Template template = freemarkerCfg.getTemplate(htmlTmp);
            // 合并数据模型与模板
            template.process(data, out); //将合并后的数据和模板写入到流中,这里使用的字符流
            out.flush();
            return out.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                out.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        return null;
    }

本快主要的就是将pdf生成,其中设计图片,图片是在html中,setBaseURL代表的是该图片的绝对路径xxx/src/main/webapp/extjs/images/,如果你还需要别的图片,如果是同级目录的那么直接在html中写该图片的名称

    public void createPdf(String content,String dest) throws IOException{

        File file = new File(dest);
        //建立数据输出通道
        FileOutputStream fileOutputStream = new FileOutputStream(file);
        ITextRenderer render = new ITextRenderer();
        // 创建字体解析器
        ITextFontResolver fontResolver = render.getFontResolver();
        // 设置字体
        try{
            fontResolver.addFont(getWorkUrl()+ "xwjys/src/main/webapp/extjs/templates/simsun.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);         
        }catch(Exception e){
             e.printStackTrace();
        }
        // 解析html生成pdf
        render.setDocumentFromString(content);
        // 解决图片相对路径的问题

        String myUrl = getWorkUrl();
        render.getSharedContext().setBaseURL("file:/"+myUrl+"xwjys/src/main/webapp/extjs/images/bg_bz01.jpg");  
        render.layout();
        try {
            render.createPDF(fileOutputStream);
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        fileOutputStream.flush();
        fileOutputStream.close();

    }

这里写图片描述

然后开始将该pdf打包成zip 并提供浏览器下载

   public void zipDowload(String filePath,HttpServletRequest request,HttpServletResponse response) throws IOException{
         //打包文件的存放路径                     
       ZipCompressorByAnt  zc = new  ZipCompressorByAnt(filePath+ "/file.zip");
        //需要打包的文件路径
       zc.compress(filePath+ "/file/");

       //开始下载
       String userAgent = request.getHeader("USER-AGENT");
       //判断浏览器代理并分别设置响应给浏览器的编码格式
       String finalFileName = null;
       String fileZip = "file.zip";
       if(StringUtils.contains(userAgent, "MSIE")||StringUtils.contains(userAgent,"Trident")){//IE浏览器
           finalFileName = URLEncoder.encode(fileZip,"UTF8");
           System.out.println("IE浏览器");
       }else if(StringUtils.contains(userAgent, "Mozilla")){//google,火狐浏览器
           finalFileName = new String(fileZip.getBytes(), "ISO8859-1");
       }else{
           finalFileName = URLEncoder.encode(fileZip,"UTF8");//其他浏览器
       }
       response.reset();  
       response.setContentType("application/x-octet-stream;charset=utf-8");
       response.setHeader("Content-Disposition" ,"attachment;filename=\"" +finalFileName+ "\"");//下载文件的名称

       ServletOutputStream servletOutputStream = null;
       try {
           servletOutputStream = response.getOutputStream();
       } catch (IOException e1) {
           // TODO Auto-generated catch block
           e1.printStackTrace();
       }
       DataOutputStream temps = new DataOutputStream(servletOutputStream);

       DataInputStream in = new DataInputStream(
                               new FileInputStream(getWorkUrl().replace('/', '\\') +"xwjys\\src\\main\\Webapp\\extjs\\zip\\file.zip"));//浏览器下载文件的路径
       byte[] b = new byte[4096];
       try {
           while ( (in.read(b)) != -1) {
           temps.write(b);
       }
           temps.flush();
           response.getOutputStream().flush();
           if(response.getOutputStream()!=null) response.getOutputStream().close();
       } catch (Exception e) {
           e.printStackTrace();
       }finally{
           if(temps!=null) temps.close();
           if(in!=null) in.close();
           servletOutputStream.close();
       }
    }

ZipCompressorByAnt .java

package com.smarts.utils.fileupload;

import java.io.File;

import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Zip;
import org.apache.tools.ant.types.FileSet;

public class ZipCompressorByAnt {
    private File zipFile;  

    public ZipCompressorByAnt(String pathName) {  
        zipFile = new File(pathName);  
    }  

    public void compress(String srcPathName) {  
        File srcdir = new File(srcPathName);  
        if (!srcdir.exists())  
            throw new RuntimeException(srcPathName + "不存在!");  

        Project prj = new Project();  
        Zip zip = new Zip();      
        zip.setProject(prj);  
        zip.setDestFile(zipFile);  
        FileSet fileSet = new FileSet();  
        fileSet.setProject(prj);
        fileSet.setDir(srcdir);  
        //fileSet.setIncludes("**/*.java"); 包括哪些文件或文件夹 eg:zip.setIncludes("*.java");  
        //fileSet.setExcludes(...); 排除哪些文件或文件夹  
        zip.addFileset(fileSet);            
        zip.execute();  
    }  

}

前台js部分代码

var link= document.createElement('a');
        link.setAttribute("href", "../customertask/pdfExport?ids="+ids.toString());
        link.setAttribute("download", `file.zip`);
        link.style.visibility = 'hidden';
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);

template_freemarker_fs.html 支持换行,图片,中文

<!DOCTYPE html>
<html lang="en">
<head>
    <meta content="text/html; charset=UTF-8"/>
    <title>Title</title>
    <style>
        body{
            font-family:SimSun; 
        }
        .color{
            color: green;
        }
        .pos{
            position:absolute;
            left:200px;
            top:5px;
            width: 200px;
            font-size: 10px;
        }
    </style>
</head>
<body>
<img src="bg_bz01.jpg" width="50px"/>
<img src="bg_bz02.jpg" width="50px"/>
<div class="color:red">
     <strong>您好</strong>,   ${curBillInfo.ypName}  中啊是个回复爱国阿三帅哥俺是个啊个啊个十大个十大伽师瓜的阿三个的撒搞定撒个的撒个撒个撒个啊
     个啊大哥 啊高大上搞定撒个
</div>
</body>
</html>
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个通过Word模板生成DOCX文件并换为PDF,并提供浏览器下载Java代码示例: ```java import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpServletResponse; import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.poi.xwpf.usermodel.XWPFParagraph; import org.apache.poi.xwpf.usermodel.XWPFRun; import org.apache.poi.xwpf.usermodel.XWPFTable; import org.apache.poi.xwpf.usermodel.XWPFTableCell; import org.apache.poi.xwpf.usermodel.XWPFTableRow; import org.apache.xmlbeans.XmlCursor; import org.apache.xmlbeans.XmlException; import org.apache.xmlbeans.XmlObject; import org.apache.xmlbeans.XmlOptions; import org.docx4j.Docx4J; import org.docx4j.convert.out.pdf.PdfConversion; import org.docx4j.convert.out.pdf.viaXSLFO.ConversionOptions; import org.docx4j.fonts.IdentityPlusMapper; import org.docx4j.fonts.Mapper; import org.docx4j.model.structure.PageSizePaper; import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import org.docx4j.openpackaging.parts.WordprocessingML.MainDocumentPart; import org.docx4j.wml.CTBorder; import org.docx4j.wml.CTBorderPr; import org.docx4j.wml.CTTbl; import org.docx4j.wml.CTTblBorders; import org.docx4j.wml.CTTblGrid; import org.docx4j.wml.CTTblLayoutType; import org.docx4j.wml.CTTblPr; import org.docx4j.wml.CTTblWidth; import org.docx4j.wml.ObjectFactory; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class WordToPdfController { @RequestMapping(value = "/word-to-pdf", method = RequestMethod.GET) public void generatePdf(HttpServletResponse response) throws Exception { // 获取Word模板文件 File templateFile = new File("template.docx"); FileInputStream in = new FileInputStream(templateFile); // 替换Word中的变量 Map<String, String> variables = new HashMap<>(); variables.put("name", "John Doe"); variables.put("age", "30"); variables.put("address", "123 Main Street"); byte[] docxBytes = replaceVariables(in, variables); // 将DOCX文件换为PDF byte[] pdfBytes = convertToPdf(docxBytes); // 设置响应头 response.setContentType("application/pdf"); response.setHeader("Content-Disposition", "attachment; filename=output.pdf"); // 将PDF文件写入响应体 OutputStream out = response.getOutputStream(); out.write(pdfBytes); out.flush(); out.close(); } private byte[] replaceVariables(InputStream in, Map<String, String> variables) throws Exception { // 加载Word模板文件 WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(in); MainDocumentPart documentPart = wordMLPackage.getMainDocumentPart(); // 获取文档中的所有段落和表格 java.util.List<Object> paragraphsAndTables = documentPart.getContent(); // 遍历文档中的所有段落和表格 for(Object paragraphOrTable : paragraphsAndTables) { if(paragraphOrTable instanceof XWPFParagraph) { // 如果是段落,则替换其中的变量 XWPFParagraph paragraph = (XWPFParagraph) paragraphOrTable; for(XWPFRun run : paragraph.getRuns()) { String text = run.getText(0); if(text != null) { for(Map.Entry<String, String> entry : variables.entrySet()) { if(text.contains(entry.getKey())) { text = text.replace(entry.getKey(), entry.getValue()); run.setText(text, 0); } } } } } else if(paragraphOrTable instanceof XWPFTable) { // 如果是表格,则遍历其中的单元格并替换其中的变量 XWPFTable table = (XWPFTable) paragraphOrTable; for(XWPFTableRow row : table.getRows()) { for(XWPFTableCell cell : row.getTableCells()) { for(XWPFParagraph paragraph : cell.getParagraphs()) { for(XWPFRun run : paragraph.getRuns()) { String text = run.getText(0); if(text != null) { for(Map.Entry<String, String> entry : variables.entrySet()) { if(text.contains(entry.getKey())) { text = text.replace(entry.getKey(), entry.getValue()); run.setText(text, 0); } } } } } } } } } // 将修改后的文档保存为字节数组 ByteArrayOutputStream out = new ByteArrayOutputStream(); Docx4J.save(wordMLPackage, out); return out.toByteArray(); } private byte[] convertToPdf(byte[] docxBytes) throws Exception { // 加载DOCX文件 ByteArrayInputStream in = new ByteArrayInputStream(docxBytes); WordprocessingMLPackage wordMLPackage = WordprocessingMLPackage.load(in); // 设置字体映射 Mapper fontMapper = new IdentityPlusMapper(); wordMLPackage.setFontMapper(fontMapper); // 设置页面大小和边距 PageSizePaper pageSizePaper = new PageSizePaper(); pageSizePaper.setCode("A4"); wordMLPackage.getDocumentModel().getSections().get(0).getPageDimensions().setPageSize(pageSizePaper); wordMLPackage.getDocumentModel().getSections().get(0).getPageDimensions().setMarginTop(1440); wordMLPackage.getDocumentModel().getSections().get(0).getPageDimensions().setMarginBottom(1440); wordMLPackage.getDocumentModel().getSections().get(0).getPageDimensions().setMarginLeft(1440); wordMLPackage.getDocumentModel().getSections().get(0).getPageDimensions().setMarginRight(1440); // 获取文档中的所有表格 java.util.List<Object> tables = wordMLPackage.getMainDocumentPart().getContent(); for (Object obj : tables) { if (obj instanceof javax.xml.bind.JAXBElement && ((javax.xml.bind.JAXBElement<?>) obj).getDeclaredType().getName().equals("org.docx4j.wml.Tbl")) { javax.xml.bind.JAXBElement<org.docx4j.wml.Tbl> element = (javax.xml.bind.JAXBElement<org.docx4j.wml.Tbl>) obj; org.docx4j.wml.Tbl table = element.getValue(); // 设置表格边框 CTTbl ctTbl = table.getCTTbl(); CTTblPr tblPr = ctTbl.getTblPr(); if (tblPr == null) { tblPr = new CTTblPr(); ctTbl.setTblPr(tblPr); } CTTblBorders borders = tblPr.getTblBorders(); if (borders == null) { borders = new CTTblBorders(); tblPr.setTblBorders(borders); } CTBorder border = new CTBorder(); border.setColor("#000000"); border.setSz(new BigInteger("2")); CTBorderPr borderPr = new CTBorderPr(); borderPr.setTop(border); borderPr.setBottom(border); borderPr.setLeft(border); borderPr.setRight(border); borders.setTop(borderPr); borders.setBottom(borderPr); borders.setLeft(borderPr); borders.setRight(borderPr); // 设置表格宽度 CTTblGrid tblGrid = ctTbl.getTblGrid(); if (tblGrid == null) { tblGrid = new CTTblGrid(); ctTbl.setTblGrid(tblGrid); } for (int i = 0; i < table.getContent().size(); i++) { Object row = table.getContent().get(i); if (row instanceof javax.xml.bind.JAXBElement && ((javax.xml.bind.JAXBElement<?>) row).getDeclaredType().getName().equals("org.docx4j.wml.Tr")) { javax.xml.bind.JAXBElement<org.docx4j.wml.Tr> rowElement = (javax.xml.bind.JAXBElement<org.docx4j.wml.Tr>) row; org.docx4j.wml.Tr tr = rowElement.getValue(); for (int j = 0; j < tr.getContent().size(); j++) { Object cell = tr.getContent().get(j); if (cell instanceof javax.xml.bind.JAXBElement && ((javax.xml.bind.JAXBElement<?>) cell).getDeclaredType().getName().equals("org.docx4j.wml.Tc")) { javax.xml.bind.JAXBElement<org.docx4j.wml.Tc> cellElement = (javax.xml.bind.JAXBElement<org.docx4j.wml.Tc>) cell; org.docx4j.wml.Tc tc = cellElement.getValue(); CTTblWidth tblWidth = new CTTblWidth(); tblWidth.setType("dxa"); tblWidth.setW(BigInteger.valueOf(1000)); tc.getTcPr().setTcW(tblWidth); } } } } } } // 将文档换为PDF ConversionOptions conversionOptions = new ConversionOptions(); conversionOptions.setQuality(PdfConversionQualityEnum.PDF_A_1_B); OutputStream out = new ByteArrayOutputStream(); PdfConversion converter = new org.docx4j.convert.out.pdf.viaXSLFO.Conversion(wordMLPackage); converter.output(out, conversionOptions); return ((ByteArrayOutputStream) out).toByteArray(); } } ``` 在上述代码中,我们首先通过`replaceVariables()`方法将Word模板中的变量替换为实际值,然后通过`convertToPdf()`方法将DOCX文件换为PDF。最后,我们将PDF文件写入响应体并设置响应头,使得浏览器可以下载该文件。注意,这里我们使用了`docx4j`和`poi`两个开源库来处理Word和PDF文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值