多线程报表生成其中报表以pdf形式保存

     设计思路采用生产者消费者模式,生产者生产报表消费者消费报表生成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));
	}

}

  

时间: 2024-11-09 16:10:22

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

把文本以图片的形式保存

private void ToConvert_Click(object sender, EventArgs e) { string strPath = System.Windows.Forms.Application.StartupPath; ConvertTextFileToImage(strPath + @"\文件\aa.txt", strPath + @"\文件\SSS.png"); pictureBox1.Image = Image.FromFile(str

使用canvas将网页内容以图片形式保存到服务器端

经过几天的折磨,终于实现了将网页以图片形式保存到服务器端的效果.在这里要特别感谢园子里白灰尘(http://www.cnblogs.com/Wylfocus/)这位朋友热心.耐心的指导.在网上有许多这样的介绍资料,但对于初学者来说,在测试过程中,有时是缺JS库文件.有时是因输入代码时没注意大小写等原因,总会出现这样或那样的错.为了让和我一样的初学者们都顺利看到程序的效果,现在把我试好的程序上传.开发环境为VS2008.特别要注意的是,IE9以下的版本不支持canvas,即使导入explorerc

将文件以二进制的形式保存到数据库中

主要应用HttpPostedFile类的InputStream属性.Stream类的read方法和Byte数据类型.首先获取上传数据文件的名称.大小和类型,建立一个访问客户端上传文件的对象HttpPostedFile和一个数据流对象Stream,然后使用数据流Stream对象将上传文件以二进制形式的数据写入Byte类型的数组中,最后将二进制数据保存的数据库中. 代码:try        {            if (this.FileUpload1.PostedFile.FileName

如何将转换好的PDF图纸保存至电脑桌面上?

如何将转换好的PDF图纸保存至电脑桌面上?通常从事CAD相关的工作人员想要转换一张CAD图纸的格式的时候都会使用CAD转换器来进行此项操作,那么完成操作之后应该将图纸保存到哪一个地方呢,当然是保存在电脑桌面上了,那这个步骤应该如何进行,今天小编就要来教教大家如何将转换好的PDF图纸保存至电脑桌面上的全部步骤,希望能够帮助到大家! 第一步:首先要打开我们桌面上的CAD转换器,如果您电脑上面没有这一款CAD转换器的话,您就可以打开您电脑上面的浏览器搜索进入官网上面下载,小编是用的就是这款"迅捷CAD

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

function TRMDesignerForm.FileSave: Boolean; var lSaved: Boolean; lFileName: string; begin Result := False; if DesignerRestrictions * [rmdrDontSaveReport] <> [] then Exit; if not FCodeMemo.ReadOnly then Report.Script.Assign(FCodeMemo.CreateStringList

网管维护——客户系统pdf文件保存到本地电脑成功后,却在对应的路径下看不到

背景:公司有四台同品牌电脑重装了系统,我是把一台电脑用原装盘安装,然后把这台电脑备份,用备份克隆安装其余三台电脑. 故障:除了用原装盘安装的那台电脑在客户系统查看.保存PDF文件正常外,其他三台电脑均出现在客户系统上PDF文件只能查看.保存能成功,但在之后的保存路径上找不到对应的PDF文件.重试,在选择保存pdf文件路径的窗口里可以看到之前保存的pdf文件,点击保存后,故障依旧. 思路与解决:网页要查看.下载PDF文件,需要IE浏览器对PDF插件的支持,根据以往的经验,我都是直接把adobe f

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

直接上码: 首先创建class1类 public class Class1 { public string name { get; set; } public int age { get; set; } public bool sex { get; set; } } 实例化class1对象并进行序列化和反序列化 static void Main(string[] args) { //实例化class1类 Class1 c1 = new Class1() { name = "jia",

Office问题_(二)_excel数字以文本形式保存

excel中通常用公式匹配某数字列,即便改成文本样式还是无法匹配(数字在左上角没有绿色三角,双击后出现绿色三角才可以匹配),如图: 但是,数据多的时候又不能一个一个双击,解决办法如下: 1.选中要转换为文本的列. 2.点击"数据"->"分列"->前几步默认,第三步选中所有列,然后选择"文本"格式->"完成" 3.可以查看结果,能够完成以文本保存

java后台简单从腾讯云下载文件通知前端以附件的形式保存

不废话 上代码 // fileName :前台传入的文件名(主要是标识文件是什么格式.png或.zip) // cosKey:上传文件时腾讯云返回的标识 // 配置腾讯云基本信息 String aliyunId = ApplicationPropertyUtils.getContextProperty("TENXUN_ACCESS_KEY_ID"); String aliyunSecret = ApplicationPropertyUtils.getContextProperty(&q