【问题标题】:How to implement automatic printing for a website?如何实现网站的自动打印?
【发布时间】:2014-02-07 10:54:59
【问题描述】:

上下文:网站的用户必须打印一些页面(报告)生成的客户端(HTML/CSS)。现在,他们需要一个能够自动打印每份报告的功能。

浏览器和服务器(Java)都可以访问打印机。

我的选择

1 / 让浏览器在没有用户操作的情况下打印报告(使用 window.print() )

-> 我认为不可能,会打开一个窗口,用户必须进行验证

2 /在服务器上启动浏览器,打印报告并关闭浏览器

-> 看起来相当复杂。有没有办法在不打开浏览器的情况下从 Java 生成 HTML/CSS/javascript 内容?

3 / 使用 Java 生成和打印报告

-> 工作起来很容易,但我必须在客户端和服务器端生成报告......我想避免这种情况。如果这是唯一的解决方案,我可以在使用 java 生成 PDF 时使用我的 CSS 吗?

其他? / 还有其他我没有想过的选择吗?

仅供参考:我们可以强制用户使用特定浏览器的特定版本

【问题讨论】:

  • 我不明白什么是导航器,但是使用写报告是在客户端生成的。为什么不使用以下 javascript 代码打印页面: function print() { document.frmForm.submit();窗口.打印(); } 或类似的东西。
  • 哦,对不起...我的英语不正确:我已经编辑了我的信息。我的意思是“浏览器”。 window.print() 将显示一个确认窗口,所以它需要用户操作,不是吗?
  • 是的,需要用户操作

标签: java html css browser printing


【解决方案1】:

我编写了一个 Java servlet,它为基于 Intranet 的 web 应用程序执行此操作,它看起来就像您正在使用的打印机请求一样。

servlet 可能会被清理一些,但本质上它使用a Java library built on wkhtmltopdf 从请求正文中解析 HTML,然后根据请求选项/方法执行以下三件事之一:

  1. 以 pdf 格式下载到客户端
  2. 将 pdf 内容打印到网络打印机之一
  3. 将 pdf 预渲染到服务器上的文件以供以后打印 / 下载

我最近还获得了允许装订、双面打印、选择托盘等的打印功能,请参阅print 方法:

import java.awt.print.PrinterJob;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.Socket;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.attribute.standard.Media;
import javax.print.attribute.standard.MediaTray;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import io.woo.htmltopdf.HtmlToPdf;
import io.woo.htmltopdf.HtmlToPdfException;
import io.woo.htmltopdf.HtmlToPdfObject;
import io.woo.htmltopdf.PdfPageSize;

public class PDFServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;
    private static final Logger myLog = LoggerFactory.getLogger(PDFServlet.class);
    private static final String PDF_CONTENT = "application/pdf";
    private static final String JSON_CONTENT = "application/json; charset=UTF-8";
    private static final String DOWNLOAD_FILE = "attachment;filename=%s.pdf";
    private static final String REQUEST_STATUS = "[{\"success\":%s}]";
    private static final String ERROR_MSG = "Error with %s request: ";

    private Map<String, File> myRenderMap = new HashMap<String, File>();
    private File myRenderDir;

    @Override
    public void init(ServletConfig config) throws ServletException {

        super.init(config);
        ServletContext servletContext = this.getServletContext();
        String appRoot = servletContext.getRealPath("/");
        myRenderDir = new File(appRoot + "render");
        if (myRenderDir.exists()) 
        {
            try 
            {
                FileUtils.cleanDirectory(myRenderDir);
            } 
            catch (IOException e) 
            {
                myLog.error("Unable to clean render directory.", e);
            }
        }
        else
        {
            myRenderDir.mkdirs();
        }
        myLog.debug("Initialized PDFServlet");

    }

    // downloads to client (or prints) a pre-rendered pdf
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException  {       

        try
        {
            String resourceId = request.getParameter("resourceId");
            String printer = request.getParameter("printer");
            String tray = request.getParameter("tray");
            String duplex = request.getParameter("duplex");
            String staple = request.getParameter("staple");

            if (resourceId == null || resourceId.equals("*") || resourceId.equals("resources"))
            {
                myLog.debug("Retrieving resources list for GET request: "
                        + request.getRequestURI()
                        + (request.getQueryString() != null ? "?" + request.getQueryString() : ""));

                response.setContentType(JSON_CONTENT);
                response.setStatus(200);
                try (PrintWriter out = response.getWriter())
                {
                    out.println(getResources());
                }
            }
            else if (resourceId.equalsIgnoreCase("printers"))
            {
                myLog.debug("Retrieving printers list for GET request: "
                        + request.getRequestURI()
                        + (request.getQueryString() != null ? "?" + request.getQueryString() : ""));

                response.setContentType(JSON_CONTENT);
                response.setStatus(200);
                try (PrintWriter out = response.getWriter())
                {
                    out.println(getPrinters());
                }
            }
            else if (myRenderMap.containsKey(resourceId))
            {
                myLog.debug("Retrieving pdf resource for GET request: "
                        + request.getRequestURI()
                        + (request.getQueryString() != null ? "?" + request.getQueryString() : ""));

                while (myRenderMap.containsKey(resourceId) && myRenderMap.get(resourceId) == null)
                {
                    Thread.sleep(100);
                }

                File file = myRenderMap.get(resourceId);

                // print
                if (printer != null)
                {
                    myLog.debug("Printing existing resource: " + resourceId);
                    byte[] document = Files.readAllBytes(file.toPath());
                    boolean printed = print(document, printer, resourceId, tray, duplex, staple);
                    response.setContentType(JSON_CONTENT);
                    response.setStatus(printed ? 200 : 500);
                    try (PrintWriter out = response.getWriter())
                    {
                        out.println(String.format(REQUEST_STATUS, String.valueOf(printed)));
                    }
                }

                // download
                else
                {
                    myLog.debug("Downloading existing resource: " + resourceId);
                    try (InputStream in = FileUtils.openInputStream(file)) 
                    {
                        response.setContentType(PDF_CONTENT);
                        response.setHeader("Content-Disposition", String.format(DOWNLOAD_FILE, resourceId));
                        ServletOutputStream out = response.getOutputStream();
                        IOUtils.copy(in, out);
                    } 
                    catch (HtmlToPdfException e) 
                    {
                        myLog.error("HTML to PDF conversion error.", e);
                    }
                }
            }
            else
            {
                myLog.debug("Resource does not exist for GET request: "
                        + request.getRequestURI()
                        + (request.getQueryString() != null ? "?" + request.getQueryString() : ""));

                response.setContentType(JSON_CONTENT);
                response.setStatus(500);
                try (PrintWriter out = response.getWriter())
                {
                    out.println(String.format(REQUEST_STATUS, "false"));
                }
            }
        }
        catch (Exception e)
        {
            String msg = String.format(ERROR_MSG, "GET") 
                    + request.getRequestURI() 
                    + (request.getQueryString() != null ? "?" + request.getQueryString() : "");

            myLog.error(msg, e);
            throw new ServletException(msg, e);
        }
    }

    // downloads to client (or prints) a pdf that is created from the body content
    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException  {

        myLog.debug("Retrieving pdf resource for POST request: "
                + request.getRequestURI()
                + (request.getQueryString() != null ? "?" + request.getQueryString() : ""));

        try
        {
            String resourceId = request.getParameter("resourceId");
            String size = request.getParameter("size");
            String printer = request.getParameter("printer");
            String tray = request.getParameter("tray");
            String duplex = request.getParameter("duplex");
            String staple = request.getParameter("staple");

            if (resourceId == null)
            {
                resourceId = request.getContextPath().substring(1);
            }

            // resource is currently being rendered
            if (myRenderMap.containsKey(resourceId) && myRenderMap.get(resourceId) == null)
            {
                myLog.debug("Waiting for rendering: " + resourceId);
                while (myRenderMap.containsKey(resourceId) && myRenderMap.get(resourceId) == null)
                {
                    Thread.sleep(100);
                }
            }

            // resource is not already rendered
            if (!myRenderMap.containsKey(resourceId))
            {
                myLog.debug("Newly rendering resource: " + resourceId);
                String[] content = IOUtils.toString(request.getReader()).split("\\|", -1);   
                HtmlToPdf html = create(content);

                html.documentTitle(resourceId);

                if (size != null)
                {
                    html.pageSize(PdfPageSize.valueOf(size));
                }
                else
                {
                    html.pageSize(PdfPageSize.Letter);
                }

                // print
                if (printer != null)
                {
                    myLog.debug("Printing new resource: " + resourceId);
                    ByteArrayOutputStream baos = new ByteArrayOutputStream();
                    IOUtils.copy(html.convert(), baos);
                    byte[] document = baos.toByteArray();
                    boolean printed = print(document, printer, resourceId, tray, duplex, staple);
                    response.setContentType(JSON_CONTENT);
                    response.setStatus(printed ? 200 : 500);
                    try (PrintWriter out = response.getWriter())
                    {
                        out.println(String.format(REQUEST_STATUS, String.valueOf(printed)));
                    }
                }

                // download
                else
                {
                    myLog.debug("Downloading new resource: " + resourceId);
                    try (InputStream in = html.convert()) 
                    {
                        response.setContentType(PDF_CONTENT);
                        response.setHeader("Content-Disposition", String.format(DOWNLOAD_FILE, resourceId));
                        ServletOutputStream out = response.getOutputStream();
                        IOUtils.copy(in, out);
                    } 
                    catch (HtmlToPdfException e) 
                    {
                        myLog.error("HTML to PDF conversion error.", e);
                    }
                }
            }

            // resource is already rendered (use file)
            else
            {
                myLog.debug("Resource already exists: " + resourceId);
                File file = myRenderMap.get(resourceId);

                // print
                if (printer != null)
                {
                    myLog.debug("Printing existing resource: " + resourceId);
                    byte[] document = Files.readAllBytes(file.toPath());
                    boolean printed = print(document, printer, resourceId, tray, duplex, staple);
                    response.setContentType(JSON_CONTENT);
                    response.setStatus(printed ? 200 : 500);
                    try (PrintWriter out = response.getWriter())
                    {
                        out.println(String.format(REQUEST_STATUS, String.valueOf(printed)));
                    }
                }

                // download
                else
                {
                    myLog.debug("Downloading existing resource: " + resourceId);
                    try (InputStream in = FileUtils.openInputStream(file)) 
                    {
                        response.setContentType(PDF_CONTENT);
                        response.setHeader("Content-Disposition", String.format(DOWNLOAD_FILE, resourceId));
                        ServletOutputStream out = response.getOutputStream();
                        IOUtils.copy(in, out);
                    } 
                    catch (Exception e) 
                    {
                        myLog.error("Unable to download existing resource.", e);
                    }
                }
            }
        }
        catch (Exception e)
        {
            String msg = String.format(ERROR_MSG, "POST") 
                    + request.getRequestURI() 
                    + (request.getQueryString() != null ? "?" + request.getQueryString() : "");

            myLog.error(msg, e);
            throw new ServletException(msg, e);
        }
    }

    // pre-renders a pdf that is created from the body content
    @Override
    public void doPut(HttpServletRequest request, HttpServletResponse response)
            throws ServletException  {       

        myLog.debug("Rendering pdf resource for PUT request: "
                + request.getRequestURI()
                + (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
        try
        {
            String resourceId = request.getParameter("resourceId");
            String size = request.getParameter("size");
            boolean created = false;

            if (resourceId == null)
            {
                resourceId = request.getContextPath().substring(1);
            }

            if (!myRenderMap.containsKey(resourceId))
            {
                myRenderMap.put(resourceId, null);
                String filePath = myRenderDir.getAbsolutePath() + "/" + resourceId + ".pdf";
                String[] content = IOUtils.toString(request.getReader()).split("\\|", -1);  
                HtmlToPdf html = create(content);

                html.documentTitle(resourceId);

                if (size != null)
                {
                    html.pageSize(PdfPageSize.valueOf(size));
                }
                else
                {
                    html.pageSize(PdfPageSize.Letter);
                }
                created = html.convert(filePath);

                if (created)
                {
                    myRenderMap.put(resourceId, new File(filePath));
                }
                else
                {
                    myRenderMap.remove(resourceId);
                }
            }
            else
            {
                while (myRenderMap.get(resourceId) == null && myRenderMap.containsKey(resourceId))
                {
                    Thread.sleep(100);
                }
                created = myRenderMap.containsKey(resourceId);
            }

            response.setContentType(JSON_CONTENT);
            response.setStatus(created ? 200 : 500);
            try (PrintWriter out = response.getWriter())
            {
                out.println(String.format(REQUEST_STATUS, String.valueOf(created)));
            }
        }
        catch (Exception e)
        {
            String msg = String.format(ERROR_MSG, "PUT") 
                    + request.getRequestURI() 
                    + (request.getQueryString() != null ? "?" + request.getQueryString() : "");

            myLog.error(msg, e);
            throw new ServletException(msg, e);
        }
    }

    // removes pre-rendered pdf from server files
    @Override
    public void doDelete(HttpServletRequest request, HttpServletResponse response)
            throws ServletException  {    

        myLog.debug("Removing pdf resource for DELETE request: "
                + request.getRequestURI()
                + (request.getQueryString() != null ? "?" + request.getQueryString() : ""));
        try
        {
            String resourceId = request.getParameter("resourceId");
            List<String> toRemove = new ArrayList<String>();
            long now = Calendar.getInstance().getTimeInMillis();
            for (String key : myRenderMap.keySet())
            {
                myLog.debug("Checking: " + key);
                File file = myRenderMap.get(key);
                if (file == null)
                {
                    Thread.sleep(10000); // wait 10 seconds to see if it renders
                }

                if (file == null || // the file doesn't actually exist
                    now - file.lastModified() > (1000 * 60 * 30) || // delete anything older than 30 minutes
                    key.equals(resourceId)) // requested to delete
                {
                    toRemove.add(key);
                }
            }

            myLog.debug("Removing: " + Arrays.toString(toRemove.toArray()));
            for (String key : toRemove)
            {
                myRenderMap.get(key).delete();
                myRenderMap.remove(key);
            }

            response.setContentType(JSON_CONTENT);
            response.setStatus(200);
            try (PrintWriter out = response.getWriter())
            {
                out.println(String.format(REQUEST_STATUS, "true"));
            }
        }
        catch (Exception e)
        {
            String msg = String.format(ERROR_MSG, "DELETE") 
                    + request.getRequestURI() 
                    + (request.getQueryString() != null ? "?" + request.getQueryString() : "");

            myLog.error(msg, e);
            throw new ServletException(msg, e);
        }
    }


    private HtmlToPdf create(String[] content)
    {
        HtmlToPdf html = HtmlToPdf.create();

        for (String document : content)
        {
            if (document.startsWith("<") && document.endsWith(">"))
            {
                html.object(HtmlToPdfObject.forHtml(document));
            }
            else
            {
                html.object(HtmlToPdfObject.forUrl(document));
            }
        }
        return html;
    }

    private boolean print(byte[] document, String printerIpAddress, String title, String tray, String duplex, String staple)
    {
        boolean success = false;
        List<byte[]> commands = new ArrayList<byte[]>();

        if (title != null)
        {
            commands.add(("@PJL SET JOBNAME=" + title + "\n").getBytes());
        }

        if (tray != null)
        {
            commands.add(("@PJL SET MEDIASOURCE=" + tray + "\n").getBytes());
        }

        if (staple != null)
        { 
            commands.add(("@PJL SET STAPLEOPTION=ONE\n").getBytes());
        }

        if (duplex != null)
        {
            commands.add(("@PJL SET DUPLEX=ON\n").getBytes());
            if (duplex.equalsIgnoreCase("short"))
            {
                commands.add(("@PJL SET BINDING=SHORTEDGE\n").getBytes());
            }
            else if (duplex.equalsIgnoreCase("long"))
            {
                commands.add(("@PJL SET BINDING=LONGEDGE\n").getBytes());
            }
        }

        try (Socket socket = new Socket(printerIpAddress, 9100))
        {
            DataOutputStream out = new DataOutputStream(socket.getOutputStream());

            out.write(27);
            out.write("%-12345X@PJL\n".getBytes());
            for (byte[] command : commands)
            {
                out.write(command);
            }
            out.write("@PJL ENTER LANGUAGE=PDF\n".getBytes());
            out.write(document);
            out.write(27);
            out.write("%-12345X".getBytes());
            out.flush();
            out.close();

            success = true;
        }
        catch (Exception e)
        {
            System.out.println(e);
        }
        return success;
    }

    private String getResources()
    {
        List<String> toRemove = new ArrayList<String>();
        StringBuilder json = new StringBuilder("[");
        long now = Calendar.getInstance().getTimeInMillis();
        for (String key : myRenderMap.keySet())
        {
            File file = myRenderMap.get(key);
            if (file != null)
            {
                if (now - file.lastModified() > (1000 * 60 * 30)) // delete anything older than 30 minutes
                {
                    toRemove.add(key);
                }
                else
                {
                    json.append("{\"resourceId\":\"");
                    json.append(key);
                    json.append("\"},");
                }
            }
        }

        if (json.length() > 1)
        {
            json.setLength(json.length() - 1);
        }
        json.append("]");

        for (String key : toRemove)
        {
            myRenderMap.get(key).delete();
            myRenderMap.remove(key);
        }

        return json.toString();
    }

    private String getPrinters()
    {
        StringBuilder json = new StringBuilder("[");
        PrintService[] services = PrinterJob.lookupPrintServices();
        DocFlavor flavor = DocFlavor.SERVICE_FORMATTED.PRINTABLE;

        for (PrintService service : services)
        {
            json.append("{\"printer\":\"");
            json.append(service.getName());
            json.append("\",\"trays\":[");

            Object o = service.getSupportedAttributeValues(Media.class, flavor, null);
            if (o != null && o.getClass().isArray())
            {
                for (Media media : (Media[]) o)
                {
                    if (media instanceof MediaTray)
                    {
                        json.append("\"");
                        json.append(media.toString());
                        json.append("\",");
                    }
                }

                if (json.charAt(json.length() - 1) == ',')
                {
                    json.setLength(json.length() - 1);
                }
            }
            json.append("]},");
        }

        if (json.length() > 1)
        {
            json.setLength(json.length() - 1);
        }
        json.append("]");

        return json.toString();
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-14
    • 1970-01-01
    • 2017-06-02
    • 2011-05-06
    • 2015-04-29
    • 1970-01-01
    相关资源
    最近更新 更多