Commit 0c964a14 authored by 王飞's avatar 王飞

Merge branch 'gaixiankang' into 'dev'

表格一个cell图文混合-demo、PDF写入器(工具类-待完善)

See merge request !53
parents 960f6683 f8714f4d
package com.ruoyi.domain.vo;
import lombok.Builder;
import lombok.Data;
/**
* PDF的测试VO类
* @author gxk
*/
@Data
@Builder
public class PdfTestVO {
/**
* 测试编号
*/
private String testNumber;
/**
* 样品编号
*/
private String sampleNumber;
/**
* 检测项目
*/
private String testItem;
/**
* 风险等级
*/
private String riskLevel;
/**
* 测试方法
*/
private String testMethod;
/**
* 测试结果
*/
private String testResult;
/**
* 漏洞危害
*/
private String vulnerabilityHazard;
/**
* 测试详情
*/
private String testDetails;
/**
* 修复建议
*/
private String repairSuggestion;
}
......@@ -37,4 +37,12 @@ public interface BookService extends IService<Book> {
* @throws Exception
*/
void generateTempPDF(HttpServletResponse response) throws Exception;
/**
* 测试生成PDF
* @param os
* @return
* @throws Exception
*/
Document testGeneratePDF(OutputStream os) throws Exception;
}
package com.ruoyi.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.hash.Hash;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.google.common.collect.ArrayListMultimap;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.codec.Base64;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.PdfUtils;
import com.ruoyi.common.utils.PdfBaseWriter;
import com.ruoyi.domain.Book;
import com.ruoyi.domain.vo.PdfTestVO;
import com.ruoyi.service.BookService;
import com.ruoyi.mapper.BookMapper;
import org.apache.skywalking.apm.toolkit.trace.Tag;
import org.apache.skywalking.apm.toolkit.trace.Tags;
import org.apache.skywalking.apm.toolkit.trace.Trace;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import javax.servlet.ServletOutputStream;
......@@ -22,10 +24,9 @@ import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;
/**
* @author wangfei
......@@ -55,55 +56,93 @@ public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements Bo
@Override
public Document generateItextPdfDocument(OutputStream os) throws Exception {
// document
Document document = new Document(PageSize.A4);
PdfWriter.getInstance(document, os);
// open
// 创建一个A4大小的PDF
PdfBaseWriter document = new PdfBaseWriter(os);
// 打开
document.open();
// add content - pdf meta information
document.addAuthor("pdai");
// PDF文档属性
document.addTitle("标题(测试基本PDF导出)");
document.addAuthor("作者");
document.addSubject("主题(基本PDF导出)");
document.addKeywords("关键字(基本PDF导出)");
document.addCreator("谁创建的(xxx有限公司)");
document.addCreationDate();
document.addTitle("pdai-pdf-itextpdf");
document.addKeywords("pdf-pdai-keyword");
document.addCreator("pdai");
// add content - page content
// Title
document.add(PdfUtils.createTitle("Java 全栈知识体系"));
// Chapter 1
document.add(PdfUtils.createChapterH1("1. 知识准备"));
document.add(PdfUtils.createChapterH2("1.1 什么是POI"));
document.add(PdfUtils.createParagraph("Apache POI 是创建和维护操作各种符合Office Open XML(OOXML)标准和微软的OLE 2复合文档格式(OLE2)的Java API。用它可以使用Java读取和创建,修改MS Excel文件.而且,还可以使用Java读取和创建MS Word和MSPowerPoint文件。更多请参考[官方文档](https://poi.apache.org/index.html)"));
document.add(PdfUtils.createChapterH2("1.2 POI中基础概念"));
document.add(PdfUtils.createParagraph("生成xls和xlsx有什么区别?POI对Excel中的对象的封装对应关系?"));
// Chapter 2
document.add(PdfUtils.createChapterH1("2. 实现案例"));
document.add(PdfUtils.createChapterH2("2.1 用户列表示例"));
document.add(PdfUtils.createParagraph("以导出用户列表为例"));
// 表格
PdfPTable table = new PdfPTable(new float[]{20, 40, 50, 40, 40});
table.setTotalWidth(500);
table.setLockedWidth(true);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
table.getDefaultCell().setBorder(1);
for (int i = 0; i < 5; i++) {
table.addCell(PdfUtils.createCell("1"));
table.addCell(PdfUtils.createCell("2"));
table.addCell(PdfUtils.createCell("3"));
table.addCell(PdfUtils.createCell("4"));
table.addCell(PdfUtils.createCell("5"));
// 测试标题加文本内容
// 添加第一个标题
Chapter chapterOne = document.setTitle1("模拟标题1", 1);
// 添加第一个标题下的第一个二级标题
document.setTitle2(chapterOne, "标题1-1");
// 添加内容
document.writeText("石油是指气态、液态和固态的烃类混合物,具有天然的产状。石油又分为原油、天然气、天然气液及天然焦油等形式,但习惯上仍将“石油”作为“原油”的定义用。");
// 添加第一个标题下的第二个二级标题
document.setTitle2(chapterOne, "标题1-2");
document.writeText("石油是一种黏稠的、深褐色液体,被称为“工业的血液”。地壳上层部分地区有石油储存。主要成分是各种烷烃、环烷烃、芳香烃的混合物。是地质勘探的主要对象之一。");
// 添加第二个标题
Chapter chapterTwo = document.setTitle1("模拟标题2", 2);
document.setTitle2(chapterTwo, "标题2-1");
document.writeText("石油的成油机理有生物沉积变油和石化油两种学说,前者较广为接受,认为石油是古代海洋或湖泊中的生物经过漫长的演化形成,属于生物沉积变油,不可再生;后者认为石油是由地壳内本身的碳生成,与生物无关,可再生。石油主要被用来作为燃油和汽油,也是许多化学工业产品,如溶液、化肥、杀虫剂和塑料等的原料。");
document.setTitle2(chapterTwo, "标题2-2");
document.writeText("2023年2月16日,中国石油和化学工业联合会发布数据称,中国炼油产能已超过美国,成为世界第一炼油大国。2023年2月16日,中国石油和化学工业联合会发布数据称,中国炼油产能已超过美国,成为世界第一炼油大国。");
// 测试自定义段(可当标题、正文使用)
document.add(document.getParagraph(1, "Paragraph"));
// 测试自定义段方向
Paragraph paragraph = document.getParagraph(2, "左对齐");
paragraph.setAlignment(Element.ALIGN_RIGHT);
document.add(paragraph);
// 测试(List)列
List<String> list = new ArrayList<>();
list.add("第一行");
list.add("第二行");
list.add("第三行");
document.writeList(list, true);
// 测试(Map)列
Map<String, String> map = new HashMap<>();
map.put("甲方", "可填入动态公司");
map.put("乙方", "可填入动态公司");
map.put("时间", String.valueOf(DateUtil.date()));
map.put("地点", "可填入动态地点");
document.writeList(map, false);
// 测试带表头的表格
ArrayList<LinkedHashMap<String, Object>> rows = new ArrayList<>();
for (int i = 0;i < 10;i ++) {
LinkedHashMap<String, Object> row = new LinkedHashMap<>();
row.put("姓名", "张三"+i);
row.put("年龄", 23 + i);
row.put("成绩", 88.32 + i);
row.put("是否合格", true);
row.put("考试日期", DateUtil.date());
rows.add(row);
}
document.writeTable(rows);
// 测试自定义表格
PdfPTable table = new PdfPTable(new float[]{40, 150});
table.setWidthPercentage(100);
// 上下边距
table.setSpacingBefore(10);
table.setSpacingAfter(10);
document.writeCell("电话:",1, 1, table);
document.writeCell("地址:", 1, 1, table);
document.writeCell("手机号:", 1, 1, table);
// 一个cell图文混合
List<String> list2 = new ArrayList<>();
list2.add("哈哈哈");
list2.add("C:/Users/gxk/Pictures/Saved Pictures/nvm.png");
list2.add("啊啊啊");
list2.add( "C:/Users/gxk/Pictures/Saved Pictures/123.jpg");
document.writeTextAndImageCell(list2, table);
// 把表格添加进入PDF
document.add(table);
document.add(PdfUtils.createChapterH2("2.2 图片导出示例"));
document.add(PdfUtils.createParagraph("以导出图片为例"));
// 图片
Image image = Image.getInstance("C:/Users/gxk/Pictures/Saved Pictures/nvm.png");
image.setAlignment(Element.ALIGN_CENTER);
......@@ -111,11 +150,124 @@ public class BookServiceImpl extends ServiceImpl<BookMapper, Book> implements Bo
image.scalePercent(60);
document.add(image);
// close
// 关闭
document.close();
return document;
}
/**
* 测试生成PDF - API方式渲染动态表格
* @param os
* @return
* @throws Exception
*/
@Override
public Document testGeneratePDF(OutputStream os) throws Exception {
// 动态数据
List<PdfTestVO> pdfTestVOS = dynamicTabularData();
// 创建PDF
PdfBaseWriter document = new PdfBaseWriter(os);
// 打开
document.open();
// 添加内容
document.add(document.getParagraph(1, "xxx调查表"));
Chapter title1 = document.setTitle1("动态测试表格", 1);
// 动态表格
addTable(pdfTestVOS, document, title1);
// 关闭
document.close();
return document;
}
private void addTable(List<PdfTestVO> pdfTestVOS, PdfBaseWriter document, Chapter chapter) {
IntStream.range(0, pdfTestVOS.size()).forEach(index -> {
PdfTestVO pdfTestVO = pdfTestVOS.get(index);
try {
document.setTitle2(chapter, pdfTestVO.getTestItem());
// 生成表格
PdfPTable table = new PdfPTable(new float[]{40, 150});
table.setTotalWidth(500);
table.setLockedWidth(true);
table.setHorizontalAlignment(Element.ALIGN_CENTER);
table.getDefaultCell().setBorder(1);
// 添加行
table.addCell(document.createCenterCell("测试编号"));
table.addCell(document.createLeftCell(pdfTestVO.getTestNumber()));
table.addCell(document.createCenterCell("样本编号"));
table.addCell(document.createLeftCell(pdfTestVO.getSampleNumber()));
table.addCell(document.createCenterCell("检测项目"));
table.addCell(document.createLeftCell(pdfTestVO.getTestItem()));
table.addCell(document.createCenterCell("风险等级"));
table.addCell(document.createLeftCell(pdfTestVO.getRiskLevel()));
table.addCell(document.createCenterCell("测试方法"));
table.addCell(document.createLeftCell(pdfTestVO.getTestMethod()));
table.addCell(document.createCenterCell("测试结果"));
table.addCell(document.createLeftCell(pdfTestVO.getTestResult()));
table.addCell(document.createCenterCell("漏洞危害"));
table.addCell(document.createLeftCell(pdfTestVO.getVulnerabilityHazard()));
table.addCell(document.createCenterCell("测试详情"));
PdfPCell cell = new PdfPCell();
cell.addElement(document.createTextInImageCell(pdfTestVO.getTestDetails()));
Image img = Image.getInstance("C:/Users/gxk/Pictures/Saved Pictures/nvm.png");
img.scaleToFit(100, 100);
cell.addElement(img);
cell.addElement(document.createTextInImageCell("车辆采用白名单策略,需客户端设置IP地址为192.168.69.71/24才可以与之通信,车辆IP地址为192.168.69.8。"));
Image imgTwo = Image.getInstance("C:/Users/gxk/Pictures/Saved Pictures/123.jpg");
img.scaleToFit(100, 100);
cell.addElement(imgTwo);
table.addCell(cell);
table.addCell(document.createCenterCell("修复建议"));
table.addCell(document.createLeftCell(pdfTestVO.getRepairSuggestion()));
document.add(table);
} catch (DocumentException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
});
}
/**
* 生成测试数据
* @return
*/
private List<PdfTestVO> dynamicTabularData() {
List<PdfTestVO> dataList = new ArrayList<>();
PdfTestVO dos = PdfTestVO.builder()
.testNumber("EH3-Vehicle-PT-001")
.sampleNumber("LNNAJDDU4PD490747")
.testItem("DOS攻击")
.riskLevel("无风险")
.testMethod("1.使用奇瑞设备接入整车OBD口; \n" +
"2.使用电脑连接OBD口; \n" +
"3.使用电脑打开OBD软件; \n" +
"4.点击软件中的“诊断”按钮;")
.testResult("对车辆以太网DOS攻击后,车辆无异常,车辆以太网服务未受到影响,测试通过。")
.vulnerabilityHazard("拒绝车辆正常的服务访问,影响车辆的正常运行")
.testDetails("1.使用奇瑞设备接入整车OBD口;")
.repairSuggestion("无").build();
dataList.add(dos);
PdfTestVO blur = PdfTestVO.builder()
.testNumber("EH3-Vehicle-PT-002")
.sampleNumber("LNNAJDDU4PD490747")
.testItem("模糊测试")
.riskLevel("无风险")
.testMethod("1.使用奇瑞设备接入整车OBD口;\n" +
"2.对Doip协议进行模糊测试,尝试影响以太网诊断的可用性,若车辆未出现异常则测试通过,否则不通过。")
.testResult("车辆模糊过程中无异常,未发现未知漏洞,测试通过。")
.vulnerabilityHazard("模糊测试可能导致车辆异常。")
.testDetails("1.使用奇瑞设备接入整车OBD口;")
.repairSuggestion("无").build();
dataList.add(blur);
return dataList;
}
@Override
public void generateTempPDF(HttpServletResponse response) throws Exception {
PdfReader reader = null;
......
......@@ -84,8 +84,12 @@ public class BookController extends BaseController {
public void download(HttpServletResponse response) {
response.setHeader("content-disposition","attachment;fileName="+"ReceiptPrinter.pdf");
try {
// bookService.generateItextPdfDocument(response.getOutputStream());
bookService.generateTempPDF(response);
// demo-API渲染
bookService.generateItextPdfDocument(response.getOutputStream());
// demo-模板
// bookService.generateTempPDF(response);
// demo-动态表格
// bookService.testGeneratePDF(response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
}
......
package com.ruoyi.common.utils;
import com.google.common.collect.ListMultimap;
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 java.io.IOException;
import java.io.OutputStream;
import java.util.*;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* PDF写入器
* @author gxk
*/
public class PdfBaseWriter extends Document{
// ---------------------------------默认参数---------------------------------
/**
* 中文字体
*/
public final String FONT_NAME_ST_SONG_LIGHT = "STSong-Light";
/**
* 中文字体编码
*/
public final String FONT_ENCODING_UNI_GB_UCS2_H = "UniGB-UCS2-H";
//---------------------------------常用字体/颜色---------------------------------
/**
* 灰色
*/
public final BaseColor GREY_COLOR = new BaseColor(139, 134, 130);
/**
* 浅黄色
*/
public final BaseColor LIGHT_YELLOW_COLOR = new BaseColor(255, 255, 153);
/**
* 浅蓝色
*/
public final BaseColor LIGHT_BLUE_COLOR = new BaseColor(133, 188, 224);
/**
* 深蓝色
*/
public final BaseColor HARD_BLUE_COLOR = new BaseColor(31, 86, 112);
/**
* 创建页面大小为A4的PDF
* @param os PDF写入流
* @throws DocumentException
*/
public PdfBaseWriter(OutputStream os) throws DocumentException {
super();
PdfWriter.getInstance(this, os);
}
/**
* 创建PDF
* @param os PDF写入流
* @param pageSize 页面大小(PageSize.A4等)
* @throws DocumentException
*/
public PdfBaseWriter(OutputStream os, Rectangle pageSize) throws DocumentException {
super(pageSize);
PdfWriter.getInstance(this, os);
}
//------------------------------------表------------------------------------
/**
* 写入表格,表格数据集合中第一行数据 key 为表格表头
* @param rows 表格数据集合
* @return 表格 {@link PdfPTable}
*/
public PdfPTable writeTable(ArrayList<LinkedHashMap<String, Object>> rows) {
if (rows == null) {
return null;
}
// 根据写入数据宽度创建表格
List<String> headers = new ArrayList<String>(rows.get(0).keySet());
PdfPTable table = createWithHeaderTable(headers);
for (LinkedHashMap<String, Object> row : rows) {
for (String k : headers) {
String text = String.valueOf(row.get(k));
writeCell(String.valueOf(text), calculateColumnNumber(k), 1, table);
}
}
addContent(table);
return table;
}
/**
* 创建带表头的表格 {@link PdfPTable}
* @param headers 表头数据集
* @return 表格 {@link PdfPTable}
*/
public PdfPTable createWithHeaderTable(List<String> headers) {
int numColumns = calculateColumnNumber(headers);
PdfPTable headerTable = new PdfPTable(numColumns);
headerTable.setWidthPercentage(100);
headerTable.setSpacingBefore(10);
for (String text : headers) {
writeCell(text, Element.ALIGN_CENTER, calculateColumnNumber(text), 1, headerTable, defaultFont(), 0f, Rectangle.BOX, LIGHT_BLUE_COLOR);
}
return headerTable;
}
/**
* 设置空白行
* @param table 表 {@link PdfPTable}
* @param bgColor 背景颜色 {@link BaseColor}
* @param columnNumber 列号
* @param fixedHeight 固定高度
*/
public void setBlankRow(PdfPTable table, BaseColor bgColor, int columnNumber, float fixedHeight) {
Paragraph paragraph = new Paragraph("");
PdfPCell pdfPCell = newPdfPCell(bgColor, 0, 1, columnNumber, 1, paragraph);
// 单元格固定高度
pdfPCell.setFixedHeight(fixedHeight);
table.addCell(pdfPCell);
}
//------------------------------------单元格------------------------------------
/**
* 写入无边框单元格 {@link PdfPCell}
* @param text 内容
* @param align 对齐方式 {@link Element}
* @param colspan 所占列数
* @param rowspan 所占行数
* @param table 表 {@link PdfPTable}
* @return 单元格 {@link PdfPCell}
*/
public PdfPCell writeNoBorderCell(String text, int align, int colspan, int rowspan, PdfPTable table) {
return writeCell(text, align, colspan, rowspan, table, defaultFont(), 0f, Rectangle.NO_BORDER, BaseColor.WHITE);
}
/**
* 写入单元格 {@link PdfPCell}
* @param text 内容
* @param colspan 所占列数
* @param rowspan 所占行数
* @param table 表 {@link PdfPTable}
* @return 单元格 {@link PdfPCell}
*/
public PdfPCell writeCell(String text, int colspan, int rowspan, PdfPTable table) {
return writeCell(text, Element.ALIGN_CENTER, colspan, rowspan, table, defaultFont(), 0f, Rectangle.BOX, BaseColor.WHITE);
}
/**
* 写入单元格 {@link PdfPCell}
* @param text 内容
* @param align 对齐方式 {@link Element}
* @param colspan 所占列数
* @param rowspan 所占行数
* @param table 表 {@link PdfPTable}
* @param font 字体 {@link Font}
* @return 单元格 {@link PdfPCell}
*/
public PdfPCell writeCell(String text, int align, int colspan, int rowspan, PdfPTable table, Font font) {
return writeCell(text, align, colspan, rowspan, table, font, 0f, Rectangle.BOX);
}
/**
* 写入单元格 {@link PdfPCell}
* @param text 内容
* @param align 对齐方式 {@link Element}
* @param colspan 所占列数
* @param rowspan 所占行数
* @param table 表 {@link PdfPTable}
* @param font 字体 {@link Font}
* @param paddingLeft 左边距
* @param border 边框 {@link Rectangle}
* @return 单元格 {@link PdfPCell}
*/
public PdfPCell writeCell(String text, int align, int colspan, int rowspan, PdfPTable table, Font font, Float paddingLeft, int border) {
return writeCell(text, align, colspan, rowspan, table, font, paddingLeft, border, true, BaseColor.WHITE);
}
/**
* 写入单元格 {@link PdfPCell}
* @param text 内容
* @param align 对齐方式 {@link Element}
* @param colspan 所占列数
* @param rowspan 所占行数
* @param table 表 {@link PdfPTable}
* @param font 字体 {@link Font}
* @param paddingLeft 左边距
* @param border 边框 {@link Rectangle}
* @param bgColor 背景颜色 {@link BaseColor}
* @return 单元格 {@link PdfPCell}
*/
public PdfPCell writeCell(String text, int align, int colspan, int rowspan, PdfPTable table, Font font, Float paddingLeft, int border, BaseColor bgColor) {
return writeCell(text, align, colspan, rowspan, table, font, paddingLeft, border, true, bgColor);
}
/**
* 写入单元格 {@link PdfPCell}
* @param text 内容
* @param align 对齐方式 {@link Element}
* @param colspan 所占列数
* @param rowspan 所占行数
* @param table 表 {@link PdfPTable}
* @param font 字体 {@link Font}
* @param paddingLeft 左边距
* @param border 边框 {@link Rectangle}
* @param isSet 是否已经设置
* @param bgColor 背景颜色 {@link BaseColor}
* @return 单元格 {@link PdfPCell}
*/
public PdfPCell writeCell(String text, int align, int colspan, int rowspan, PdfPTable table, Font font, Float paddingLeft, int border, boolean isSet, BaseColor bgColor) {
if (text == null) {
text = "";
}
// 包含中文,则使用中文字体
if (isChinese(text)) {
font = chineseFont(font.getSize(), font.getStyle(), font.getColor());
}
Paragraph elements = new Paragraph(text, font);
elements.setAlignment(align);
PdfPCell cell = newPdfPCell(bgColor, border, align, colspan, rowspan, elements);
if (paddingLeft != null) {
cell.setPaddingLeft(paddingLeft);
}
if (isSet) {
table.addCell(cell);
}
return cell;
}
/**
* 创建新的单元格 {@link PdfPCell}
* @param bgColor 背景颜色 {@link BaseColor}
* @param border 边框 {@link Rectangle}
* @param align 对齐方式 {@link Element}
* @param colspan 所占列数
* @param rowspan 所占行数
* @param paragraph 段落 {@link Paragraph}
* @return 单元格 {@link PdfPCell}
*/
public PdfPCell newPdfPCell(BaseColor bgColor, int border, int align, int colspan, int rowspan, Paragraph paragraph) {
PdfPCell cell = new PdfPCell();
cell.setBorderColor(BaseColor.BLACK);
cell.setBorderColorLeft(BaseColor.BLACK);
cell.setBorderColorRight(BaseColor.BLACK);
cell.setBackgroundColor(bgColor);
cell.setBorder(border);
// 水平居中
cell.setHorizontalAlignment(align);
// 垂直居中
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setColspan(colspan);
cell.setRowspan(rowspan);
cell.setMinimumHeight(10);
cell.addElement(paragraph);
// 设置单元格的边框宽度和颜色
cell.setBorderWidth(0.5f);
cell.setBorderColor(GREY_COLOR);
return cell;
}
/**
* 创建内容为图片的单元格 {@link PdfPCell}
* @param colspan 所占列数
* @param rowspan 所占行数
* @param image 内容(文字或图片对象) {@link Image}
* @param fitWidth 宽度自适应
* @param fitHeight 高度自适应
* @return 单元格 {@link PdfPCell}
*/
public PdfPCell newPdfPCellOfImage(int colspan, int rowspan, Image image, float fitWidth, float fitHeight) {
PdfPCell cell = new PdfPCell();
cell.setUseAscender(Boolean.TRUE);
cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
cell.setBorder(Rectangle.BOX);
cell.setBorderColor(BaseColor.GRAY);
cell.setBackgroundColor(BaseColor.WHITE);
cell.setColspan(colspan);
cell.setRowspan(rowspan);
image.scaleToFit(fitWidth, fitHeight);
cell.addElement(image);
return cell;
}
/**
* 把图文混合写入单元格
* @param list
* @param table
* @return
*/
public PdfPCell writeTextAndImageCell(List<String> list, PdfPTable table) throws DocumentException, IOException {
PdfPCell cell = new PdfPCell();
cell.setBorderColor(BaseColor.GRAY);
for (String value : list) {
if (value.contains("/") && (value.endsWith(".jpg") || value.endsWith(".png") || value.endsWith(".jpeg"))) {
Image image = Image.getInstance(value);
cell.addElement(image);
} else {
cell.addElement(createTextInImageCell(value));
}
}
table.addCell(cell);
return cell;
}
//------------------------------------文本内容------------------------------------
/**
* 设置一级标题
* @param title 章节标题
* @param number 章节编号
* @return 返回当前标题 {@link Chapter}
*/
public Chapter setTitle1(String title, int number) {
Paragraph paragraph = getParagraph(2, title);
Chapter chapter = new Chapter(paragraph, number);
chapter.setTriggerNewPage(false);
addContent(chapter);
return chapter;
}
/**
* 设置二级标题
* @param chapter 对应一级标题 {@link Chapter}
* @param title 章节标题
* @return 返回当前标题 {@link Section}
*/
public Section setTitle2(Chapter chapter, String title) {
Paragraph paragraph = getParagraph(3, title);
Section section = chapter.addSection(paragraph);
section.setNumberStyle(Section.NUMBERSTYLE_DOTTED_WITHOUT_FINAL_DOT);
addContent(section);
return section;
}
/**
* 设置三级标题
* @param section 对应二级标题 {@link Section}
* @param title 章节标题
*/
public void setTitle3(Section section, String title) {
Paragraph paragraph = getParagraph(4, title);
Section subsection = section.addSection(paragraph);
subsection.setNumberStyle(Section.NUMBERSTYLE_DOTTED);
addContent(subsection);
}
/**
* 写出段落正文
* @param text 正文内容
*/
public void writeText(String text) {
writeText(text, defaultFont(), true);
}
/**
* 写出段落正文
* @param text 正文内容
* @param font 字体 {@link Font}
*/
public void writeText(String text, Font font) {
writeText(text, font, true);
}
/**
* 写出段落正文
* @param text 正文内容
* @param font 字体 {@link Font}
* @param firstLineIndent 首行是否需要缩进
*/
public void writeText(String text, Font font, boolean firstLineIndent) {
Paragraph paragraph = new Paragraph(text, font);
if (firstLineIndent) {
paragraph.setFirstLineIndent(24);
}
addContent(paragraph);
}
/**
* 写出段落正文
* @param text 正文内容
* @param font 字体 {@link Font}
* @param alignment 设置此段落的对齐方式 {@link Element}
*/
public void writeText(String text, Font font, int alignment) {
Paragraph paragraph = new Paragraph(text, font);
paragraph.setAlignment(alignment);
addContent(paragraph);
}
/**
* 写出列表
* @param texts 列表内容集合
* @param wantNumbering 是否需要序号
*/
public void writeList(List<String> texts, boolean wantNumbering) {
if (texts == null || texts.size() == 0) {
return;
}
int i = 1;
for (String text : texts) {
if (wantNumbering) {
writeText(i + "、" + text, defaultFont(), false);
}else {
writeText(text, defaultFont(), false);
}
i++;
}
}
/**
* 写出列表
* @param formData 列表内容集合
* @param tagValue value 值是否需要下划线
*/
public void writeList(Map<String, String> formData, boolean tagValue) {
if (formData == null || formData.size() == 0) {
return;
}
for (String v : formData.keySet()) {
addContent(new Phrase(v + ":", defaultFont()));
Phrase phrase = new Phrase();
Chunk chunk = new Chunk(formData.get(v), defaultFont());
if (tagValue) {
chunk.setUnderline(0.2f, -2f);
}
phrase.add(chunk);
addContent(phrase);
addContent(Chunk.NEWLINE);
}
}
// /**
// * 标题
// * @param content
// * @return
// * @throws IOException
// * @throws DocumentException
// */
// public static Paragraph createTitle(String content) throws IOException, DocumentException {
// Font font = new Font(getBaseFont(), 24, Font.BOLD);
// Paragraph paragraph = new Paragraph(content, font);
// paragraph.setAlignment(Element.ALIGN_CENTER);
// return paragraph;
// }
//
// /**
// * H1标题
// * @param content
// * @return
// * @throws IOException
// * @throws DocumentException
// */
// public static Paragraph createChapterH1(String content) throws IOException, DocumentException {
// Font font = new Font(getBaseFont(), 22, Font.BOLD);
// Paragraph paragraph = new Paragraph(content, font);
// paragraph.setAlignment(Element.ALIGN_LEFT);
// return paragraph;
// }
//
// /**
// * H2标题
// * @param content
// * @return
// * @throws IOException
// * @throws DocumentException
// */
// public static Paragraph createChapterH2(String content) throws IOException, DocumentException {
// Font font = new Font(getBaseFont(), 18, Font.BOLD);
// Paragraph paragraph = new Paragraph(content, font);
// paragraph.setAlignment(Element.ALIGN_LEFT);
// // 设置段落上空白
// paragraph.setSpacingAfter(5f);
// return paragraph;
// }
//
// /**
// * 段
// * @param content
// * @return
// * @throws IOException
// * @throws DocumentException
// */
// public static Paragraph createParagraph(String content) throws IOException, DocumentException {
// Paragraph paragraph = new Paragraph(content, defaultFont());
// paragraph.setAlignment(Element.ALIGN_LEFT);
// // 设置左缩进
// paragraph.setIndentationLeft(12);
// // 设置右缩进
// paragraph.setIndentationRight(12);
// // 设置首行缩进
// paragraph.setFirstLineIndent(24);
// // 行间距
// paragraph.setLeading(20f);
// // 设置段落上空白
// paragraph.setSpacingBefore(5f);
// // 设置段落下空白
// paragraph.setSpacingAfter(10f);
// return paragraph;
// }
/**
* 创建文本
* @param type 1-标题 2-标题一 3-标题二 4-标题三 5-正文 6-正文左对齐
*/
public Paragraph getParagraph(int type, String text) {
Font font = new Font(defaultFont());
if (1 == type) {
font.setSize(22f);
font.setStyle(Font.BOLD);
} else if(2 == type) {
font.setSize(16f);
font.setStyle(Font.BOLD);
} else if(3 == type) {
font.setSize(14f);
font.setStyle(Font.BOLD);
} else if(4 == type) {
font.setSize(14f);
} else if(5 == type) {
font.setSize(10.5f);
} else if(6 == type) {
font.setSize(10.5f);
} else {
font.setSize(10.5f);
}
Paragraph paragraph = new Paragraph(text, font);
if (1 == type) {
paragraph.setAlignment(Paragraph.ALIGN_CENTER);
paragraph.setSpacingBefore(10f);
paragraph.setSpacingAfter(10f);
} else if(2 == type) {
paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
paragraph.setSpacingBefore(2f);
paragraph.setSpacingAfter(2f);
} else if(3 == type){
paragraph.setSpacingBefore(2f);
paragraph.setSpacingAfter(1f);
} else if(4 == type){
paragraph.setSpacingBefore(2f);
paragraph.setSpacingAfter(2f);
} else if(5 == type){
paragraph.setAlignment(Element.ALIGN_JUSTIFIED);
paragraph.setFirstLineIndent(24);
paragraph.setSpacingBefore(1f);
paragraph.setSpacingAfter(1f);
} else if(6 == type){
paragraph.setAlignment(Element.ALIGN_LEFT);
paragraph.setSpacingBefore(1f);
paragraph.setSpacingAfter(1f);
}
return paragraph;
}
/**
*
* 添加 PDF 内容
* @param element
* @return 如果添加了元素,则为true ,否则为false
*/
public boolean addContent(Element element) {
try {
return this.add(element);
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
//------------------------------------表格内容------------------------------------
/**
* 表格内容
* @param content
* @param alignmentMode
* @return
* @throws IOException
* @throws DocumentException
*/
public PdfPCell createCell(String content, int alignmentMode) throws IOException, DocumentException {
PdfPCell cell = new PdfPCell();
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(alignmentMode);
cell.setPhrase(new Phrase(content, defaultFont()));
return cell;
}
/**
* 表格内既有文字又有图片
* @param content
* @return
* @throws IOException
* @throws DocumentException
*/
public Phrase createTextInImageCell(String content) throws IOException, DocumentException {
return new Phrase(content, defaultFont());
}
/**
* 表格内居中对齐
* @param content
* @return
* @throws IOException
* @throws DocumentException
*/
public PdfPCell createCenterCell(String content) throws IOException, DocumentException {
PdfPCell cell = createCell(content, Element.ALIGN_CENTER);
return cell;
}
/**
* 表格内左对齐
* @param content
* @return
* @throws IOException
* @throws DocumentException
*/
public PdfPCell createLeftCell(String content) throws IOException, DocumentException {
PdfPCell cell = createCell(content, Element.ALIGN_LEFT);
return cell;
}
//------------------------------------字体------------------------------------
/**
* 默认中文字体<br>
* 大小:12<br>
* 样式:正常<br>
* 颜色:黑色<br>
* @return 中文字体 {@link Font}
*/
public Font defaultFont() {
return chineseFont(10.5f, Font.NORMAL, BaseColor.BLACK);
}
/**
* 默认中文字体
* @return 中文字体 {@link BaseFont}
*/
public BaseFont defaultBaseFont() {
try {
return BaseFont.createFont(FONT_NAME_ST_SONG_LIGHT, FONT_ENCODING_UNI_GB_UCS2_H, BaseFont.EMBEDDED);
} catch (DocumentException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 中文字体 {@link Font}
* @param fontSize 字体大小
* @param style 字体风格 {@link Font}
* @param color 字体颜色 {@link BaseColor}
* @return {@link Font}
*/
public Font chineseFont(float fontSize, int style, BaseColor color) {
BaseFont baseFont = null;
try {
baseFont = BaseFont.createFont(FONT_NAME_ST_SONG_LIGHT, FONT_ENCODING_UNI_GB_UCS2_H, BaseFont.EMBEDDED);
} catch (DocumentException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
return createFont(baseFont, fontSize, style, color);
}
/**
* 自定义中文字体 {@link Font}
* @param fontPath 字体格式文件路径(如:.ttc、.ttf),支持绝对路径或项目静态资源相对路径
* @param fontSize 字体大小
* @param style 字体风格 {@link Font}
* @param color 字体颜色 {@link BaseColor}
* @return {@link Font}
*/
public Font customFont(String fontPath, float fontSize, int style, BaseColor color) {
BaseFont baseFont = null;
try {
baseFont = BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
} catch (DocumentException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
return createFont(baseFont, fontSize, style, color);
}
/**
* 创建字体 {@link Font}
* @param baseFont 字体 {@link BaseFont}
* @param fontSize 字体大小
* @param style 字体风格 {@link Font}
* @param color 字体颜色 {@link BaseColor}
* @return {@link Font}
*/
public Font createFont(BaseFont baseFont, float fontSize, int style, BaseColor color) {
return new Font(baseFont, fontSize, style, color);
}
/**
* 字体
* @return
* @throws IOException
* @throws DocumentException
*/
public BaseFont getBaseFont() throws IOException, DocumentException {
return BaseFont.createFont(FONT_NAME_ST_SONG_LIGHT, FONT_ENCODING_UNI_GB_UCS2_H, BaseFont.NOT_EMBEDDED);
}
//------------------------------------其他------------------------------------
/**
* 根据标题列表计算列表列数
* @param header 标题列表
* @return 列表列数
*/
private int calculateColumnNumber(List<String> header) {
int numColumns = 0;
for (String s : header) {
numColumns += calculateColumnNumber(s);
}
return numColumns;
}
/**
* 根据标题计算列表列数
* @param header 标题列表
* @return 列表列数
*/
private int calculateColumnNumber(String header) {
int numColumns = header.length();
if (!isChinese(header)) {
numColumns = numColumns / 2 + (numColumns % 2 != 0 ? 1 : 0);
}
return numColumns;
}
/**
* 字符串是否是中文
* @param str 字符串
* @return 是否是中文
*/
private boolean isChinese(String str) {
Pattern p = Pattern.compile("[\u4e00-\u9fa5]");
Matcher m = p.matcher(str);
return m.find();
}
}
package com.ruoyi.common.utils;
import com.itextpdf.text.*;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfPCell;
import java.io.IOException;
/**
* PDF工具类
* @author gxk
*/
public class PdfUtils {
/**
* 标题
* @param content
* @return
* @throws IOException
* @throws DocumentException
*/
public static Paragraph createTitle(String content) throws IOException, DocumentException {
Font font = new Font(getBaseFont(), 24, Font.BOLD);
Paragraph paragraph = new Paragraph(content, font);
paragraph.setAlignment(Element.ALIGN_CENTER);
return paragraph;
}
/**
* H1标题
* @param content
* @return
* @throws IOException
* @throws DocumentException
*/
public static Paragraph createChapterH1(String content) throws IOException, DocumentException {
Font font = new Font(getBaseFont(), 22, Font.BOLD);
Paragraph paragraph = new Paragraph(content, font);
paragraph.setAlignment(Element.ALIGN_LEFT);
return paragraph;
}
/**
* H2标题
* @param content
* @return
* @throws IOException
* @throws DocumentException
*/
public static Paragraph createChapterH2(String content) throws IOException, DocumentException {
Font font = new Font(getBaseFont(), 18, Font.BOLD);
Paragraph paragraph = new Paragraph(content, font);
paragraph.setAlignment(Element.ALIGN_LEFT);
return paragraph;
}
/**
* 段
* @param content
* @return
* @throws IOException
* @throws DocumentException
*/
public static Paragraph createParagraph(String content) throws IOException, DocumentException {
Font font = new Font(getBaseFont(), 12, Font.NORMAL);
Paragraph paragraph = new Paragraph(content, font);
paragraph.setAlignment(Element.ALIGN_LEFT);
// 设置左缩进
paragraph.setIndentationLeft(12);
// 设置右缩进
paragraph.setIndentationRight(12);
// 设置首行缩进
paragraph.setFirstLineIndent(24);
// 行间距
paragraph.setLeading(20f);
// 设置段落上空白
paragraph.setSpacingBefore(5f);
// 设置段落下空白
paragraph.setSpacingAfter(10f);
return paragraph;
}
/**
* 表格内容
* @param content
* @return
* @throws IOException
* @throws DocumentException
*/
public static PdfPCell createCell(String content) throws IOException, DocumentException {
PdfPCell cell = new PdfPCell();
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
Font font = new Font(getBaseFont(), 12, Font.NORMAL);
cell.setPhrase(new Phrase(content, font));
return cell;
}
/**
* 字体
* @return
* @throws IOException
* @throws DocumentException
*/
public static BaseFont getBaseFont() throws IOException, DocumentException {
return BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment