目录
1.POM依赖
<!--PDF工具-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.9</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>2.1.4</version>
</dependency>
<dependency>
<groupId>com.jfinal</groupId>
<artifactId>jfinal</artifactId>
<version>3.3</version>
</dependency>
<!--二维码与条形码工具-->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.4.1</version>
</dependency>
2.测试用的实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class BillDto {
/**
* 序号
*/
private String serialNum;
/**
* 费用项目
*/
private String feeTypeName;
/**
* 单价
*/
private String price;
/**
* 数量
*/
private String qty;
/**
* 小计
*/
private String amount;
/**
* 备注
*/
private String remark;
}
3.二维码与条形码工具类
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.oned.Code128Writer;
import com.google.zxing.qrcode.QRCodeWriter;
import com.itextpdf.text.BadElementException;
import com.itextpdf.text.Image;
import org.apache.commons.lang3.StringUtils;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class QRCodeGenerator {
/**
* 获取二维码PDF-Image对象
*
* @param text 生成二维码的字符文本
* @param width 二维码宽度
* @param height 二维码高度
*/
public static Image buildQR(String text, int width, int height) throws WriterException, IOException, BadElementException {
return getImage(generateQRCodeImage(text, width, height));
}
/**
* 获取条形码PDF-Image对象
*
* @param text 生成条形码的字符文本
* @param width 条形码宽度
* @param height 条形码高度
*/
public static Image buildBar(String text, int width, int height) throws WriterException, IOException, BadElementException {
return getImage(generateBarcode(text, width, height));
}
/**
* 获取条形码PDF-Image对象(底部带文本--默认与条码一样的串)
*
* @param text 生成条形码的字符文本
* @param width 条形码宽度
* @param height 条形码高度
*/
public static Image buildBarWithText(String text, int width, int height) throws WriterException, IOException, BadElementException {
return getImage(generateBarcodeWithText(text, width, height, text));
}
/**
* 获取条形码PDF-Image对象(底部带文本--自定义)
*
* @param text 生成条形码的字符文本
* @param width 条形码宽度
* @param height 条形码高度
* @param additionalText 条形码底部文本
*/
public static Image buildBarWithText(String text, int width, int height, String additionalText) throws WriterException, IOException, BadElementException {
if (StringUtils.isEmpty(additionalText)) {
additionalText = text;
}
return getImage(generateBarcodeWithText(text, width, height, additionalText));
}
//生成二维码
public static BufferedImage generateQRCodeImage(String text, int width, int height) throws WriterException, IOException {
if (width == 0) {
width = 200;
}
if (height == 0) {
height = 200;
}
QRCodeWriter qrCodeWriter = new QRCodeWriter();
BitMatrix bitMatrix = qrCodeWriter.encode(text, BarcodeFormat.QR_CODE, width, height);
return MatrixToImageWriter.toBufferedImage(bitMatrix);
}
//生成条形码
private static BufferedImage generateBarcode(String text, int width, int height) throws WriterException {
if (width == 0) {
width = 400;
}
if (height == 0) {
height = 200;
}
Code128Writer barcodeWriter = new Code128Writer();
BitMatrix bitMatrix = barcodeWriter.encode(text, BarcodeFormat.CODE_128, width, height, null);
return MatrixToImageWriter.toBufferedImage(bitMatrix);
}
//生成条形码并在底部添加附加文本
private static BufferedImage generateBarcodeWithText(String text, int width, int height, String additionalText) throws WriterException, IOException {
if (width == 0) {
width = 200;
}
if (height == 0) {
height = 100;
}
// 生成条形码
BufferedImage barcodeImage = generateBarcode(text, width, height);
// 创建更高的 BufferedImage,用于容纳条形码和附加文本
BufferedImage combinedImage = new BufferedImage(width, height + 20, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = combinedImage.createGraphics();
// 设置整个图像的背景为白色
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height + 20);
// 将条形码绘制到新的 BufferedImage 中
g2d.drawImage(barcodeImage, 0, 0, null);
// 设置字体和颜色
Font font = new Font("Arial", Font.PLAIN, 15);
g2d.setFont(font);
g2d.setColor(Color.BLACK);
// 计算文本位置
int textWidth = g2d.getFontMetrics().stringWidth(additionalText);
int x = (width - textWidth) / 2;
int y = height + 15; // 在条形码下方留出一定的空白
// 添加附加文本到图片
g2d.drawString(additionalText, x, y);
g2d.dispose();
return combinedImage;
}
//装换文件流的图片对象为PDF图片对象
public static Image getImage(BufferedImage bufferedImage) throws IOException, BadElementException {
// 将BufferedImage转换为字节数组
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, "png", outputStream);
byte[] imageBytes = outputStream.toByteArray();
// 将字节数组转换为iText的Image对象
return Image.getInstance(imageBytes);
}
}
4.PDF模板构建
注意:这个模板并非傻瓜包,纯属自定义构建一个表单,然后输出,因此每个不一样的模板都需要独立编写
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.google.zxing.WriterException;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.RectangleReadOnly;
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 com.zeng.demo.uitls.QRCodeGenerator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.time.YearMonth;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Slf4j
public class PdfGenerator {
public static BaseFont bfChinese;
/**
* 公用字体对象
*/
static {
try {
bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
//虚拟方法可以忽略,一般自己构建好入参
private static List<String> getColNames() {
List<String> columnNameList = new ArrayList<>();
columnNameList.add("serialNum");
columnNameList.add("feeTypeName");
columnNameList.add("price");
columnNameList.add("qty");
columnNameList.add("amount");
columnNameList.add("remark");
return columnNameList;
}
//虚拟方法可以忽略,一般自己查询完数据再入参
private static ArrayList<BillDto> queryDataList() {
ArrayList<BillDto> billDtos = new ArrayList<>();
BillDto billDto = new BillDto("1", "仓租费", "1000", "1", "1000", "元/月");
billDtos.add(billDto);
BillDto billDto2 = new BillDto("2", "卸货费", "1000", "1", "1000", "元/月");
billDtos.add(billDto2);
BillDto billDto3 = new BillDto("3", "配送费", "1000", "1", "1000", "元/月");
billDtos.add(billDto3);
BillDto billDto4 = new BillDto("4", "退货费", "1000", "1", "1000", "元/月");
billDtos.add(billDto4);
BillDto billDto5 = new BillDto("5", "打单费", "1000", "1", "1000", "元/月");
billDtos.add(billDto5);
BillDto billDto6 = new BillDto("6", "分拣费", "1000", "1", "1000", "元/月");
billDtos.add(billDto6);
return billDtos;
}
/**
* 输出模板(这个方法只是用于方便调试看效果)
*/
public static void main(String[] args) {
//文件模板
Document document = null;
FileOutputStream outputStream = null;
try {
document = new Document(new RectangleReadOnly(842.0F, 595.0F), 50, 50, 50, 50);
//这里不输出需要替换为stream
outputStream = new FileOutputStream(String.format("D:\\xxxx\\xxxx\\Desktop\\%s.pdf", "123456"));//输出本地的url地址
PdfWriter.getInstance(document, outputStream);
document.open();
// 构建表单(这里的参数不是固定的,可根据自己的表单内容来决定调整方法参数)
PdfPTable table = createTable();
// 添加表格到文档中
document.add(table);
} catch (DocumentException | IOException e) {
e.printStackTrace();
} catch (WriterException e) {
e.printStackTrace();
} finally {
//先关闭文档
if (document != null) {
document.close();
}
//后关闭流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException ioException) {
log.error("释放流失败:", ioException);
}
}
}
}
/**
* 构建PDF-File对象(一般使用该方法得到文件对象)
*/
public static File buildPdf(String fileName) {
//文件模板
File file = null;
Document document = null;
FileOutputStream outputStream = null;
try {
file = File.createTempFile(fileName, ".pdf");
document = new Document(new RectangleReadOnly(842.0F, 595.0F), 50, 50, 50, 50);
//这里不输出需要替换为stream
outputStream = new FileOutputStream(file);
PdfWriter.getInstance(document, outputStream);
document.open();
// 构建表单
PdfPTable table = createTable();
// 添加表格到文档中
document.add(table);
} catch (DocumentException | IOException e) {
e.printStackTrace();
} catch (WriterException e) {
e.printStackTrace();
} finally {
//先关闭文档
if (document != null) {
document.close();
}
//后关闭流
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException ioException) {
log.error("释放流失败:", ioException);
}
}
}
return file;
}
//TODO 构建表单内容这里
private static PdfPTable createTable() throws DocumentException, IOException, WriterException {
//TODO 配置动态值(默认数据库查询得到一些信息,也可以作为入参直接传入)
//查询明细
List<String> columnNameList = getColNames();
List<BillDto> dataList = queryDataList();
String fileName = "xxx月结账单";
BigDecimal taxes = new BigDecimal("0.16");
String supplierName = "xxx有限公司";
Integer startYear = 2024;
Integer startMonth = 2;
Calendar calendar = Calendar.getInstance();
calendar.set(startYear, startMonth - 1, 1);
calendar.add(Calendar.MONTH, 1);
//账单的下一个月的年份
int nextYear = calendar.get(Calendar.YEAR);
//账单的下一个月的月份
int nextMonth = calendar.get(Calendar.MONTH) + 1;
YearMonth yearMonth = YearMonth.of(nextYear, nextMonth);
//账单结算的最后一天
int endDays = yearMonth.lengthOfMonth();
//不含税总金额
BigDecimal totalAmount = CollectionUtils.isNotEmpty(dataList) ? dataList.stream().map(e -> new BigDecimal(e.getAmount())).reduce(BigDecimal.ZERO, BigDecimal::add) : BigDecimal.ZERO;
//税金
BigDecimal taxesPrice = taxes.multiply(totalAmount);
String taxesPriceStr = taxesPrice.setScale(2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
//含税总金额
BigDecimal totalPrice = totalAmount.add(taxesPrice);
String totalPriceStr = totalPrice.setScale(2, RoundingMode.HALF_UP).stripTrailingZeros().toPlainString();
// 创建表格
PdfPTable table = new PdfPTable(6);
table.setWidthPercentage(100);
//构建空单元格(标准化的单元格,使用全边框)
PdfPCell Empty = buildEmpty(0);
//--------------------------------------抬头6列的大标题(开始)--------------------------------------
//LOGO图片需要切换成项目的相对路径
/*try {
//获取指定地址的图片(可以是网络图片地址,也可以是本地的图片地址)
//Image logo = Image.getInstance("https://www.xxxx.com.png");
//通过输入流获取resources目录下的相对路径图片文件
InputStream inputStream = PdfGenerator.class.getClassLoader().getResourceAsStream("picture/anntoLogo.png");
BufferedImage logoBuffer = ImageIO.read(inputStream);
Image logo = Image.getInstance(logoBuffer, null);
//设置图片的参数
logo.scaleAbsolute(95, 80);//图片尺寸
logo.scaleToFit(95, 80);//填充图片的尺寸
logo.setAlignment(Image.RIGHT | Image.ALIGN_TOP);//图片的位置
PdfPCell logCell = new PdfPCell(logo, false);//构建的图片大小填充选择,false以absolute为准,ture以scaleToFit为准
logCell.setBorder(PdfPCell.TOP | PdfPCell.BOTTOM | PdfPCell.LEFT);//边框的显示注意要同时指定用|分隔
logCell.setPaddingTop(0);//图片距离顶部的边距
logCell.setPaddingLeft(5);//图片距离左侧的边距
logCell.setPaddingRight(2);//图片距离右侧的边距
logCell.setPaddingBottom(10);//图片距离底部的边距
table.addCell(logCell);
} catch (Exception pe) {
log.error("logo图片读取失败,已设置为空单元格");
//没有图片时直接变成空元素,这里由于logo位置在左上角,因此空单元格的边框去上下左即可
PdfPCell leftEmptyCell = buildEmpty(PdfPCell.TOP | PdfPCell.BOTTOM | PdfPCell.LEFT);
table.addCell(leftEmptyCell);
}*/
//生成二维码
String QR = "BH2024041600001";
Image qr = QRCodeGenerator.buildQR(QR, 200, 200);
qr.scaleAbsolute(50, 50);
qr.scaleToFit(50, 50);
qr.setAlignment(Image.RIGHT | Image.ALIGN_TOP);
PdfPCell logCell = new PdfPCell(qr, true);
logCell.setBorder(PdfPCell.TOP | PdfPCell.BOTTOM | PdfPCell.LEFT);
logCell.setPaddingTop(2);
logCell.setPaddingLeft(2);
logCell.setPaddingRight(2);
logCell.setPaddingBottom(30);
table.addCell(logCell);
//创建标题
String topic = "芜湖安得智联科技有限公司" + "\n" + "\n" + "Wuhu Annto Logisitics Technology Co., Ltd.";
PdfPCell topicCell = buildTopicCell(topic, 15);
//topicCell.setColspan(4);
topicCell.setColspan(3);
topicCell.setBorder(PdfPCell.TOP | PdfPCell.BOTTOM);
topicCell.setPadding(10);
table.addCell(topicCell);
//因为想堆成LOGO的单元格,左右两边各占用一个位
/*PdfPCell rightEmptyCell = buildEmpty(PdfPCell.TOP | PdfPCell.BOTTOM | PdfPCell.RIGHT);
table.addCell(rightEmptyCell);*/
//条形码(取代上面的空单元格为条形码,但此处占用的是2列,上面标题那里Colspan也从4列改成了3列)
String barcode = "1234567890";
Image bar = QRCodeGenerator.buildBar(barcode, 500, 150);
bar.scaleAbsolute(150, 50);
bar.scaleToFit(150, 50);
bar.setAlignment(Image.RIGHT | Image.ALIGN_TOP);
PdfPCell barcodeCell = new PdfPCell(bar, true);
barcodeCell.setColspan(2);
barcodeCell.setBorder(PdfPCell.TOP | PdfPCell.BOTTOM | PdfPCell.RIGHT);
barcodeCell.setPaddingTop(20);
barcodeCell.setPaddingLeft(2);
barcodeCell.setPaddingRight(2);
barcodeCell.setPaddingBottom(20);
table.addCell(barcodeCell);
//--------------------------------------抬头6列的大标题(结束)--------------------------------------
//账单名称
String billName = String.format("%s年%s月应收款对账单", startYear, startMonth);
PdfPCell billNameCell = buildTopicCell(billName, 15);
billNameCell.setColspan(6);
table.addCell(billNameCell);
//费用简述
String billDesc = String.format("%s年%s月%s日前%s应向芜湖安得智联科技有限公司支付%s年%s月份的物流服务费%s元,详见下表:", nextYear, nextMonth, endDays, supplierName, startYear, startMonth, totalPriceStr);
PdfPCell billDescCell = buildCell(billDesc, 9);
billDescCell.setColspan(6);
table.addCell(billDescCell);
//账单表头
PdfPCell headerCell1 = buildCell("序号", 9);
PdfPCell headerCell2 = buildCell("日期/月份", 9);
PdfPCell headerCell3 = buildCell("费用标准", 9);
PdfPCell headerCell4 = buildCell("数量", 9);
PdfPCell headerCell5 = buildCell("小计(单位元)", 9);
PdfPCell headerCell6 = buildCell("备注", 9);
table.addCell(headerCell1);
table.addCell(headerCell2);
table.addCell(headerCell3);
table.addCell(headerCell4);
table.addCell(headerCell5);
table.addCell(headerCell6);
//TODO 创建数据行(这里自定义生成的东西)
if (CollectionUtils.isNotEmpty(dataList)) {
for (BillDto billDto : dataList) {
//序列化成Map<String,String>
Map<String, String> data = JSON.parseObject(JSON.toJSONString(billDto), new TypeReference<Map<String, String>>() {
});
for (String columnName : columnNameList) {
String dataCol = data.get(columnName);
PdfPCell dataCell = buildCell(dataCol);
table.addCell(dataCell);
}
}
}
//税金行
String taxesSerNum = String.valueOf(dataList.size() + 1);
PdfPCell taxesSerCell = buildCell(taxesSerNum);
PdfPCell taxesNameCell = buildCell("税金");
PdfPCell taxesPriceCell = buildCell(taxesPriceStr);
table.addCell(taxesSerCell);
table.addCell(taxesNameCell);
table.addCell(Empty);
table.addCell(Empty);
table.addCell(taxesPriceCell);
table.addCell(Empty);
//合计金额行
PdfPCell totalPriceNameCell = buildCell("合计金额");
totalPriceNameCell.setColspan(4);
table.addCell(totalPriceNameCell);
PdfPCell totalPriceCell = buildCell(totalPriceStr);
table.addCell(totalPriceCell);
table.addCell(Empty);
//落款
String warning = String.format("烦请贵司于%s年%s月15日前核对后签字盖章回传我司,谢谢合作!", nextYear, nextMonth);
PdfPCell warningCell = buildLeftCell(warning);
warningCell.setColspan(4);
table.addCell(warningCell);
table.addCell(Empty);
table.addCell(Empty);
//委托方
String supplier = String.format("委托方:%s(盖章)", supplierName);
PdfPCell supplierCell = buildLeftCell(supplier);
supplierCell.setColspan(3);
//承运方
String factory = String.format("承运方:芜湖安得智联科技有限公司(盖章)");
PdfPCell factoryCell = buildLeftCell(factory);
factoryCell.setColspan(3);
table.addCell(supplierCell);
table.addCell(factoryCell);
//地址行
String addressPre = "地址:";
String factorAddDetail = "湖北省武汉市蔡甸区千子山大道199号";
PdfPCell supplierAddCell = buildLeftCell(addressPre);
supplierAddCell.setColspan(3);
PdfPCell factorAddCell = buildLeftCell(addressPre + factorAddDetail);
factorAddCell.setColspan(3);
table.addCell(supplierAddCell);
table.addCell(factorAddCell);
//电话行
String telPre = "电话:";
String factorTel = "13657221132";
PdfPCell supplierTelCell = buildLeftCell(telPre);
supplierTelCell.setColspan(3);
PdfPCell factorTelCell = buildLeftCell(telPre + factorTel);
factorTelCell.setColspan(3);
table.addCell(supplierTelCell);
table.addCell(factorTelCell);
//确认行
String confirmPre = "确认:";
PdfPCell confirmCell = buildLeftCell(confirmPre);
confirmCell.setColspan(3);
table.addCell(confirmCell);
table.addCell(confirmCell);
//日期行
//电话行
String datePre = "日期:";
String nowDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
PdfPCell supplierDateCell = buildLeftCell(datePre);
supplierDateCell.setColspan(3);
PdfPCell factorDateCell = buildLeftCell(datePre + nowDate);
factorDateCell.setColspan(3);
table.addCell(supplierDateCell);
table.addCell(factorDateCell);
return table;
}
//构建空单元格(入参0是默认全边框,也可以自定义全边框)
private static PdfPCell buildEmpty(int borderParam) throws DocumentException, IOException {
int defaultBorder = PdfPCell.TOP | PdfPCell.BOTTOM | PdfPCell.LEFT | PdfPCell.RIGHT;
PdfPCell Empty = buildCell("", 15);
if (borderParam == 0) {
Empty.setBorder(defaultBorder);
} else {
Empty.setBorder(borderParam);
}
Empty.setPadding(10);
return Empty;
}
//构建标题单元格(默认加粗,黑色字体)
private static PdfPCell buildTopicCell(String text, int size) {
//字体文本格式
Font fontChinese = new Font(bfChinese, size, Font.BOLD, BaseColor.BLACK);
PdfPCell cell = new PdfPCell(new Paragraph(text, fontChinese));
cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
cell.setPadding(5);
return cell;
}
//创建正常单元格(字体大小自定义,不加粗,黑色字体)
private static PdfPCell buildCell(String text, float size) throws DocumentException, IOException {
//字体文本格式
Font fontChinese = new Font(bfChinese, size, Font.NORMAL, BaseColor.BLACK);
PdfPCell cell = new PdfPCell(new Paragraph(text, fontChinese));
cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
cell.setPadding(5);
return cell;
}
//创建默认单元格(字体大小-10,不加粗,黑色字体)
private static PdfPCell buildCell(String text) throws DocumentException, IOException {
//字体文本格式
Font fontChinese = new Font(bfChinese, 10, Font.NORMAL, BaseColor.BLACK);
PdfPCell cell = new PdfPCell(new Paragraph(text, fontChinese));
//统一文本与边框的边距
cell.setHorizontalAlignment(PdfPCell.ALIGN_CENTER);
cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
cell.setPadding(5);
return cell;
}
//创建字体靠左的单元格(字体大小-10,不加粗,黑色字体)
private static PdfPCell buildLeftCell(String text) throws DocumentException, IOException {
//字体文本格式
Font fontChinese = new Font(bfChinese, 10, Font.BOLD, BaseColor.BLACK);
PdfPCell cell = new PdfPCell(new Paragraph(text, fontChinese));
//统一文本与边框的边距
cell.setHorizontalAlignment(PdfPCell.ALIGN_LEFT);
cell.setVerticalAlignment(PdfPCell.ALIGN_MIDDLE);
cell.setPadding(5);
return cell;
}
}
5.Rest层测试
import com.zeng.demo.pdf.PdfGenerator;
import org.springframework.core.io.ByteArrayResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
@RestController
public class TestFileDownload {
/**
* 通过读取url下载文件
*/
@GetMapping(value = "/getPdfFile")
public ResponseEntity<ByteArrayResource> getPdfFile(@RequestParam("url") String url) throws IOException {
try {
//优化url处理,有些地址会自带这玩意导致无法正常加载文件
url = url.replace("\u202A", "");
File file = new File(url);
byte[] bytes = toByteArray(file);
ByteArrayResource resource = new ByteArrayResource(bytes);
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=output.pdf");
return ResponseEntity.ok().headers(headers).contentLength(bytes.length).contentType(MediaType.APPLICATION_PDF).body(resource);
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
/**
* 直接输出字节流文件给前端
*/
@GetMapping(value = "/getPdfFileByLocal")
public ResponseEntity<ByteArrayResource> getPdfFileByLocal(@RequestParam("name") String name) throws IOException {
try {
File file = PdfGenerator.buildPdf(name);
byte[] bytes = toByteArray(file);
ByteArrayResource resource = new ByteArrayResource(bytes);
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=output.pdf");
return ResponseEntity.ok().headers(headers).contentLength(bytes.length).contentType(MediaType.APPLICATION_PDF).body(resource);
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
public static byte[] toByteArray(File file) throws IOException {
FileInputStream fis = null;
try {
fis = new FileInputStream(file);
byte[] bytes = new byte[(int) file.length()];
fis.read(bytes);
return bytes;
} finally {
if (fis != null) {
fis.close();
}
}
}
}