依赖
implementation 'com.itextpdf:itextpdf:5.5.13.3'
implementation 'com.itextpdf:itext-asian:5.2.0'
implementation 'com.alibaba:fastjson:1.2.83'
compileOnly 'org.projectlombok:lombok:1.18.22'
annotationProcessor "org.projectlombok:lombok:1.18.22"
测试
import com.alibaba.fastjson.JSON;
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 lombok.SneakyThrows;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.List;
import java.util.Map;
public class GeneratePdfReport {
private static final Logger logger = LoggerFactory.getLogger(GeneratePdfReport.class);
public static void main(String[] args) {
FontFactory.registerDirectories();
// drawTable();
drawRowspan0();
}
public static ByteArrayInputStream citiesReport(List<City> cities) {
Document document = new Document();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try {
// 建立一个书写器(内存流方式)
PdfWriter.getInstance(document, byteArrayOutputStream);
document.open();
PdfPTable table = new PdfPTable(3);
table.setWidthPercentage(60);
table.setWidths(new int[]{1, 3, 3});
Font headFont = FontFactory.getFont(FontFactory.HELVETICA_BOLD);
PdfPCell h_cell;
h_cell = new PdfPCell(new Phrase("Id", headFont));
h_cell.setHorizontalAlignment(Element.ALIGN_CENTER);
// Leading
Paragraph paragraph = new Paragraph();
paragraph.setLeading(2.5f);
table.addCell(h_cell);
h_cell = new PdfPCell(new Phrase("Name", headFont));
h_cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(h_cell);
h_cell = new PdfPCell(new Phrase("Population", headFont));
h_cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(h_cell);
for (City city : cities) {
PdfPCell cell;
cell = new PdfPCell(new Phrase(city.getId().toString()));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
cell = new PdfPCell(new Phrase(city.getName()));
cell.setPaddingLeft(5);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_LEFT);
table.addCell(cell);
cell = new PdfPCell(new Phrase(String.valueOf(city.getPopulation())));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_RIGHT);
cell.setPaddingRight(5);
table.addCell(cell);
}
document.add(table);
} catch (DocumentException ex) {
logger.error("Error occurred: {0}", ex);
} finally {
document.close();
}
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
@SneakyThrows
private static void drawTable() {
String[] headers = {"列一", "列二", "列三", "列四", "列五", "列六"};
String list = "[{\"balance\":\"42402\",\"changeDate\":\"20211026111641\",\"dgst\":\"SSTR\",\"outMoney\":\"0\",\"bankSeqNo\":\"00000000000641199893\",\"inMoney\":\"11539\"},{\"balance\":\"30863\",\"changeDate\":\"20211005133736\",\"dgst\":\"SALE\",\"outMoney\":\"7500\",\"bankSeqNo\":\"00000000000635138192\",\"inMoney\":\"0\"},{\"balance\":\"38363\",\"changeDate\":\"20210926113940\",\"dgst\":\"SSTR\",\"outMoney\":\"0\",\"bankSeqNo\":\"00000000000632420138\",\"inMoney\":\"11539\"},{\"balance\":\"26824\",\"changeDate\":\"20210925111144\",\"dgst\":\"SALE\",\"outMoney\":\"11150\",\"bankSeqNo\":\"00000000000632752221\",\"inMoney\":\"0\"},{\"balance\":\"37974\",\"changeDate\":\"20210922083109\",\"dgst\":\"SALE\",\"outMoney\":\"4860\",\"bankSeqNo\":\"00000000000631851353\",\"inMoney\":\"0\"},{\"balance\":\"42834\",\"changeDate\":\"20210919153251\",\"dgst\":\"SALE\",\"outMoney\":\"7910\",\"bankSeqNo\":\"00000000000631503750\",\"inMoney\":\"0\"},{\"balance\":\"50744\",\"changeDate\":\"20210917080014\",\"dgst\":\"SALE\",\"outMoney\":\"5870\",\"bankSeqNo\":\"00000000000630377865\",\"inMoney\":\"0\"},{\"balance\":\"56614\",\"changeDate\":\"20210915153430\",\"dgst\":\"SALE\",\"outMoney\":\"8560\",\"bankSeqNo\":\"00000000000630120441\",\"inMoney\":\"0\"},{\"balance\":\"65174\",\"changeDate\":\"20210830103432\",\"dgst\":\"SALE\",\"outMoney\":\"6200\",\"bankSeqNo\":\"00000000000625635279\",\"inMoney\":\"0\"},{\"balance\":\"71374\",\"changeDate\":\"20210825124135\",\"dgst\":\"SSTR\",\"outMoney\":\"0\",\"bankSeqNo\":\"00000000000624479550\",\"inMoney\":\"11539\"}]";
List<Map<String, Object>> mapList = (List) JSON.parseArray(list);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PdfWriter writer = null;
Document document = null;
try {
// 创建纵向文件
{
// 生成pdf
document = new Document();
// 页面大小
Rectangle rectangle;
{
rectangle = new Rectangle(PageSize.A4);
// 页面背景颜色
rectangle.setBackgroundColor(BaseColor.WHITE);
}
document.setPageSize(rectangle);
// 页边距 左,右,上,下
document.setMargins(20, 40, 40, 20);
}
// 建立一个书写器(内存流方式)
PdfWriter.getInstance(document, byteArrayOutputStream);
// 打开文件
document.open();
// 添加字体样式
Font bigFont, blueFont;
{
BaseFont bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
bigFont = new Font(bf, 14, Font.NORMAL, BaseColor.BLACK);
blueFont = new Font(bf, 10, Font.NORMAL, BaseColor.BLACK);
}
// 段落内容
Paragraph title;
{
title = new Paragraph("测试pdf", bigFont);
title.setSpacingBefore(5);
title.setSpacingAfter(5);
// 文字居中显示
title.setAlignment(Element.ALIGN_CENTER);
}
// 添加段落内容
document.add(title);
// 创建表格列数
PdfPTable table;
{
table = new PdfPTable(headers.length);
// 宽度100%填充
table.setWidthPercentage(100);
}
// 创建表头
{
for (String header_text : headers) {
PdfPCell cell;
{
cell = new PdfPCell(new Paragraph(header_text, bigFont));
cell.setFixedHeight(27f);
// 默认不跨行、跨列
cell.setRowspan(1);
cell.setColspan(1);
// 居中显示
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
// 设置边框
cell.setBorder(Rectangle.RIGHT + Rectangle.BOTTOM);
cell.setPadding(5);
}
table.addCell(cell);
}
}
// document.add(table); // mark
// 填充数据
for (Map<String, Object> map : mapList) {
// 获取对象
// Map 获取key & value
for (Map.Entry<String, Object> entry : map.entrySet()) {
Object value = entry.getValue();
PdfPCell cell;
{
cell = new PdfPCell(new Paragraph(value.toString(), blueFont));
cell.setFixedHeight(27f);
// 默认不跨行、跨列 ps: 0 or 1 没有区别
cell.setRowspan(1);
cell.setColspan(1);
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_LEFT);
// 设置边框
cell.setBorder(Rectangle.LEFT);
// cell.setBorderWidthRight(1f);
cell.setPadding(5);
}
table.addCell(cell);
}
// document.add(table); // mark
}
document.add(table); // mark
} catch (DocumentException | IOException ignored) {
} finally {
if (document != null) {
// 关闭文档
document.close();
}
if (writer != null) {
// 关闭书写器
writer.close();
}
}
Base64.Encoder encoder = Base64.getEncoder();
String url = "data:application/pdf;base64," + encoder.encodeToString(byteArrayOutputStream.toByteArray());
System.out.println(url);
}
@SneakyThrows
public static void drawRowspan0() {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Document document = new Document();
PdfWriter.getInstance(document, byteArrayOutputStream);
document.open();
PdfPTable table = new PdfPTable(3); // 创建一个三列的表格
for (int i = 0; i < 5; i++) {
PdfPCell cell = new PdfPCell();
cell.addElement(new com.itextpdf.text.Paragraph("Cell 1"));
if (i == 2)
cell.setRowspan(2); // 第三个单元格不跨行
// else
// cell.setRowspan(2);
table.addCell(cell);
}
document.add(table);
document.close();
Base64.Encoder encoder = Base64.getEncoder();
String url = "data:application/pdf;base64," + encoder.encodeToString(byteArrayOutputStream.toByteArray());
System.out.println(url);
}
}
添加图层
// 引入itextpdf库X
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
// 打开PDF文件
PdfReader reader = new PdfReader("input.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("output.pdf"));
// 创建图层对象
PdfLayer layer = new PdfLayer("New Layer", stamper.getWriter());
// 添加内容到图层
layer.setOn(true);
// 将图层添加到PDF文件
stamper.addAnnotation(layer);
stamper.close();
// 引入itextpdf库X
import com.itextpdf.text.Document;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
// 打开PDF文件
PdfReader reader = new PdfReader("input.pdf");
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("output.pdf"));
// 创建图层对象
PdfLayer layer = new PdfLayer("New Layer", stamper.getWriter());
// 添加内容到图层
layer.setOn(true);
// 将图层添加到PDF文件
stamper.addAnnotation(layer);
stamper.close();
(END)
jdk 运行 js
import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.FileNotFoundException;
import java.io.FileReader;
class JavascriptUtils {
public static void runDisplay() {
ScriptEngine engine = new ScriptEngineManager().getEngineByName("js");
try {
// REPL read eval print loop
engine.eval(new FileReader("test.js"));
Invocable invocable = (Invocable) engine;
Object result;
result = invocable.invokeFunction("addNumber", 1, 2);
System.out.println(engine);
System.out.println(result);
System.out.println(result.getClass());
} catch (FileNotFoundException | NoSuchMethodException | ScriptException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
runDisplay();
}
}
事件监听
事件监听有 Event
, Event Publisher
, Event Listener
, Event Listener 注册
4 类主要角色
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class EventDemo {
public static void main(String[] args) {
// 在 Spring 中,事件发布和监听器注册都是通过 ApplicationContext 来实现的
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(EventDemo.class);
context.publishEvent(new MyEvent("hello world")); // Event Publisher
// Spring 内置了很多事件, 例如: ContextStartedEvent, ContextStoppedEvent, ContextRefreshedEvent, ContextClosedEvent (应用程序的不同生命周期阶段), RequestHandledEvent (Web 请求处理过程) 等
}
private static class MyEvent extends ApplicationEvent { // Event
private final String message;
public MyEvent(String message) {
super(message);
this.message = message;
}
public String getMessage() {
return message;
}
}
// (need inject)
private static class MyListener implements ApplicationListener<MyEvent> {
@Override
public void onApplicationEvent(MyEvent event) { // Event Listener
System.out.println("Received event: " + event.getMessage());
}
}
@Bean
public MyListener myListener() { // Event Listener 注册
// 使用注入进行注册{监听器} 来响应其他{自定义事件}
return new MyListener();
}
}
指定 PDF 的跳转页面
reference: https://technicalwriting.dev/www/pdf.html
在 pdf 的链接末尾加上 #page=X
, e.g. http://site.com/hello.pdf#page=2