富文本转化pdf

dongdingding
dongdingding 2 weeks ago
parent 8fdfc9e466
commit c51fffe8e0

@ -16,6 +16,41 @@
</description>
<dependencies>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.14.3</version>
</dependency>
<!-- 本地文件转为MultipartFile file 因为我加了oss上传无上传可不加 如有启动错误请改变版本号-->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.itextpdf/itext-asian -->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<!--富文本转pdfhtml转pdfitext转pdf-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.13</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
@ -68,6 +103,11 @@
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId>
<version>4.4.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>html2pdf</artifactId>
<version>1.17.2</version>
</dependency>
</dependencies>
<build>

@ -7,10 +7,14 @@ import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.gysl.entity.Dpclgl;
import com.ruoyi.gysl.entity.request.DpclglPageReq;
import com.ruoyi.gysl.service.DpclglService;
import com.ruoyi.gysl.utils.HtmlToPdfConverter;
import com.ruoyi.gysl.utils.PdfUtils;
import com.ruoyi.web.controller.common.CommonController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.io.Serializable;
@ -22,11 +26,15 @@ import java.util.List;
* @author makejava
* @since 2025-03-22 11:11:55
*/
@Api(tags ="单片材料管理" )
@Api(tags = "单片材料管理")
@RestController
@RequestMapping("/gysl/dpclgl")
@PreAuthorize("@ss.hasAnyRoles('admin,common')")
//@PreAuthorize("@ss.hasAnyRoles('admin,common')")
public class DpclglController extends BaseController {
@Resource
private CommonController commonController;
/**
*
*/
@ -36,7 +44,7 @@ public class DpclglController extends BaseController {
/**
*
*
* @param page
* @param page
* @param dpclgl
* @return
*/
@ -93,5 +101,25 @@ public class DpclglController extends BaseController {
public AjaxResult delete(@RequestParam("idList") List<Long> idList) {
return success(dpclglService.removeByIds(idList));
}
/**
*
*
* @return
*/
@ApiOperation(value = "副编辑器内容生成pdf文件url")
@GetMapping("/unloadPdf")
public AjaxResult unloadPdf(@RequestParam(defaultValue = "文章标题") String htmlArticleTitle, @RequestParam(defaultValue = "文章内容") String htmlContent) {
try {
MultipartFile multipartFile = HtmlToPdfConverter.convertHtmlToPdf(htmlArticleTitle, htmlContent);
commonController.uploadFile(multipartFile);
} catch (Exception e) {
e.printStackTrace();
}
return AjaxResult.success();
}
}

@ -0,0 +1,211 @@
package com.ruoyi.gysl.utils;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Image;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class HtmlToPdfConverter {
public static MultipartFile convertHtmlToPdf(String htmlArticleTitle, String htmlContent) throws IOException {
String ht = content2Html(htmlContent);
String path = System.getProperty("user.dir");
// 根据日期建文件夹
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String[] split = format.split("-");
Path dirPath = Paths.get(path, "temporary", split[0], split[1], split[2]);
try {
Files.createDirectories(dirPath);
} catch (IOException e) {
throw new RuntimeException("创建文件夹失败: " + e.getMessage(), e);
}
File pdfFile = new File(dirPath.toFile(), "pdf-" + System.currentTimeMillis() + ".pdf");
// 创建PDF文档
Document document = new Document();
FileOutputStream fos = null;
InputStream is = null;
try {
fos = new FileOutputStream(pdfFile);
PdfWriter writer = PdfWriter.getInstance(document, fos);
XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
fontProvider.register("C:/Windows/Fonts/simsun.ttc");
document.open();
// 添加标题
Paragraph paragraph = new Paragraph(htmlArticleTitle); // 设置你自定义的字体格式
document.add(paragraph);
String updatedHtmlContent = "";
if (htmlContent.contains("img")) {
updatedHtmlContent = replaceImgSrcWithBase64(ht);
if (updatedHtmlContent != null) {
is = new ByteArrayInputStream(updatedHtmlContent.getBytes(StandardCharsets.UTF_8));
XMLWorkerHelper.getInstance().parseXHtml(writer, document, is, StandardCharsets.UTF_8, fontProvider);
// 添加图片
Elements imgElements = Jsoup.parse(updatedHtmlContent).select("img");
for (Element img : imgElements) {
String imgSrc = img.attr("src");
if (imgSrc.startsWith("data:image/jpeg;base64,")) {
String base64Data = imgSrc.substring("data:image/jpeg;base64,".length());
byte[] imageBytes = Base64.getDecoder().decode(base64Data);
Image image = Image.getInstance(imageBytes);
document.add(image); // 添加图片到 PDF
}
}
}
} else {
is = new ByteArrayInputStream(ht.getBytes(StandardCharsets.UTF_8));
XMLWorkerHelper.getInstance().parseXHtml(writer, document, is, StandardCharsets.UTF_8, fontProvider);
}
} catch (DocumentException | IOException e) {
throw new RuntimeException("转换PDF失败: " + e.getMessage(), e);
} finally {
if (document.isOpen()) {
document.close(); // 确保Document关闭
}
if (fos != null) {
try {
fos.close(); // 关闭文件输出流
} catch (IOException e) {
e.printStackTrace();
}
}
if (is != null) {
try {
is.close(); // 关闭输入流
} catch (IOException e) {
e.printStackTrace();
}
}
}
return getMultipartFile(pdfFile);
}
private static MultipartFile getMultipartFile(File file) throws IOException {
try (FileInputStream fileInputStream = new FileInputStream(file)) {
return new MockMultipartFile(file.getName(), file.getName(), "application/pdf", fileInputStream);
}
}
public static String content2Html(String htmlContent) {
String COMPLETE_CONTENT = "<html><head></head><body style=\"font-family: SimSun;\">" + htmlContent + "</body></html>";
return COMPLETE_CONTENT.replace("<br>", "<br/>");
}
private static String replaceImgSrcWithBase64(String htmlContent) {
List<String> imgSrcs = new ArrayList<>();
String regex = "<img[^>]+src=\"([^\"]+)\"[^>]*>"; // 正确的正则表达式
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(htmlContent);
String baseUrl = "http://39.101.188.84:7071";
// 使用 StringBuilder 来构建新的 HTML
StringBuilder updatedHtml = new StringBuilder(htmlContent);
// 定义要替换的起始位置
int offset = 0;
while (matcher.find()) {
String imgSrc = matcher.group(1); // 捕获组返回 img src 的值
String imgUrl = baseUrl + imgSrc;
// 将 URL 转化为 Base64
try {
URL url = new URL(imgUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("User-Agent", "Mozilla/5.0"); // 添加 User-Agent
connection.setDoInput(true);
connection.connect();
InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
byte[] imageBytes = outputStream.toByteArray();
String base64 = Base64.getEncoder().encodeToString(imageBytes);
// 替换 img 标签的 src 属性为 Base64 数据
String base64ImgTag = "<img src=\"data:image/jpeg;base64," + base64 + "\" />";
int start = matcher.start() + offset; // 累计偏移量
int end = matcher.end();
// 替换原来的 img 标签
updatedHtml.replace(start, end, base64ImgTag);
//System.out.println(updatedHtml.toString());
// 更新偏移量
offset += base64ImgTag.length() - (end - start);
} catch (Exception e) {
e.printStackTrace();
return null; // 处理异常或返回特定的错误值
}
}
return updatedHtml.toString();
}
public String convertImageToBase64(String imgUrl) {
try {
// String encodedImgUrl = URLEncoder.encode(imgUrl, StandardCharsets.UTF_8.toString());
URL url = new URL(imgUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("User-Agent", "Mozilla/5.0"); // 添加 User-Agent
connection.setDoInput(true);
connection.connect();
InputStream inputStream = connection.getInputStream();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
byte[] imageBytes = outputStream.toByteArray();
String base64 = Base64.getEncoder().encodeToString(imageBytes);
return "data:image/jpeg;base64," + base64; // 根据实际情况修改 MIME 类型
} catch (Exception e) {
e.printStackTrace();
return null; // 处理异常或返回特定的错误值
}
}
}

@ -0,0 +1,55 @@
package com.ruoyi.gysl.utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Base64;
import java.util.List;
public class ImgBase64Extractor {
public static void main(String[] args) throws IOException {
String imgUrl ="http://39.101.188.84:7071/profile/upload/2025/03/24/abc_20250324154129A006.jpg";
URL url = new URL(imgUrl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setDoInput(true);
// 添加请求头
connection.setRequestProperty("User-Agent", "Mozilla/5.0");
connection.setRequestProperty("Accept", "image/webp,image/apng,image/*,*/*;q=0.8");
connection.setRequestProperty("Accept-Language", "en-US,en;q=0.5");
// 连接并获取响应
connection.connect();
// 检查响应码
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
// 连接成功,获取输入流
InputStream inputStream = connection.getInputStream();
// 读取输入流
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
inputStream.close();
byte[] imageBytes = outputStream.toByteArray();
System.out.println(imageBytes);
} else {
System.out.println("Error: Server returned HTTP response code: " + responseCode);
}
}
}

@ -0,0 +1,168 @@
package com.ruoyi.gysl.utils;
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.Paragraph;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Date;
public class PdfUtils {
// 定义全局的字体静态变量
private static Font titlefont;
private static Font headfont;
private static Font keyfont;
private static Font textfont;
// 最大宽度
private static int maxWidth = 520;
// 静态代码块
static {
try {
// 不同字体这里定义为同一种字体包含不同字号、不同style
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
titlefont = new Font(bfChinese, 16, Font.BOLD);
headfont = new Font(bfChinese, 14, Font.BOLD);
keyfont = new Font(bfChinese, 10, Font.BOLD);
textfont = new Font(bfChinese, 10, Font.NORMAL);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* htmlpdf
*
* @param htmlContent
* @throws Exception
*/
public MultipartFile html2Pdf(String htmlArticleTitle, String htmlContent) throws Exception {
htmlContent = this.content2Html(htmlContent);
String path = System.getProperty("user.dir");
//根据日期建文件夹
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
String format = formatter.format(date);
String[] split = format.split("-");
File dir = new File(path + "/temporary");
if (!dir.exists()) {
dir.mkdir();
}
File dir2 = new File(path + "/temporary" + "/" + split[0]);
if (!dir2.exists()) {
dir2.mkdir();
}
File dir3 = new File(path + "/temporary" + "/" + split[0] + "/" + split[1]);
if (!dir3.exists()) {
dir3.mkdir();
}
File dir4 = new File(path + "/temporary" + "/" + split[0] + "/" + split[1] + "/" + split[2]);
if (!dir4.exists()) {
dir4.mkdir();
}
File pdfFile = new File(dir4 + "/pdf" + "-" + System.currentTimeMillis() + ".pdf");
//1 打开文件流
Document document = new Document();
FileOutputStream fos = new FileOutputStream(pdfFile);
System.out.println(pdfFile);
InputStream is = new ByteArrayInputStream(htmlContent.getBytes(StandardCharsets.UTF_8));
//InputStream cssIs = new ByteArrayInputStream(getCssFile());
PdfWriter writer = null;
try {
writer = PdfWriter.getInstance(document, fos);
//3. 设置字体
XMLWorkerFontProvider fontProvider1 = new XMLWorkerFontProvider(XMLWorkerFontProvider.DONTLOOKFORFONTS);
//fontProvider1.register(path+"\\simsun.ttc");//本地
fontProvider1.register(path + "/simsun.ttc");//部署服务器
//3 打开文档
document.open();
// 段落
Paragraph paragraph = new Paragraph(htmlArticleTitle, titlefont);
paragraph.setAlignment(1); //设置文字居中 0靠左 1居中 2靠右
paragraph.setIndentationLeft(12); //设置左缩进
paragraph.setIndentationRight(12); //设置右缩进
paragraph.setFirstLineIndent(24); //设置首行缩进
paragraph.setLeading(20f); //行间距
paragraph.setSpacingBefore(5f); //设置段落上空白
paragraph.setSpacingAfter(10f); //设置段落下空白
document.add(paragraph);
//4 html转为pdf
//XMLWorkerHelper.getInstance().parseXHtml(writer, document, is, cssIs, Charset.forName("UTF-8"), fontProvider1);
XMLWorkerHelper.getInstance().parseXHtml(writer, document, is, StandardCharsets.UTF_8, fontProvider1);
} catch (DocumentException | IOException e) {
throw new RuntimeException("转pdf失败罗~");
} finally {
if (null != writer) {
writer.flush();
}
//5 关闭文档
document.close();
fos.close();
//cssIs.close();
is.close();
writer.close();
MultipartFile multipartFile = getMulipartFiles2(pdfFile + "");
System.out.println("pdfFile = " + pdfFile);
return multipartFile;
}
}
public MultipartFile getMulipartFiles2(String filePath) throws IOException {
File file = new File(filePath);
FileInputStream fileInputStream = new FileInputStream(file);
MultipartFile multipartFile = new MockMultipartFile(file.getName(), file.getName(),
"application/sql", fileInputStream);
long size = multipartFile.getSize();
return multipartFile;
}
/**
* html
*
* @return
*/
public String content2Html(String htmlContent) {
String COMPLETE_CONTENT = "<html><head></head><body style=\"font-family: SimSun;\">" + htmlContent + "</body></html>";
String content = COMPLETE_CONTENT;
content = content.replace("<br>", "<br/>");
return content;
}
/**
*
*
* @return
* @throws Exception
*/
protected byte[] getCssFile() throws Exception {
FileInputStream fileInputStream = new FileInputStream("D:\\editor.css");
ByteArrayOutputStream outStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1204];
int len = 0;
while ((len = fileInputStream.read(buffer)) != -1) {
outStream.write(buffer, 0, len);
}
fileInputStream.close();
return outStream.toByteArray();
}
}
Loading…
Cancel
Save