富文本编辑器的上传的图片默认转为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");
}
}