参考 https://github.com/superad/pdf-kit.git
先看效果(不能上传PDF文档。。。)
POM.XML
4.0.0
com.github.superad.pdf.kit
pdf-kit
jar
${project.artifactId}
1.1-RELEASE
1.7
1.7
UTF-8
org.sonatype.oss
oss-parent
7
com.itextpdf
itextpdf
5.4.2
com.itextpdf.tool
xmlworker
5.4.1
com.itextpdf
itext-asian
5.2.0
org.xhtmlrenderer
flying-saucer-pdf
9.0.3
org.freemarker
freemarker
2.3.26-incubating
jfree
jfreechart
1.0.2
ch.qos.logback
logback-core
1.0.13
ch.qos.logback
logback-classic
1.0.13
ch.qos.logback
logback-access
1.0.13
org.slf4j
slf4j-api
1.7.5
org.slf4j
log4j-over-slf4j
1.7.21
com.google.guava
guava
20.0
org.projectlombok
lombok
1.14.8
org.apache.commons
commons-io
1.3.2
commons-lang
commons-lang
2.6
javax.servlet
servlet-api
2.5
provided
release
src/main/resources
true
org.apache.maven.plugins
maven-compiler-plugin
3.5.1
${java.target.version}
${project.encoding}
org.apache.maven.plugins
maven-source-plugin
2.2.1
package
jar-no-fork
org.apache.maven.plugins
maven-javadoc-plugin
2.9.1
package
jar
org.apache.maven.plugins
maven-gpg-plugin
1.5
verify
sign
oss
https://oss.sonatype.org/content/repositories/snapshots/
oss
https://oss.sonatype.org/service/local/staging/deploy/maven2
The Apache Software License, Version 2.0
http://www.apache.org/licenses/LICENSE-2.0.txt
repo
alpha
https://github.com/superad/pdf-kit.git
scm:git:https://github.com/superad/pdf-kit.git
scm:git:https://github.com/superad/pdf-kit.git
hello.ftl
${templateName}
iText官网:${ITEXTUrl}
FreeMarker官网:${freeMarkerUrl}
JFreeChart教程:${JFreeChartUrl}
静态logo图
气温变化对比图
发展建议分布图
第二页开始了
列表值:
<#list scores as item>
${item}
#list>
report_template.ftl
report_template
姓名:${name}
年龄:${age}
成绩:
<#list scores as item>
${item}
#list>
第二页开始了
TemplateBO
@Data
public class TemplateBO {
private String templateName;
private String freeMarkerUrl;
private String ITEXTUrl;
private String JFreeChartUrl;
private List scores;
private String imageUrl;
private String picUrl;
private String scatterUrl;
}
reportKit360.java
package pdf.kit;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import pdf.kit.component.PDFHeaderFooter;
import pdf.kit.component.PDFKit;
import pdf.kit.component.chart.ScatterPlotChart;
import pdf.kit.component.chart.model.XYLine;
import pdf.kit.component.chart.impl.DefaultLineChart;
import java.util.ArrayList;
import java.util.List;
/**
* Created by fgm on 2017/4/17.
* 360报告
*
*/
@Slf4j
public class ReportKit360 {
public static List getTemperatureLineList() {
List list= Lists.newArrayList();
for(int i=1;i<=7;i++){
XYLine line=new XYLine();
float random=Math.round(Math.random()*10);
line.setXValue("星期"+i);
line.setYValue(20+random);
line.setGroupName("下周");
list.add(line);
}
for(int i=1;i<=7;i++){
XYLine line=new XYLine();
float random=Math.round(Math.random()*10);
line.setXValue("星期"+i);
line.setYValue(20+random);
line.setGroupName("这周");
list.add(line);
}
return list;
}
public String createPDF(String templatePath,Object data, String fileName){
//pdf保存路径
try {
//设置自定义PDF页眉页脚工具类
PDFHeaderFooter headerFooter=new PDFHeaderFooter();
PDFKit kit=new PDFKit();
kit.setHeaderFooterBuilder(headerFooter);
//设置输出路径
kit.setSaveFilePath("D:\\gitee\\pdf-kit\\hello.pdf");
String saveFilePath=kit.exportToFile(fileName,data);
return saveFilePath;
} catch (Exception e) {
log.error("PDF生成失败{}", ExceptionUtils.getFullStackTrace(e));
return null;
}
}
public static void main(String[] args) {
ReportKit360 kit=new ReportKit360();
TemplateBO templateBO=new TemplateBO();
templateBO.setTemplateName("Hello iText! Hello freemarker! Hello jFreeChart!");
templateBO.setFreeMarkerUrl("http://www.zheng-hang.com/chm/freemarker2_3_24/ref_directive_if.html");
templateBO.setITEXTUrl("http://developers.itextpdf.com/examples-itext5");
templateBO.setJFreeChartUrl("http://www.yiibai.com/jfreechart/jfreechart_referenced_apis.html");
templateBO.setImageUrl("http://mss.vip.sankuai.com/v1/mss_74e5b6ab17f44f799a524fa86b6faebf/360report/logo_1.png");
List scores=new ArrayList();
scores.add("90");
scores.add("95");
scores.add("98");
templateBO.setScores(scores);
//折线图
List lineList=getTemperatureLineList();
DefaultLineChart lineChart=new DefaultLineChart();
lineChart.setHeight(500);
lineChart.setWidth(300);
String picUrl=lineChart.draw(lineList,0);
templateBO.setPicUrl(picUrl);
//散点图
String scatterUrl=ScatterPlotChart.draw(ScatterPlotChartTest.getData(),1,"他评得分(%)","自评得分(%)");
templateBO.setScatterUrl(scatterUrl);
String templatePath="D:\\gitee\\pdf-kit\\src\\test\\resources\\templates";
String path = kit.createPDF(templatePath, templateBO, "hello.pdf");
System.out.println(path);
}
}
ScatterPlotChartTest.java
package pdf.kit;
import com.google.common.collect.Lists;
import pdf.kit.component.chart.ScatterPlotChart;
import pdf.kit.component.chart.model.XYScatter;
import java.util.List;
/**
* Created by fgm on 2017/7/9.
*/
public class ScatterPlotChartTest {
public static void main(String[] args) {
List list=getData();
String path= ScatterPlotChart.draw(list,-1,"他评得分(%)","自评得分(%)");
System.out.println(path);
}
public static List getData() {
List list= Lists.newArrayList();
XYScatter xy=new XYScatter();
xy.setX(45);
xy.setY(55);
xy.setLabel("主见");
list.add(xy);
XYScatter xy1=new XYScatter();
xy1.setX(75);
xy1.setY(80);
xy1.setLabel("定战略");
list.add(xy1);
XYScatter xy2=new XYScatter();
xy2.setX(80);
xy2.setY(80);
xy2.setLabel("拿结果");
list.add(xy2);
XYScatter xy3=new XYScatter();
xy3.setX(90);
xy3.setY(25);
xy3.setLabel("带团队");
list.add(xy3);
return list;
}
}
interface HeaderFooterBuilder
package pdf.kit.component.builder;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
/**
* Created by fgm on 2017/4/15.
*/
public interface HeaderFooterBuilder {
/**
* @description 写页眉
*/
void writeHeader(PdfWriter writer, Document document, Object data, Font font, PdfTemplate template);
/**
* @description 写页脚
*/
void writeFooter(PdfWriter writer, Document document, Object data, Font font, PdfTemplate template);
/**
* @description 关闭文档前,获取替换页眉页脚处设置模板的文本
*/
String getReplaceOfTemplate(PdfWriter writer, Document document, Object data);
}
class PDFBuilder
package pdf.kit.component.builder;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pdf.kit.exception.PDFException;
import java.io.IOException;
/**
* 设置页面附加属性
*
*/
public class PDFBuilder extends PdfPageEventHelper {
private static Logger log= LoggerFactory.getLogger(PDFBuilder.class);
//字体文件名
private String fontFileName;
// 基础字体对象
private BaseFont bf;
// 利用基础字体生成的字体对象,一般用于生成中文文字
private Font fontDetail;
//文档字体大小
private int fontSize=12;
//模板
private PdfTemplate template;
//数据实体
private Object data;
//页眉页脚定制接口
private HeaderFooterBuilder headerFooterBuilder;
//不允许空的构造方法
private PDFBuilder() {
}
public PDFBuilder(HeaderFooterBuilder headerFooterBuilder) {
this(headerFooterBuilder,null);
}
public PDFBuilder(HeaderFooterBuilder headerFooterBuilder, Object data) {
this(headerFooterBuilder, data, "ping_fang_light.ttf");
}
public PDFBuilder(HeaderFooterBuilder headerFooterBuilder, Object data, String fontFileName) {
this(headerFooterBuilder, data, fontFileName, 12);
}
public PDFBuilder(HeaderFooterBuilder headerFooterBuilder, Object data, String fontFileName, int fontSize) {
this.headerFooterBuilder = headerFooterBuilder;
this.data=data;
this.fontFileName=fontFileName;
this.fontSize=fontSize;
}
public void onOpenDocument(PdfWriter writer, Document document) {
template = writer.getDirectContent().createTemplate(50, 50);
}
/**
*
* 关闭每页的时候,写入页眉,页脚等
*
*/
public void onEndPage(PdfWriter writer, Document document) {
this.addPage(writer, document);
}
//加分页
private void addPage(PdfWriter writer, Document document){
if(headerFooterBuilder !=null){
//1.初始化字体
initFront();
//2.写入页眉
headerFooterBuilder.writeHeader(writer,document,data,fontDetail,template);
//3.写入前半部分页脚
headerFooterBuilder.writeFooter(writer,document,data,fontDetail,template);
}
}
/**
*
* 关闭文档时,替换模板,完成整个页眉页脚组件
*
*/
public void onCloseDocument(PdfWriter writer, Document document) {
if(headerFooterBuilder !=null){
template.beginText();
template.setFontAndSize(bf,fontSize);
String replace= headerFooterBuilder.getReplaceOfTemplate(writer,document,data);
template.showText(replace);
template.endText();
template.closePath();
}
}
/**
* @description 初始化字体
*/
private void initFront(){
if(StringUtils.isEmpty(fontFileName)){
throw new PDFException("PDF文档字体未设置!");
}
try {
if (bf == null) {
//添加字体,以支持中文
String classpath=PDFBuilder.class.getClassLoader().getResource("").getPath();
String fontPath =classpath+"fonts/"+fontFileName;
//创建基础字体
bf = BaseFont.createFont(fontPath,BaseFont.IDENTITY_H,BaseFont.EMBEDDED);
}
if (fontDetail == null) {
fontDetail = new Font(bf, fontSize, Font.NORMAL);// 数据体字体
log.info("PDF文档字体初始化完成!");
}
} catch (DocumentException e) {
log.error("字体初始化失败{}", ExceptionUtils.getFullStackTrace(e));
throw new PDFException("字体初始化失败",e);
} catch (IOException e) {
log.error("字体初始化失败{}", ExceptionUtils.getFullStackTrace(e));
throw new PDFException("字体初始化失败",e);
}
}
public int getPresentFontSize() {
return fontSize;
}
public void setPresentFontSize(int fontSize) {
this.fontSize = fontSize;
}
public String getFontFileName() {
return fontFileName;
}
public void setFontFileName(String fontFileName) {
this.fontFileName = fontFileName;
}
}
class DefaultLineChart
package pdf.kit.component.chart.impl;
import lombok.extern.slf4j.Slf4j;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.ui.TextAnchor;
import pdf.kit.component.chart.LineChart;
/**
* Created by fgm on 2017/5/15.
* 设置默认的画图工具
*
*/
@Slf4j
public class DefaultLineChart extends LineChart {
private int width;
private int height;
protected void initPlot(JFreeChart chart, DefaultCategoryDataset dataSet) {
CategoryPlot plot = chart.getCategoryPlot();
super.initDefaultXYPlot(plot);
//设置节点的值显示
LineAndShapeRenderer lineRender = new LineAndShapeRenderer();
lineRender.setBaseItemLabelGenerator(new StandardCategoryItemLabelGenerator());
lineRender.setBaseItemLabelsVisible(true);
lineRender.setBasePositiveItemLabelPosition(
new ItemLabelPosition(ItemLabelAnchor.OUTSIDE12, TextAnchor.BASELINE_CENTER));
plot.setRenderer(lineRender);
}
@Override
public int getWidth() {
if(width==0){
return super.getWidth();
}
return width;
}
@Override
public void setWidth(int width) {
this.width = width;
}
@Override
public int getHeight() {
if(height==0){
return super.getHeight();
}
return height;
}
@Override
public void setHeight(int height) {
this.height = height;
}
}
class XYLine
package pdf.kit.component.chart.model;
import lombok.Data;
/**
* Created by fgm on 2017/4/7.
*/
@Data
public class XYLine {
private double yValue;
private String xValue;
private String groupName;
public XYLine(){
}
public XYLine(double yValue, String xValue, String groupName){
this.yValue=yValue;
this.xValue=xValue;
this.groupName=groupName;
}
}
class XYScatter
package pdf.kit.component.chart.model;
import lombok.Data;
/**
* Created by fgm on 2017/7/9.
*/
@Data
public class XYScatter {
private double x;
private double y;
private String label;
}
abstract class LineChart
package pdf.kit.component.chart;
import lombok.extern.slf4j.Slf4j;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.CategoryLabelPositions;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.category.DefaultCategoryDataset;
import pdf.kit.component.chart.model.XYLine;
import pdf.kit.util.FontUtil;
import java.awt.*;
import java.io.File;
import java.io.IOException;
import java.util.List;
/**
* Created by fgm on 2017/4/7.
*/
@Slf4j
public abstract class LineChart {
private int width;
private int height;
private static int defaultWidth=500;
private static int defaultHeight=220;
private String fileName;
public String draw(List lineList, int picId){
return draw("","","",lineList,picId);
}
public String draw(String title, String xLabel, String yLabel,
List lineList, int picId){
if(lineList==null || lineList.size()==0){
return "";
}
DefaultCategoryDataset dataSet=new DefaultCategoryDataset();
for(XYLine line:lineList){
dataSet.addValue(line.getYValue(),line.getGroupName(),line.getXValue());
}
try {
return drawLineChar(title,xLabel,yLabel,dataSet,picId);
}catch (Exception ex){
log.error("画图异常{}",ex);
return "";
}
}
/**
* @description 设置自定义的线条和背景色
*/
protected abstract void initPlot(JFreeChart chart,DefaultCategoryDataset dataSet);
protected void initDefaultXYPlot(CategoryPlot plot){
// 设置X轴
CategoryAxis domainAxis = plot.getDomainAxis();
domainAxis.setLabelFont(FontUtil.getFont(Font.PLAIN,13)); // 设置横轴字体
domainAxis.setTickLabelFont(FontUtil.getFont(Font.PLAIN,13));// 设置坐标轴标尺值字体
domainAxis.setLowerMargin(0.01);// 左边距 边框距离
domainAxis.setUpperMargin(0.06);// 右边距 边框距离,防止最后边的一个数据靠近了坐标轴。
domainAxis.setMaximumCategoryLabelLines(10);
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.DOWN_45);// 横轴 lable 的位置 横轴上的 Lable 45度倾斜 DOWN_45
// 设置Y轴
NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
rangeAxis.setLabelFont(FontUtil.getFont(Font.PLAIN, 13));
rangeAxis.setAutoRangeMinimumSize(1); //最小跨度
rangeAxis.setUpperMargin(0.18);//上边距,防止最大的一个数据靠近了坐标轴。
rangeAxis.setLowerBound(18); //最小值显示18
rangeAxis.setUpperBound(33); //最大值显示33
rangeAxis.setAutoRange(false); //不自动分配Y轴数据
rangeAxis.setTickMarkStroke(new BasicStroke(1.6f)); // 设置坐标标记大小
rangeAxis.setTickMarkPaint(Color.BLACK); // 设置坐标标记颜色
rangeAxis.setTickUnit(new NumberTickUnit(1));//每1个刻度显示一个刻度值
}
/**
* @description 画出折线图
* @return 图片地址
*/
private String drawLineChar(String title, String xLabel, String yLabel, DefaultCategoryDataset dataSet, int picId)
throws IOException {
JFreeChart lineChartObject= ChartFactory.createLineChart(
title,
xLabel, // 横轴
yLabel, // 纵轴
dataSet, // 获得数据集
PlotOrientation.VERTICAL,// 图标方向垂直
true, // 显示图例
false, // 不用生成工具
false // 不用生成URL地址
);
String path=this.getClass().getClassLoader().getResource("").getPath();
String filePath=path+"/images/"+picId+"/"+getFileName();
File lineChart = new File(filePath);
if(!lineChart.getParentFile().exists()){
lineChart.getParentFile().mkdirs();
}
//初始化表格样式
initDefaultPlot(lineChartObject,dataSet);
ChartUtilities.saveChartAsJPEG(lineChart ,lineChartObject, getWidth() ,getHeight());
return lineChart.getAbsolutePath();
}
private void initDefaultPlot(JFreeChart chart,DefaultCategoryDataset dataSet){
//设置公共颜色
chart.getTitle().setFont(FontUtil.getFont(Font.PLAIN, 15)); // 设置标题字体
chart.getLegend().setItemFont(FontUtil.getFont(Font.PLAIN, 13));// 设置图例类别字体
chart.setBackgroundPaint(Color.white);// 设置背景色
CategoryPlot plot = chart.getCategoryPlot();
plot.setNoDataMessage("无对应的数据。");
plot.setNoDataMessageFont(FontUtil.getFont(Font.PLAIN, 13));//字体的大小
plot.setNoDataMessagePaint(Color.RED);//字体颜色
//设置自定义颜色
initPlot(chart,dataSet);
}
public int getWidth() {
if(width==0){
return defaultWidth;
}
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
if(height==0){
return defaultHeight;
}
return height;
}
public void setHeight(int height) {
this.height = height;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
}
class ScatterPlotChart extends ChartFactory
package pdf.kit.component.chart;
import com.google.common.collect.Lists;
import freemarker.template.utility.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.annotations.XYBoxAnnotation;
import org.jfree.chart.annotations.XYTextAnnotation;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.StandardXYToolTipGenerator;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.StandardXYItemRenderer;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.urls.StandardXYURLGenerator;
import org.jfree.data.xy.DefaultXYDataset;
import org.jfree.data.xy.XYDataset;
import pdf.kit.component.chart.model.XYScatter;
import pdf.kit.util.FontUtil;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
/**
* Created by fgm on 2017/7/4.
* 散点图生成
*/
@Slf4j
public class ScatterPlotChart extends ChartFactory {
private static BufferedImage backgroundImage;
private static String fileName="scatterChart.png";
private static int width=700;
private static int height=600;
//上方垂直
private static double turnTop=4.712389;
public static String draw(List list,int picId,String xLabel,String yLabel){
return draw(list,picId,"",xLabel,yLabel);
}
public static String draw(List list,int picId,String title,String xLabel,String yLabel){
XYDataset xyDataset= ScatterPlotChart.createXYDataSet(list,"");
String path=LineChart.class.getClassLoader().getResource("").getPath();
String filePath=path+"/images/"+picId+"/"+fileName;
File scatterChartFile = new File(filePath);
if(!scatterChartFile.getParentFile().exists()){
scatterChartFile.getParentFile().mkdirs();
}
try {
JFreeChart jFreeChart = createChart(xyDataset,list,title,xLabel,yLabel);
ChartUtilities.saveChartAsJPEG(scatterChartFile ,jFreeChart, width ,height);
} catch (IOException ex) {
log.error("散点图生成异常:{}", ExceptionUtils.getFullStackTrace(ex));
return "";
}
return scatterChartFile.getAbsolutePath();
}
public static JFreeChart createScatterPlot(String title, String xAxisLabel, String yAxisLabel, XYDataset dataset, PlotOrientation orientation, boolean legend, boolean tooltips, boolean urls) {
if(orientation == null) {
throw new IllegalArgumentException("Null \'orientation\' argument.");
} else {
NumberAxis xAxis = new NumberAxis(xAxisLabel);
xAxis.setAutoRangeIncludesZero(false);
NumberAxis yAxis = new NumberAxis(yAxisLabel);
yAxis.setAutoRangeIncludesZero(false);
XYItemRenderer render=new StandardXYItemRenderer();
render.setBaseItemLabelsVisible(false);
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, render);
StandardXYToolTipGenerator toolTipGenerator = null;
if(tooltips) {
toolTipGenerator = new StandardXYToolTipGenerator();
}
StandardXYURLGenerator urlGenerator = null;
if(urls) {
urlGenerator = new StandardXYURLGenerator();
}
XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(false, true);
renderer.setSeriesItemLabelFont(0,FontUtil.getFont(Font.PLAIN,14));
renderer.setBaseItemLabelsVisible(false);
renderer.setBaseToolTipGenerator(toolTipGenerator);
renderer.setURLGenerator(urlGenerator);
plot.setRenderer(renderer);
plot.setOrientation(orientation);
JFreeChart chart = new JFreeChart(title, FontUtil.getFont(Font.PLAIN,18), plot, legend);
return chart;
}
}
public static XYDataset createXYDataSet(List dataList,
String dataName) {
DefaultXYDataset dataSet = new DefaultXYDataset();
if(dataList==null ||dataList.size()==0){
return dataSet;
}
int size = dataList.size();
double[][] data = new double[2][size];
for (int i = 0; i < size; i++) {
XYScatter behaviorBO = dataList.get(i);
double x = behaviorBO.getX();
double y = behaviorBO.getY();
data[0][i] = x;
data[1][i] = y;
}
dataSet.addSeries(dataName,data);
return dataSet;
}
public static JFreeChart createChart(XYDataset xydataset, List dataList,
String title,String xLabel,String yLabel) throws IOException {
JFreeChart jfreechart = createScatterPlot(title,xLabel,yLabel,
xydataset, PlotOrientation.VERTICAL, true, true, false);
jfreechart.getLegend().setItemFont(FontUtil.getFont(Font.PLAIN,14));
//去掉图例
jfreechart.getLegend().setBorder(0,0,0,0);
//画每个坐标点
Shape shape = new Ellipse2D.Double(-4,-4,8,8);
XYPlot xyPlot = (XYPlot) jfreechart.getPlot();
XYItemRenderer renderer = xyPlot.getRenderer();
renderer.setItemLabelFont(FontUtil.getFont(Font.PLAIN, 14));
for(int i=0;i dataList) {
//数据录入
if(dataList==null ||dataList.size()==0){
return;
}
XYPlot xyplot = (XYPlot) jfreechart.getPlot();
for(XYScatter xyScatter:dataList){
XYPointerFrameAnnotation pointerAnnotation=new XYPointerFrameAnnotation(
xyScatter.getLabel(),
xyScatter.getX(),
xyScatter.getY(),
turnTop
);
pointerAnnotation.setFont(FontUtil.getFont(Font.PLAIN, 13));
xyplot.addAnnotation(pointerAnnotation);
}
}
/**
* @description 初始化背景色
*/
private static void initBackGroundAndAxis(JFreeChart jfreechart) throws IOException {
jfreechart.setBackgroundPaint(Color.white);
jfreechart.setBorderPaint(Color.black);
jfreechart.setBorderStroke(new BasicStroke(1.5f));
XYPlot xyplot = (XYPlot) jfreechart.getPlot();
//无数据显示
xyplot.setNoDataMessage("没有数据");
xyplot.setNoDataMessageFont(FontUtil.getFont(Font.PLAIN, 18));
//背景色
if(backgroundImage==null){
String classpath= ScatterPlotChart.class.getClassLoader().getResource("").getPath();
String backgroundImg=classpath+"/background/back.png";
backgroundImage = ImageIO.read(new FileInputStream(backgroundImg));
}
xyplot.setBackgroundImage(backgroundImage);
xyplot.setBackgroundImageAlpha(1.0F);
xyplot.setOutlineStroke(new BasicStroke(1.5f)); // 边框粗细
ValueAxis vaaxis = xyplot.getDomainAxis();
vaaxis.setAxisLineStroke(new BasicStroke(1.5f));
vaaxis.setLabelFont(FontUtil.getFont(Font.PLAIN,14));
//坐标轴和背景色
ValueAxis va = xyplot.getDomainAxis(0);
va.setAxisLineStroke(new BasicStroke(1.5f));
va.setAxisLineStroke(new BasicStroke(1.5f)); // 坐标轴粗细
va.setAxisLinePaint(Color.black); // 坐标轴颜色
va.setLabelPaint(Color.black); // 坐标轴标题颜色
va.setTickLabelPaint(Color.black); // 坐标轴标尺值颜色
va.setAxisLineVisible(false);
va.setLabelFont(FontUtil.getFont(Font.PLAIN, 14));
ValueAxis axis = xyplot.getRangeAxis();
axis.setAxisLineStroke(new BasicStroke(1.5f));
XYLineAndShapeRenderer xylineandshaperenderer = (XYLineAndShapeRenderer) xyplot
.getRenderer();
xylineandshaperenderer.setSeriesOutlinePaint(0, Color.WHITE);
xylineandshaperenderer.setUseOutlinePaint(false);
//x 轴
NumberAxis xAxis = (NumberAxis) xyplot.getDomainAxis();
xAxis.setAutoRangeIncludesZero(false);
xAxis.setAutoRangeStickyZero(false);
xAxis.setTickMarkInsideLength(2.0F);
xAxis.setTickMarkOutsideLength(0.0F);
xAxis.setAxisLineStroke(new BasicStroke(1.5f));
xAxis.setTickUnit(new NumberTickUnit(25));
xAxis.setLabelFont(FontUtil.getFont(Font.PLAIN, 14));
xAxis.setUpperBound(101);//最大值
xAxis.setLowerBound(0);//最小值
//y 轴
NumberAxis yAxis = (NumberAxis) xyplot.getRangeAxis();
yAxis.setAutoRangeIncludesZero(false);
yAxis.setAutoRangeStickyZero(false);
yAxis.setTickMarkInsideLength(2.0F);
yAxis.setTickMarkOutsideLength(0.0F);
yAxis.setTickUnit(new NumberTickUnit(25));
yAxis.setAxisLineStroke(new BasicStroke(1.5f));
yAxis.setLabelFont(FontUtil.getFont(Font.PLAIN, 14));
yAxis.setUpperBound(101);//最大值
yAxis.setLowerBound(0);//最小值
}
/**
* @description 初始化区域划分
* | 00 | 10 | 20 |
* | 01 | 11 | 21 |
* | 02 | 21 | 22 |
*
*
*/
private static void initRegionPartition(JFreeChart jfreechart) {
Stroke stroke=new BasicStroke(0.5F);
Paint outlinePaint=Color.WHITE;
//划分区间
XYBoxAnnotation box00 = new XYBoxAnnotation(0, 0, 50, 50,stroke,outlinePaint);
XYBoxAnnotation box01 = new XYBoxAnnotation(0, 50, 50, 75,stroke,outlinePaint);
XYBoxAnnotation box02 = new XYBoxAnnotation(0, 75, 50, 101,stroke,outlinePaint);
XYBoxAnnotation box10 = new XYBoxAnnotation(50, 0, 75, 50,stroke,outlinePaint);
XYBoxAnnotation box11 = new XYBoxAnnotation(50, 50, 75, 75,stroke,outlinePaint);
XYBoxAnnotation box12 = new XYBoxAnnotation(50, 75, 75, 101,stroke,outlinePaint);
XYBoxAnnotation box20 = new XYBoxAnnotation(75, 0, 101, 50,stroke,outlinePaint);
XYBoxAnnotation box21 = new XYBoxAnnotation(75, 50, 101, 75,stroke,outlinePaint);
XYBoxAnnotation box22 = new XYBoxAnnotation(75, 75, 101, 101,stroke,outlinePaint);
XYPlot xyplot = (XYPlot) jfreechart.getPlot();
xyplot.addAnnotation(box00);
xyplot.addAnnotation(box01);
xyplot.addAnnotation(box02);
xyplot.addAnnotation(box10);
xyplot.addAnnotation(box11);
xyplot.addAnnotation(box12);
xyplot.addAnnotation(box20);
xyplot.addAnnotation(box21);
xyplot.addAnnotation(box22);
//添加区间标识
XYTextAnnotation text1 = new XYTextAnnotation("盲区", 4, 98);
text1.setFont(FontUtil.getFont(Font.PLAIN, 18));
text1.setPaint(new Color(255,165,0));
XYTextAnnotation text2 = new XYTextAnnotation("待发展共识区", 10, 3);
text2.setFont(FontUtil.getFont(Font.PLAIN, 18));
text2.setPaint(new Color(253, 88, 72));
XYTextAnnotation text3 = new XYTextAnnotation("潜能区", 96, 3);
text3.setFont(FontUtil.getFont(Font.PLAIN, 18));
text3.setPaint(new Color(45, 139, 251));
XYTextAnnotation text4 = new XYTextAnnotation("优势共识区", 93, 98);
text4.setFont(FontUtil.getFont(Font.PLAIN, 18));
text4.setPaint(new Color(20, 149, 134));
xyplot.addAnnotation(text1);
xyplot.addAnnotation(text2);
xyplot.addAnnotation(text3);
xyplot.addAnnotation(text4);
}
}
class XYPointerFrameAnnotation extends XYTextAnnotation implements Cloneable, PublicCloneable, Serializable
package pdf.kit.component.chart;
import org.jfree.chart.annotations.XYTextAnnotation;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.Plot;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.PlotRenderingInfo;
import org.jfree.chart.plot.XYPlot;
import org.jfree.io.SerialUtilities;
import org.jfree.text.TextUtilities;
import org.jfree.ui.RectangleEdge;
import org.jfree.ui.TextAnchor;
import org.jfree.util.ObjectUtilities;
import org.jfree.util.PublicCloneable;
import java.awt.*;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* Created by fgm on 2017/7/4.
*/
public class XYPointerFrameAnnotation extends XYTextAnnotation implements Cloneable, PublicCloneable, Serializable{
private static final long serialVersionUID = -4031161445009858499L;
public static final double DEFAULT_TIP_RADIUS = 10.0D;
public static final double DEFAULT_BASE_RADIUS = 40.0D;
public static final double DEFAULT_LABEL_OFFSET = 8.0D;
public static final double DEFAULT_ARROW_LENGTH = 10.0D;
public static final double DEFAULT_ARROW_WIDTH = 3.0D;
private double angle;
private double tipRadius;
private double baseRadius;
private double arrowLength;
private double arrowWidth;
private transient Stroke arrowStroke;
private transient Paint arrowPaint;
private double labelOffset;
private transient Paint linePaint;
public XYPointerFrameAnnotation(String label, double x, double y, double angle) {
super(label, x, y);
this.angle = angle;
this.tipRadius = 1;//连接线到点的距离
this.baseRadius =50;//连接线的半径
this.arrowLength =0;//箭头长度 不需要
this.arrowWidth = 0;//箭头宽度 不需要
this.labelOffset = 10;//label字体和竖线的距离
this.arrowStroke = new BasicStroke(1.0F);
this.arrowPaint = Color.WHITE;
this.linePaint=Color.WHITE;
}
public double getAngle() {
return this.angle;
}
public void setAngle(double angle) {
this.angle = angle;
}
public double getTipRadius() {
return this.tipRadius;
}
public void setTipRadius(double radius) {
this.tipRadius = radius;
}
public double getBaseRadius() {
return this.baseRadius;
}
public void setBaseRadius(double radius) {
this.baseRadius = radius;
}
public double getLabelOffset() {
return this.labelOffset;
}
public void setLabelOffset(double offset) {
this.labelOffset = offset;
}
public double getArrowLength() {
return this.arrowLength;
}
public void setArrowLength(double length) {
this.arrowLength = length;
}
public double getArrowWidth() {
return this.arrowWidth;
}
public void setArrowWidth(double width) {
this.arrowWidth = width;
}
public Stroke getArrowStroke() {
return this.arrowStroke;
}
public Paint getLinePaint() {
return linePaint;
}
public void setLinePaint(Paint linePaint) {
this.linePaint = linePaint;
}
public void setArrowStroke(Stroke stroke) {
if(stroke == null) {
throw new IllegalArgumentException("Null \'stroke\' not permitted.");
} else {
this.arrowStroke = stroke;
}
}
public Paint getArrowPaint() {
return this.arrowPaint;
}
public void setArrowPaint(Paint paint) {
this.arrowPaint = paint;
}
public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, ValueAxis domainAxis, ValueAxis rangeAxis, int rendererIndex, PlotRenderingInfo info) {
PlotOrientation orientation = plot.getOrientation();
RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(plot.getDomainAxisLocation(), orientation);
RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(plot.getRangeAxisLocation(), orientation);
double j2DX = domainAxis.valueToJava2D(this.getX(), dataArea, domainEdge);
double j2DY = rangeAxis.valueToJava2D(this.getY(), dataArea, rangeEdge);
double startX;
if(orientation == PlotOrientation.HORIZONTAL) {
startX = j2DX;
j2DX = j2DY;
j2DY = startX;
}
startX = j2DX + Math.cos(this.angle) * this.baseRadius;
double startY = j2DY + Math.sin(this.angle) * this.baseRadius;
double endX = j2DX + Math.cos(this.angle) * this.tipRadius;
double endY = j2DY + Math.sin(this.angle) * this.tipRadius;
g2.setStroke(this.arrowStroke);
g2.setPaint(this.arrowPaint);
Line2D.Double line = new Line2D.Double(startX, startY, endX, endY);
g2.draw(line);
g2.setFont(this.getFont());
g2.setPaint(this.getPaint());
double labelX = j2DX + Math.cos(this.angle) * (this.baseRadius + this.labelOffset);
double labelY = j2DY + Math.sin(this.angle) * (this.baseRadius + this.labelOffset);
Rectangle2D rectangle2D=TextUtilities.drawAlignedString(this.getText(), g2,(float)labelX, (float)labelY, TextAnchor.BASELINE_CENTER);
//添加边框
g2.setColor(Color.WHITE);
g2.setStroke(new BasicStroke(1.0F));
rectangle2D.setFrame(rectangle2D.getX()-3,rectangle2D.getY()-2,rectangle2D.getWidth()+5,rectangle2D.getHeight()+2);
g2.draw(rectangle2D);
}
public boolean equals(Object obj) {
if(obj == null) {
return false;
} else if(obj == this) {
return true;
} else if(!(obj instanceof XYPointerFrameAnnotation)) {
return false;
} else if(!super.equals(obj)) {
return false;
} else {
XYPointerFrameAnnotation that = (XYPointerFrameAnnotation)obj;
return this.angle != that.angle?false:(this.tipRadius != that.tipRadius?false:(this.baseRadius != that.baseRadius?false:(this.arrowLength != that.arrowLength?false:(this.arrowWidth != that.arrowWidth?false:(!this.arrowPaint.equals(that.arrowPaint)?false:(!ObjectUtilities.equal(this.arrowStroke, that.arrowStroke)?false:this.labelOffset == that.labelOffset))))));
}
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
private void writeObject(ObjectOutputStream stream) throws IOException {
stream.defaultWriteObject();
SerialUtilities.writePaint(this.arrowPaint, stream);
SerialUtilities.writeStroke(this.arrowStroke, stream);
}
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
this.arrowPaint = SerialUtilities.readPaint(stream);
this.arrowStroke = SerialUtilities.readStroke(stream);
}
}
class PDFHeaderFooter implements HeaderFooterBuilder
package pdf.kit.component;
import com.itextpdf.text.Document;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import pdf.kit.component.builder.HeaderFooterBuilder;
/**
* Created by fgm on 2017/4/22.
* 页眉页脚定制工具
*/
public class PDFHeaderFooter implements HeaderFooterBuilder {
/**
* @param writer PDF编写类
* @param document PDF文档对象
* @param data 业务数据
* @param font 字体设置
* @param template PDF模板
* @description PDF页脚设置类
*/
public void writeFooter(PdfWriter writer,
Document document,
Object data,
Font font,
PdfTemplate template) {
if (data == null) {
return;
}
int pageS = writer.getPageNumber();
int currentPage = pageS - 1;
if (currentPage <= 0) {
return;
}
Phrase footer1 = new Phrase("页脚一", font);
Phrase footer2 = new Phrase("页脚二" + " " + currentPage + "/", font);
PdfContentByte cb = writer.getDirectContent();
ColumnText.showTextAligned(
cb,
Element.ALIGN_LEFT,
footer1,
(document.left() + 10),
document.bottom() - 20,
0);
ColumnText.showTextAligned(
cb,
Element.ALIGN_RIGHT,
footer2,
(document.right() - 30),
document.bottom() - 20, 0);
//设置模板位置
cb.addTemplate(template, document.right() - 30, document.bottom() - 20);
}
/**
* @param writer PDF编写类
* @param document PDF文档对象
* @param data 业务数据
* @param font 字体设置
* @param template PDF模板
* @description PDF页头设置类
*/
public void writeHeader(PdfWriter writer,
Document document,
Object data,
Font font,
PdfTemplate template) {
ColumnText.showTextAligned(
writer.getDirectContent(),
Element.ALIGN_LEFT,
new Phrase("我是页眉", font),
document.left(),
document.top() + 20, 0);
}
/**
* @param writer PDF编写类
* @param document PDF文档对象
* @param data 业务数据
* @description 页头、页眉设置的模板替换类
*/
public String getReplaceOfTemplate(PdfWriter writer, Document document, Object data) {
int total = writer.getPageNumber() - 2;
return total + "";
}
}
PDFKit
package pdf.kit.component;
import com.itextpdf.text.Document;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.xhtmlrenderer.pdf.ITextRenderer;
import pdf.kit.component.builder.HeaderFooterBuilder;
import pdf.kit.component.builder.PDFBuilder;
import pdf.kit.exception.PDFException;
import pdf.kit.util.FreeMarkerUtil;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.nio.charset.Charset;
@Slf4j
public class PDFKit {
//PDF页眉、页脚定制工具
private HeaderFooterBuilder headerFooterBuilder;
private String saveFilePath;
/**
* @description 导出pdf到文件
* @param fileName 输出PDF文件名
* @param data 模板所需要的数据
*
*/
public String exportToFile(String fileName,Object data){
String htmlData= FreeMarkerUtil.getContent(fileName, data);
if(StringUtils.isEmpty(saveFilePath)){
saveFilePath=getDefaultSavePath(fileName);
}
File file=new File(saveFilePath);
if(!file.getParentFile().exists()){
file.getParentFile().mkdirs();
}
FileOutputStream outputStream=null;
try{
//设置输出路径
outputStream=new FileOutputStream(saveFilePath);
//设置文档大小
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, outputStream);
//设置页眉页脚
PDFBuilder builder = new PDFBuilder(headerFooterBuilder,data);
builder.setPresentFontSize(10);
writer.setPageEvent(builder);
//输出为PDF文件
convertToPDF(writer,document,htmlData);
}catch(Exception ex){
throw new PDFException("PDF export to File fail",ex);
}finally{
IOUtils.closeQuietly(outputStream);
}
return saveFilePath;
}
/**
* 生成PDF到输出流中(ServletOutputStream用于下载PDF)
* @param ftlPath ftl模板文件的路径(不含文件名)
* @param data 输入到FTL中的数据
* @param response HttpServletResponse
* @return
*/
public OutputStream exportToResponse(String ftlPath,Object data,
HttpServletResponse response){
String html= FreeMarkerUtil.getContent(ftlPath,data);
try{
OutputStream out = null;
ITextRenderer render = null;
out = response.getOutputStream();
//设置文档大小
Document document = new Document(PageSize.A4);
PdfWriter writer = PdfWriter.getInstance(document, out);
//设置页眉页脚
PDFBuilder builder = new PDFBuilder(headerFooterBuilder,data);
writer.setPageEvent(builder);
//输出为PDF文件
convertToPDF(writer,document,html);
return out;
}catch (Exception ex){
throw new PDFException("PDF export to response fail",ex);
}
}
/**
* @description PDF文件生成
*/
private void convertToPDF(PdfWriter writer,Document document,String htmlString){
//获取字体路径
String fontPath=getFontPath();
document.open();
try {
XMLWorkerHelper.getInstance().parseXHtml(writer,document,
new ByteArrayInputStream(htmlString.getBytes()),
XMLWorkerHelper.class.getResourceAsStream("/default.css"),
Charset.forName("UTF-8"),new XMLWorkerFontProvider(fontPath));
} catch (IOException e) {
e.printStackTrace();
throw new PDFException("PDF文件生成异常",e);
}finally {
document.close();
}
}
/**
* @description 创建默认保存路径
*/
private String getDefaultSavePath(String fileName){
String classpath=PDFKit.class.getClassLoader().getResource("").getPath();
String saveFilePath=classpath+"pdf/"+fileName;
File f=new File(saveFilePath);
if(!f.getParentFile().exists()){
f.mkdirs();
}
return saveFilePath;
}
/**
* @description 获取字体设置路径
*/
public static String getFontPath() {
String classpath=PDFKit.class.getClassLoader().getResource("").getPath();
String fontpath=classpath+"fonts";
return fontpath;
}
public HeaderFooterBuilder getHeaderFooterBuilder() {
return headerFooterBuilder;
}
public void setHeaderFooterBuilder(HeaderFooterBuilder headerFooterBuilder) {
this.headerFooterBuilder = headerFooterBuilder;
}
public String getSaveFilePath() {
return saveFilePath;
}
public void setSaveFilePath(String saveFilePath) {
this.saveFilePath = saveFilePath;
}
}
BaseException
package pdf.kit.exception;
/**
* Created by fgm on 2017/4/22.
*/
public class BaseException extends RuntimeException {
public int errorCode;
public String errorMsg;
public BaseException(){
super("运行时异常");
}
public BaseException(int errorCode, String errorMsg){
super(errorMsg);
this.errorCode=errorCode;
this.errorMsg=errorMsg;
}
public BaseException(String errorMsg){
super(errorMsg);
this.errorCode=500;
this.errorMsg=errorMsg;
}
public BaseException(String errorMsg, Exception e){
super(errorMsg,e);
this.errorCode=500;
this.errorMsg=errorMsg;
}
}
FreeMarkerException
package pdf.kit.exception;
/**
* Created by fgm on 2017/4/22.
*/
public class FreeMarkerException extends BaseException {
public FreeMarkerException(){
super("FreeMarker异常");
}
public FreeMarkerException(int errorCode, String errorMsg){
super(errorMsg);
this.errorCode=errorCode;
this.errorMsg=errorMsg;
}
public FreeMarkerException(String errorMsg){
super(errorMsg);
this.errorCode=500;
this.errorMsg=errorMsg;
}
public FreeMarkerException(String errorMsg, Exception e){
super(errorMsg,e);
this.errorCode=500;
this.errorMsg=errorMsg;
}
}
PDFException
package pdf.kit.exception;
/**
* Created by fgm on 2017/4/22.
*/
public class PDFException extends BaseException {
public PDFException(){
super("PDF异常");
}
public PDFException(int errorCode, String errorMsg){
super(errorMsg);
this.errorCode=errorCode;
this.errorMsg=errorMsg;
}
public PDFException(String errorMsg){
super(errorMsg);
this.errorCode=500;
this.errorMsg=errorMsg;
}
public PDFException(String errorMsg, Exception e){
super(errorMsg,e);
this.errorCode=500;
this.errorMsg=errorMsg;
}
}
FontUtil
package pdf.kit.util;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.exception.ExceptionUtils;
import java.awt.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;
/**
* Created by fgm on 2017/4/22.
*/
@Slf4j
public class FontUtil {
private static final Map fontCache= Maps.newConcurrentMap();
public static String getFontPath(String fontName){
String classPath=FontUtil.class.getClassLoader().getResource("").getPath();
return classPath+"/fonts/"+fontName;
}
/**
* @description 加载自定义字体
*/
public static Font loadFont(String fontFileName, int style, float fontSize) throws IOException {
FileInputStream fis=null;
String key=fontFileName+"|"+style;
Font dynamicFont=fontCache.get(key);
if(dynamicFont==null){
try{
File file = new File(fontFileName);
fis= new FileInputStream(file);
dynamicFont = Font.createFont(style, fis);
fontCache.put(key,dynamicFont);
}catch(Exception e){
return new Font("宋体", Font.PLAIN, 14);
}finally{
fis.close();
}
}
Font dynamicFontPt = dynamicFont.deriveFont(fontSize);
return dynamicFontPt;
}
public static Font getFont(int style,float fontSize){
try {
String fontPath = FontUtil.getFontPath("SIMLI.TTF");
Font font = loadFont(fontPath,style,fontSize);
return font;
} catch (IOException e) {
log.error("字体加载异常{}", ExceptionUtils.getFullStackTrace(e));
}
return null;
}
}
FreeMarkerUtil
package pdf.kit.util;
import com.google.common.collect.Maps;
import freemarker.cache.FileTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateExceptionHandler;
import org.apache.commons.lang.StringUtils;
import pdf.kit.component.PDFKit;
import pdf.kit.exception.FreeMarkerException;
import pdf.kit.exception.PDFException;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.util.Map;
/**
* Created by fgm on 2017/4/22.
* FREEMARKER 模板工具类
*/
public class FreeMarkerUtil {
private static final String WINDOWS_SPLIT = "\\";
private static final String UTF_8="UTF-8";
private static Map fileTemplateLoaderCache=Maps.newConcurrentMap();
private static Map configurationCache= Maps.newConcurrentMap();
public static Configuration getConfiguration(String templateFilePath){
if(null!=configurationCache.get(templateFilePath)){
return configurationCache.get(templateFilePath);
}
Configuration config = new Configuration(Configuration.VERSION_2_3_25);
config.setDefaultEncoding(UTF_8);
config.setTemplateExceptionHandler(TemplateExceptionHandler.RETHROW_HANDLER);
config.setLogTemplateExceptions(false);
FileTemplateLoader fileTemplateLoader=null;
if(null!=fileTemplateLoaderCache.get(templateFilePath)){
fileTemplateLoader=fileTemplateLoaderCache.get(templateFilePath);
}
try {
fileTemplateLoader=new FileTemplateLoader(new File(templateFilePath));
fileTemplateLoaderCache.put(templateFilePath,fileTemplateLoader);
} catch (IOException e) {
throw new FreeMarkerException("fileTemplateLoader init error!",e);
}
config.setTemplateLoader(fileTemplateLoader);
configurationCache.put(templateFilePath,config);
return config;
}
/**
* @description 获取模板
*/
public static String getContent(String fileName, Object data) {
String templatePath = getPDFTemplatePath(fileName);
String templateFileName = getTemplateName(templatePath);
String templateFilePath = getTemplatePath(templatePath);
if (StringUtils.isEmpty(templatePath)) {
throw new FreeMarkerException("templatePath can not be empty!");
}
try {
Template template=getConfiguration(templateFilePath).getTemplate(templateFileName);
StringWriter writer = new StringWriter();
template.process(data, writer);
writer.flush();
return writer.toString();
} catch (Exception ex) {
throw new FreeMarkerException("FreeMarkerUtil process fail", ex);
}
}
private static String getTemplatePath(String templatePath) {
if (StringUtils.isEmpty(templatePath)) {
return "";
}
if (templatePath.contains(WINDOWS_SPLIT)) {
return templatePath.substring(0, templatePath.lastIndexOf(WINDOWS_SPLIT));
}
return templatePath.substring(0, templatePath.lastIndexOf("/"));
}
private static String getTemplateName(String templatePath) {
if (StringUtils.isEmpty(templatePath)) {
return "";
}
if (templatePath.contains(WINDOWS_SPLIT)) {
return templatePath.substring(templatePath.lastIndexOf(WINDOWS_SPLIT) + 1);
}
return templatePath.substring(templatePath.lastIndexOf("/") + 1);
}
/**
* @param fileName PDF文件名 (hello.pdf)
* @return 匹配到的模板名
* @description 获取PDF的模板路径,
* 默认按照PDF文件名匹对应模板
*/
public static String getPDFTemplatePath(String fileName) {
String classpath = PDFKit.class.getClassLoader().getResource("").getPath();
String templatePath = classpath + "/templates";
File file = new File(templatePath);
if (!file.isDirectory()) {
throw new PDFException("PDF模板文件不存在,请检查templates文件夹!");
}
String pdfFileName = fileName.substring(0, fileName.lastIndexOf("."));
File defaultTemplate = null;
File matchTemplate = null;
for (File f : file.listFiles()) {
if (!f.isFile()) {
continue;
}
String templateName = f.getName();
if (templateName.lastIndexOf(".ftl") == -1) {
continue;
}
if (defaultTemplate == null) {
defaultTemplate = f;
}
if (StringUtils.isEmpty(fileName) && defaultTemplate != null) {
break;
}
templateName = templateName.substring(0, templateName.lastIndexOf("."));
if (templateName.toLowerCase().equals(pdfFileName.toLowerCase())) {
matchTemplate = f;
break;
}
}
if (matchTemplate != null) {
return matchTemplate.getAbsolutePath();
}
if (defaultTemplate != null) {
return defaultTemplate.getAbsolutePath();
}
return null;
}
}
default.css
pre, tt, code, kbd, samp {
font-family: Courier;
font-size: 9pt;
line-height: 12pt;
}
dt {
margin: 0;
}
/* styles below are taken from Mozilla Defaults */
body {
margin: 10%;
font-size: 12pt;
}
p, dl, multicol {
margin: 1em 0;
}
dd {
margin-left: 40px;
margin-bottom: 0;
margin-right: 0;
margin-top: 0;
}
blockquote, figure {
margin: 1em 40px;
}
center {
display: block;
text-align: center;
}
blockquote[type="cite"] {
border: 3px solid;
padding-left: 1em;
border-color: blue;
border-width: thin;
margin: 1em 0;
}
h1 {
font-size: 2em;
font-weight: bold;
margin: 0.67em 0;
}
h2 {
font-size: 1.5em;
font-weight: bold;
margin: 0.83em 0;
}
h3 {
font-size: 1.17em;
font-weight: bold;
margin: 1em 0;
}
h4{
font-size: 1em;
font-weight: bold;
margin: 1.33em 0;
}
h5 {
font-size: 0.83em;
font-weight: bold;
margin: 1.67em 0;
}
h6 {
font-size: 0.67em;
font-weight: bold;
margin: 2.33em 0;
}
listing {
font-size: medium;
margin: 1em 0;
white-space: pre;
}
xmp, pre, plaintext {
margin: 1em 0;
white-space: pre;
}
table {
margin-bottom: 0;
margin-top: 0;
margin-left: 0;
margin-right: 0;
text-indent: 0;
}
caption {
text-align: center;
}
tr {
vertical-align: inherit;
}
tbody {
vertical-align: middle;
}
thead {
vertical-align: middle;
}
tfoot {
vertical-align: middle;
}
table > tr {
vertical-align: middle;
}
td {
padding: 1px;
text-align: inherit;
vertical-align: inherit;
}
th {
display: table-cell;
font-weight: bold;
padding: 1px;
vertical-align: inherit;
}
sub {
font-size: smaller;
vertical-align: sub;
}
sup {
font-size: smaller;
vertical-align: super;
}
nobr {
white-space: nowrap;
}
mark {
background: none repeat scroll 0 0 yellow;
color: black;
}
abbr[title], acronym[title] {
border-bottom: 1px dotted;
}
ul, menu, dir {
list-style-type: disc;
}
ul li ul {
list-style-type: circle;
}
ol {
list-style-type: decimal;
}
hr {
color: gray;
height: 2px;
}