需求
给如下PDF中的所有图片添加超链接
实现原理
org.apache.pdfbox +e-iceblue的spire.pdf 实现pdf中图片解析,获取图片在pdf画布中的坐标点,根据图片的长宽绘制图片区域,添加超链接。
实现方式
springboot+vue3
vue前端代码
代码结构
前端运行之后的样子
对应代码
request.js
import axios from 'axios';
//import QS from 'qs';
const api = axios.create({
baseURL: '/api', // 所有请求的公共地址部分(因为服务器解析了域名,方便转发)
timeout: 12000 // 请求超时时间 这里的意思是当请求时间超过5秒还未取得结果时 提示用户请求超时
})
axios.interceptors.request.use(
config => {
config.headers.token = sessionStorage.getItem('token');
return config;
},
error => {
return Promise.reject(error);
}
);
axios.interceptors.response.use(
response => {
if (response.status === 200) {
return Promise.resolve(response);
} else {
return Promise.reject(response);
}
},
error => {
if (error.response && error.response.status) {
switch (error.response.status) {
case 401:
//异常处理
break;
case 403:
break;
case 404:
break;
default:
return Promise.reject(error.response);
}
}
return Promise.reject(error);
}
);
const $get = (url, params) => {
return new Promise((resolve, reject) => {
api.get(url, { params })
.then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
};
const $post = (url, params) => {
return new Promise((resolve, reject) => {
api.post(url, params ).then(res => {
resolve(res.data);
})
.catch(err => {
reject(err);
});
});
};
/**
* 文件上传
* @param {String} url 地址
* @param {File} file 文件
*/
const $methodUpload = (url, file) => {
return new Promise((resolve, reject) => {
const formData = new FormData()
formData.append('file', file)
formData.append('currentDate', Date.now())
api.post(url, formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
}).then((response) => {
resolve(response.data)
}).catch((error) => {
reject(error)
})
})
};
export default {
install: (app) => {
app.config.globalProperties.$get = $get;
app.config.globalProperties.$post = $post;
app.config.globalProperties.$axios = axios;
app.config.globalProperties.$methodUpload = $methodUpload;
}
};
PdfChange.vue
<template>
<div>
Excel表格:<input type="file" id="ExcelPath" accept=".xlsx" :v-model="ExcelPath">
<button id="myButtonExcel" @click="uploadFileExcel" :disabled="EV">上传</button><span v-show="ExcelShow">✔️</span><br/>
PDF文件:<input type="file" id="PdfPath" accept=".pdf" :v-model="PdfPath">
<button id="myButtonPdf" @click="uploadFilePdf" :disabled="PV">上传</button><span v-show="PdfShow">✔️</span><br/>
<form id="myForm">
<label>
<input type="checkbox" name="option1" value="Y" :disabled="checkV"> 转换成英文
</label>
<label>
<input type="checkbox" name="option2" value="N" :disabled="checkV"> 转换成中文</label>
</form>
<button id="submit" @click="submit" v-loading="isLoading">开始添加超链接</button>
<div v-if="isLoading">Loading...</div>
<a v-show="linksShow" :href="links" target="_blank">点击此链接下载附件</a>
<button id="refresh" @click="refreshPage">刷新界面</button><br/>
<div id="loadingSpinner"><span id="loadingText">处理中...</span></div>
</div>
</template>
<style scoped>
.icon1 {
display: none; /* 初始时隐藏图标 */
}
.icon2 {
display: none; /* 初始时隐藏图标 */
}
.icon3 {
display: none; /* 初始时隐藏图标 */
}
#loadingSpinner {
border: 16px solid #f3f3f3;
border-top: 16px solid #3498db;
border-radius: 50%;
width: 120px;
height: 120px;
animation: spin 2s linear infinite;
display: none; /* 初始状态下隐藏等待框 */
}
#loadingText {
position: absolute; /* 添加绝对定位 */
top: 50%; /* 将文字垂直居中 */
left: 50%; /* 将文字水平居中 */
transform: translate(-50%, -50%); /* 将文字居中 */
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.hidden-file-input {
display: none;
}
</style>
<script>
export default {
name:"PdfChange",
data() {
return {
linksShow:false,
links:"",
isLoading:false,
checkV:false,
PV:false,
EV:false,
ExcelPath:"",
ExcelShow:false,
PdfPath:"",
PdfShow:false
};
},
methods: {
refreshPage(){
location.reload()
},
uploadFileExcel(){
var fileInput = document.getElementById('ExcelPath');
var file = fileInput.files[0];
this.$methodUpload('/upload',file).then((res) => {
console.log(res)
this.ExcelPath=res
this.ExcelShow=true
this.EV=true
}).catch((err) => {
console.log(err)
})
},
uploadFilePdf(){
var fileInput = document.getElementById('PdfPath');
var file = fileInput.files[0];
this.$methodUpload('/upload',file).then((res) => {
console.log(res)
this.PdfPath=res
this.PdfShow=true
this.PV=true
}).catch((err) => {
console.log(err)
})
},
submit(){
var form = document.getElementById("myForm");
var checkboxes = form.querySelectorAll('input[type="checkbox"]:checked');
// eslint-disable-next-line no-unused-vars
let English="";
// eslint-disable-next-line no-unused-vars
var selectedValues = Array.from(checkboxes).map(function(checkbox) {
English=checkbox.value
});
if(this.ExcelPath==""||this.PdfPath==""||English==""){
alert("必要参数没有录入,无法进行转换!")
return;
}
var formData = new FormData();
formData.append('ExcelPath', this.ExcelPath);
formData.append('PDFPath', this.PdfPath);
formData.append('English', English);
this.isLoading=true
this.$post("/operate",formData).then((res) => {
console.log(res)
this.links=res
this.showlinks()
}).catch((err) => {
console.log(err)
})
},
showlinks(){
this.isLoading=false
this.linksShow=true
}
}
}
</script>
App.vue
<template>
<img alt="Vue logo" src="./assets/logo.png">
<PdfChange msg="Welcome to Your Vue.js App"/>
</template>
<script>
import PdfChange from "@/components/PdfChange.vue";
export default {
name: 'App',
components: {
// eslint-disable-next-line vue/no-unused-components
PdfChange
}
}
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
main.js
import { createApp } from 'vue'
import App from './App.vue'
import http from './utils/request'
import VLoading from 'v-loading';
const app = createApp(App)
app.use(http) //axios封装
app.use(VLoading) //Loading
app.mount('#app')
java后端代码
代码结构
具体代码
首先需要下载 spire.pdf-9.6.2.jar 放在/src/main/resources/lib/路径下
这个可以在绑定资源中下载
pom依赖
<dependency>
<groupId>e-iceblue</groupId>
<artifactId>spire.pdf</artifactId>
<version>9.6.2</version>
<scope>system</scope>
<systemPath>${pom.basedir}/src/main/resources/lib/spire.pdf-9.6.2.jar</systemPath>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>fontbox</artifactId>
<version>2.0.27</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>jempbox</artifactId>
<version>1.8.17</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>xmpbox</artifactId>
<version>2.0.27</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>preflight</artifactId>
<version>2.0.27</version>
</dependency>
<dependency>
<groupId>org.apache.pdfbox</groupId>
<artifactId>pdfbox-tools</artifactId>
<version>2.0.27</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.9</version>
</dependency>
<!--xlsx(07)-->
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.9</version>
</dependency>
application.properties文件添加
#生产环境保存上传文件的路径
property.OutPutFilSavePathDev=/usr/share/nginx/html/files/
#测试环境保存文件的路径
property.OutPutFilSavePathTest=/Users/gwx/Desktop/java/pdf/
#nginx配置的资源下载路径
property.StaticResourcelink=http://81.71.97.165:80/downloads
#生成文件之后需要执行的权限脚本,以便nginx有权限访问
property.CommandChangeRight=sudo chmod -R 755 /usr/share/nginx/html/files
#0是生产环境,1是测试环境
property.test=0
ReadExcelData.java 读取Excel文件
package com.boot.springboot.utils;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.*;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
public class ReadExcelData {
/**
* 读取数据转换为list
* @param filePath
* @param i
*/
public static List<String> ReadExcelToList(String filePath, Integer i) {
List<String> finalList=new ArrayList<String>();
try {
FileInputStream file = new FileInputStream(filePath);
Workbook workbook = new XSSFWorkbook(file);
Sheet sheet = workbook.getSheetAt(i);
List<List<String>> dataList = new ArrayList<>();
Iterator<Row> rowIterator = sheet.iterator();
while (rowIterator.hasNext()) {
Row row = rowIterator.next();
List<String> rowData = new ArrayList<>();
Iterator<Cell> cellIterator = row.cellIterator();
String cellValue = "";
while (cellIterator.hasNext()) {
Cell cell = cellIterator.next();
if (cell.getCellType() == 1) {
cellValue = cell.getStringCellValue();
}
rowData.add(cellValue);
}
dataList.add(rowData);
}
// 输出结果
for (List<String> rowData : dataList) {
finalList.addAll(rowData);
for (String cellValue : rowData) {
// System.out.print(cellValue + "\t");
}
}
file.close();
} catch (IOException e) {
e.printStackTrace();
finalList=null;
}
return finalList;
}
public static Map<String, Object> ReadExcelToListMap(String filePath, String English) {
int startRow = 2; // 数据起始行(从1开始计数)
int endRow = 6373; // 数据结束行(从1开始计数)
int column1Index = 0; // 第一列的索引(从0开始计数)
int column2Index = 1; // 第二列的索引(从0开始计数)
Map<String, Object> dataList = new HashMap<>();
try {
FileInputStream fis = new FileInputStream(filePath);
Workbook workbook = new XSSFWorkbook(fis) ;
//获取所有的sheet页数
int numberOfSheets = workbook.getNumberOfSheets();
int sheetNumber=0;
if(English=="Y"){
sheetNumber=numberOfSheets-1;
}else{
sheetNumber=numberOfSheets-2;
}
Sheet sheet = workbook.getSheetAt(sheetNumber);
for (int rowNum = startRow; rowNum <=endRow ; rowNum++) {
Row row = sheet.getRow(rowNum - 1);
if (row == null) {
continue;
}
Cell cell1 = row.getCell(column1Index);
Cell cell2 = row.getCell(column2Index);
if (cell1 == null || cell2 == null) {
continue;
}
dataList.put(cell1.getStringCellValue(), cell2.getStringCellValue());
}
} catch (IOException e) {
e.printStackTrace();
}
return dataList;
}
public static List<String> getFinalList(String ExcelfilePath,Integer pageNum,String English){
List<String> listSheet1= ReadExcelData.ReadExcelToList(ExcelfilePath,pageNum-2);
Map<String, Object> sum= ReadExcelData.ReadExcelToListMap(ExcelfilePath,English);
List<String> listSheet1_r=ListUtils.listCom(listSheet1,sum);
return listSheet1_r;
}
}
PDFReader.java 解析pdf文件
package com.boot.springboot.utils;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.io.RandomAccessFile;
import org.apache.pdfbox.pdfparser.PDFParser;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.graphics.image.PDImageXObject;
import org.apache.pdfbox.text.PDFTextStripper;
import com.boot.springboot.pojo.Point;
import javax.imageio.ImageIO;
import java.io.File;
import java.util.Iterator;
import java.util.List;
public class PDFReader {
static String fileName = "/Users/gwx/Desktop/pythonFiles/读取PDF/416--添加链接.pdf";
/**
* 一次获取整个文件的内容
*
* @throws Exception
*/
public static void readFile() throws Exception {
File file = new File(fileName);
RandomAccessFile is = new RandomAccessFile(file, "r");
PDFParser parser = new PDFParser(is);
parser.parse();
PDDocument doc = parser.getPDDocument();
PDFTextStripper textStripper = new PDFTextStripper();
String s = textStripper.getText(doc);
System.out.println("总页数:" + doc.getNumberOfPages());
System.out.println("输出内容:");
System.out.println(s);
doc.close();
}
/**
* 分页获取文字的内容
*
* @throws Exception
*/
public static void readPage() throws Exception {
File file = new File(fileName);
RandomAccessFile is = new RandomAccessFile(file, "r");
PDFParser parser = new PDFParser(is);
parser.parse();
PDDocument doc = parser.getPDDocument();
PDFTextStripper textStripper = new PDFTextStripper();
for (int i = 1; i <= doc.getNumberOfPages(); i++) {
textStripper.setStartPage(i);
textStripper.setEndPage(i);
// 一次输出多个页时,按顺序输出
textStripper.setSortByPosition(true);
String s = textStripper.getText(doc);
System.out.println("当前页:" + i);
System.out.println("输出内容:");
System.out.println(s);
}
doc.close();
}
/**
* 读取文本内容和图片
*
* @throws Exception
*/
public static void readTextImage() throws Exception {
File file = new File(fileName);
PDDocument doc = PDDocument.load(file);
PDFTextStripper textStripper = new PDFTextStripper();
for (int i = 1; i <= doc.getNumberOfPages(); i++) {
textStripper.setStartPage(i);
textStripper.setEndPage(i);
String s = textStripper.getText(doc);
System.out.println("第 " + i + " 页 :" + s);
// 读取图片
PDPage page = doc.getPage(i - 1);
PDResources resources = page.getResources();
// 获取页中的对象
Iterable<COSName> xobjects = resources.getXObjectNames();
if (xobjects != null) {
Iterator<COSName> imageIter = xobjects.iterator();
while (imageIter.hasNext()) {
COSName cosName = imageIter.next();
boolean isImageXObject = resources.isImageXObject(cosName);
if (isImageXObject) {
// 获取每页资源的图片
PDImageXObject ixt = (PDImageXObject) resources.getXObject(cosName);
File outputfile = new File("第 " + (i) + " 页" + cosName.getName() + ".jpg");
ImageIO.write(ixt.getImage(), "jpg", outputfile);
}
}
}
}
doc.close();
}
/**
* 读取某一页文本内容和图片
*
* @throws Exception
*/
public static void readImage(PDPage page, Integer num, PDDocument document, List<Point> lists, String ExcelPath, String English) throws Exception {
PDResources resources = page.getResources();
// 获取页中的对象
AddLinks link = new AddLinks();
//添加超链接
link.addLink(document, num, lists, ExcelPath, English);
}
}
ListUtils.java
package com.boot.springboot.utils;
import com.boot.springboot.pojo.Point;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
public class ListUtils {
/**
* 去重,降序排列
* @param list
* @return
*/
public static List<Integer> duplicateListBySet(List<Integer> list) {
HashSet h = new HashSet(list);
List newList = new ArrayList();
newList.addAll(h);
newList.sort(null);
return newList;
}
/**
* LIST反转
* @param originalList
* @return
*/
public static List<Integer> reverse(List<Integer> originalList) {
List<Integer> reversedList = new ArrayList<>();
for (int i = originalList.size() - 1; i >= 0; i--) {
reversedList.add(originalList.get(i));
}
return reversedList;
}
/**
* LIST去除杂数据(相邻坐标差<5的剔除一个)
* @param list
* @return
*/
public static List<Integer> deviation(List<Integer> list) {
for(int i = list.size()-1;i>0; i--){
if( Math.abs(list.get(i)- list.get(i-1))<5){
list.remove(i);
}
}
return list;
}
/**
* 自定义封装:将每页坐标点转换为每个画布点的实体LIST
* @param x
* @param y
* @return
*/
public static List<Point> listPoint(List<Integer> x, List<Integer> y, int num){
List<Point> pointMap=new ArrayList<>();
for(int i = 0; i < y.size(); i++){
for(int j = 0; j < x.size(); j++){
Point point=new Point();
point.setStartX(x.get(j));
point.setStartY(y.get(i));
pointMap.add(point);
}
}
if(pointMap.size()-num>0){
pointMap = pointMap.subList(0, pointMap.size() - (pointMap.size()-num));
}
return pointMap;
}
public static List<Point> listPointTrans(List<Point> a,int num){
List<Point> pointMap=new ArrayList<>();
if(pointMap.size()-num>0){
pointMap = pointMap.subList(0, pointMap.size() - (pointMap.size()-num));
}
return pointMap;
}
/**
* 合并LIST
* @param sheet1
* @param map
* @return
*/
public static List<String> listCom(List<String> sheet1, Map<String, Object> map) {
List<String> result=new ArrayList<>();
for(int i=0;i< sheet1.size();i++){
result.add((String) map.get(sheet1.get(i)));
}
return result;
}
public static void compareAndAssign(List<Integer> list1, List<Integer> list2) {
int size = Math.min(list1.size(), list2.size());
for (int i = 0; i < size; i++) {
int diff = Math.abs(list1.get(i) - list2.get(i));
if (diff > 10) {
if (list1.get(i) < list2.get(i)) {
list1.set(i, list2.get(i));
} else {
list2.set(i, list1.get(i));
}
}
}
}
}
getCoordinateOfImage.java 获取图片所在坐标
package com.boot.springboot.utils;
import com.boot.springboot.pojo.Point;
import com.spire.pdf.PdfDocument;
import com.spire.pdf.PdfPageBase;
import com.spire.pdf.exporting.PdfImageInfo;
import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;
public class GetCoordinateOfImage {
/**
* 获取当页所有图片坐标位置,输出List实类
* @param doc PdfDocument ==》PDF文件
* @param num PDF文件循环的页码
* @return
* @throws Exception
*/
public List<Point> getCoordinateOfImage(PdfDocument doc, Integer num) throws Exception {
List<Point> listPoint=new ArrayList<>();
//获取页的内容
PdfPageBase page = doc.getPages().get(num);
//获取当页图片List
PdfImageInfo[] imageInfo = page.getImagesInfo();
//获取图片大致的X坐标点和Y坐标点
List<Integer> listX=new ArrayList<>();
List<Integer> listY=new ArrayList<>();
Integer boxHigh= (int) page.getCropBox().getHeight();
for (int i = 0; i < imageInfo.length; i++) {
//获取指定图片的边界属性
Rectangle2D rect = imageInfo[i].getBounds();
listX.add((int) rect.getX());
//pdfbox获取的坐标点在左上角,需要转换成左下角的坐标
listY.add(boxHigh-(int) rect.getY()-28);
//如下方法可以保存PDF的图片到本地
//File outputfile = new File("第 " + (i) + "张" + i + ".jpg");
//ImageIO.write(imageInfo[i].getImage(), "jpg", outputfile);
//获取左上角坐标
// System.out.println(
// String.format("第%d张图片的左下角坐标为:(%f, %f),右上角坐标为:( %f, %f),页面宽高:%f, %f",
// i+1,rect.getX(), rect.getY()
// ,rect.getX()+rect.getWidth(), rect.getY()+rect.getHeight(),
// page.getCropBox().getWidth(),page.getCropBox().getHeight()));
}
//当前页码(用于打印)
Integer pageNum=num+1;
//XY用于去重+去杂+反转
List<Integer> listXFinal=new ArrayList<>();
List<Integer> listYFinal=new ArrayList<>();
//坐标处理
listXFinal=ListUtils.duplicateListBySet(listX);
listYFinal=ListUtils.reverse(ListUtils.duplicateListBySet(listY));
System.out.println( "第"+pageNum+"页的X坐标处理后的数据为:"+ListUtils.deviation(listXFinal));
System.out.println( "第"+pageNum+"页的Y坐标处理后的数据为:"+ListUtils.deviation(listYFinal));
System.out.println( "第"+pageNum+"页的数据量为:"+ListUtils.listPoint(ListUtils.deviation(listXFinal),ListUtils.deviation(listYFinal),imageInfo.length).size());
listPoint=ListUtils.listPoint(ListUtils.deviation(listXFinal), ListUtils.deviation(listYFinal),imageInfo.length);
return listPoint;
}
}
CommandOperate.java 执行Linux脚本
package com.boot.springboot.utils;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class CommandOperate {
/**
* JAVA执行指令
* @param command
* @throws IOException
*/
public static void executeRootCommand(String command) throws IOException {
Process process = Runtime.getRuntime().exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
reader.close();
}
}
AddLinks.java 添加链接的主要实现方法
package com.boot.springboot.utils;
import com.boot.springboot.pojo.Point;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.interactive.action.PDActionURI;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDAnnotationLink;
import org.apache.pdfbox.pdmodel.interactive.annotation.PDBorderStyleDictionary;
import java.io.IOException;
import java.util.List;
public class AddLinks {
/**
* 每页PDF添加超链接
* @param document
* @param pageNumber
* @param lists
* @param ExcelPath
* @return
* @throws IOException
*/
public String addLink(PDDocument document, int pageNumber, List<Point> lists, String ExcelPath, String English) throws IOException {
Integer pagenum=pageNumber+1;
System.out.println("AddLinks===页码"+pagenum+"开始添加link任务!");
String tips="";
PDPage page = document.getDocumentCatalog().getPages().get(pageNumber);
List<String> picUrls=ReadExcelData.getFinalList(ExcelPath,pageNumber,English);
if(pageNumber==document.getDocumentCatalog().getPages().getCount()) {
tips="AddLinks===PDF任务全部完成!!!!";
return tips;
}
else{
for(int i = 0; i < lists.size(); i++){
if(i==lists.size()){
tips="页码"+pagenum+"完成添加link任务!";
return tips;
}
try {
//添加链接区域
PDAnnotationLink txtLink = new PDAnnotationLink();
PDRectangle position = new PDRectangle(0, 0, page.getCropBox().getWidth(), page.getCropBox().getHeight());
//设置区域坐标点
position.setLowerLeftX(lists.get(i).getStartX());
position.setUpperRightX(lists.get(i).getStartX() + lists.get(i).getWidth());
position.setLowerLeftY(lists.get(i).getStartY());
position.setUpperRightY(lists.get(i).getStartY()+ lists.get(i).getHight());
txtLink.setRectangle(position);
// 去除区域边框
PDBorderStyleDictionary borderStyle = new PDBorderStyleDictionary();
borderStyle.setWidth(0);
txtLink.setBorderStyle(borderStyle);
PDActionURI action = new PDActionURI();
//循环插入excel读取的顺序链接
action.setURI(picUrls.get(i));
txtLink.setAction(action);
page.getAnnotations().add(txtLink);
tips= "Finished!";
} catch (IOException e) {
tips="页码"+pagenum+"添加失败==》"+e.getMessage();
}
}
}
tips="页码"+pagenum+"完成添加link任务!";
return tips;
}
}
Point.java 图片坐标实体
package com.boot.springboot.pojo;
public class Point {
private Integer startX;
private Integer startY;
private Integer startXMax;
private Integer startYMin;
public Point() {
}
@Override
public String toString() {
return "Point{" +
"startX=" + startX +
", startY=" + startY +
", startXMax=" + startXMax +
", startYMin=" + startYMin +
", width=" + width +
", hight=" + hight +
'}';
}
public Integer getStartXMax() {
return startXMax;
}
public void setStartXMax(Integer startXMax) {
this.startXMax = startXMax;
}
public Integer getStartYMin() {
return startYMin;
}
public void setStartYMin(Integer startYMin) {
this.startYMin = startYMin;
}
private final float width= 56.000000F;
private final float hight= 28.000000F;
public float getStartX() {
return startX;
}
public void setStartX(Integer startX) {
this.startX = startX;
}
public float getStartY() {
return startY;
}
public void setStartY(Integer startY) {
this.startY = startY;
}
public float getWidth() {
return width;
}
public float getHight() {
return hight;
}
}
PdfOperation.java 添加链接controller
package com.boot.springboot.controller;
import com.boot.springboot.pojo.Point;
import com.boot.springboot.utils.GetCoordinateOfImage;
import com.boot.springboot.utils.PDFReader;
import com.spire.pdf.PdfDocument;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import static com.boot.springboot.utils.CommandOperate.executeRootCommand;
@Controller
public class PdfOperation {
@Value("${property.test}")
private String test;
@Value("${property.OutPutFilSavePathDev}")
private String OutPutFilSavePathDev;
@Value("${property.OutPutFilSavePathTest}")
private String OutPutFilSavePathTest;
@Value("${property.StaticResourcelink}")
private String StaticResourcelink;
@Value("${property.CommandChangeRight}")
private String CommandChangeRight;
@RequestMapping(value = "/operate",method = RequestMethod.POST,produces = "application/json;charset=UTF-8")
@ResponseBody
public String operate(@RequestParam("ExcelPath") String ExcelPath,
@RequestParam("PDFPath") String PDFPath,
@RequestParam("English") String English) throws Exception {
String FileSavePath="";
if(this.test.equals("1")){
FileSavePath=OutPutFilSavePathTest;
}else{
FileSavePath=OutPutFilSavePathDev;
}
//创建PdfDocument对象
PdfDocument doc = new PdfDocument();
//加载一个PDF文档
doc.loadFromFile(PDFPath);
File file = new File(PDFPath);
PDDocument doc1 = PDDocument.load(file);
GetCoordinateOfImage test=new GetCoordinateOfImage();
System.out.println("Main==PDF文件总共"+doc1.getNumberOfPages()+"页!");
for (int i = 2; i <doc1.getNumberOfPages(); i++) {
//int i=4;
Integer pageNum=i+1;
if(pageNum==doc1.getNumberOfPages()){
System.out.println("Main==PDF文件执行完成!");
break;
}
System.out.println("Main页码任务"+pageNum+"开始喽~");
List<Point> list = test.getCoordinateOfImage(doc,i);
PDPage page=doc1.getPage(i);
PDFReader.readImage(page,i,doc1,list,ExcelPath,English);
}
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
String dateStr = simpleDateFormat.format(new Date());
System.out.println("文件名:"+file.getName());
doc1.save(FileSavePath+ file.getName().substring(0,file.getName().length()-4)+"-"+dateStr+"版本.pdf");
String FileOutPath=FileSavePath+file.getName().substring(0,file.getName().length()-4)+"-"+dateStr+"版本.pdf";
System.out.println("Main==已经输出文件,输出文件路径为:"+FileOutPath);
doc1.close();
doc.close();
String link="";
if(this.test.equals("1")){
}else{
//Linux服务器需要配置文件夹的运行用户组和文件夹权限
executeRootCommand(CommandChangeRight);
System.out.print("linux指令执行完成!");
link=StaticResourcelink;
}
// 返回解析后的结果
return link+"/"+file.getName().substring(0,file.getName().length()-4)+"-"+dateStr+"版本.pdf";
}
}
FileUploadController.java 文件上传
package com.boot.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
@RestController
@CrossOrigin("*")
public class FileUploadController {
@PostMapping("/upload")
@ResponseBody
public String handleFileUpload(@RequestParam("file") MultipartFile file) throws IOException {
String filePath="";
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMdd");
String dateStr = simpleDateFormat.format(new Date());
if (file.isEmpty()) {
}
try {
// 获取文件名
String fileName = file.getOriginalFilename();
// 指定文件保存路径
filePath= "/Users/gwx/Desktop/"+dateStr+"/"+ fileName;
// 创建文件对象
File dest = new File(filePath);
// 检查父目录是否存在,不存在则创建
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
// 保存文件
file.transferTo(dest);
} catch (IOException e) {
e.printStackTrace();
System.out.print("文件上传失败:"+e.getMessage());
filePath= "";
}
System.out.print(filePath+",UPLOADED SUCCESSFUL!!");
return filePath;
}
}
项目运行结果
生成的文件:http://81.71.97.165/downloads/416-2023-12-07-20-43-40版本.pdf
执行完成后的界面