web应用票据打印实现(四)

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/ape_goku/article/details/44303805

上一篇中,我们已经通过iText生成了共打印的pdf文档,如果没有特别的要求,利用浏览器的pdf插件来预览和打印已经能供满足我们Web应用在浏览器端实现票据套打的要求了。但在我们的项目中,客户要求一次操作之后连续进行打印,即使用不同的数据填充模板,连续套打上百张的票据。
当时考虑的实现方式有两种:

  • 生成一个多页的pdf文档,还是利用浏览器的pdf插件来进行打印
  • 生成多个pdf文档,使用applet利用java print service来进行浏览器端的连续打印

最终我们选择了第二种方案,好处是浏览器不用打开新的tab来显示pdf文档,用户的注意力可以始终停留在同一页面。此外打印选项可以直接显示在页面中,比较直观。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.print.*;

import java.io.IOException;
import java.io.InputStream;

import java.nio.ByteBuffer;

import javax.print.PrintService;
import javax.print.PrintServiceLookup;

import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;
import com.sun.pdfview.PDFPrintPage;

public class PDFPrintApplet extends JApplet implements ActionListener {
    /**
     * 
     */
    private static final long serialVersionUID = 6293078385198700265L;

    private PrintService[] services;
    private boolean degugFlg = true;
    private PrinterJob pjob = PrinterJob.getPrinterJob();
    private JComboBox printerList;
    private JButton printBtn;

    public void init() {
        // 创建applet的GUI,由event dispatching thread运行
        try {
            SwingUtilities.invokeAndWait(new Runnable() {
                public void run() {
                    createGUI();
                }
            });
        } catch (Exception e) {
            System.err.println("createGUI didn't complete successfully");
        }
    }

    //简单的打印选项UI,只包括选择打印机,可以根据需要添加更多的选项
    private void createGUI() {
        JLabel lbl = new JLabel("选择打印机: ");
        String[] printerServiceNames = getAllAvailablePrintServicesNames();
        printerList = new JComboBox(printerServiceNames);
        printerList.addActionListener(this);

        JPanel printerSelectorPanel = new JPanel(new FlowLayout());
        printerSelectorPanel.setBackground(Color.WHITE);
        printerSelectorPanel.add(lbl);
        printerSelectorPanel.add(printerList);

        JPanel buttonPanel = new JPanel();
        buttonPanel.setBackground(Color.WHITE);

        printBtn = new JButton("打印");
        printBtn.addActionListener(this);
        buttonPanel.add(printBtn);

        setLayout(new GridLayout(2, 1));
        add(printerSelectorPanel);
        add(buttonPanel);
    }

    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == printBtn) {
            launchPrint();
        } else if (e.getSource() == printerList) {
            JComboBox cb = (JComboBox) e.getSource();
            String printerName = (String) cb.getSelectedItem();
            setSelectedPrintService(printerName);
        }
    }

    //得到要打印的pdf文件的url列表,并开始打印
    private void launchPrint() {
        final List<String> inputArr = convertArrayParameter(getParameter("pdfFileNameArray"));
        try {
            List<URL> pdfInputStreamList = load(inputArr);          
            print(pdfInputStreamList);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    // 根据传给Applet的参数,下载相应的PDF文件,生成URL
    private List<URL> load(List<String> fileNameList)
            throws URISyntaxException, IOException {
        List<URL> pdfURLList = new ArrayList<URL>();
        for (String fileName : fileNameList) {
            URL url = new URL(fileName);
            pdfURLList.add(url);
        }
        return pdfURLList;
    }

    // 解析传给Applet的参数,将以逗号分隔的字符串分成参数List
    private List<String> convertArrayParameter(String parameterArrStr) {
        List<String> list = new ArrayList<String>();
        String[] parameterArr = parameterArrStr.split(",");
        Collections.addAll(list, parameterArr);
        return list;
    }

    // 将InputStream转为ByteBuffer
    private ByteBuffer getByteBufferFormInputStream(InputStream is)
            throws IOException {
        int BUFSIZE = 1024;
        List<Byte> byteV = new ArrayList<Byte>();
        byte[] tmp1 = new byte[BUFSIZE];
        while (true) {
            int r = is.read(tmp1, 0, BUFSIZE);
            if (r == -1)
                break;
            for (int i = 0; i < r; i++) {
                byteV.add(new Byte(tmp1[i]));
            }
        }
        byte[] tmp2 = new byte[byteV.size()];
        for (int i = 0; i < byteV.size(); i++) {
            tmp2[i] = byteV.get(i).byteValue();
        }
        return ByteBuffer.wrap(tmp2);
    }

    // 得到本地所有可用的打印服务名
    private String[] getAllAvailablePrintServicesNames() {
        services = PrintServiceLookup.lookupPrintServices(null, null);
        if (services.length == 0) {
        }
        String[] printServicesNames = new String[services.length];
        for (int i = 0; i < services.length; i++) {
            printServicesNames[i] = services[i].getName();
        }
        return printServicesNames;
    }

    // 设置要使用的打印服务
    private void setSelectedPrintService(String serviceName) {
        try {
            for (PrintService service : services) {
                if (service.getName().equals(serviceName)) {
                    pjob.setPrintService(service);
                    return;
                }
            }
        } catch (PrinterException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void setDefaultPrintService() {
        services = PrintServiceLookup.lookupPrintServices(null, null);
        while (services.length == 0) {
            services = PrintServiceLookup.lookupPrintServices(null, null);
        }
        int j = 0;
        for (PrintService ps : services) {
            if (ps.getName().equals("doPDF v7")) {
                try {
                    pjob.setPrintService(services[j]);
                } catch (PrinterException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } else {
                j++;
            }
        }
    }

    //执行打印
    private void print(List<URL> pdfURLList) throws IOException {
        if (pjob.getPrintService() == null && degugFlg == true) {
            setDefaultPrintService();
        }

        for (URL pdfURL : pdfURLList) {
            ByteBuffer buf = getByteBufferFormInputStream(pdfURL.openStream());
            PDFFile pdfFile = new PDFFile(buf);
            PDFPrintPage pages = new PDFPrintPage(pdfFile);
            PDFPage page = pdfFile.getPage(1);

            PageFormat pf = pjob.defaultPage();
            pf.setOrientation(PageFormat.PORTRAIT);

            Paper paper = new Paper();
            paper.setSize(page.getWidth(), page.getHeight());
            // This is to fix an error in PDF-Renderer
            // View
            // http://juixe.com/techknow/index.php/2008/01/17/print-a-pdf-document-in-java/
            // for details
            // Printing a PDF is also possible by sending the bytes directly to
            // the printer, but
            // the printer would have to support it.

            paper.setImageableArea(0, 0, paper.getWidth() * 2,
                    paper.getHeight());

            Book book = new Book();
            pf.setPaper(paper);
            book.append(pages, pf, 1);
            pjob.setPageable(book);
            try {
                pjob.print();
            } catch (PrinterException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
}

上面是applet代码,通过Java Network Launch Protocol (JNLP) 协议来部署applet,并传入数据,JS代码如下:

var attributes = {
    code:'PDFPrintApplet',
    width:500, height:200} ;
var jnlp_path= '<%=basePath%>applet/pdfprintapplet.jnlp';
var parameters = {
    jnlp_href : jnlp_path,
    //这个参数就是传递给applet的待打印pdf文件的url列表
    pdfFileNameArray : array
};
var version = '1.6';
deployJava.runApplet(attributes, parameters, version);
展开阅读全文

没有更多推荐了,返回首页