mirror of
https://gitee.com/yudaocode/yudao-boot-mini.git
synced 2026-03-22 05:27:15 +08:00
Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # yudao-module-system/src/main/java/cn/iocoder/yudao/module/system/service/mail/MailTemplateServiceImpl.java
This commit is contained in:
@@ -85,7 +85,7 @@ public class SocialClientApiImpl implements SocialClientApi {
|
||||
// 2. 获得社交用户
|
||||
SocialUserRespDTO socialUser = socialUserService.getSocialUserByUserId(reqDTO.getUserType(), reqDTO.getUserId(),
|
||||
SocialTypeEnum.WECHAT_MINI_PROGRAM.getType());
|
||||
if (StrUtil.isBlankIfStr(socialUser.getOpenid())) {
|
||||
if (ObjUtil.isNull(socialUser) || StrUtil.isBlankIfStr(socialUser.getOpenid())) {
|
||||
log.warn("[sendWxaSubscribeMessage][reqDTO({}) 发送订阅消息失败,原因:会员 openid 缺失]", reqDTO);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,14 @@ public class LoginLogController {
|
||||
@Resource
|
||||
private LoginLogService loginLogService;
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得登录日志")
|
||||
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
|
||||
public CommonResult<LoginLogRespVO> getLoginLog(Long id) {
|
||||
LoginLogDO loginLog = loginLogService.getLoginLog(id);
|
||||
return success(BeanUtils.toBean(loginLog, LoginLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得登录日志分页列表")
|
||||
@PreAuthorize("@ss.hasPermission('system:login-log:query')")
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
package cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog;
|
||||
|
||||
import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import cn.idev.excel.annotation.ExcelIgnoreUnannotated;
|
||||
import cn.idev.excel.annotation.ExcelProperty;
|
||||
import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
|
||||
import com.fhs.core.trans.anno.Trans;
|
||||
import com.fhs.core.trans.constant.TransType;
|
||||
import com.fhs.core.trans.vo.VO;
|
||||
@@ -31,6 +33,11 @@ public class OperateLogRespVO implements VO {
|
||||
@ExcelProperty("操作人")
|
||||
private String userName;
|
||||
|
||||
@Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1", implementation = Integer.class)
|
||||
@ExcelProperty("用户类型")
|
||||
@DictFormat(DictTypeConstants.USER_TYPE)
|
||||
private Integer userType;
|
||||
|
||||
@Schema(description = "操作模块类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "订单")
|
||||
@ExcelProperty("操作模块类型")
|
||||
private String type;
|
||||
|
||||
@@ -11,10 +11,12 @@ import cn.iocoder.yudao.module.system.controller.admin.sms.vo.log.SmsLogRespVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.sms.SmsLogDO;
|
||||
import cn.iocoder.yudao.module.system.service.sms.SmsLogService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@@ -44,6 +46,15 @@ public class SmsLogController {
|
||||
return success(BeanUtils.toBean(pageResult, SmsLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得短信日志")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('system:sms-log:query')")
|
||||
public CommonResult<SmsLogRespVO> getSmsLog(@RequestParam("id") Long id) {
|
||||
SmsLogDO smsLog = smsLogService.getSmsLog(id);
|
||||
return success(BeanUtils.toBean(smsLog, SmsLogRespVO.class));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出短信日志 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('system:sms-log:export')")
|
||||
|
||||
@@ -12,6 +12,14 @@ import javax.validation.Valid;
|
||||
*/
|
||||
public interface LoginLogService {
|
||||
|
||||
/**
|
||||
* 获得登录日志
|
||||
*
|
||||
* @param id 编号
|
||||
* @return 登录日志
|
||||
*/
|
||||
LoginLogDO getLoginLog(Long id);
|
||||
|
||||
/**
|
||||
* 获得登录日志分页
|
||||
*
|
||||
|
||||
@@ -21,6 +21,11 @@ public class LoginLogServiceImpl implements LoginLogService {
|
||||
@Resource
|
||||
private LoginLogMapper loginLogMapper;
|
||||
|
||||
@Override
|
||||
public LoginLogDO getLoginLog(Long id) {
|
||||
return loginLogMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<LoginLogDO> getLoginLogPage(LoginLogPageReqVO pageReqVO) {
|
||||
return loginLogMapper.selectPage(pageReqVO);
|
||||
|
||||
@@ -11,16 +11,18 @@ import cn.iocoder.yudao.module.system.dal.dataobject.mail.MailTemplateDO;
|
||||
import cn.iocoder.yudao.module.system.dal.mysql.mail.MailTemplateMapper;
|
||||
import cn.iocoder.yudao.module.system.dal.redis.RedisKeyConstants;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
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,7 +131,77 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
|
||||
@Override
|
||||
public String formatMailTemplateContent(String content, Map<String, Object> params) {
|
||||
return StrUtil.format(content, params);
|
||||
// 1. 先替换模板变量
|
||||
String formattedContent = StrUtil.format(content, params);
|
||||
|
||||
// 关联 Pull Request:https://gitee.com/zhijiantianya/ruoyi-vue-pro/pulls/1461 讨论
|
||||
// 2.1 反转义HTML特殊字符
|
||||
formattedContent = unescapeHtml(formattedContent);
|
||||
// 2.2 处理代码块(确保<pre><code>标签格式正确)
|
||||
formattedContent = formatHtmlCodeBlocks(formattedContent);
|
||||
// 2.3 将最外层的 pre 标签替换为 div 标签
|
||||
formattedContent = replaceOuterPreWithDiv(formattedContent);
|
||||
return formattedContent;
|
||||
}
|
||||
|
||||
private String replaceOuterPreWithDiv(String content) {
|
||||
if (StrUtil.isEmpty(content)) {
|
||||
return content;
|
||||
}
|
||||
// 使用正则表达式匹配所有的 <pre> 标签,包括嵌套的 <code> 标签
|
||||
String regex = "(?s)<pre[^>]*>(.*?)</pre>";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
Matcher matcher = pattern.matcher(content);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
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 (StrUtil.isEmpty(input)) {
|
||||
return input;
|
||||
}
|
||||
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);
|
||||
StringBuilder sb = new StringBuilder();
|
||||
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
|
||||
@@ -137,14 +209,31 @@ public class MailTemplateServiceImpl implements MailTemplateService {
|
||||
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}
|
||||
*
|
||||
* @param content 内容
|
||||
* @return 参数列表
|
||||
*/
|
||||
private List<String> parseTemplateContentParams(String content) {
|
||||
List<String> parseTemplateContentParams(String content) {
|
||||
return ReUtil.findAllGroup1(PATTERN_PARAMS, content);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -255,6 +255,9 @@ public class MenuServiceImpl implements MenuService {
|
||||
return;
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的菜单
|
||||
if (id == null) {
|
||||
throw exception(MENU_NAME_DUPLICATE);
|
||||
}
|
||||
if (!menu.getId().equals(id)) {
|
||||
throw exception(MENU_NAME_DUPLICATE);
|
||||
}
|
||||
@@ -277,7 +280,7 @@ public class MenuServiceImpl implements MenuService {
|
||||
}
|
||||
// 如果 id 为空,说明不用比较是否为相同 id 的菜单
|
||||
if (id == null) {
|
||||
return;
|
||||
throw exception(MENU_COMPONENT_NAME_DUPLICATE);
|
||||
}
|
||||
if (!menu.getId().equals(id)) {
|
||||
throw exception(MENU_COMPONENT_NAME_DUPLICATE);
|
||||
|
||||
@@ -58,6 +58,14 @@ public interface SmsLogService {
|
||||
void updateSmsReceiveResult(Long id, String apiSerialNo, Boolean success,
|
||||
LocalDateTime receiveTime, String apiReceiveCode, String apiReceiveMsg);
|
||||
|
||||
/**
|
||||
* 获得短信日志
|
||||
*
|
||||
* @param id 日志编号
|
||||
* @return 短信日志
|
||||
*/
|
||||
SmsLogDO getSmsLog(Long id);
|
||||
|
||||
/**
|
||||
* 获得短信日志分页
|
||||
*
|
||||
|
||||
@@ -78,6 +78,11 @@ public class SmsLogServiceImpl implements SmsLogService {
|
||||
.receiveTime(receiveTime).apiReceiveCode(apiReceiveCode).apiReceiveMsg(apiReceiveMsg).build());
|
||||
}
|
||||
|
||||
@Override
|
||||
public SmsLogDO getSmsLog(Long id) {
|
||||
return smsLogMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<SmsLogDO> getSmsLogPage(SmsLogPageReqVO pageReqVO) {
|
||||
return smsLogMapper.selectPage(pageReqVO);
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user