通过后台打印jsp画面的Servlet,通过后台访问jsp画面得到相应的画面html,然后转化为pdf,输出到打印机
<p>通过ajax post,url为http://localhost/printJsp.do?jspName=FMBDRPDEMO1.jsp<p/>
web.xml:
<servlet>
<servlet-name>printJsp</servlet-name>
<servlet-class>com.baosight.wms.common.beans.ServletPrintJsp</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>printJsp</servlet-name>
<url-pattern>/printJsp.do</url-pattern>
</servlet-mapping>
public class ServletPrintJsp extends HttpServlet{
private static final long serialVersionUID = 1L;
private static final Logger log = LoggerFactory.getLogger(ServletPrintJsp.class);
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setHeader("content-type", "text/html;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
//获取参数
String printReportId = request.getParameter(BM2PReportConstants.PARA_PRINT_REPORT_ID);//打印报表ID
String keyword = request.getParameter(BM2PReportConstants.PARA_KEYWORD);//关键字
String formEname = request.getParameter(BM2PReportConstants.PARA_FORM_ENAME);//调用画面英文名
String buttonEname = request.getParameter(BM2PReportConstants.PARA_BUTTON_ENAME);//调用按钮英文名
//根据打印报表ID查询对应的报表画面和打印机
Tfmbdc0 printReportConfig = FMManagerFactory.getMgrPrintReportConfig().getPrintReportConfigByUI(printReportId);
String reportFormEname = printReportConfig.getReportFormEname();
String printerName = printReportConfig.getPrinterName();
//通过后台访问的url地址
String url = MessageFormat.format("/DispatchAction.do?efFormEname={0}&printReportId={1}&keyword={2}&previewFlag=0", reportFormEname, printReportId, keyword);
final ByteArrayOutputStream os =new ByteArrayOutputStream();
final ServletOutputStream stream =new ServletOutputStream() {
public boolean isReady() {
return false;
}
public void setWriteListener(WriteListener writeListener) {
}
public void write(byte[] data, int offset, int length){
os.write(data, offset, length);
}
@Override
public void write(int b) throws IOException {
os.write(b);
}
};
final PrintWriter pw =new PrintWriter(new OutputStreamWriter(os, "utf-8"));//保存html中文乱码
HttpServletResponse rep =new HttpServletResponseWrapper(response){
public ServletOutputStream getOutputStream(){
return stream;
}
public PrintWriter getWriter(){
return pw;
}
};
rep.setHeader("content-type", "text/html;charset=UTF-8");
rep.setCharacterEncoding("UTF-8");
ServletContext sc = getServletContext();
RequestDispatcher rd = sc.getRequestDispatcher(url);
//include 最后的主导权仍保留在本servlet
rd.include(request, rep);
//获取当前服务器部署目录的物理路径
String currentPath = this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
currentPath = new File(new File(currentPath).getParent()).getParent();
String uuid = BM2PStringUtil.getUUID();
// 这是生成的html文件名, uuid.html (根目录下)
String htmlName =currentPath + "//" +uuid + ".html";
pw.flush();
FileOutputStream fos =new FileOutputStream(htmlName);//把jsp输出的内容写到xxx.html
os.writeTo(fos);
fos.close();
//生成的HTML文件
File file = new File(currentPath + "//" +uuid + ".html");
System.out.println("生成HTML文件:" + file.getAbsolutePath());
//生成的pdf文件路径,uuid.pdf(根目录下)
String pdfPath = currentPath + "\\" + uuid + ".pdf";
Html2PdfUtil.convertHtmlToPdfCmd(file.getAbsolutePath(), pdfPath );
System.out.println("生成PDF文件:" + pdfPath);
//读取生成好的pdf文件,形成字节流
//pdf file ->byte[]
File pdfFile = new File(pdfPath);
FileInputStream fis = null;
ByteArrayOutputStream bos = null;
byte[] pdfBytes = null;
try {
fis = new FileInputStream(pdfFile);
bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
if(bos!=null) {
pdfBytes = bos.toByteArray();
}
} catch (Exception e1) {
log.error(e1);
}finally {
if(bos!=null) {
try {
bos.close();
} catch (IOException e) {
log.error(e);
}
}
if(fis!=null) {
try {
fis.close();
} catch (IOException e) {
log.error(e);
}
}
}
//调用打印机服务
System.out.println("目标打印机名称:" + printerName);
ServerPrintUtil.startPrintPdfThread(pdfBytes, printerName);
//记录打印履历及数据
Tfmbdc1 his = new Tfmbdc1();
his.setPrintReportId(printReportId);
his.setKeyword(keyword);
his.setFormEname(formEname);
his.setButtonEname(buttonEname);
//获取返回的打印ID
his.setPrintId(request.getAttribute(BM2PReportConstants.COL_PRINT_ID).toString());
his.setOperaId(BM2PStringUtil.getUUID());
Tfmbdc2 data = new Tfmbdc2();
//获取返回的业务数据json
data.setDataJson(request.getAttribute(BM2PReportConstants.COL_DATA_JSON).toString());
FMManagerFactory.getMgrPrintReportHistory().addPrintReportHistory(his, data);
}
}
public class ServerPrintThread implements Runnable {
private static final Logger log = LoggerFactory.getLogger(ServerPrintThread.class);
private byte[] buffer;
private PrintFileType fileType;
private String printerName;
/**
* 服务端打印线程
* @param buffer 待打印的字节流
* @param fileType 待打印的文件类型
*/
public ServerPrintThread(byte[] buffer, PrintFileType fileType) {
this.buffer = buffer;
this.fileType = fileType;
this.printerName = BM2PConstants.STRING_EMPTY;
}
/**
* 服务端打印线程
* @param buffer 待打印的字节流
* @param fileType 待打印的文件类型
* @param printerName 服务端配置的打印机名称
*/
public ServerPrintThread(byte[] buffer, PrintFileType fileType, String printerName) {
this.buffer = buffer;
this.fileType = fileType;
this.printerName = printerName;
}
@Override
public void run() {
try {
if(this.fileType == PrintFileType.PDF){
printPDF(this.buffer, this.printerName);
}
} catch (PlatException e) {
log.error(e);
//e.printStackTrace();
}
}
/**
* 打印PDF
* @param buffer 待打印的pdf文件字节流
* @param printerName 服务端配置的打印机名称
* @throws Exception
*/
private void printPDF(byte[] buffer, String printerName) throws PlatException{
try{
InputStream stream = new ByteArrayInputStream(buffer);
PDDocument document = PDDocument.load(stream);
System.out.println("doc"+document.getDocumentInformation());
PrinterJob job = PrinterJob.getPrinterJob();
//job.setPageable(new PDFPageable(document, Orientation.LANDSCAPE, true));
// PrintRequestAttributeSet attr = new HashPrintRequestAttributeSet();
//attr.add()
// define custom paper
Paper paper = new Paper();
/**
* DPI:72px/inch,A4 size(598 * 842);
DPI:96px/inch,A4 size(794* 1123);
DPI:120px/inch,A4 size(1487* 2105);
DPI:150px/inch,A4 size(1240* 1754);
DPI:300px/inch,A4 size(2480* 3508);
*/
//paper.setSize(3508, 2480);
//paper.setImageableArea(20, 0, paper.getWidth()-20, paper.getHeight()); // no margins
//目前 横板无法居中,且较小
// PDPage page = new PDPage(PDRectangle.A4);
// page.setRotation(90);
// document.addPage(page);
// custom page format
PageFormat pageFormat = new PageFormat();
pageFormat.setPaper(paper);
//pageFormat.setOrientation(PageFormat.LANDSCAPE);//landscape
//pageFormat.
// override the page format
Book book = new Book();
// append all pages
book.append(new PDFPrintable(document, Scaling.SCALE_TO_FIT),//, true, 300.0F, true),
pageFormat, document.getNumberOfPages());
job.setPageable(book);
//如果设置了打印机名称,则按照打印机名称查询打印服务并使用
//否则走默认打印机
if(StringUtils.hasContent(printerName)){
PrintService printService = this.getPrintService(printerName);
if(printService != null){
System.out.println("服务器存在打印机名称"+printerName);
job.setPrintService(printService);
}
}
//if(job.printDialog()) {//弹出打印机属性窗口
job.print();
//}
document.close();
}
catch(Exception e){
throw new PlatException(e.getMessage());
}
}
/**
* 根据打印机名称获取打印服务
* @param printerName 打印机名称
* @return 打印服务
*/
private PrintService getPrintService(String printerName) {
PrintService[] printServices = PrintServiceLookup.lookupPrintServices(null, null);
for (PrintService printService : printServices) {
if (printService.getName().trim().equals(printerName)) {
return printService;
}
}
return null;
}
/**
* 后台打印支持的文件类型
*
*
*/
public enum PrintFileType{
PDF
}
}
//HTML转换PDF工具类(需要在客户端安装转换工具:wkhtmltox-0.12.4_msvc2015-win64:默认路径:c:/wkhtmltopdf)
public class Html2PdfUtil {
/**
* 将html转成PDF
* <p>该方法转出来的pdf格式上有瑕疵,暂未使用<p/>
* @param inputHTMLFileName
* @param outputPDFFile
* @throws Exception
*/
public static void convertHtmlToPdf(String inputHTMLFileName, String outputPDFFile) throws Exception {
FileOutputStream fos = new FileOutputStream(outputPDFFile);
PD4ML pd4ml = new PD4ML();
pd4ml.setPageInsets(new Insets(20, 10, 10, 10));
pd4ml.setHtmlWidth(950);
pd4ml.setPageSize(pd4ml.changePageOrientation(PD4Constants.A4));
pd4ml.useTTF("java:fonts", true);
pd4ml.setDefaultTTFs("KaiTi_GB2312", "KaiTi_GB2312", "KaiTi_GB2312");
pd4ml.enableDebugInfo();
pd4ml.render("file:" + inputHTMLFileName, fos);
}
/**
* 将html转成PDF
* @param srcHtmlPath html路径
* @param destPdfPath pdf生成路径
*/
public static void convertHtmlToPdfCmd(String srcHtmlPath, String destPdfPath) {
try {
//wkhtmltopdf软件安装目录/bin/wkhtmltopdf.exe 完整路径
//软件下载地址 https://wkhtmltopdf.org/downloads.html
//服务器默认路径 "C:\\wkhtmltopdf\\bin\\wkhtmltopdf.exe" 在业务参数管理中配置
//这里有点问题,理论上不应该引用FM相关方法,但这个安装路径也没有地方配置,借用业务参数配置
IBizPara paraMgr = FMManagerFactory.getMgrBizPara();
String configPath = paraMgr.getBizParaDataByModuleIdAndParaId(BizModuleId.FM, BizParaId.WKHTMLTOPDF_INSTALLATION_PATH);
if (!StringUtils.hasContent(configPath)) {
throw new PlatException("未配置wkhtmltopdf软件路径");
}
String command = configPath;
command += " --javascript-delay 2000 ";
command += " " + srcHtmlPath + " " + destPdfPath;
System.out.println("command:" + command);
final Process p = Runtime.getRuntime().exec(command);
final StringBuilder output = new StringBuilder();
new Thread(new Runnable() {
@Override
public void run() {
try {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line = br.readLine();
while (line != null) {
if (line.trim().length() > 0) {
output.append(line).append("\n");
}
line = br.readLine();
}
} finally {
if (p.getErrorStream() != null) {
p.getErrorStream().close();
}
}
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
try {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = br.readLine();
while (line != null) {
if (line.trim().length() > 0) {
output.append(line).append("\n");
}
line = br.readLine();
}
} finally {
if (p.getInputStream() != null) {
p.getInputStream().close();
}
}
} catch (IOException ex) {
ex.printStackTrace(System.err);
}
}
}).start();
p.waitFor();
String result = command + "\n" + output.toString() + output.toString();
System.out.print(result);//wkhtmltopdf程序运行时的软件输出,保存pdf的过程,可以选择不打印
} catch (Exception e) {
throw new PlatException(e.getMessage());
}
}
}
/**
* 通过服务端打印工具类
*
*
*/
public class ServerPrintUtil {
/**
* 启动打印PDF
* <p>不指定打印机,则为默认打印机<p/>
* @param printByte 待打印的PDF文件字节流
*/
public static void startPrintPdfThread(byte[] printByte){
ServerPrintThread printThread = new ServerPrintThread(printByte, PrintFileType.PDF);
Thread thread = new Thread(printThread);
thread.start();
}
/**
* 启动打印PDF
* @param printByte 待打印的PDF文件字节流
* @param printerName 服务端配置的打印机名称
*/
public static void startPrintPdfThread(byte[] printByte, String printerName){
ServerPrintThread printThread = new ServerPrintThread(printByte, PrintFileType.PDF, printerName);
Thread thread = new Thread(printThread);
thread.start();
}
}