import com.itextpdf.text.Font;import com.itextpdf.text.Image;import com.itextpdf.text.Rectangle;import com.itextpdf.text.*;import com.itextpdf.text.pdf.BaseFont;import com.itextpdf.text.pdf.PdfPCell;import com.itextpdf.text.pdf.PdfPTable;import com.itextpdf.text.pdf.PdfWriter;import org.apache.commons.lang3.StringUtils;import org.jfree.chart.ChartFactory;import org.jfree.chart.ChartUtils;import org.jfree.chart.JFreeChart;import org.jfree.chart.axis.CategoryAxis;import org.jfree.chart.axis.ValueAxis;import org.jfree.chart.labels.ItemLabelAnchor;import org.jfree.chart.labels.ItemLabelPosition;import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;import org.jfree.chart.labels.StandardPieSectionLabelGenerator;import org.jfree.chart.plot.CategoryPlot;import org.jfree.chart.plot.PiePlot3D;import org.jfree.chart.plot.PlotOrientation;import org.jfree.chart.renderer.category.BarRenderer;import org.jfree.chart.renderer.category.LineAndShapeRenderer;import org.jfree.chart.title.TextTitle;import org.jfree.chart.ui.TextAnchor;import org.jfree.data.category.CategoryDataset;import org.jfree.data.general.PieDataset;import javax.servlet.http.HttpServletResponse;import java.awt.*;import java.io.BufferedOutputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.lang.reflect.Field;import java.net.URLEncoder;import java.text.DecimalFormat;import java.text.NumberFormat;import java.text.SimpleDateFormat;import java.util.List;import java.util.*;/** * @author X-MD * @version 1.0.0 * @Description PDF导出工具类 * @createTime 2022年01月19日 16:47:00 */public class PdfExportUtil { private static String templatePath = PdfExportUtil.class.getResource("/").getPath() + "/templates/"; private static final String FONTNAME = "微软雅黑"; private static final String FONTCONT = "宋体"; /** * 需要导出的字段名称 */ private static List<String> fieldNameList; /** * 需要导出的字段 */ private static List<String> fieldList; /** * 需要增加的列 */ private static int relativeWidths; /** * 字段所占列 */ private static Map<String, Integer> colspanMap; /** * 字段所占行 */ private static Map<String, Integer> rowspanMap; private static List<Element> elementList = new ArrayList<>(); private static List<Element> newPageList = new ArrayList<>(); /** * 纯文字 * @param content 文字内容 * @return */ public static void createParagraph(String content) { createParagraph(content, 12, Font.NORMAL, BaseColor.BLACK, Element.ALIGN_LEFT); } /** * 纯文字 * @param content 文字内容 * @param size 文字大小 * @param style 格式 * @param color 颜色 * @param alignment 位置 * @return */ public static void createParagraph(String content, float size, int style, BaseColor color, int alignment) { try { //设置中文样式(不设置,中文将不会显示) BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); Font fontChineseContent = new Font(bfChinese, size,style, color); Paragraph pieParagraph = new Paragraph(content, fontChineseContent); pieParagraph.setAlignment(alignment); elementList.add(pieParagraph); } catch (Exception e) { e.printStackTrace(); } } /** * 添加图片 * @param filename 文件路径 */ public static void createImage(String filename) { createImage(filename,Element.ALIGN_CENTER,400F, 200F); } /** * 添加图片 * @param filename 文件路径 * @param alignment 位置 (Element 接口) * ALIGN_CENTER = 1 * ALIGN_LEFT = 0 * ALIGN_RIGHT = 2 * @param newWidth 宽度 * @param newHeight 高度 */ public static void createImage(String filename,int alignment,float newWidth, float newHeight) { try { Image image = Image.getInstance(filename); image.setAlignment(alignment); image.scaleAbsolute(newWidth, newHeight); //依照比例缩放 //image.scalePercent(40); elementList.add(image); } catch (Exception e) { e.printStackTrace(); } } /** * 导出表格 * @param dataSet 数据 * @param pojoClass 数据对应的类 * @return */ public static void createPdfPTable(List<?> dataSet, Class<?> pojoClass) { createPdfPTable(dataSet,pojoClass, 15, Font.BOLD, BaseColor.BLUE, Font.DEFAULTSIZE, Font.NORMAL, BaseColor.BLACK); } /** * 导出表格 * @param dataSet * @param pojoClass * @param titleSize 标题字体大小 * @param titleStyle 标题字体格式 * @param titleColor 标题字体颜色 * @param contentSize 内容字体大小 * @param contentStyle 内容字体格式 * @param contentColor 内容字体颜色 * @return */ public static void createPdfPTable(List<?> dataSet, Class<?> pojoClass, int titleSize, int titleStyle, BaseColor titleColor, int contentSize, int contentStyle, BaseColor contentColor) { try { fieldNameList = new ArrayList<>(); fieldList = new ArrayList<>(); relativeWidths = 0; colspanMap = new HashMap<>(); rowspanMap = new HashMap<>(); filedTitle(pojoClass); PdfPCell cell; //标题字体设置 Font bigFont = createFont(titleSize, titleStyle, titleColor); PdfPTable pdfPTable = createPdfPTable(fieldList.size() + relativeWidths); pdfPTable.setWidthPercentage(100.0F); //先设置需要导出的字段名称 for (String header : fieldNameList) { cell = new PdfPCell(new Phrase(header, bigFont)); cell.setFixedHeight(60); cell.setUseAscender(true); if (colspanMap.containsKey(header)) { Integer integer = colspanMap.get(header); cell.setColspan(integer); } cell.setVerticalAlignment(Element.ALIGN_MIDDLE); //水平居中 cell.setHorizontalAlignment(Element.ALIGN_CENTER); pdfPTable.addCell(cell); } //设置具体值 //具体值得字体设置 bigFont = createFont(contentSize, contentStyle, contentColor); for (Object o : dataSet) { for (String pama : fieldList) { String afterData = getFieldValueByFieldName(pama, o); //产品编号 cell = new PdfPCell(new Phrase(afterData, bigFont)); if (colspanMap.containsKey(pama)) { Integer integer = colspanMap.get(pama); cell.setColspan(integer); } if (rowspanMap.containsKey(pama)) { Integer integer = rowspanMap.get(pama); cell.setRowspan(integer); cell.setRowspan(integer); } cellSet(cell); pdfPTable.addCell(cell); } } elementList.add(pdfPTable); } catch (Exception e) { e.printStackTrace(); } } /** * 创建饼状图 * @param dataset 数据 * @param title 标题 * @return String 图片地址 */ public static String createPieChart3D(PieDataset dataset,String title) { return createPieChart3D(dataset, title, 12, 12, 20); } /** * 创建饼状图 * @param dataset 数据 * @param title 标题 * @param labelSize Label字体大小 * @param legendSize Legend字体大小 * @param textTitleSize 图标字体大小 * @return String 图片地址 * @return */ public static String createPieChart3D(PieDataset dataset,String title,int labelSize,int legendSize,int textTitleSize) { String strUrl = templatePath + "pieChart3D.jpg"; try ( FileOutputStream fosJpg = new FileOutputStream(strUrl) ) { JFreeChart chart = ChartFactory.createPieChart3D(title, dataset, true, true, false); PiePlot3D plot = (PiePlot3D) chart.getPlot(); //设置Label字体 plot.setLabelFont(new java.awt.Font(FONTNAME, java.awt.Font.PLAIN, labelSize)); //设置legend字体 chart.getLegend().setItemFont(new java.awt.Font(FONTNAME, java.awt.Font.PLAIN, legendSize)); // 图片中显示百分比:默认方式 //plot.setLabelGenerator(new StandardPieSectionLabelGenerator(StandardPieToolTipGenerator.DEFAULT_TOOLTIP_FORMAT)); // 图片中显示百分比:自定义方式,{0} 表示选项, {1} 表示数值, {2} 表示所占比例 ,小数点后两位 plot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}={1}({2})", NumberFormat.getNumberInstance(), new DecimalFormat("0.00%"))); // 图例显示百分比:自定义方式, {0} 表示选项, {1} 表示数值, {2} 表示所占比例 plot.setLegendLabelGenerator(new StandardPieSectionLabelGenerator("{0}={1}({2})")); // 设置背景色为白色 chart.setBackgroundPaint(Color.white); // 指定图片的透明度(0.0-1.0) plot.setForegroundAlpha(1.0f); // 指定显示的饼图上圆形(false)还椭圆形(true) plot.setCircular(true); // 设置图标题的字体 java.awt.Font font = new java.awt.Font(FONTCONT, java.awt.Font.CENTER_BASELINE, textTitleSize); TextTitle textTitle = new TextTitle(title); textTitle.setFont(font); chart.setTitle(textTitle); ChartUtils.writeChartAsJPEG(fosJpg, 0.7f, chart, 800, 1000, null);// createImage(strUrl,alignment,newWidth,newHeight); return strUrl; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 折线图 * @param lineDataset 数据 * @param title 标题 * @param categoryAxisLabel * @param valueAxisLabel * @return Document */ public static String createLineChart(CategoryDataset lineDataset,String title,String categoryAxisLabel,String valueAxisLabel) { return createLineChart(lineDataset, title, categoryAxisLabel, valueAxisLabel, 12, 15, false); } /** * 折线图 * @param lineDataset 数据 * @param title 标题 * @param categoryAxisLabel * @param valueAxisLabel * @param legendSize * @param titleSize * @param bool 拐点是否显式小图标 * @return Document */ public static String createLineChart(CategoryDataset lineDataset, String title, String categoryAxisLabel, String valueAxisLabel, int legendSize, int titleSize,boolean bool) { String strUrl = templatePath + "lineChart.jpg"; try ( FileOutputStream fosJpg = new FileOutputStream(strUrl) ) { JFreeChart lineChart = ChartFactory.createLineChart(title, categoryAxisLabel, valueAxisLabel, lineDataset, PlotOrientation.VERTICAL, true, true, true); lineChart.getLegend().setItemFont(new java.awt.Font(FONTCONT, java.awt.Font.PLAIN, legendSize)); lineChart.getTitle().setFont(new java.awt.Font(FONTCONT, java.awt.Font.PLAIN, titleSize)); //获取绘图区对象 CategoryPlot linePlot = lineChart.getCategoryPlot(); //设置绘图区域背景的 alpha 透明度 ,在 0.0f 到 1.0f 的范围内 linePlot.setBackgroundAlpha(0.0f); //区域背景色 //linePlot.setBackgroundPaint(Color.white); //背景底部横虚线 linePlot.setRangeGridlinePaint(Color.gray); //linePlot.setOutlinePaint(Color.RED);//边界线 // 设置水平方向背景线颜色 // 设置是否显示水平方向背景线,默认值为true linePlot.setRangeGridlinesVisible(true); // 设置垂直方向背景线颜色 linePlot.setDomainGridlinePaint(Color.gray); // 设置是否显示垂直方向背景线,默认值为false linePlot.setDomainGridlinesVisible(true); //获取坐标轴对象 CategoryAxis lineAxis = linePlot.getDomainAxis(); //设置坐标轴字体 lineAxis.setLabelFont(new java.awt.Font(FONTCONT, java.awt.Font.PLAIN, 12)); //设置坐标轴标尺值字体(x轴) lineAxis.setTickLabelFont(new java.awt.Font(FONTCONT, java.awt.Font.PLAIN, 12)); //获取数据轴对象(y轴) ValueAxis rangeAxis = linePlot.getRangeAxis(); rangeAxis.setLabelFont(new java.awt.Font(FONTCONT, java.awt.Font.PLAIN, 12)); //将折线设置为虚线 LineAndShapeRenderer renderer = (LineAndShapeRenderer) linePlot.getRenderer(); // 设置显示小图标 renderer.setDefaultShapesVisible(bool); //利用虚线绘制// float[] dashes = {5.0f};// BasicStroke brokenLine = new BasicStroke(2.2f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 8f, dashes, 0.6f);// renderer.setSeriesStroke(0, brokenLine); //折点显式数值// DecimalFormat decimalformat1 = new DecimalFormat("##"); // 数据点显示数据值的格式// renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator("{2}", decimalformat1));// renderer.setDefaultItemLabelsVisible(true); // 设置项标签显示// renderer.setDefaultItemLabelsVisible(true); // 基本项标签显示 ChartUtils.writeChartAsJPEG(fosJpg, 0.7f, lineChart, 600, 300); return strUrl; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 柱状图 * @param title * @param categoryAxisLabel * @param valueAxisLabel * @param dataSet 数据 * @return */ public static String createBarChart(String title, String categoryAxisLabel, String valueAxisLabel, CategoryDataset dataSet) { String strUrl = templatePath + "barChart.jpg"; try ( FileOutputStream fos = new FileOutputStream(strUrl) ) { JFreeChart jfreechart = ChartFactory.createBarChart(title, categoryAxisLabel, valueAxisLabel, dataSet); CategoryPlot categoryPlot = jfreechart.getCategoryPlot(); categoryPlot.setBackgroundAlpha(0.0f); categoryPlot.setRangeGridlinePaint(Color.gray); categoryPlot.setRangeGridlinesVisible(true); // 设置网格beijingse categoryPlot.setBackgroundPaint(Color.WHITE); // 设置网格竖线颜色 categoryPlot.setDomainGridlinePaint(Color.pink); // 设置网格横线颜色 categoryPlot.setRangeGridlinePaint(Color.pink); // 显示每个柱的数值,并修改该数值的字体属性 BarRenderer renderer2 = new BarRenderer(); renderer2.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator()); renderer2.setDefaultItemLabelsVisible(true); renderer2.setDefaultPositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.INSIDE8, TextAnchor.BASELINE_CENTER)); renderer2.setItemLabelAnchorOffset(10D); // 设置平行柱的之间距离 renderer2.setItemMargin(0.2); categoryPlot.setRenderer(renderer2); ChartUtils.writeChartAsJPEG(fos, 0.7f, jfreechart, 600, 300); return strUrl; } catch (Exception e) { e.printStackTrace(); return null; } } /** * 分页 */ public static void newPage(){ Element element = elementList.get(elementList.size() - 1); newPageList.add(element); } /** * PDF预览 * @param response * @param filename 文件名称 * @param rect PDF每张页面大小 * @param backgroundColor 背景颜色 * @param marginLeft 左页边距 * @param marginRight 右页边距 * @param marginTop 顶部页边距 * @param marginBottom 底部页面距 * @throws Exception */ public static void pdfExportPreview(HttpServletResponse response, String filename,Rectangle rect,BaseColor backgroundColor, float marginLeft, float marginRight, float marginTop, float marginBottom) throws Exception { response.setContentType("application/pdf"); pdfExport(response, filename, rect, backgroundColor, marginLeft, marginRight, marginTop, marginBottom); } /** * 预览PDF * @param response * @param filename 文件名 * @throws Exception */ public static void pdfExportPreview(HttpServletResponse response, String filename) throws Exception { response.setContentType("application/pdf"); pdfExport(response, filename, PageSize.A4,BaseColor.WHITE,20, 20, 20, 20); } /** * PDF导出 * @param response * @param filename 文件名称 * @param rect PDF每张页面大小 * @param backgroundColor 背景颜色 * @param marginLeft 左页边距 * @param marginRight 右页边距 * @param marginTop 顶部页边距 * @param marginBottom 底部页面距 * @throws Exception */ public static void pdfExportDownload(HttpServletResponse response, String filename,Rectangle rect,BaseColor backgroundColor, float marginLeft, float marginRight, float marginTop, float marginBottom) throws Exception { response.setContentType("application/x-download"); pdfExport(response, filename, rect, backgroundColor, marginLeft, marginRight, marginTop, marginBottom); } /** * 下载PDF * @param response * @param filename 文件名 * @throws Exception */ public static void pdfExportDownload(HttpServletResponse response, String filename) throws Exception { response.setContentType("application/x-download"); pdfExport(response, filename, PageSize.A4,BaseColor.WHITE,20, 20, 20, 20); } private static void pdfExport(HttpServletResponse response,String filename,Rectangle rect,BaseColor backgroundColor, float marginLeft, float marginRight, float marginTop, float marginBottom) throws IOException { Document document = null; OutputStream os = null; try { response.addHeader("Content-Disposition", "inline;filename=" + URLEncoder.encode(filename, "UTF-8") + ".pdf"); document =createDocument(rect,backgroundColor,marginLeft, marginRight, marginTop, marginBottom); os = new BufferedOutputStream(response.getOutputStream()); // 2. 获取writer PdfWriter.getInstance(document, os); // 3. open() document.open(); for (Element element : elementList) { document.add(element); if (newPageList.contains(element)) { document.newPage(); } } } catch (Exception e) { e.printStackTrace(); } finally { elementList.clear(); newPageList.clear(); if (document != null){ document.close(); } if (os != null){ os.close(); } } } /** * 创建 Document * @param marginLeft * @param marginRight * @param marginTop * @param marginBottom * @return */ public static Document createDocument(Rectangle rect, BaseColor backgroundColor, float marginLeft, float marginRight, float marginTop, float marginBottom) { //生成pdf Document document = new Document(); // 页面大小 Rectangle rectangle = new Rectangle(rect); // 页面背景颜色 rectangle.setBackgroundColor(backgroundColor); document.setPageSize(rectangle); // 页边距 左,右,上,下 document.setMargins(marginLeft, marginRight, marginTop, marginBottom); return document; } /** * @param len 表格列数 * @return */ public static PdfPTable createPdfPTable(int len) { PdfPTable pdfPTable = new PdfPTable(len); pdfPTable.setSpacingBefore(5); pdfPTable.setWidthPercentage(100.0F); pdfPTable.setHorizontalAlignment(Element.ALIGN_CENTER); return pdfPTable; } /** * 创建字体 * @param size * @param style * @param fontColor * @return */ public static Font createFont(int size, int style, BaseColor fontColor) { //中文字体 ----不然中文会乱码 BaseFont bf = null; try { bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); return new Font(bf, size, style, fontColor); } catch (Exception e) { e.printStackTrace(); } return new Font(bf, Font.DEFAULTSIZE, Font.NORMAL, BaseColor.BLACK); } /** * 设置PdfPCell * @param cell */ private static void cellSet(PdfPCell cell) { cell.setFixedHeight(40); cell.setUseAscender(true); cell.setVerticalAlignment(Element.ALIGN_MIDDLE); //水平居中 cell.setHorizontalAlignment(Element.ALIGN_CENTER); } /** * 根据属性名获取属性值 * * @param fieldName * @param object * @return */ private static String getFieldValueByFieldName(String fieldName, Object object) { try { Field field = object.getClass().getDeclaredField(fieldName); //设置对象的访问权限,保证对private的属性的访问 field.setAccessible(true); Object ostr = field.get(object); String value = (String) ostr; PdfField excel = field.getAnnotation(PdfField.class); String[] replace = excel.replace(); if (replace != null && replace.length > 0) { value = (String) replaceValue(replace, (String) ostr); } else if (StringUtils.isNotBlank(excel.format())) { SimpleDateFormat formatDate = new SimpleDateFormat(excel.format()); Date parse = formatDate.parse(String.valueOf(ostr)); value = formatDate.format(parse); } return value; } catch (Exception e) { return null; } } private static Object replaceValue(String[] replace, String value) { String[] temp; for (String str : replace) { temp = str.split("_"); if (value.equals(temp[1])) { value = temp[0]; break; } } return value; } /** * 获取所有字段名称 * * @param pojoClass * @return */ private static void filedTitle(Class<?> pojoClass) { Field[] fileds = getClassFields(pojoClass); for (Field filed : fileds) { if (filed.getAnnotation(PdfField.class) != null) { PdfField excel = filed.getAnnotation(PdfField.class); fieldNameList.add(excel.name()); fieldList.add(filed.getName()); if (excel.colspan() > 0) { relativeWidths += excel.colspan(); relativeWidths--; colspanMap.put(excel.name(), excel.colspan()); colspanMap.put(filed.getName(), excel.colspan()); } if (excel.rowspan() > 0) { colspanMap.put(filed.getName(), excel.rowspan()); } } } } /** * 根据class获取类字段 * * @param clazz * @return */ public static Field[] getClassFields(Class<?> clazz) { List<Field> list = new ArrayList<>(); Field[] fields; do { fields = clazz.getDeclaredFields(); list.addAll(Arrays.asList(fields)); clazz = clazz.getSuperclass(); } while (clazz != Object.class && clazz != null); return list.toArray(fields); }}