Highcharts图表导出为pdf的JavaWeb实践
2016-03-31 17:34
661 查看
写给读者的话^_^:
众所周知,基于Highcharts插件生成的svg图片组(注意这里鄙人指的组是若干图有序组合,并非一张图片,具有业务意义)导出为PDF文档是有难度滴。鄙人也曾“异想天开”用前端技术拍个快照然后转换为pdf文件导出,后来因为能力有限未能完美实现。因此,参照互联网已有的经验和做法,创造出一套较为有操作性的方案,详情见下文。
---------------------------------------------------说正事儿分割线----------------------------------------------------
假设需求如下:
如图所示的复杂图表报告
对其进行PDF导出(demo中所有数据为伪造,并无任何价值)
PDF文档绘制工具类
此工具类可以根据前端传来的svg信息,前文中提到的自定义position等属性,布局完成所要输出的PDF文档,因时间有限,不再一一赘述,有想研究的可以下载demo,我已做了一个demo供各位交流学习,下载地址:http://yun.baidu.com/share/link?shareid=2976350494&uk=657798452
众所周知,基于Highcharts插件生成的svg图片组(注意这里鄙人指的组是若干图有序组合,并非一张图片,具有业务意义)导出为PDF文档是有难度滴。鄙人也曾“异想天开”用前端技术拍个快照然后转换为pdf文件导出,后来因为能力有限未能完美实现。因此,参照互联网已有的经验和做法,创造出一套较为有操作性的方案,详情见下文。
---------------------------------------------------说正事儿分割线----------------------------------------------------
假设需求如下:
如图所示的复杂图表报告
对其进行PDF导出(demo中所有数据为伪造,并无任何价值)
package com.demo.utils; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URLDecoder; import java.util.ArrayList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.batik.transcoder.TranscoderException; import org.apache.batik.transcoder.TranscoderInput; import org.apache.batik.transcoder.TranscoderOutput; import org.apache.batik.transcoder.image.PNGTranscoder; import com.itextpdf.text.BadElementException; import com.itextpdf.text.BaseColor; import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Element; import com.itextpdf.text.Font; import com.itextpdf.text.Image; import com.itextpdf.text.Paragraph; import com.itextpdf.text.Phrase; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPRow; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; /** * @Description XXX分析页面PDF导出工具方法 */ public class ComprehensivePdfUtil { /** * 获得PDF字节输出流及pdf布局业务逻辑 * @param request * @param response * @param resultMap 包含参数:svg(绘图svg参数及hicharts图布局参数) logoT(页面总标题) * @param list 页面包含植入栏目排行表格图,该list存储绘制表格所用的数据 * @param tableTh 页面包含植入栏目排行表格图,该字符串作为表格表头 * @param tableTd 页面包含植入栏目排行表格图,该字符串作为表格内容填充时,实体类反射值所用的方法名(必须与实体方法严格一致) * @return */ public ByteArrayOutputStream getPDFStream(HttpServletRequest request, HttpServletResponse response, Map<String,Object> resultMap){ try { //图片变量定义 String noData = "/style/images/noData.png";//无数据左右图 String noDataCenter = "/style/images/noDataCenter.png";//无数据中间图 String waterMark = "/style/images/PDFSHUIYIN.png";//PDF导出文件水印图片 String [] svgName = (String[]) resultMap.get("svg");//导出PDF页面所有svg图像 Document document = new Document(); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); PdfWriter pdfWriter = PdfWriter.getInstance(document, buffer); //设置页面大小 int pageHeight = 2000; Rectangle rect = new Rectangle(0,0,1200,pageHeight); rect.setBackgroundColor(new BaseColor(248,248,248));//页面背景色 document.setPageSize(rect);//页面参数 //页边空白 document.setMargins(20, 20, 30, 20); document.open(); //设置页头信息 if(null!=resultMap.get("logoT")){ BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font FontChinese = new Font(bfChinese,20, Font.BOLD); Paragraph paragraph = new Paragraph((String)resultMap.get("logoT"),FontChinese); paragraph.setAlignment(Element.ALIGN_CENTER); document.add(paragraph); } PdfPTable table = null; String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; //开始循环写入svg图像到pdf文档对象 for(String str:svgName){ ////////////////////////////////////////////////////////////////////////////////////////////////////////// //positionAndSvg数组中元素说明: //positionAndSvg[0]表示svg图像所在页面的div的id //positionAndSvg[1]表示svg图像在水平方向的相对位置: // 1.left(水平方向两张图,居左且占比50%) // 2.right(水平方向两张图,居右且占比50%) // 3.center(水平方向一张图,居中且占比100%) //positionAndSvg[2]表示svg图像模块的标题如:xxx走势图 //positionAndSvg[3]表示soft/hard即软广图或者硬广图,当无数据时为无数据提示效果图提供判断依据 //positionAndSvg[4]表示svg图像元素,形如<svg...../> ////////////////////////////////////////////////////////////////////////////////////////////////////////// String[] positionAndSvg = str.split("___"); Image image1 = null; boolean havaData = true; if("noData".equals(positionAndSvg[4])){//无数据时 image1 = Image.getInstance(basePath+noData); havaData = false; }else{//有数据 image1 = Image.getInstance(highcharts(request,response,positionAndSvg[4]).toByteArray()); havaData = true; } if("left".equals(positionAndSvg[1])){ String title1 = URLDecoder.decode(positionAndSvg[2],"utf-8"); setTitleByCharts(document,30,title1,"",0,87,55,Element.ALIGN_LEFT,headfont); if(!"cooperateProporOne".equals(positionAndSvg[0])){ setTitleByCharts(document,0,"左图","右图",248,248,248,Element.ALIGN_CENTER,blackTextFont); }else{ setTitleByCharts(document,0,"","",248,248,248,Element.ALIGN_CENTER,blackTextFont); } table = new PdfPTable(2); float[] wid ={0.50f,0.50f}; //列宽度的比例 table.setWidths(wid); table = PdfPTableImage(table,image1,80f); }else if("right".equals(positionAndSvg[1])){ table = PdfPTableImage(table,image1,80f); table.setSpacingBefore(10); table=setTableHeightWeight(table,360f,1000); document.add(table); table = null; }else if("center".equals(positionAndSvg[1])){//总览全局 String title1 = URLDecoder.decode(positionAndSvg[2],"utf-8"); setTitleByCharts(document,30,title1,"",0,87,55,Element.ALIGN_LEFT,headfont); setTitleByCharts(document,0,"","",248,248,248,Element.ALIGN_CENTER,blackTextFont); table = new PdfPTable(1); float[] wid ={1.00f}; //列宽度的比例 table.setWidths(wid); if(havaData){ table = PdfPTableImageTable(table,image1,1000f,600f); }else{ table = PdfPTableImageTable(table,Image.getInstance(basePath+noDataCenter),1000f,600f); } table=setTableHeightWeight(table,400f,1000); document.add(table); table=null; } } //添加水印Start--------------------------------------------------------------------------------------------- PdfFileExportUtil pdfFileExportUtil = new PdfFileExportUtil(); pdfWriter.setPageEvent(pdfFileExportUtil.new PictureWaterMarkPdfPageEvent(basePath+waterMark)); // pdfWriter.setPageEvent(pdfFileExportUtil.new TextWaterMarkPdfPageEvent("xxx科技")); //添加水印End----------------------------------------------------------------------------------------------- document.close(); return buffer; } catch (BadElementException e) { e.printStackTrace(); return null; } catch (MalformedURLException e) { e.printStackTrace(); return null; } catch (DocumentException e) { e.printStackTrace(); return null; } catch (IOException e) { e.printStackTrace(); return null; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 设置图片类型Cell属性 * @param table * @param image1 * @param imgPercent * @return * @throws Exception */ private PdfPTable PdfPTableImage(PdfPTable table,Image image1,float imgPercent){ table = useTable(table,Element.ALIGN_CENTER); PdfPCell cellzr = createCellImage(image1,imgPercent); cellzr.setBorder(0); cellzr.setBackgroundColor(new BaseColor(248,248,248)); table.addCell(cellzr); return table; } /** * 设置图片类型Table的Cell属性 * @param table * @param image1 * @param imgPercentWidth * @param imgPercentHeight * @return * @throws Exception */ private PdfPTable PdfPTableImageTable(PdfPTable table,Image image1,float imgPercentWidth,float imgPercentHeight){ table = useTable(table,Element.ALIGN_CENTER); PdfPCell cellzr = createCellImageTable(image1,imgPercentWidth,imgPercentHeight); cellzr.setBorder(0); cellzr.setBackgroundColor(new BaseColor(248,248,248)); table.addCell(cellzr); return table; } /** * 设置表头 * @param document * @param SpacingBefore * @param title1 * @param title2 * @param r1 * @param r2 * @param r3 * @param ele * @param font * @throws Exception */ private void setTitleByCharts(Document document,int SpacingBefore,String title1,String title2,int r1,int r2,int r3,int ele,Font font){ try { float[] titlewidthsLeft = {0.50f,0.50f}; PdfPTable zrfbtitleTable = createTable(titlewidthsLeft); PdfPCell cellzr = createCellLeft(title1,font,ele); cellzr.setBorder(0); cellzr.setBackgroundColor(new BaseColor(r1,r2,r3)); zrfbtitleTable.addCell(cellzr); PdfPCell cellzr1 = createCellLeft(title2,font,ele); cellzr1.setBorder(0); cellzr1.setBackgroundColor(new BaseColor(r1,r2,r3)); zrfbtitleTable.addCell(cellzr1); zrfbtitleTable.setSpacingBefore(SpacingBefore); zrfbtitleTable=setTableHeightWeight(zrfbtitleTable,30f,1000); document.add(zrfbtitleTable); } catch (DocumentException e) { e.printStackTrace(); } } /** * 导出Pdf所用字体静态变量 */ private static Font headfont ;// title字体 private static Font blackTextFont ;// 黑色字体 private static Font colorfont; int maxWidth = 500; static{ BaseFont bfChinese; try { bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); headfont = new Font(bfChinese, 15, Font.BOLD);// 设置字体大小 headfont.setColor(BaseColor.WHITE); blackTextFont = new Font(bfChinese, 11, Font.BOLD);// 设置字体大小 blackTextFont.setColor(BaseColor.BLACK); colorfont = new Font(bfChinese, 11, Font.NORMAL);// 设置字体大小 colorfont.setColor(BaseColor.RED); } catch (Exception e) { e.printStackTrace(); } } /** * 创建指定内容背景色的Table元素Cell * @param value * @param font * @param c1 * @param c2 * @param c3 * @return */ public PdfPCell createCell(String value,Font font,int c1,int c2, int c3){ PdfPCell cell = new PdfPCell(); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); cell.setHorizontalAlignment(Element.ALIGN_CENTER); cell.setPhrase(new Phrase(value,font)); cell.setBackgroundColor(new BaseColor(c1,c2,c3)); cell.setFixedHeight(33.33f); cell.setBorder(0); return cell; } /** * 创建指定位置的Table元素Cell * @param value * @param font * @param ele * @return */ public PdfPCell createCellLeft(String value,Font font,int ele){ PdfPCell cell = new PdfPCell(); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); cell.setHorizontalAlignment(ele); cell.setPaddingLeft(10); cell.setPhrase(new Phrase(value,font)); return cell; } /** * 创建内容为Image的Table元素Cell * @param image * @param imgPercent * @return */ public PdfPCell createCellImage(Image image,float imgPercent){ image.scalePercent(imgPercent); PdfPCell cell = new PdfPCell(image,false); cell.setUseAscender(true); cell.setUseDescender(true); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); cell.setHorizontalAlignment(Element.ALIGN_CENTER); cell.setPaddingLeft(10); return cell; } /** * 创建table元素cell * @param image * @param imgPercentWidth * @param imgPercentHeight * @return */ public PdfPCell createCellImageTable(Image image,float imgPercentWidth,float imgPercentHeight){ image.scaleAbsoluteWidth(imgPercentWidth); if(imgPercentHeight==410f){ image.scaleAbsoluteHeight(imgPercentHeight); } PdfPCell cell = new PdfPCell(image,false); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); cell.setHorizontalAlignment(Element.ALIGN_CENTER); return cell; } /** * 创建Table * @param widths 列宽比例 * @return */ public PdfPTable createTable(float[] widths){ for(int i=0;i<widths.length;i++){ widths[i] = widths[i]*maxWidth; } PdfPTable table = new PdfPTable(widths); try{ table.setTotalWidth(maxWidth); table.setLockedWidth(true); table.setHorizontalAlignment(Element.ALIGN_CENTER); table.getDefaultCell().setBorder(1); }catch(Exception e){ e.printStackTrace(); } return table; } /** * 设置table参数 * @param table * @param position * @return */ public PdfPTable useTable(PdfPTable table,int position){ try{ table.setTotalWidth(maxWidth); table.setLockedWidth(true); table.setHorizontalAlignment(position); table.getDefaultCell().setBorder(0); }catch(Exception e){ e.printStackTrace(); } return table; } /** * 设置PdfTable行高 * @param table * @param maxHeight * @param maxWidth * @return */ public PdfPTable setTableHeightWeight(PdfPTable table,float maxHeight,float maxWidth){ table.setTotalWidth(maxWidth); List<PdfPRow> list=new ArrayList<PdfPRow>(); list=table.getRows(); for(PdfPRow pr:list){ pr.setMaxHeights(maxHeight); } return table; } /** * 根据SVG字符串得到一个输出流 * @param request * @param response * @param svg * @return * @throws Exception */ public ByteArrayOutputStream highcharts(HttpServletRequest request,HttpServletResponse response,String svg){ try { request.setCharacterEncoding("utf-8");// 注意编码 //转码防止乱码 byte[] arrayStr = svg.getBytes("utf-8"); svg = new String(arrayStr, "UTF-8"); ByteArrayOutputStream stream = new ByteArrayOutputStream(); try { stream=this.transcode(stream, svg); } catch (Exception e) { e.printStackTrace(); } return stream; } catch (UnsupportedEncodingException e) { e.printStackTrace(); return null; } } /** * 对svg进行转码 * @param stream * @param svg * @return * @throws Exception */ public synchronized ByteArrayOutputStream transcode(ByteArrayOutputStream stream, String svg){ try { TranscoderInput input = new TranscoderInput(new StringReader(svg)); TranscoderOutput transOutput = new TranscoderOutput(stream); PNGTranscoder transcoder = new PNGTranscoder(); transcoder.transcode(input, transOutput); return stream; } catch (TranscoderException e) { e.printStackTrace(); return null; } } }
PDF文档绘制工具类
此工具类可以根据前端传来的svg信息,前文中提到的自定义position等属性,布局完成所要输出的PDF文档,因时间有限,不再一一赘述,有想研究的可以下载demo,我已做了一个demo供各位交流学习,下载地址:http://yun.baidu.com/share/link?shareid=2976350494&uk=657798452
相关文章推荐
- 学JavaWeb必看文章!为什么我们会使用struts2,springMVC和spring这样的框架?
- java、jsp之poi解析excel2007xlsx方法及参考
- 张老师:java读写锁
- Thread详解15:ReentrantReadWriteLock
- Java基础07 包
- java内存模型
- Eclipse JDBC连接Hive 两种方法 hiveserver hiveserver2
- javaweb学习笔记之项目运行
- CSRF spring mvc 跨站请求伪造防御,使用详解--基于上篇文章
- JAVA多线程实现的三种方式
- 自学java之hibernate操作数据库的增删查改
- Myeclipse搭建SSH框架
- 开发环境配置-eclipse中git的安装、配置与使用-4
- java 接口,抽象类 继承 归纳
- SpringMVC文件上传错误
- 我理解的--java策略模式
- java web QQ(六)
- spring中配置了事务,数据业务层捕获异常,事务配置不成功?
- JavaSE学习笔记(2016.3.31)
- java 中jdbc 链接数据库