mirror of
https://gitee.com/zhijiantianya/ruoyi-vue-pro.git
synced 2026-03-22 05:07:17 +08:00
feat(mail): 增强邮件模板参数解析和HTML内容格式化功能
- 修改邮件模板创建和更新逻辑,同时解析标题和内容中的参数 - 增强邮件内容格式化方法,支持HTML特殊字符反转义 - 实现代码块格式化,为<pre><code>标签添加样式 - 替换最外层pre标签为div标签以改善显示效果 - 添加完整的HTML邮件模板处理测试用例 - 扩展参数解析方法以合并标题和内容中的参数并去重
This commit is contained in:
@@ -19,8 +19,10 @@ import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
@@ -53,7 +55,7 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
// 插入
|
||||
MailTemplateDO template = BeanUtils.toBean(createReqVO, MailTemplateDO.class)
|
||||
.setParams(parseTemplateContentParams(createReqVO.getContent()));
|
||||
.setParams(parseTemplateTitleAndContentParams(createReqVO.getTitle(), createReqVO.getContent()));
|
||||
mailTemplateMapper.insert(template);
|
||||
return template.getId();
|
||||
}
|
||||
@@ -69,7 +71,7 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
// 更新
|
||||
MailTemplateDO updateObj = BeanUtils.toBean(updateReqVO, MailTemplateDO.class)
|
||||
.setParams(parseTemplateContentParams(updateReqVO.getContent()));
|
||||
.setParams(parseTemplateTitleAndContentParams(updateReqVO.getTitle(), updateReqVO.getContent()));
|
||||
mailTemplateMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@@ -129,13 +131,108 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
@Override
|
||||
public String formatMailTemplateContent(String content, Map<String, Object> params) {
|
||||
return StrUtil.format(content, params);
|
||||
// 先替换模板变量
|
||||
String formattedContent = StrUtil.format(content, params);
|
||||
|
||||
// 反转义HTML特殊字符
|
||||
formattedContent = unescapeHtml(formattedContent);
|
||||
|
||||
// 处理代码块(确保<pre><code>标签格式正确)
|
||||
formattedContent = formatHtmlCodeBlocks(formattedContent);
|
||||
|
||||
// 将最外层的pre标签替换为div标签
|
||||
formattedContent = replaceOuterPreWithDiv(formattedContent);
|
||||
|
||||
return formattedContent;
|
||||
}
|
||||
|
||||
private String replaceOuterPreWithDiv(String content) {
|
||||
if (content == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 使用正则表达式匹配所有的<pre>标签,包括嵌套的<code>标签
|
||||
String regex = "(?s)<pre[^>]*>(.*?)</pre>";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(content);
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
// 提取<pre>标签内的内容
|
||||
String innerContent = matcher.group(1);
|
||||
// 返回div标签包裹的内容
|
||||
matcher.appendReplacement(sb, "<div>" + innerContent + "</div>");
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 反转义HTML特殊字符
|
||||
*
|
||||
* @param input 输入字符串
|
||||
* @return 反转义后的字符串
|
||||
*/
|
||||
private String unescapeHtml(String input) {
|
||||
if (input == null) {
|
||||
return null;
|
||||
}
|
||||
return input
|
||||
.replace("&", "&")
|
||||
.replace("<", "<")
|
||||
.replace(">", ">")
|
||||
.replace(""", "\"")
|
||||
.replace("'", "'")
|
||||
.replace(" ", " ");
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化HTML中的代码块
|
||||
*
|
||||
* @param content 邮件内容
|
||||
* @return 格式化后的邮件内容
|
||||
*/
|
||||
private String formatHtmlCodeBlocks(String content) {
|
||||
// 匹配<pre><code>标签的代码块
|
||||
Pattern codeBlockPattern = Pattern.compile("<pre\\s*.*?><code\\s*.*?>(.*?)</code></pre>", Pattern.DOTALL);
|
||||
Matcher matcher = codeBlockPattern.matcher(content);
|
||||
|
||||
StringBuffer sb = new StringBuffer();
|
||||
while (matcher.find()) {
|
||||
// 获取代码块内容
|
||||
String codeBlock = matcher.group(1);
|
||||
|
||||
// 为代码块添加样式
|
||||
String replacement = "<pre style=\"background-color: #f5f5f5; padding: 10px; border-radius: 5px; overflow-x: auto;\"><code>" + codeBlock + "</code></pre>";
|
||||
matcher.appendReplacement(sb, replacement);
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMailTemplateCountByAccountId(Long accountId) {
|
||||
return mailTemplateMapper.selectCountByAccountId(accountId);
|
||||
}
|
||||
/**
|
||||
* 解析标题和内容中的参数
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public List<String> parseTemplateTitleAndContentParams(String title, String content) {
|
||||
List<String> titleParams = ReUtil.findAllGroup1(PATTERN_PARAMS, title);
|
||||
List<String> contentParams = ReUtil.findAllGroup1(PATTERN_PARAMS, content);
|
||||
|
||||
// 合并参数并去重
|
||||
List<String> allParams = new ArrayList<>(titleParams);
|
||||
for (String param : contentParams) {
|
||||
if (!allParams.contains(param)) {
|
||||
allParams.add(param);
|
||||
}
|
||||
}
|
||||
return allParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得邮件模板中的参数,形如 {key}
|
||||
@@ -143,8 +240,8 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
* @param content 内容
|
||||
* @return 参数列表
|
||||
*/
|
||||
private List<String> parseTemplateContentParams(String content) {
|
||||
List<String> parseTemplateContentParams(String content) {
|
||||
return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user