问题出现原因
本人业务需求需要使用jeecgBoot的前端富文本组件<kindeditor>
<a-collapse-panel id="one3" key="one3" header="主要研究内容">
<kindeditor
id="kindex2"
height="550px"
@kindeditorChange="(val) => form.jobContent = val "
:content="form.jobContent"
/>
</a-collapse-panel>
在项目上线后出现了几个问题:
-
当存放的内容过多后报错提示插入过长的数据,经过定位处理为jeecgBoot代码生成器生成的数据库表中MySQL存放富文本的字符串是
text
,只需要修改为longtext
即可,text字段类型的字节限制为65535字节,longtext字段类型的字节限制为2147483647字节 -
虽然完美解决了因为数据量大而插入数据失败的问题,但是又出现了一个新的问题,由于数据量巨大,在前端打开富文本组件时渲染加载的时间特别长,可能有
10秒
左右,这在系统的使用是完全不能接受的。于是经过我的分析,我发现jeecgBoot的富文本组件在保存图片时是保存的图片对应的Base64编码
这样来方便图片渲染。如果图片少可能不会有什么影响,但是不巧的是我的项目使用场景中需要考虑大量的图片问题,所以就很慢。
解决办法:我想到将图片保存我们公司的minIO服务器,再将富文本字符串中图片的Base64编码
保存形式替换成<img src="/jeecg-boot/**/**/**/*****.jpg" alt="" />
这样就大大减少了数据量,虽然想到解决办法但是实现起来有几个麻烦的地方. -
从富文本字符串中定位到
<img>
标签抓取Base64编码
-
转换为对应的图片
文件流
,调用minIO保存接口
-
拿到返回的
图片url地址
,替换富文本字符串的<img>
标签
废话不多说直接上代码
private Pattern pattern = Pattern.compile("<img\\s+[^>]*?src=\"data:image/[a-zA-Z]*;base64,([^\"\\s]+)\"");
public String replaceImgBase64ToUrl(String richText){
if(StringUtils.isEmpty(richText)){
return richText;
}
// 匹配 img 标签中的 base64 数据
//Pattern pattern = Pattern.compile("<img\\s+src=\"data:image/[a-zA-Z]*;base64,([^\"]+)\"");
//Pattern pattern = Pattern.compile("<img\\s+[^>]*src=\"data:image/[a-zA-Z]*;base64,([^\"]+)\"");
Matcher matcher = pattern.matcher(richText);
while (matcher.find()) {
String base64Data = matcher.group(1);
byte[] imageBytes = Base64.decodeBase64(base64Data);
MinioClient minioClient = MinioClient.builder().endpoint(minioUrl).credentials(minioName, minioPass).build();
// 上传图片到 MinIO
String objectName = "zt"+ System.currentTimeMillis() + RandomUtil.randomString(10) + ".jpg";
try (InputStream inputStream = new ByteArrayInputStream(imageBytes)) {
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object("img/"+objectName)
.stream(inputStream, inputStream.available(), -1)
.build());
} catch (Exception e) {
throw new TipInfoException("富文本上传图片到minIO出现异常!!");
}
// 替换富文本字符串中的 img 标签
String imageUrl = "/jeecg-boot/***/***/***/"+ objectName;
richText = richText.replace("data:image/png;base64," + base64Data, imageUrl);
}
return richText;
}
完美。。但是这样做又又有一个衍生问题,我们需要写的导出word文件
导出时富文本字符串不能将<img src="/jeecg-boot/**/**/**/*****.jpg" alt="" />
转换成对应的图片,所以我们又需要逆向思考
- 先根据富文本中
<img>
标签中的url地址去minIO服务器
获取图片文件流
- 将
文件流
转换会对应的Base64编码
- 替换富文本字符串中的
<img>
标签,换成Base64编码
的标签 - 然后再执行我得word导出
同样废话不多说直接上代码
private Pattern pattern = Pattern.compile("<img\\s+[^>]*?src=\"(/jeecg-boot/**/**/**/[^/\">]+)\"[^>]*>");
public String replaceUrlToImgBase64(String richText) {
if (StringUtils.isEmpty(richText)) {
return richText;
}
// 匹配 img 标签中的图片 URL
Matcher matcher = pattern.matcher(richText);
while (matcher.find()) {
String imgTag = matcher.group(0); // 获取匹配到的整个 img 标签
String imageUrl = matcher.group(1); // 获取匹配到的图片 URL
int lastIndex = imageUrl.lastIndexOf('/');
String imageName = imageUrl.substring(lastIndex + 1);
try {
MinioClient minioClient = MinioClient.builder().endpoint(minioUrl).credentials(minioName, minioPass).build();
// 下载文件
InputStream inputStream = minioClient.getObject(
GetObjectArgs.builder().bucket(bucketName).object("img/" + imageName).build()
);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
String base64Data = Base64.encodeBase64String(outputStream.toByteArray());
// 替换富文本字符串中的图片 URL
richText = richText.replace(imageUrl, "data:image/png;base64," + base64Data);
} catch (Exception e) {
throw new TipInfoException("word导出图片转换错误!" + e.toString());
// 处理异常情况
}
}
return richText;
}
又一次完美解决问题,写完收工!!^ _ ^