设计思路采用生产者消费者模式,生产者生产报表消费者消费报表生成pdf文件其中报表以html形式存储在线程安全列表中.使用到技术有:多线程协作,线程池,线程安全,html 生成pdf.

一.生产者生成html模版,方式通过多线程将数据和html模版整合技术是使用freemarker.

1.ValPdfProduce

package hk.buttonwood.ops.report;

import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import hk.buttonwood.ops.pdf.Msg;
import hk.buttonwood.ops.pdf.PdfProducer;
import hk.buttonwood.ops.portfolio.PortfolioService;
import net.zweb.core.ioc.annotation.Inject;
import net.zweb.core.ioc.annotation.Resource;
import net.zweb.core.util.FileUtil; /**
* @author maybo 2015年10月31日
*/
@Resource
public class ValPdfProduce {
private String root = "/home/maybo/myProject/";// 保存文件的根目录
private String tPath = "src/main/webapp/WEB-INF/templates/ops/report/cash_pdf.html";// html模版文件
public ThreadPoolExecutor producerPool;
public PdfProducer pdfProducer;
@Inject
private PortfolioService portfolioService;// 投资组合服务用于获取所有列
private ValProducer producer;
public ThreadPoolExecutor getProducerPool() {
return this.producerPool;
}
public void setPortfolioService(PortfolioService portfolioService) {
this.portfolioService = portfolioService;
} public ValPdfProduce(String root, String tPath, ValProducer producer) {
this.root = root;
this.tPath = tPath;
this.producer = producer;
}
public ValPdfProduce() {
}
/*
* 生成pdf
*/
public void produce(List<Integer> portfolios,String from,String to,String root, String tPath, ValProducer producer) {
this.root=root;
this.tPath=tPath;
this.producer=producer;
int cpu = Runtime.getRuntime().availableProcessors();
Msg msg=new Msg();
//如果portfolio存在无需查询
if(portfolios==null||portfolios.size()<=0){
// 获取所有portfolio列表
portfolios = this.portfolioService.findAll();
}
if (portfolios == null || portfolios.isEmpty()||portfolios.size()<=0) {
Msg.State state=new Msg.State();
state.setState(Msg.State.NO_DATA);
msg.add(state);
msg.setTotal(-1);
return;
}
pdfProducer = PdfProducer.newInstance();
LinkedBlockingQueue<HashMap<String, Object>> queue = pdfProducer.getCached();
String html = htmlToString(tPath);
if (html == null || html == "") {
Msg.State state=new Msg.State();
state.setState(Msg.State.NO_DATA);
msg.add(state);
msg.setTotal(-1);
return;
}
msg.setTotal(portfolios.size());
pdfProducer.setMsg(msg);
// 开启一个生产估值数据的线程池
producerPool = new ThreadPoolExecutor(cpu / 2, 500, 5, TimeUnit.MINUTES, new ArrayBlockingQueue<Runnable>(500));
for (Integer p : portfolios) {
if (p< 0) {//但没有值时返回状态
Msg.State state=new Msg.State();
state.setPortfolio(p);
state.setState(Msg.State.NO_DATA);
msg.add(state);
continue;
}
producerPool.execute(new ValProduceTask( msg,queue, p,html, root, this.producer,from,to));
try {
pdfProducer.addTask(null);
} catch (Exception e) { e.printStackTrace();
}
}
try { pdfProducer.shutDown();
} catch (Exception e) {
e.printStackTrace();
}
producerPool.shutdown();
} /*
* 将html和数据整合到一起
*
* @param:html文件路径
*
*/
private String htmlToString(String htmlFile) {
String html = "";
File file = new File(htmlFile);
if (file.exists() && file.isFile()) {
html = FileUtil.readFile(file);
}
return html;
}
}

 2.

package hk.buttonwood.ops.report;

import java.util.Map;

import hk.buttonwood.ops.pdf.ExcTask;

/**
* @author maybo 2015年10月31日
*/
public abstract class ValProducer{
/*
* 将月结单数据保存到数据模版中
*
* @param:portfolio中id
*
* @param:保存文件的根目录
*
* @param:htmlFile的位置
* @param:更新日期
*/
protected abstract Map<String, Object> valToPdfTemplate(int portfolio,String root, String html,String date);
/*
* 将月结单数据保存到数据模版中
*
* @param:portfolio中id
*
* @param:保存文件的根目录
*
* @param:htmlFile的位置
*
* @param:更新日期
* @param:截至日期
*/
protected abstract Map<String, Object> valToPdfTemplate(int portfolio, String root, String html,String from,String to);
}

  3.生产任务

package hk.buttonwood.ops.report;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue; import hk.buttonwood.ops.pdf.Msg; /*
* 建立一个获取数据的线程
*/
/**
* @author maybo
* 2015年10月31日
*/
public class ValProduceTask extends Thread {
// 线程安全队列用以存储数据
private LinkedBlockingQueue<HashMap<String, Object>> queue;
private int portfolio;// 投资组合的id
private String from;// 当前日期
private String html;// html模版
private String root;// 存储的根目录
private ValProducer valProducer;// 获取相应的数据
private String to;// 截至日期日期
private Msg msg;//执行状态
/*
* 传递所需数据
*
* @param:缓存队列
*
* @param:投资组合id
*
* @param:查询日期
*
* @param:html模版
*
* @param:提供的数据获取方法有调用者实现传递
*
* @param:跟目录
*
* @保存文件名
*/ public ValProduceTask(Msg msg,LinkedBlockingQueue<HashMap<String, Object>> queue, int portfolio,String html,
String root, ValProducer valProducer,String from,String to) {
this.queue = queue;
this.from = from;
this.html = html;
this.to=to;
this.portfolio = portfolio;
this.root = root;
this.valProducer = valProducer;
this.msg=msg;
} @Override
public void run() {
synchronized (queue) {
Map<String, Object> data;
if(to==null){
data = valProducer.valToPdfTemplate(portfolio,root, html, from);
}else{
data = valProducer.valToPdfTemplate(portfolio,root, html, from,to);
}
if (data != null) {
queue.add((HashMap<String, Object>) data);
}else{
Msg.State state=new Msg.State();
state.setPortfolio(this.portfolio);
state.setState(Msg.State.NO_DATA);
msg.add(state);
}
queue.notifyAll();
}
}
}

 二.消费者也就是pdf的生产者消费html模版生成pdf.

1.底层类实现将html to pdf.

/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package zweb.plugins.pdf; /**
*
* @author john
*/
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.util.HashMap;
import java.util.Map; import net.zweb.core.config.Config;
import net.zweb.core.config.MapConfig;
import net.zweb.core.util.FileUtil; import org.apache.commons.lang.StringUtils; import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper; public class HtmlToPDF { private HeaderFooter headerFooter = null; public HtmlToPDF(){ } public HtmlToPDF(HeaderFooter headerFooter){
this.headerFooter = headerFooter;
} public String print(String html, Map<String, Object> data, String path) throws Exception {
try { Document document = null;
if(data!=null){
Config<String, Object> cfg = new MapConfig<String, Object>(data);
String pageSize = cfg.getString("pageSize");
String direction = cfg.getString("direction");
if(StringUtils.isBlank(pageSize)){
pageSize = "letter";
}
if(StringUtils.isBlank(direction))
direction = "verticle";
if(StringUtils.equals(direction, "verticle"))
document = new Document(PageSize.getRectangle(pageSize)); // 竖向打印
else
document = new Document(PageSize.getRectangle(pageSize).rotate()); // 横向打印
}else{
document = new Document(PageSize.LETTER);
}
PdfWriter pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(path)); if (this.headerFooter != null)
pdfWriter.setPageEvent(headerFooter); document.open();
document.addAuthor(String.valueOf(data.get("author")));
document.addCreator(String.valueOf(data.get("creator")));
document.addSubject(String.valueOf(data.get("subject")));
document.addCreationDate();
document.addTitle(String.valueOf(data.get("title")));
XMLWorkerHelper worker = XMLWorkerHelper.getInstance();
// worker.parseXHtml(pdfWriter, document, new StringReader(str));
worker.parseXHtml(pdfWriter, document, new ByteArrayInputStream(html.getBytes()), null,
new XMLWorkerFontProvider(){
@Override
public Font getFont(final String fontname, final String encoding,
final boolean embedded, final float size, final int style,final BaseColor color) {
String fntname = fontname;
if(fntname==null){
fntname="宋体";
fntname="微软雅黑";
// fntname="uming";
}
return super.getFont(fntname, encoding, size, style);
}
}
);
// worker.parseXHtml(pdfWriter, document, new
// ByteArrayInputStream(html.getBytes()));
document.close();
} catch (Exception e) {
throw e;
}
return null;
} public static void main(String... args) throws Exception {
String root = "src/main/webapp";
HeaderFooter headerFooter = new HeaderFooter(root);
headerFooter.setPrintDirection("horizon");
headerFooter.setX(-30);
headerFooter.setY(630);
headerFooter.setImg("/images/print_holder.png");
HtmlToPDF toPdf = new HtmlToPDF(headerFooter);
String path = "d:/testpdf3.pdf";
//String str = FileUtil.readFile(new File("src/main/webapp/WEB-INF/templates/custody/fund/voucher/print.html"));
String str = FileUtil.readFile(new File("src/main/webapp/WEB-INF/templates/register/holder/print_bond.html"));
Map<String, Object> data = new HashMap<String, Object>();
data.put("author", "author");
data.put("creator", "creator");
data.put("subject", "subject");
data.put("title", "title");
data.put("direction", "horizon");
data.put("pageSize", "A4");
toPdf.print(str, data, path);
} }

  2.PdfPrint 基本执行生成pdf.

package hk.buttonwood.ops.pdf;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.zweb.core.mvc.template.AbstractTemplateEnginePlugin;
import net.zweb.core.mvc.template.TemplateEngine;
import zweb.plugins.pdf.HeaderFooter;
import zweb.plugins.velocity.VelocityPlugin; public class PrintPdf implements ExcTask {
private Map<String, Object> data;
private static TemplateEngine engine;
private HeaderFooter headerFooter;
private Logger logger=LoggerFactory.getLogger(PdfTask.class);
static {
AbstractTemplateEnginePlugin plugin = new VelocityPlugin();
engine = plugin.templateEngine();
} public PrintPdf(Map<String, Object> data,HeaderFooter headerFooter) {
this.data = data;
this.headerFooter=headerFooter;
} @SuppressWarnings("unchecked")
@Override
public void excute() throws Exception {
String html = "";
html = htmlToString((String) data.get("html"), (Map<String, Object>) data.get("datas"));
if ("".equals(html)) {
return;
}
new BuildPdfUtil(this.headerFooter).build(html, (String) data.get("saveFile"), (Map<String, Object>) data.get("datas"));
logger.debug((String)data.get("saveFile")+"---------------完成");
} /*
* 将html和数据整合到一起
*
* @param:html文件路径
*
* @param:数据模型
*/
private String htmlToString(String html, Map<String, Object> datas) {
String htl = "";
htl = engine.render(html, datas);
return htl;
} }

 3.线程任务生成pdf调用PdfPrint

package hk.buttonwood.ops.pdf;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import zweb.plugins.pdf.HeaderFooter; /**
* @author maybo 2015年10月28日 估值报告线程任务
*/
public class PdfTask extends Thread {
// 线程安全队列用以存储数据
private LinkedBlockingQueue<HashMap<String, Object>> queue;
private HeaderFooter headerFooter;
private Msg msg;
public PdfTask(LinkedBlockingQueue<HashMap<String, Object>> queue,HeaderFooter headerFooter,Msg msg) {
this.queue = queue;
this.headerFooter=headerFooter;
this.msg=msg;
} @Override
public void run() {
synchronized(queue){
while (queue.size() <= 0) {
try {
queue.wait();
} catch (InterruptedException e) {
e.printStackTrace();
queue.notifyAll();
}
}
Map<String, Object> data = queue.poll();
queue.notifyAll();
try {
ExcTask excTask = new PrintPdf(data,headerFooter);
excTask.excute();
Msg.State state=new Msg.State();
if(data.get("portfolio")!=null){
state.setPortfolio((Integer)data.get("portfolio"));
state.setState(Msg.State.OK);
msg.add(state);
}
} catch (Exception e1) {
Msg.State state=new Msg.State();
if(data.get("portfolio")!=null){
state.setPortfolio((Integer)data.get("portfolio"));
state.setState(Msg.State.ERROR);
msg.add(state);
}
e1.printStackTrace();
}
}
}
}

  4.PdfProducer //也就是消费者

package hk.buttonwood.ops.pdf;
import java.util.HashMap;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import zweb.plugins.pdf.HeaderFooter; public class PdfProducer {
private LinkedBlockingQueue<HashMap<String, Object>> queue;
private ThreadPoolExecutor pool;
private Msg msg;
private PdfProducer() {
} public static PdfProducer newInstance() {
PdfProducer pdfProducer = new PdfProducer();
int cpu = Runtime.getRuntime().availableProcessors();// 获取cpu核数
pdfProducer.queue = new LinkedBlockingQueue<HashMap<String, Object>>();// 创建队列用于缓存任务
// 开启一个生产估值数据的线程池
pdfProducer.pool = new ThreadPoolExecutor(cpu / 2-1<=0?1:cpu/2-1, 500, 5, TimeUnit.MINUTES,
new ArrayBlockingQueue<Runnable>(500));// 开启线程池
return pdfProducer;
} public LinkedBlockingQueue<HashMap<String, Object>> getCached() {
return queue;
}
public void setMsg(Msg msg) {
this.msg = msg;
}
public Msg getMsg() {
return this.msg;
}
// 关闭线程池
public void shutDown() {
this.pool.shutdown();
} // 现在关闭
public void shutDownNow() {
this.pool.shutdownNow();
} // 关闭状态
public boolean isShutDown() {
return this.pool.isShutdown();
}
// 是否完成任务
public boolean isTerminated() {
return this.pool.isTerminated();
} public boolean isTerminating() {
return this.pool.isTerminating();
} /*
* 添加任务数
* param:pdf的页眉
*/
public void addTask(HeaderFooter footer) throws Exception {
if (this.isShutDown()) {
throw new Exception("已经关闭任务.");
}
pool.execute(new PdfTask(queue,footer,msg));
} }

  

多线程报表生成其中报表以pdf形式保存的更多相关文章

  1. 锐浪报表 导出 PDF ANSI码 乱码 问题解决

    锐浪 报表 导出PDF时如果 ANSI 码 打勾了会乱码,能将这个选项默认不打勾吗 //在报表导出事件脚本里写脚本,可实现导出控制Sender.AsE2PDFOption.AnsiTextMode=0 ...

  2. XML序列化/反序列化数据库形式保存和读取。

    直接上码: 首先创建class1类 public class Class1 { public string name { get; set; } public int age { get; set; ...

  3. RM报表,点击保存,为何每次都显示 另存为的对话框?

    function TRMDesignerForm.FileSave: Boolean; var lSaved: Boolean; lFileName: string; begin Result := ...

  4. php利用mpdf生成pdf并保存到目录

    下载mpdf7.0两种方法 (1). github地址:https://github.com/mpdf/mpdf (2). composer require mpdf/mpdf <?php er ...

  5. html5使用local storage存储的数据在本地是以何种形式保存的

    html5使用local storage存储的数据是如何保存在本地的?(我使用的是chrome浏览器,chrom浏览器是用sqlite来保存本地数据的) Html5 的local storage 是通 ...

  6. php+tcpdf如何把生成的pdf文件保存在服务端

    tcpdf组件目前应用得非常广泛,但是对于如何把生成的pdf文件自动保存在服务端却很少有人提及.让我们先来看看标准输出代码:   //服务器存档模式 $pdf->Output('output.p ...

  7. 水晶报表导出pdf文件

    /// <summary> /// 导出pdf文件 /// </summary> /// <param name="mjsReport">报表文 ...

  8. 用表格形式保存文档 xlwt

    # - * _- coding:utf-8-*-import requestsimport json #转成字典形式import xlwtimport sys #转码reload(sys)sys.se ...

  9. 二维码图片以字符串的形式保存DB,已文件流显示页面上

    以下是生成二维码的方法,我只用其中一个方法 这个需要引用ZXing.DLL 链接:https://pan.baidu.com/s/1mCTwHiAm_awtsPcibAotZw 提取码:ufp6 pu ...

随机推荐

  1. Unity原生渲染方案

    Unity原生渲染方案 作者:3dimensions three_dimensions@live.cn 本文为原创内容,转载请注明出处. 做这个的动机是想在原生代码中使用Unity的材质系统绘制,同时 ...

  2. Facebook三种分享方式

    一.去Facebook开发者中心注册APP,获取APP ID https://developers.facebook.com 二.导入 FBSDKCoreKit.Framework, FBSDKLog ...

  3. hive安装(一)

    1.解压 [root@cluster3 hadoop]# tar -zxvf apache-hive--bin.tar.gz 2.修改环境变量 export HIVE_HOME=/usr/local/ ...

  4. 洛谷P1473 零的数列 Zero Sum

    P1473 零的数列 Zero Sum 134通过 170提交 题目提供者该用户不存在 标签USACO 难度普及/提高- 提交  讨论  题解 最新讨论 路过的一定帮我看错了我死了- 题目描述 请考虑 ...

  5. 洛谷P1207 [USACO1.2]双重回文数 Dual Palindromes

    P1207 [USACO1.2]双重回文数 Dual Palindromes 291通过 462提交 题目提供者该用户不存在 标签USACO 难度普及- 提交  讨论  题解 最新讨论 暂时没有讨论 ...

  6. 二模09day2解题报告

    T1.domino骨牌 n张有黑有白的骨牌排一排,连续三张同色排一起就不好看,求共多少方案不好看. 分析一下,f[3]=2,f[4]=6,f[n]:如果n-1==n 那么方案数为f[n-2],如果不同 ...

  7. C++学了这么多年,你仍不知道的事

    C++学了这么多年你知道为什么定义类时,类的定义放在.h文件中,而类的实现放在cpp文件中.它们为什么能够关联到一起呢?你知道什么东西可以放在.h文件中,什么不能.什么东西又可以放在cpp文件中.如果 ...

  8. mysql时间日期相加相减实现

    分享篇mysql中日期的一些操作,就是我们常常会用到的mysql时间日期的相加或者相减的了,这个mysql也自己带了函数,有需要的朋友可以参考一下. 最简单的方法 select TO_DAYS(str ...

  9. @service中构造方法报错

    因为类首先被Spring实例化的时候,会调用构造函数.只有实例化后,才会注入.你等于没注入就调用了,所以报错.

  10. 手机NFC模拟门禁卡

    楼主所在的某电子科技类大学,从宿舍楼到实验楼到图书馆办公楼,全部都有门禁,前两天突然在某安软件市场看到一个可以模拟门禁卡的软件,然而可能是我的手机系统太6了,竟然模拟不了,无奈自己动手,从根本上解决问 ...