业务介绍:
财务报销任务单太多需要实现批量打印的功能。
实现运用技术
1.用第三方工具实现网页转换pdf。(我用的是”wkhtmltox”大家可以百度下载)
2.itext 操作pdf
3.pdfobject.js 显示pdf的脚本
直接上代码:
主要工具类
package com.rtaksoft.suite.batchprint.service;
import com.lowagie2.text.Document;
import com.lowagie2.text.pdf.PdfCopy;
import com.lowagie2.text.pdf.PdfImportedPage;
import com.lowagie2.text.pdf.PdfReader;
import com.rtaksoft.core.common.tools.Format;
import com.rtaksoft.core.init.spring.support.NtcoPropertyPlaceholderConfigurer;
import com.rtaksoft.frameextend.struts.context.ServiceContext;
import com.rtaksoft.suite.batchprint.util.HtmlToPdf;
import com.rtaksoft.system.wf.dao.WfStepDao;
import com.rtaksoft.system.wf.dao.WfTaskLogDao;
import com.rtaksoft.system.wf.model.WfStepModel;
import com.rtaksoft.system.wf.model.WfTaskLogModel;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.io.FileOutputStream;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
/**
* 文档预览
* 1.所有可查看的文件转为pdf并且添加水印
* 2.pdf合并
* 3.打开pdf进行打印
* User: 栗超崇
* Date: 2018/4/13 0013
* Time: 15:56
* Description:
*/
@Service
public class DocPreviewServiceImpl {
Logger logger = Logger.getLogger(DocPreviewServiceImpl.class);
@Resource
private WfTaskLogDao wfTaskLogDao;
@Resource
private WfStepDao wfStepDao;
/**
* 根据taskid生成表单pdf(只支持已办)
* @param serviceContext
* @return
*/
public List<String> generatePdf(ServiceContext serviceContext) throws Exception{
List<String> files = new ArrayList<String>();
String savePath = serviceContext.getRequest().getRealPath("");
String filediskpath = Format.formatStrNullForEmpty(NtcoPropertyPlaceholderConfigurer.get("filediskpath"));
if(!filediskpath.equals("")){
savePath = filediskpath;
}
savePath = savePath + "/upload/batchprin/";
try {
String url = Format.formatStrNullForEmpty(NtcoPropertyPlaceholderConfigurer.get("batchprint.url"));
String taskIds =Format.formatStrNullForEmpty(serviceContext.getParameter("taskIds"));
for (String s : taskIds.split(";")) {
String filename = savePath+""+s+".pdf";
WfTaskLogModel m = this.wfTaskLogDao.getById(s);
if(m==null){
continue;
}
// 获取节点信息
WfStepModel stepModel = this.wfStepDao.getById(m.getStepId());
//生成一个打印的url
String format_url = MessageFormat.format(url, serviceContext.getSessionId(),s, stepModel.getFormId());
HtmlToPdf htmlToPdf = new HtmlToPdf();
boolean convert = htmlToPdf.convert(format_url, filename);
if(convert){
files.add(filename);
}
}
} catch (Exception e) {
logger.error(e);
}
return files;
}
/**
* pdf合并
* @param files
* @param newfile
* @return
*/
public boolean mergePdfFiles(String[] files, String newfile) throws Exception {
boolean retValue = false;
Document document = null;
try {
document = new Document(new PdfReader(files[0]).getPageSize(1));
PdfCopy copy = new PdfCopy(document, new FileOutputStream(newfile));
document.open();
for (int i = 0; i < files.length; i++) {
PdfReader reader = new PdfReader(files[i]);
int n = reader.getNumberOfPages();
for (int j = 1; j <= n; j++) {
document.newPage();
PdfImportedPage page = copy.getImportedPage(reader, j);
copy.addPage(page);
}
}
retValue = true;
} catch (Exception e) {
e.printStackTrace();
} finally {
document.close();
}
for (String file : files) {
new File(file).delete();
}
return retValue;
}
}
package com.rtaksoft.suite.batchprint.util;
import com.rtaksoft.core.init.spring.support.NtcoPropertyPlaceholderConfigurer;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import java.io.File;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
* html转pdf
* 1.安装wkhtmltopdf (https://wkhtmltopdf.org/downloads.html)
* 2.配置地址
* User: 栗超崇
* Date: 2018/5/14 0014
* Time: 15:29
* Description:
*/
@Component
public class HtmlToPdf {
Logger logger = Logger.getLogger(HtmlToPdf.class);
/**
* html转pdf
* @param srcPath html路径,可以是硬盘上的路径,也可以是网络路径
* @param destPath pdf保存路径
* @return 转换成功返回true
*/
public boolean convert(String srcPath, String destPath){
String toPdfTool = NtcoPropertyPlaceholderConfigurer.get("wkhtmltopdf_window");
File file = new File(destPath);
File parent = file.getParentFile();
//如果pdf保存路径不存在,则创建路径
if(!parent.exists()){
parent.mkdirs();
}
StringBuilder cmd = new StringBuilder();
if(System.getProperty("os.name").indexOf("Windows") == -1){
//非windows 系统
toPdfTool =NtcoPropertyPlaceholderConfigurer.get("wkhtmltopdf_linux");
}
cmd.append(toPdfTool);
cmd.append(" ");
//cmd.append(" --header-line");//页眉下面的线
//cmd.append(" --header-center 这里是页眉这里是页眉这里是页眉这里是页眉 ");//页眉中间内容
cmd.append(" --margin-top 3cm ");//设置页面上边距 (default 10mm)
//cmd.append(" --header-html file:///"+WebUtil.getServletContext().getRealPath("")+FileUtil.convertSystemFilePath("\\style\\pdf\\head.html"));// (添加一个HTML页眉,后面是网址)
cmd.append(" --header-spacing 5 ");// (设置页眉和内容的距离,默认0)
//cmd.append(" --footer-center (设置在中心位置的页脚内容)");//设置在中心位置的页脚内容
//cmd.append(" --footer-html file:///"+WebUtil.getServletContext().getRealPath("")+FileUtil.convertSystemFilePath("\\style\\pdf\\foter.html"));// (添加一个HTML页脚,后面是网址)
//cmd.append(" --footer-line");//* 显示一条线在页脚内容上)
cmd.append(" --footer-spacing 5 ");// (设置页脚和内容的距离)
cmd.append(" --encoding utf-8 ");// (设置编码)
cmd.append(srcPath);
cmd.append(" ");
cmd.append(destPath);
boolean result = true;
try{
// 线程池
ExecutorService pool = Executors.newFixedThreadPool(10);
Process proc = Runtime.getRuntime().exec(cmd.toString());
Callable<String> error = new HtmlToPdfInterceptor(proc.getErrorStream());
Callable<String> output = new HtmlToPdfInterceptor(proc.getInputStream());
Future<String> f1 = pool.submit(error);
Future<String> f2 = pool.submit(output);
proc.waitFor();
System.out.println("f1:"+f1.get());
System.out.println("f2:"+f2.get());
System.out.println("转换成功");
pool.shutdown();
}catch(Exception e){
result = false;
e.printStackTrace();
}
return result;
}
}
package com.rtaksoft.suite.batchprint.util;
import org.apache.log4j.Logger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.concurrent.Callable;
/**
* html转pdf日志输出
* User: 栗超崇
* Date: 2018/5/14 0014
* Time: 15:36
* Description:
*/
public class HtmlToPdfInterceptor implements Callable<String> {
Logger logger = Logger.getLogger(HtmlToPdf.class);
private InputStream is;
public HtmlToPdfInterceptor(InputStream is){
this.is = is;
}
public String call(){
InputStreamReader isr = null;
BufferedReader br = null;
StringBuffer err = new StringBuffer();
try{
isr = new InputStreamReader(is, "utf-8");
br = new BufferedReader(isr);
String line = null;
while ((line = br.readLine()) != null) {
if(line.indexOf("Error") !=-1){
err.append(line.toString()).append("</br>");
}
logger.debug(line.toString()); //输出内容
}
}catch (IOException e){
e.printStackTrace();
}finally {
try {
isr.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return err.toString();
}
}
调用实例
//转换所有的网页,并且返回文件列表
List<String> files = docPreviewService.generatePdf(serviceContext);
String savePath = serviceContext.getRequest().getRealPath("");
savePath = savePath+"/temp";
File file = new File(savePath);
if(!file.isDirectory()){
file.mkdirs();
}
//随机名称并且合并pdf
String filename = GetKey.get32UuidKeyValue()+".pdf";
String pdf = savePath+"/"+filename;
docPreviewService.mergePdfFiles(files.toArray(new String[files.size()]),pdf);
//合并成功后返回到前端。用pdfobject.js 显示即可