完成基础邮件发送功能
parent
f9f895c518
commit
1e35045f67
22
pom.xml
22
pom.xml
|
|
@ -39,6 +39,9 @@
|
|||
<lombok.version>1.18.30</lombok.version>
|
||||
<mybatis.gen.version>1.4.2</mybatis.gen.version>
|
||||
<mybatis.dynamic.version>1.5.0</mybatis.dynamic.version>
|
||||
<jakarta.mail.version>2.1.2</jakarta.mail.version>
|
||||
<angus.mail.version>2.0.2</angus.mail.version>
|
||||
<angus.activation.version>2.0.1</angus.activation.version>
|
||||
</properties>
|
||||
|
||||
<!-- 依赖声明 -->
|
||||
|
|
@ -166,6 +169,25 @@
|
|||
<version>${mybatis.gen.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Java邮件标准接口 -->
|
||||
<dependency>
|
||||
<groupId>jakarta.mail</groupId>
|
||||
<artifactId>jakarta.mail-api</artifactId>
|
||||
<version>${jakarta.mail.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Java邮件实现者 -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>jakarta.mail</artifactId>
|
||||
<version>${angus.mail.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-activation</artifactId>
|
||||
<version>${angus.activation.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 核心模块 -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
|
|
|
|||
|
|
@ -124,6 +124,12 @@
|
|||
<version>${mybatis.dynamic.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Java邮件标准接口 -->
|
||||
<dependency>
|
||||
<groupId>jakarta.mail</groupId>
|
||||
<artifactId>jakarta.mail-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,124 @@
|
|||
package com.ruoyi.common.core.mail;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 邮件发送参数
|
||||
*
|
||||
* @since 2022/8/17
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class MailMessage {
|
||||
|
||||
/**
|
||||
* 邮件头信息(标题、收件人、抄送等)
|
||||
*/
|
||||
private MailMessageHead headInfo = new MailMessageHead();
|
||||
|
||||
/**
|
||||
* 正文
|
||||
*/
|
||||
private String content;
|
||||
|
||||
/**
|
||||
* 正文里的多媒体文件
|
||||
*/
|
||||
private Map<String, File> inLineMap;
|
||||
|
||||
/**
|
||||
* 正文是否为html。true代表是
|
||||
*/
|
||||
private boolean isHtml = false;
|
||||
|
||||
/**
|
||||
* 附件
|
||||
*/
|
||||
private final Map<String, File> attachments = new LinkedHashMap<>();
|
||||
|
||||
public void clearHeadInfo() {
|
||||
headInfo.setFrom(null);
|
||||
headInfo.setTo(null);
|
||||
headInfo.setCc(null);
|
||||
headInfo.setSubject(null);
|
||||
}
|
||||
|
||||
public MailMessage setFrom(String fromAddress) {
|
||||
headInfo.setFrom(fromAddress);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MailMessage setTo(String toAddress) {
|
||||
headInfo.setTo(toAddress);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MailMessage setCc(String cc) {
|
||||
headInfo.setCc(cc);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MailMessage setSubject(String subject) {
|
||||
headInfo.setSubject(subject);
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getFrom() {
|
||||
return headInfo.getFrom();
|
||||
}
|
||||
|
||||
public String getTo() {
|
||||
return headInfo.getTo();
|
||||
}
|
||||
|
||||
public String getCc() {
|
||||
return headInfo.getCc();
|
||||
}
|
||||
|
||||
public String getSubject() {
|
||||
return headInfo.getSubject();
|
||||
}
|
||||
|
||||
public MailMessage addAttachment(String fileKey, File attachment) {
|
||||
attachments.put(fileKey, attachment);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MailMessage addAttachment(File attachment) {
|
||||
attachments.put(attachment.getName(), attachment);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MailMessage addAttachments(List<File> attachments) {
|
||||
if (attachments != null) {
|
||||
for (File attachment : attachments) {
|
||||
this.attachments.put(attachment.getName(), attachment);
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public void clearAttachments() {
|
||||
attachments.clear();
|
||||
}
|
||||
|
||||
public File getAttachment(String fileKey) {
|
||||
return attachments.get(fileKey);
|
||||
}
|
||||
|
||||
public List<File> getAttachmentsList() {
|
||||
List<File> list = new ArrayList<>();
|
||||
for (Map.Entry<String, File> entry : attachments.entrySet()) {
|
||||
list.add(entry.getValue());
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.ruoyi.common.core.mail;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 邮件头信息
|
||||
*
|
||||
* @since 2022/8/17
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class MailMessageHead {
|
||||
|
||||
/**
|
||||
* 发件人
|
||||
*/
|
||||
private String from;
|
||||
|
||||
/**
|
||||
* 收件人
|
||||
*/
|
||||
private String to;
|
||||
|
||||
/**
|
||||
* 抄送
|
||||
*/
|
||||
private String cc;
|
||||
|
||||
/**
|
||||
* 邮件标题(Subject)
|
||||
*/
|
||||
private String subject;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.ruoyi.common.core.mail;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 邮箱账号信息(发邮件用)
|
||||
* @since 2021/6/25
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class MailSendAccount {
|
||||
|
||||
/**
|
||||
* SMTP服务器地址
|
||||
*/
|
||||
private String host;
|
||||
|
||||
/**
|
||||
* SMTP服务器端口号
|
||||
*/
|
||||
private Integer port;
|
||||
|
||||
/**
|
||||
* 用户名
|
||||
*/
|
||||
private String username;
|
||||
|
||||
/**
|
||||
* 密码/授权码
|
||||
*/
|
||||
private String password;
|
||||
|
||||
/**
|
||||
* 是否用SSL加密
|
||||
*/
|
||||
private boolean sslFlag = false;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
package com.ruoyi.common.core.mail;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
/**
|
||||
* 邮件发送结果
|
||||
*
|
||||
* @since 2022/8/18
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
public class MailSendResult {
|
||||
|
||||
/**
|
||||
* 是否成功,true代表成功
|
||||
*/
|
||||
private boolean success;
|
||||
|
||||
/**
|
||||
* 错误信息
|
||||
*/
|
||||
private String errMsg;
|
||||
|
||||
/**
|
||||
* 如果有抛出异常,则此为抛出的异常对象
|
||||
*/
|
||||
private Throwable errObj;
|
||||
|
||||
public MailSendResult setFailure(Throwable errObj) {
|
||||
this.success = false;
|
||||
if (errObj != null) {
|
||||
this.errMsg = errObj.toString();
|
||||
this.errObj = errObj;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public static MailSendResult success() {
|
||||
return new MailSendResult().setSuccess(true);
|
||||
}
|
||||
|
||||
public static MailSendResult failure(String errMsg) {
|
||||
return new MailSendResult().setSuccess(false).setErrMsg(errMsg);
|
||||
}
|
||||
|
||||
public static MailSendResult failure(Throwable errObj) {
|
||||
return new MailSendResult().setFailure(errObj);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
package com.ruoyi.common.core.mail;
|
||||
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 邮件发送工具
|
||||
* date 2021/8/18
|
||||
*/
|
||||
public interface MailSender {
|
||||
|
||||
String ADDRESS_SPLIT = ";";
|
||||
|
||||
//======================================= ↓↓↓ 快速构建 ↓↓↓ =======================================
|
||||
|
||||
/**
|
||||
* 构建发送工具
|
||||
*
|
||||
* @param senderAccount 发送账号
|
||||
* @param enableDebug 是否开启debug信息输出
|
||||
*/
|
||||
static MailSender build(MailSendAccount senderAccount, int timeout, boolean enableDebug) {
|
||||
return new SpringMailSender(senderAccount, timeout, enableDebug);
|
||||
}
|
||||
|
||||
static MailSender build(MailSendAccount senderAccount, boolean enableDebug) {
|
||||
return new SpringMailSender(senderAccount, 20000, enableDebug);
|
||||
}
|
||||
|
||||
static MailSender build(MailSendAccount senderAccount) {
|
||||
return new SpringMailSender(senderAccount);
|
||||
}
|
||||
|
||||
//======================================= ↓↓↓ 主要API ↓↓↓ =======================================
|
||||
|
||||
/**
|
||||
* 发送MIME邮件
|
||||
*
|
||||
* @param form 发送参数
|
||||
* @return 发送结果
|
||||
*/
|
||||
MailSendResult sendMail(MailMessage form);
|
||||
|
||||
default MailSendResult sendMail(String from, String to, String cc, String subject, String text, List<File> attachments) {
|
||||
MailMessage message = new MailMessage()
|
||||
.setFrom(from)
|
||||
.setTo(to)
|
||||
.setCc(cc)
|
||||
.setSubject(subject)
|
||||
.setContent(text)
|
||||
.addAttachments(attachments);
|
||||
return sendMail(message);
|
||||
}
|
||||
|
||||
default MailSendResult sendMail(String to, String cc, String subject, String text, List<File> attachments) {
|
||||
return sendMail(null, to, cc, subject, text, attachments);
|
||||
}
|
||||
|
||||
default MailSendResult sendMail(String to, String subject, String text, List<File> attachments) {
|
||||
return sendMail(null, to, null, subject, text, attachments);
|
||||
}
|
||||
|
||||
default MailSendResult sendMail(String to, String cc, String subject, String text) {
|
||||
return sendMail(null, to, cc, subject, text, null);
|
||||
}
|
||||
|
||||
default MailSendResult sendMail(String to, String subject, String text) {
|
||||
return sendMail(null, to, null, subject, text, null);
|
||||
}
|
||||
|
||||
//======================================= ↓↓↓ 其他API ↓↓↓ =======================================
|
||||
|
||||
MailSendAccount getSenderAccount();
|
||||
|
||||
JavaMailSenderImpl getExecutor();
|
||||
|
||||
void resetSenderAccount(MailSendAccount senderAccount);
|
||||
|
||||
default void resetSenderAccount(String host, int port, String username, String password) {
|
||||
resetSenderAccount(new MailSendAccount(host, port, username, password, (password != null && !password.isEmpty())));
|
||||
}
|
||||
|
||||
boolean available();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,184 @@
|
|||
package com.ruoyi.common.core.mail;
|
||||
|
||||
import org.springframework.mail.javamail.JavaMailSenderImpl;
|
||||
import org.springframework.mail.javamail.MimeMessageHelper;
|
||||
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.internet.MimeMessage;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 邮件发送器
|
||||
*
|
||||
* @since 2021/8/18
|
||||
*/
|
||||
public class SpringMailSender implements MailSender {
|
||||
|
||||
//发送执行者
|
||||
private final JavaMailSenderImpl executor;
|
||||
|
||||
private MailSendAccount senderAccount;
|
||||
|
||||
public SpringMailSender(MailSendAccount senderAccount) {
|
||||
this(senderAccount, 20000, false);
|
||||
}
|
||||
|
||||
public SpringMailSender(MailSendAccount senderAccount, int timeout, boolean enableDebug) {
|
||||
this.senderAccount = senderAccount;
|
||||
//创建发送执行者
|
||||
executor = buildExecutor(senderAccount, timeout, enableDebug);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建发送执行者
|
||||
*
|
||||
* @param account 发送账号
|
||||
* @return 发送执行者
|
||||
*/
|
||||
private JavaMailSenderImpl buildExecutor(MailSendAccount account, int timeout, boolean enableDebug) {
|
||||
//邮箱设定
|
||||
JavaMailSenderImpl javaMailSender = new JavaMailSenderImpl();
|
||||
Properties mailProperties = new Properties();
|
||||
//邮件发送时输出debug信息
|
||||
mailProperties.setProperty("mail.debug", enableDebug ? "true" : "false");
|
||||
//发送服务器需要身份验证
|
||||
mailProperties.setProperty("mail.smtp.auth", "true");
|
||||
//发送邮件协议名称 这里使用的是smtp协议
|
||||
mailProperties.setProperty("mail.transport.protocol", "smtp");
|
||||
//默认开启starttls
|
||||
mailProperties.setProperty("mail.smtp.starttls.enable", "true");
|
||||
//超时设置
|
||||
mailProperties.setProperty("mail.smtp.connectiontimeout", timeout + "");//与邮件服务器建立连接的超时
|
||||
mailProperties.setProperty("mail.smtp.writetimeout", timeout + "");//邮件发送时间限制
|
||||
if (account.isSslFlag()) {
|
||||
//开启ssl
|
||||
System.out.println("****** enable ssl for mail send ******");
|
||||
mailProperties.setProperty("mail.smtp.socketFactory.class", "javax.net.ssl.SSLSocketFactory");
|
||||
mailProperties.setProperty("mail.smtp.socketFactory.port", account.getPort().toString());
|
||||
mailProperties.setProperty("mail.smtp.ssl.enable", "true");
|
||||
} else {
|
||||
System.out.println("****** disable ssl for mail send ******");
|
||||
javaMailSender.setPort(account.getPort());
|
||||
}
|
||||
javaMailSender.setJavaMailProperties(mailProperties);
|
||||
javaMailSender.setHost(account.getHost());
|
||||
javaMailSender.setUsername(account.getUsername());
|
||||
javaMailSender.setPassword(account.getPassword());
|
||||
javaMailSender.setDefaultEncoding("UTF-8");
|
||||
System.setProperty("mail.mime.splitlongparameters", "false"); //注意:不截断base64编码后的长附件名
|
||||
return javaMailSender;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 创建邮件信息
|
||||
*
|
||||
* @param executor 发送执行者
|
||||
* @param form 发送参数
|
||||
* @return 邮件信息
|
||||
* @throws MessagingException 邮件信息创建失败
|
||||
*/
|
||||
private MimeMessage createMimeMessage(JavaMailSenderImpl executor, MailMessage form) throws MessagingException {
|
||||
MailMessageHead headInfo = form.getHeadInfo();
|
||||
Map<String, File> inLineMap = form.getInLineMap();
|
||||
Map<String, File> attachments = form.getAttachments();
|
||||
|
||||
MimeMessage mimeMessage = executor.createMimeMessage();
|
||||
//创建发送MIME邮件的工具类
|
||||
MimeMessageHelper messageHelper = getMimeMessageHelper(form, mimeMessage, headInfo);
|
||||
//设置正文多媒体信息
|
||||
if (inLineMap != null) {
|
||||
for (Map.Entry<String, File> inLine : inLineMap.entrySet()) {
|
||||
messageHelper.addInline(inLine.getKey(), inLine.getValue());
|
||||
}
|
||||
}
|
||||
//添加附件
|
||||
if (attachments != null) {
|
||||
for (Map.Entry<String, File> entry : attachments.entrySet()) {
|
||||
String fileName = entry.getKey();
|
||||
File file = entry.getValue();
|
||||
messageHelper.addAttachment(fileName, file);
|
||||
}
|
||||
}
|
||||
return mimeMessage;
|
||||
}
|
||||
|
||||
private MimeMessageHelper getMimeMessageHelper(MailMessage form, MimeMessage mimeMessage, MailMessageHead headInfo) throws MessagingException {
|
||||
MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage, true, "UTF-8");
|
||||
//发件人
|
||||
if (form.getFrom() == null || form.getFrom().isEmpty()) {
|
||||
form.setFrom(senderAccount.getUsername());
|
||||
} else {
|
||||
form.setFrom(form.getFrom());
|
||||
}
|
||||
//收件人 这里的参数可以是多个收件人,用英文分号分割
|
||||
messageHelper.setTo(headInfo.getTo().split(ADDRESS_SPLIT));
|
||||
//抄送 这里的参数可以是多个抄送人,用英文分号分割
|
||||
if (headInfo.getCc() != null && !headInfo.getCc().isEmpty()) {
|
||||
messageHelper.setCc(headInfo.getCc().split(ADDRESS_SPLIT));
|
||||
}
|
||||
//邮件主题
|
||||
messageHelper.setSubject(headInfo.getSubject());
|
||||
//邮件正文
|
||||
if (form.getContent() != null && !form.getContent().isEmpty()) {
|
||||
messageHelper.setText(form.getContent(), form.isHtml());
|
||||
}
|
||||
return messageHelper;
|
||||
}
|
||||
|
||||
/**
|
||||
* 发送邮件
|
||||
*
|
||||
* @param form 发送参数
|
||||
* @return 发送结果
|
||||
*/
|
||||
@Override
|
||||
public MailSendResult sendMail(MailMessage form) {
|
||||
try {
|
||||
MimeMessage mimeMessage = createMimeMessage(executor, form);
|
||||
executor.send(mimeMessage);
|
||||
return MailSendResult.success();
|
||||
} catch (Exception e) {
|
||||
return MailSendResult.failure(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public MailSendAccount getSenderAccount() {
|
||||
return senderAccount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaMailSenderImpl getExecutor() {
|
||||
return executor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetSenderAccount(MailSendAccount senderAccount) {
|
||||
checkAccount(senderAccount);
|
||||
this.senderAccount = senderAccount;
|
||||
}
|
||||
|
||||
private void checkAccount(MailSendAccount account) {
|
||||
if (account == null) {
|
||||
throw new IllegalArgumentException("account is null");
|
||||
}
|
||||
if (account.getHost() == null || account.getHost().isEmpty()) {
|
||||
throw new IllegalArgumentException("host is blank");
|
||||
}
|
||||
if (account.getPort() == null) {
|
||||
throw new IllegalArgumentException("port is null");
|
||||
}
|
||||
if (account.getPort() <= 0 || account.getPort() > 65535) {
|
||||
throw new IllegalArgumentException("port is invalid (0-65535)");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean available() {
|
||||
return (senderAccount.getHost() != null && !senderAccount.getHost().isEmpty() ) && senderAccount.getPort() != null;
|
||||
}
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ public final class SpringUtils implements BeanFactoryPostProcessor {
|
|||
* 获取类型为requiredType的对象
|
||||
*/
|
||||
public static <T> T getBean(Class<T> clz) throws BeansException {
|
||||
T result = (T) beanFactory.getBean(clz);
|
||||
T result = beanFactory.getBean(clz);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
package com.ruoyi.common.security.utils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.utils.SpringUtils;
|
||||
|
|
@ -9,35 +7,47 @@ import com.ruoyi.common.core.utils.StringUtils;
|
|||
import com.ruoyi.common.redis.service.RedisService;
|
||||
import com.ruoyi.system.api.domain.SysDictData;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典工具类
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class DictUtils
|
||||
{
|
||||
public class DictUtils {
|
||||
|
||||
private DictUtils() {
|
||||
throw new IllegalStateException("Utility class cannot be instantiated");
|
||||
}
|
||||
|
||||
private static RedisService redisService;
|
||||
|
||||
/**
|
||||
* 设置字典缓存
|
||||
*
|
||||
* @param key 参数键
|
||||
* @param dictDatas 字典数据列表
|
||||
*
|
||||
* @param key 参数键
|
||||
* @param dictDataList 字典数据列表
|
||||
*/
|
||||
public static void setDictCache(String key, List<SysDictData> dictDatas)
|
||||
{
|
||||
SpringUtils.getBean(RedisService.class).setCacheObject(getCacheKey(key), dictDatas);
|
||||
public static void setDictCache(String key, List<SysDictData> dictDataList) {
|
||||
if (redisService == null) {
|
||||
redisService = SpringUtils.getBean(RedisService.class);
|
||||
}
|
||||
redisService.setCacheObject(getCacheKey(key), dictDataList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取字典缓存
|
||||
*
|
||||
*
|
||||
* @param key 参数键
|
||||
* @return dictDatas 字典数据列表
|
||||
* @return dictDataList 字典数据列表
|
||||
*/
|
||||
public static List<SysDictData> getDictCache(String key)
|
||||
{
|
||||
JSONArray arrayCache = SpringUtils.getBean(RedisService.class).getCacheObject(getCacheKey(key));
|
||||
if (StringUtils.isNotNull(arrayCache))
|
||||
{
|
||||
public static List<SysDictData> getDictCache(String key) {
|
||||
if (redisService == null) {
|
||||
redisService = SpringUtils.getBean(RedisService.class);
|
||||
}
|
||||
JSONArray arrayCache = redisService.getCacheObject(getCacheKey(key));
|
||||
if (StringUtils.isNotNull(arrayCache)) {
|
||||
return arrayCache.toList(SysDictData.class);
|
||||
}
|
||||
return null;
|
||||
|
|
@ -45,31 +55,34 @@ public class DictUtils
|
|||
|
||||
/**
|
||||
* 删除指定字典缓存
|
||||
*
|
||||
*
|
||||
* @param key 字典键
|
||||
*/
|
||||
public static void removeDictCache(String key)
|
||||
{
|
||||
SpringUtils.getBean(RedisService.class).deleteObject(getCacheKey(key));
|
||||
public static void removeDictCache(String key) {
|
||||
if (redisService == null) {
|
||||
redisService = SpringUtils.getBean(RedisService.class);
|
||||
}
|
||||
redisService.deleteObject(getCacheKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空字典缓存
|
||||
*/
|
||||
public static void clearDictCache()
|
||||
{
|
||||
Collection<String> keys = SpringUtils.getBean(RedisService.class).keys(CacheConstants.SYS_DICT_KEY + "*");
|
||||
SpringUtils.getBean(RedisService.class).deleteObject(keys);
|
||||
public static void clearDictCache() {
|
||||
if (redisService == null) {
|
||||
redisService = SpringUtils.getBean(RedisService.class);
|
||||
}
|
||||
Collection<String> keys = redisService.keys(CacheConstants.SYS_DICT_KEY + "*");
|
||||
redisService.deleteObject(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置cache key
|
||||
*
|
||||
*
|
||||
* @param configKey 参数键
|
||||
* @return 缓存键key
|
||||
*/
|
||||
public static String getCacheKey(String configKey)
|
||||
{
|
||||
public static String getCacheKey(String configKey) {
|
||||
return CacheConstants.SYS_DICT_KEY + configKey;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
package com.ruoyi.common.security.utils;
|
||||
|
||||
import com.ruoyi.common.core.constant.CacheConstants;
|
||||
import com.ruoyi.common.core.utils.SpringUtils;
|
||||
import com.ruoyi.common.redis.service.RedisService;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
/**
|
||||
* 系统参数工具类 (sys_config)
|
||||
*
|
||||
* @author Alan Scipio
|
||||
* created on 2024/3/1
|
||||
*/
|
||||
public class SysConfigUtils {
|
||||
|
||||
private SysConfigUtils() {
|
||||
throw new IllegalStateException("Utility class cannot be instantiated");
|
||||
}
|
||||
|
||||
private static RedisService redisService;
|
||||
|
||||
/**
|
||||
* 设置参数缓存
|
||||
*
|
||||
* @param configKey 参数键
|
||||
* @param configValue 参数值
|
||||
*/
|
||||
public static void setConfigCache(String configKey, String configValue) {
|
||||
if (redisService == null) {
|
||||
redisService = SpringUtils.getBean(RedisService.class);
|
||||
}
|
||||
redisService.setCacheObject(getCacheKey(configKey), configValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取参数缓存
|
||||
*
|
||||
* @param configKey 参数键
|
||||
* @return configValue 参数值
|
||||
*/
|
||||
public static String getConfigCache(String configKey) {
|
||||
if (redisService == null) {
|
||||
redisService = SpringUtils.getBean(RedisService.class);
|
||||
}
|
||||
return redisService.getCacheObject(getCacheKey(configKey));
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除指定参数缓存
|
||||
*
|
||||
* @param key 字典键
|
||||
*/
|
||||
public static void removeConfigCache(String key) {
|
||||
if (redisService == null) {
|
||||
redisService = SpringUtils.getBean(RedisService.class);
|
||||
}
|
||||
redisService.deleteObject(getCacheKey(key));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空所有参数缓存
|
||||
*/
|
||||
public static void clearConfigCaches() {
|
||||
if (redisService == null) {
|
||||
redisService = SpringUtils.getBean(RedisService.class);
|
||||
}
|
||||
Collection<String> keys = redisService.keys(CacheConstants.SYS_CONFIG_KEY + "*");
|
||||
redisService.deleteObject(keys);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置cache key
|
||||
*
|
||||
* @param configKey 参数键
|
||||
* @return 缓存键key
|
||||
*/
|
||||
public static String getCacheKey(String configKey) {
|
||||
return CacheConstants.SYS_CONFIG_KEY + configKey;
|
||||
}
|
||||
}
|
||||
|
|
@ -64,6 +64,16 @@
|
|||
<artifactId>mysql-connector-j</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Java邮件实现者 -->
|
||||
<dependency>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>jakarta.mail</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.angus</groupId>
|
||||
<artifactId>angus-activation</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RuoYi Common DataSource -->
|
||||
<dependency>
|
||||
<groupId>com.ruoyi</groupId>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,64 @@
|
|||
package com.ruoyi.system.config;
|
||||
|
||||
import com.ruoyi.common.core.mail.MailSendAccount;
|
||||
import com.ruoyi.common.core.mail.MailSender;
|
||||
import com.ruoyi.common.core.utils.StringUtils;
|
||||
import com.ruoyi.common.security.utils.SysConfigUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 邮件配置
|
||||
*
|
||||
* @author Alan Scipio
|
||||
* created on 2024/2/29
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class MailConfig {
|
||||
|
||||
@Value("${spring.mail.host:#{null}}")
|
||||
private String host;
|
||||
@Value("${spring.mail.port:#{null}}")
|
||||
private Integer port;
|
||||
@Value("${spring.mail.username:#{null}}")
|
||||
private String username;
|
||||
@Value("${spring.mail.password:#{null}}")
|
||||
private String password;
|
||||
|
||||
@Bean
|
||||
public MailSender mailSender() {
|
||||
MailSendAccount account = new MailSendAccount();
|
||||
|
||||
// 加载配置文件中的邮件配置
|
||||
account.setHost(host);
|
||||
account.setPort(port);
|
||||
account.setUsername(username);
|
||||
account.setPassword(password);
|
||||
|
||||
// 加载数据库中的邮件配置(会缓存到redis中,并覆盖前面的配置)
|
||||
String hostCache = SysConfigUtils.getConfigCache("sys.mail.smtpHost");
|
||||
String portCache = SysConfigUtils.getConfigCache("sys.mail.smtpPort");
|
||||
String usernameCache = SysConfigUtils.getConfigCache("sys.mail.username");
|
||||
String passwordCache = SysConfigUtils.getConfigCache("sys.mail.password");
|
||||
if (StringUtils.isNotBlank(hostCache) && StringUtils.isNotBlank(portCache)) {
|
||||
account.setHost(hostCache);
|
||||
account.setPort(Integer.parseInt(portCache));
|
||||
if (StringUtils.isNotBlank(usernameCache)) {
|
||||
account.setUsername(usernameCache);
|
||||
}
|
||||
if (StringUtils.isNotBlank(passwordCache)) {
|
||||
account.setPassword(passwordCache);
|
||||
}
|
||||
} else {
|
||||
log.warn("Mail configuration from database table 'sys_config' is empty. Use the configuration from application.yaml instead.");
|
||||
}
|
||||
|
||||
account.setSslFlag(account.getPassword() != null && !account.getPassword().isEmpty());
|
||||
log.info("Mail configuration has been initialized. smtpHost: [{}], smtpPort: [{}], username: [{}]", account.getHost(), account.getPort(), account.getUsername());
|
||||
return MailSender.build(account, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.ruoyi.system.mapper;
|
||||
|
||||
import com.ruoyi.system.domain.SysConfig;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
|
@ -34,6 +35,14 @@ public interface SysConfigMapper {
|
|||
*/
|
||||
List<SysConfig> selectConfigList(SysConfig config);
|
||||
|
||||
/**
|
||||
* 查询参数配置列表
|
||||
*
|
||||
* @param configKeyList 参数键名集合
|
||||
* @return 参数配置集合
|
||||
*/
|
||||
List<SysConfig> selectConfigListByKeys(@Param("configKeyList") List<String> configKeyList);
|
||||
|
||||
/**
|
||||
* 根据键名查询参数配置信息
|
||||
*
|
||||
|
|
|
|||
|
|
@ -34,6 +34,14 @@ public interface ISysConfigService {
|
|||
*/
|
||||
List<SysConfig> selectConfigList(SysConfig config);
|
||||
|
||||
/**
|
||||
* 根据键名查询参数配置信息
|
||||
*
|
||||
* @param configKeyList 参数键名集合
|
||||
* @return 参数配置集合
|
||||
*/
|
||||
List<SysConfig> selectConfigListByKeys(List<String> configKeyList);
|
||||
|
||||
/**
|
||||
* 新增参数配置
|
||||
*
|
||||
|
|
|
|||
|
|
@ -83,6 +83,11 @@ public class SysConfigServiceImpl implements ISysConfigService {
|
|||
return configMapper.selectConfigList(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SysConfig> selectConfigListByKeys(List<String> configKeyList) {
|
||||
return configMapper.selectConfigListByKeys(configKeyList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增参数配置
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1,110 +1,101 @@
|
|||
package com.ruoyi.system.service.impl;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.ruoyi.common.security.utils.DictUtils;
|
||||
import com.ruoyi.system.api.domain.SysDictData;
|
||||
import com.ruoyi.system.mapper.SysDictDataMapper;
|
||||
import com.ruoyi.system.service.ISysDictDataService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 字典 业务层处理
|
||||
*
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Service
|
||||
public class SysDictDataServiceImpl implements ISysDictDataService
|
||||
{
|
||||
@Autowired
|
||||
public class SysDictDataServiceImpl implements ISysDictDataService {
|
||||
@Resource
|
||||
private SysDictDataMapper dictDataMapper;
|
||||
|
||||
/**
|
||||
* 根据条件分页查询字典数据
|
||||
*
|
||||
*
|
||||
* @param dictData 字典数据信息
|
||||
* @return 字典数据集合信息
|
||||
*/
|
||||
@Override
|
||||
public List<SysDictData> selectDictDataList(SysDictData dictData)
|
||||
{
|
||||
public List<SysDictData> selectDictDataList(SysDictData dictData) {
|
||||
return dictDataMapper.selectDictDataList(dictData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典类型和字典键值查询字典数据信息
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
*
|
||||
* @param dictType 字典类型
|
||||
* @param dictValue 字典键值
|
||||
* @return 字典标签
|
||||
*/
|
||||
@Override
|
||||
public String selectDictLabel(String dictType, String dictValue)
|
||||
{
|
||||
public String selectDictLabel(String dictType, String dictValue) {
|
||||
return dictDataMapper.selectDictLabel(dictType, dictValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据字典数据ID查询信息
|
||||
*
|
||||
*
|
||||
* @param dictCode 字典数据ID
|
||||
* @return 字典数据
|
||||
*/
|
||||
@Override
|
||||
public SysDictData selectDictDataById(Long dictCode)
|
||||
{
|
||||
public SysDictData selectDictDataById(Long dictCode) {
|
||||
return dictDataMapper.selectDictDataById(dictCode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除字典数据信息
|
||||
*
|
||||
*
|
||||
* @param dictCodes 需要删除的字典数据ID
|
||||
*/
|
||||
@Override
|
||||
public void deleteDictDataByIds(Long[] dictCodes)
|
||||
{
|
||||
for (Long dictCode : dictCodes)
|
||||
{
|
||||
public void deleteDictDataByIds(Long[] dictCodes) {
|
||||
for (Long dictCode : dictCodes) {
|
||||
SysDictData data = selectDictDataById(dictCode);
|
||||
dictDataMapper.deleteDictDataById(dictCode);
|
||||
List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
|
||||
DictUtils.setDictCache(data.getDictType(), dictDatas);
|
||||
List<SysDictData> dictData = dictDataMapper.selectDictDataByType(data.getDictType());
|
||||
DictUtils.setDictCache(data.getDictType(), dictData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 新增保存字典数据信息
|
||||
*
|
||||
*
|
||||
* @param data 字典数据信息
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int insertDictData(SysDictData data)
|
||||
{
|
||||
public int insertDictData(SysDictData data) {
|
||||
int row = dictDataMapper.insertDictData(data);
|
||||
if (row > 0)
|
||||
{
|
||||
List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
|
||||
DictUtils.setDictCache(data.getDictType(), dictDatas);
|
||||
if (row > 0) {
|
||||
List<SysDictData> dictData = dictDataMapper.selectDictDataByType(data.getDictType());
|
||||
DictUtils.setDictCache(data.getDictType(), dictData);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改保存字典数据信息
|
||||
*
|
||||
*
|
||||
* @param data 字典数据信息
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
public int updateDictData(SysDictData data)
|
||||
{
|
||||
public int updateDictData(SysDictData data) {
|
||||
int row = dictDataMapper.updateDictData(data);
|
||||
if (row > 0)
|
||||
{
|
||||
List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
|
||||
DictUtils.setDictCache(data.getDictType(), dictDatas);
|
||||
if (row > 0) {
|
||||
List<SysDictData> dictData = dictDataMapper.selectDictDataByType(data.getDictType());
|
||||
DictUtils.setDictCache(data.getDictType(), dictData);
|
||||
}
|
||||
return row;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
where config_key = #{configKey} limit 1
|
||||
</select>
|
||||
|
||||
<select id="selectConfigListByKeys" resultType="com.ruoyi.system.domain.SysConfig">
|
||||
<include refid="selectConfigVo"/>
|
||||
<where>
|
||||
<if test="configKeyList != null and configKeyList.size > 0">
|
||||
and config_key in
|
||||
<foreach collection="configKeyList" item="configKey" open="(" separator="," close=")">
|
||||
#{configKey}
|
||||
</foreach>
|
||||
</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
<insert id="insertConfig" parameterType="com.ruoyi.system.domain.SysConfig">
|
||||
insert into sys_config (
|
||||
<if test="configName != null and configName != '' ">config_name,</if>
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@
|
|||
</foreach>
|
||||
</delete>
|
||||
|
||||
<update id="updateDictType" parameterType="com.ruoyi.system.api.domain.SysDictTypeSysDictType">
|
||||
<update id="updateDictType" parameterType="com.ruoyi.system.api.domain.SysDictType">
|
||||
update sys_dict_type
|
||||
<set>
|
||||
<if test="dictName != null and dictName != ''">dict_name = #{dictName},</if>
|
||||
|
|
@ -87,7 +87,7 @@
|
|||
where dict_id = #{dictId}
|
||||
</update>
|
||||
|
||||
<insert id="insertDictType" parameterType="com.ruoyi.system.api.domain.SysDictTypeSysDictType">
|
||||
<insert id="insertDictType" parameterType="com.ruoyi.system.api.domain.SysDictType">
|
||||
insert into sys_dict_type(
|
||||
<if test="dictName != null and dictName != ''">dict_name,</if>
|
||||
<if test="dictType != null and dictType != ''">dict_type,</if>
|
||||
|
|
|
|||
Loading…
Reference in New Issue