代码之家  ›  专栏  ›  技术社区  ›  Avijit Barua

无法在春季使用wkhtmltopdf将html页面生成为pdf

  •  0
  • Avijit Barua  · 技术社区  · 6 年前

    在我最近的spring项目中,我需要从html页面生成一个pdf文件。我正试着用 WkhtmlToPdf 是的。但是我无法从html页面生成pdf文件。我搜索了许多关于 WKHTMLTOPDF格式 但我没有找到答案。我在这里贴代码。 这是我的控制器类,它重定向到带有学生列表的html页面

    @Controller
    public class TestController {
    
        @Autowired
        StudentService studentService;
    
        @Autowired
        PdfDemo pdfDemo;
    
        @GetMapping("/test")
        private String testPage(Model model)
        {    
            List<Student> studentList = studentService.findAll();
            System.out.println(studentList);
           model.addAttribute(studentList);
            return "sample";
        }
    }
    

    这是我的html页面,显示学生列表

    <body>
    <div class="container" id="pdfDiv">
        <h2>HTML Table</h2>
        <table class="table table-striped">
            <tr>
                <th>Id</th>
                <th>Name</th>
                <th>Session</th>
                <th>Department</th>
                <th>Roll</th>
                <th>Mobile</th>
            </tr>
            <tr th:each="student : ${studentList}">
                <td th:text="${student.id}"></td>
                <td th:text="${student.name}"></td>
                <td th:text="${student.session}"></td>
                <td th:text="${student.department}"></td>
                <td th:text="${student.roll}"></td>
                <td th:text="${student.mobile}"></td>
            </tr>
        </table>
    </div>
    <a href="#" th:href="@{/getStudentsListAsPdf}">Download PDF</a>
    </body>
    

    在这里你可以看到,我有一个链接生成pdf。这个 PdfGenerateController 班级是

    @Controller
    public class PdfGenerateController {
    
        @GetMapping("/getStudentsListAsPdf")
        public ResponseEntity<Resource> generateReportOfStudent() {
    
            String downloadFilePath = generatePdfListForStudents();
            System.out.println("DL File Path: "+downloadFilePath);
            if (downloadFilePath == null)
                throw new NullPointerException("data missing");
    
            if (downloadFilePath == null)
                return ResponseEntity.badRequest()
                        .contentType(MediaType.parseMediaType("application/pdf"))
                        .body(null);
    
            File file = new File(downloadFilePath);
    
            Path path = Paths.get(file.getAbsolutePath());
            ByteArrayResource resource = null;
            try {
                resource = new ByteArrayResource(Files.readAllBytes(path));
            } catch (IOException e) {
                e.printStackTrace();
            }
    
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Disposition", "attachment; filename=\"student_list" + ".pdf\"");
    
            return ResponseEntity.ok()
                    .headers(headers)
                    .contentLength(file.length())
                    .contentType(MediaType.parseMediaType("application/pdf"))
                    .body(resource);
        }
    }
    

    这是编写代码生成pdf的类

    @Service
    public class PdfDemo {
    
        @Value("${file.download.base}")
        private String DOWNLOAD_FOLDER;
    
        public static final String DOWNLOAD_PATH = "tmp/downloads/";
        public static final String ZIP_PATH = "/tmp/zip_files";
        public static final String FILE_NAME = "student_list";
        public static final String SERVER_REPORT_URL = "/report/html";
        public static final String DOWNLOAD_FILE_PATH = DOWNLOAD_PATH + FILE_NAME;
        public static final String ZIPFILE = "/tmp/zip_files/cmed_report.zip";
        public static final String ZIPFILE_NAME = "cmed_report.zip";
        public static final String SRCDIR = "/tmp/downloads";
        public static final String DATE_FORMAT_PATTERN = "yyyy-MM-dd-HH";
    
        public static String getBaseURL() throws MalformedURLException {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder
                    .getRequestAttributes()).getRequest();
            String baseUrl = "";
            if (request != null) {
                // handle proxy forward
                String scheme = request.getScheme();
                if (request.getHeader("x-forwarded-proto") != null) {
                    scheme = request.getHeader("x-forwarded-proto");
                }
    
                Integer serverPort = request.getServerPort();
                if ((serverPort == 80) || (serverPort == 443)) {
                    // No need to add the server port for standard HTTP and HTTPS ports, the scheme will help determine it.
                    baseUrl = String.format("%s://%s%s", scheme, request.getServerName(), request.getContextPath());
                } else {
                    baseUrl = String.format("%s://%s:%d%s", scheme, request.getServerName(), serverPort, request.getContextPath());
                }
            }
    
            return baseUrl;
        }
    
        public static String generatePdfListForStudents()
        {
            WkHtmlToPdf pdf = new WkHtmlToPdf();
    
    
            try {
                pdf.addSources(Source.fromUrl(getServerAbsolutePath(SERVER_REPORT_URL)));
    
                System.out.println("Server absolute path: " + getServerAbsolutePath(SERVER_REPORT_URL));
                System.out.println(Source.fromUrl(getServerAbsolutePath(SERVER_REPORT_URL)));
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            String downloadPath = DOWNLOAD_FILE_PATH + ".pdf";
    
            pdf.addArguments(
                    Argument.from(EnableJavascript));
    
            System.out.println("PDF Location: " + downloadPath);
            // Save the PDF
            File file = new File(downloadPath);
            System.out.println("Directory status: " + file.exists() + " " + file.isDirectory());
    
            try {
                System.out.println("Paths.get: " + Paths.get(downloadPath));
    
                pdf.save(Paths.get(downloadPath));
            } catch (IOException e) {
                e.printStackTrace();
            }
            return downloadPath;
        }
    
        public static String getServerAbsolutePath(String requestPath) throws MalformedURLException {
            String URL = getBaseURL() + requestPath;
            return URL;
        }
    }
    

    这是 Controller SERVER_REPORT_URL 在里面 PdfDemo

    @Controller
    public class HtmlViewReportController {
    
        @Autowired
        StudentService studentService;
    
    
        @GetMapping(value = "/report/html")
        public String getPdfReportForStudent(Model model) {
            model.addAttribute("studentList", studentService.findAll());
            return "sample";
        }
    }
    

    现在,当我偶然发现 Download PDF 在html页面中 error 是的。此处为错误堆栈跟踪

    java.io.IOException: Cannot run program "wkhtmltopdf": error=2, No such file or directory
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1048)
        at java.lang.Runtime.exec(Runtime.java:620)
        at java.lang.Runtime.exec(Runtime.java:528)
        at com.ztomic.wkhtmltopdf.WkHtmlToPdf.convert(WkHtmlToPdf.java:84)
        at com.ztomic.wkhtmltopdf.WkHtmlToPdf.getPdfBytes(WkHtmlToPdf.java:77)
        at com.ztomic.wkhtmltopdf.WkHtmlToPdf.save(WkHtmlToPdf.java:68)
        at com.avijit.test.PdfUtil.PdfDemo.generatePdfListForStudents(PdfDemo.java:109)
        at com.avijit.test.Controller.PdfGenerateController.generateReportOfStudent(PdfGenerateController.java:28)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:155)
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:123)
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
    Caused by: java.io.IOException: error=2, No such file or directory
        at java.lang.UNIXProcess.forkAndExec(Native Method)
        at java.lang.UNIXProcess.<init>(UNIXProcess.java:247)
        at java.lang.ProcessImpl.start(ProcessImpl.java:134)
        at java.lang.ProcessBuilder.start(ProcessBuilder.java:1029)
        ... 71 more
    DL File Path: tmp/downloads/student_list.pdf
    java.nio.file.NoSuchFileException: /home/dracula/IdeaProjects/WkhtmlToPdfGeneratorProject/tmp/downloads/student_list.pdf
        at sun.nio.fs.UnixException.translateToIOException(UnixException.java:86)
        at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:102)
        at sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:107)
        at sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:214)
        at java.nio.file.Files.newByteChannel(Files.java:361)
        at java.nio.file.Files.newByteChannel(Files.java:407)
        at java.nio.file.Files.readAllBytes(Files.java:3152)
        at com.avijit.test.Controller.PdfGenerateController.generateReportOfStudent(PdfGenerateController.java:43)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:635)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:851)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:155)
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:123)
        at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:800)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1471)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)
    

    这里是Github link 是的。如果有人能解决这个问题,那将是非常有帮助的。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Guilherme Alencar    5 年前

    你在你的机器上安装了wkhtmltopf吗?试穿一下 https://wkhtmltopdf.org/downloads.html

    我用一种更简单的方式使用了

    import com.github.jhonnymertz.wkhtmltopdf.wrapper.Pdf;
    

    生成pdf看起来更容易,如下所示:

    @Override
    public String save(String url) throws IOException, InterruptedException{
        Pdf pdf = new Pdf();
        pdf.addPageFromUrl(url);
        return mockSaveS3(pdf);
    }
    
    private String mockSaveS3(Pdf pdf) throws IOException, InterruptedException{
        File fileTemp = File.createTempFile("pdf-", "");
        File file = pdf.saveAs("apps/" + fileTemp.getName());
        return file.getAbsolutePath();
    }
    

    然后我将url返回到我存储在 apps/ 目录。

        2
  •  0
  •   Avijit Barua    5 年前

    我解决了这个问题。花了很长时间才解决。我在媒体上一步一步写博客。我在这里发布了这个链接。你可以看到这里所有的台阶。我还提供了示例项目的github链接。看 here