富文本编辑器的上传的图片默认转为base64,但是如果需要保存到数据库,base64的数据就太大了,所以一般都会长传到文件服务器,然会返回图片url。
但是当我们需要把富文本编辑器的内容导出为html时,因为图片时url,当浏览器离线浏览时就无法显示了,所以,在导出时,如果是图片,就把图片转为base64,这样即使在离线的情况下也能显示图片了。
package com.chen.utils;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;import com.jfinal.kit.PathKit;import cn.hutool.core.util.IdUtil;/**
* @author 作者 @Chenxc:
*
*/
public class Export2HtmlUtil {private static final String localPath = PathKit.getWebRootPath()+File.separator+"genhtml";private static final String uploadPath = PathKit.getWebRootPath()+File.separator+"upload";/****把html字符串转成文件*/public static File HtmlToFile(String html) {if(null == html) {return null;}String uuid = IdUtil.simpleUUID();String htmlFilePath = localPath+File.separator+uuid+".html";String convertedHtml;try {convertedHtml = convertHtmlImagesToBase64(html);Path path = Paths.get(htmlFilePath);Files.write(path, convertedHtml.getBytes("utf-8"));return path.toFile();} catch (IOException e) {System.err.println("Failed to HtmlToFile: ");e.printStackTrace();return null;}}private static String convertHtmlImagesToBase64(String html) throws IOException {Document doc = Jsoup.parse(html);Elements imgs = doc.select("img");for (Element img : imgs) {String imageUrl = img.attr("src");if (isRemoteUrl(imageUrl)) {try {String base64Data = fetchImageAsBase64(imageUrl);img.attr("src", base64Data);} catch (IOException e) {System.err.println("Failed to process image: " + imageUrl);e.printStackTrace();}}else if(isLocalUrl(imageUrl)){try {String substring = imageUrl.substring(imageUrl.lastIndexOf("/")+1);String path = uploadPath+File.separator+substring;String base64Data = convertLocalImgToBase64WithPrefix(path);img.attr("src", base64Data);} catch (Exception e) {System.err.println("Failed to process image: " + imageUrl);e.printStackTrace();}}}return doc.outerHtml();}private static String convertLocalImgToBase64WithPrefix(String filePath) throws Exception {byte[] imageBytes = readFileBytes(filePath);String mimeType = Files.probeContentType(Paths.get(filePath));return "data:" + mimeType + ";base64," +Base64.getEncoder().encodeToString(imageBytes);}private static String fetchImageAsBase64(String imageUrl) throws IOException {URL url = new URL(imageUrl);HttpURLConnection connection = (HttpURLConnection) url.openConnection();connection.setConnectTimeout(5000);connection.setReadTimeout(5000);try (InputStream inputStream = connection.getInputStream();ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {if (connection.getResponseCode() != 200) {throw new IOException("HTTP error: " + connection.getResponseCode());}String contentType = connection.getContentType();if (contentType == null || !contentType.startsWith("image/")) {contentType = getContentTypeFromExtension(imageUrl);}byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = inputStream.read(buffer)) != -1) {outputStream.write(buffer, 0, bytesRead);}byte[] imageBytes = outputStream.toByteArray();String base64 = Base64.getEncoder().encodeToString(imageBytes);return "data:" + contentType + ";base64," + base64;} finally {connection.disconnect();}}private static String getContentTypeFromExtension(String imageUrl) {if (imageUrl.toLowerCase().endsWith(".png")) return "image/png";if (imageUrl.toLowerCase().endsWith(".jpg") || imageUrl.toLowerCase().endsWith(".jpeg")) return "image/jpeg";if (imageUrl.toLowerCase().endsWith(".gif")) return "image/gif";if (imageUrl.toLowerCase().endsWith(".webp")) return "image/webp";return "application/octet-stream";}private static byte[] readFileBytes(String filePath) throws Exception {Path path = Paths.get(filePath);return Files.readAllBytes(path);}private static boolean isRemoteUrl(String url) {return url.startsWith("http://") || url.startsWith("https://");}private static boolean isLocalUrl(String url) {return url.startsWith("/upload") || url.startsWith("upload");}
}