Pre Merge pull request !171 from MichelleChung/dev

This commit is contained in:
MichelleChung 2022-05-02 12:48:59 +00:00 committed by Gitee
commit 7299926f02
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
19 changed files with 701 additions and 35 deletions

View File

@ -38,6 +38,7 @@
<dynamic-ds.version>3.5.1</dynamic-ds.version> <dynamic-ds.version>3.5.1</dynamic-ds.version>
<tlog.version>1.3.6</tlog.version> <tlog.version>1.3.6</tlog.version>
<xxl-job.version>2.3.0</xxl-job.version> <xxl-job.version>2.3.0</xxl-job.version>
<mail.version>1.6.2</mail.version>
<!-- jdk11 缺失依赖 jaxb--> <!-- jdk11 缺失依赖 jaxb-->
<jaxb.version>3.0.1</jaxb.version> <jaxb.version>3.0.1</jaxb.version>

View File

@ -19,9 +19,9 @@ import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.time.Duration;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
/** /**
* 验证码操作处理 * 验证码操作处理
@ -60,7 +60,7 @@ public class CaptchaController {
captcha.setGenerator(codeGenerator); captcha.setGenerator(codeGenerator);
captcha.createCode(); captcha.createCode();
String code = isMath ? getCodeResult(captcha.getCode()) : captcha.getCode(); String code = isMath ? getCodeResult(captcha.getCode()) : captcha.getCode();
RedisUtils.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES); RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
ajax.put("uuid", uuid); ajax.put("uuid", uuid);
ajax.put("img", captcha.getImageBase64()); ajax.put("img", captcha.getImageBase64());
return R.ok(ajax); return R.ok(ajax);

View File

@ -137,6 +137,34 @@ spring:
# 是否开启ssl # 是否开启ssl
ssl: false ssl: false
# 邮件
mail:
enabled: false
# 邮件服务地址 (enabled = true 时打开该配置)
# host: smtp.qq.com
# 用户名
username: xxx@qq.com
# 授权码 (设置 - 账户 - POP3/SMTP服务)
password: xxx
# QQ邮箱加密端口不同邮箱的端口不一样
port: 465
properties:
mail:
smtp:
socketFactory:
class: javax.net.ssl.SSLSocketFactory
ssl:
trust: smtp.qq.com
# 是否需要用户认证
auth: true
starttls:
# 启用TLS加密
enable: true
required: true
# 传输协议 starttls.enable = true 时为 smtps
protocol: smtps
debug: true
redisson: redisson:
# 线程池数量 # 线程池数量
threads: 4 threads: 4

View File

@ -159,6 +159,12 @@
<artifactId>lock4j-redisson-spring-boot-starter</artifactId> <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
</dependency> </dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>${mail.version}</version>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -0,0 +1,471 @@
package com.ruoyi.common.utils.email;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.CharUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.mail.*;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import javax.mail.Authenticator;
import javax.mail.Session;
import java.io.File;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* 邮件工具类
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class MailUtils extends MailUtil {
private static final MailAccount ACCOUNT = SpringUtils.getBean(MailAccount.class);
/**
* 获取邮件发送实例
*/
public static MailAccount getMailAccount() {
return ACCOUNT;
}
/**
* 获取邮件发送实例 (自定义发送人以及授权码)
*
* @param username 发送人
* @param password 授权码
*/
public static MailAccount getMailAccount(String username, String password) {
ACCOUNT.setFrom(StringUtils.blankToDefault(username, ACCOUNT.getUser()));
ACCOUNT.setUser(StringUtils.blankToDefault(username, ACCOUNT.getUser()));
ACCOUNT.setPass(StringUtils.blankToDefault(password, ACCOUNT.getPass()));
return ACCOUNT;
}
/**
* 使用配置文件中设置的账户发送文本邮件发送给单个或多个收件人<br>
* 多个收件人可以使用逗号,分隔也可以通过分号;分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendText(String to, String subject, String content, File... files) {
return send(to, subject, content, false, files);
}
/**
* 使用配置文件中设置的账户发送HTML邮件发送给单个或多个收件人<br>
* 多个收件人可以使用逗号,分隔也可以通过分号;分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendHtml(String to, String subject, String content, File... files) {
return send(to, subject, content, true, files);
}
/**
* 使用配置文件中设置的账户发送邮件发送单个或多个收件人<br>
* 多个收件人可以使用逗号,分隔也可以通过分号;分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
*/
public static String send(String to, String subject, String content, boolean isHtml, File... files) {
return send(splitAddress(to), subject, content, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送邮件发送单个或多个收件人<br>
* 多个收件人抄送人密送人可以使用逗号,分隔也可以通过分号;分隔
*
* @param to 收件人可以使用逗号,分隔也可以通过分号;分隔
* @param cc 抄送人可以使用逗号,分隔也可以通过分号;分隔
* @param bcc 密送人可以使用逗号,分隔也可以通过分号;分隔
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(String to, String cc, String bcc, String subject, String content, boolean isHtml, File... files) {
return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送文本邮件发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param files 附件列表
* @return message-id
*/
public static String sendText(Collection<String> tos, String subject, String content, File... files) {
return send(tos, subject, content, false, files);
}
/**
* 使用配置文件中设置的账户发送HTML邮件发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendHtml(Collection<String> tos, String subject, String content, File... files) {
return send(tos, subject, content, true, files);
}
/**
* 使用配置文件中设置的账户发送邮件发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
*/
public static String send(Collection<String> tos, String subject, String content, boolean isHtml, File... files) {
return send(tos, null, null, subject, content, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送邮件发送给多人
*
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
return send(getMailAccount(), true, tos, ccs, bccs, subject, content, null, isHtml, files);
}
// ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
/**
* 发送邮件给多人
*
* @param mailAccount 邮件认证对象
* @param to 收件人多个收件人逗号或者分号隔开
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String send(MailAccount mailAccount, String to, String subject, String content, boolean isHtml, File... files) {
return send(mailAccount, splitAddress(to), subject, content, isHtml, files);
}
/**
* 发送邮件给多人
*
* @param mailAccount 邮件帐户信息
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
*/
public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, boolean isHtml, File... files) {
return send(mailAccount, tos, null, null, subject, content, isHtml, files);
}
/**
* 发送邮件给多人
*
* @param mailAccount 邮件帐户信息
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, boolean isHtml, File... files) {
return send(mailAccount, false, tos, ccs, bccs, subject, content, null, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送HTML邮件发送给单个或多个收件人<br>
* 多个收件人可以使用逗号,分隔也可以通过分号;分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendHtml(String to, String subject, String content, Map<String, InputStream> imageMap, File... files) {
return send(to, subject, content, imageMap, true, files);
}
/**
* 使用配置文件中设置的账户发送邮件发送单个或多个收件人<br>
* 多个收件人可以使用逗号,分隔也可以通过分号;分隔
*
* @param to 收件人
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
*/
public static String send(String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(splitAddress(to), subject, content, imageMap, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送邮件发送单个或多个收件人<br>
* 多个收件人抄送人密送人可以使用逗号,分隔也可以通过分号;分隔
*
* @param to 收件人可以使用逗号,分隔也可以通过分号;分隔
* @param cc 抄送人可以使用逗号,分隔也可以通过分号;分隔
* @param bcc 密送人可以使用逗号,分隔也可以通过分号;分隔
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(String to, String cc, String bcc, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(splitAddress(to), splitAddress(cc), splitAddress(bcc), subject, content, imageMap, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送HTML邮件发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String sendHtml(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, File... files) {
return send(tos, subject, content, imageMap, true, files);
}
/**
* 使用配置文件中设置的账户发送邮件发送给多人
*
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
*/
public static String send(Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(tos, null, null, subject, content, imageMap, isHtml, files);
}
/**
* 使用配置文件中设置的账户发送邮件发送给多人
*
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML
* @param files 附件列表
* @return message-id
* @since 4.0.3
*/
public static String send(Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(getMailAccount(), true, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
}
// ------------------------------------------------------------------------------------------------------------------------------- Custom MailAccount
/**
* 发送邮件给多人
*
* @param mailAccount 邮件认证对象
* @param to 收件人多个收件人逗号或者分号隔开
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 3.2.0
*/
public static String send(MailAccount mailAccount, String to, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(mailAccount, splitAddress(to), subject, content, imageMap, isHtml, files);
}
/**
* 发送邮件给多人
*
* @param mailAccount 邮件帐户信息
* @param tos 收件人列表
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 4.6.3
*/
public static String send(MailAccount mailAccount, Collection<String> tos, String subject, String content, Map<String, InputStream> imageMap, boolean isHtml, File... files) {
return send(mailAccount, tos, null, null, subject, content, imageMap, isHtml, files);
}
/**
* 发送邮件给多人
*
* @param mailAccount 邮件帐户信息
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:$IMAGE_PLACEHOLDER
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 4.6.3
*/
public static String send(MailAccount mailAccount, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content, Map<String, InputStream> imageMap,
boolean isHtml, File... files) {
return send(mailAccount, false, tos, ccs, bccs, subject, content, imageMap, isHtml, files);
}
/**
* 根据配置文件获取邮件客户端会话
*
* @param mailAccount 邮件账户配置
* @param isSingleton 是否单例全局共享会话
* @return {@link Session}
* @since 5.5.7
*/
public static Session getSession(MailAccount mailAccount, boolean isSingleton) {
Authenticator authenticator = null;
if (mailAccount.isAuth()) {
authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
}
return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) //
: Session.getInstance(mailAccount.getSmtpProps(), authenticator);
}
// ------------------------------------------------------------------------------------------------------------------------ Private method start
/**
* 发送邮件给多人
*
* @param mailAccount 邮件帐户信息
* @param useGlobalSession 是否全局共享Session
* @param tos 收件人列表
* @param ccs 抄送人列表可以为null或空
* @param bccs 密送人列表可以为null或空
* @param subject 标题
* @param content 正文
* @param imageMap 图片与占位符占位符格式为cid:${cid}
* @param isHtml 是否为HTML格式
* @param files 附件列表
* @return message-id
* @since 4.6.3
*/
private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection<String> tos, Collection<String> ccs, Collection<String> bccs, String subject, String content,
Map<String, InputStream> imageMap, boolean isHtml, File... files) {
final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession);
// 可选抄送人
if (CollUtil.isNotEmpty(ccs)) {
mail.setCcs(ccs.toArray(new String[0]));
}
// 可选密送人
if (CollUtil.isNotEmpty(bccs)) {
mail.setBccs(bccs.toArray(new String[0]));
}
mail.setTos(tos.toArray(new String[0]));
mail.setTitle(subject);
mail.setContent(content);
mail.setHtml(isHtml);
mail.setFiles(files);
// 图片
if (MapUtil.isNotEmpty(imageMap)) {
for (Map.Entry<String, InputStream> entry : imageMap.entrySet()) {
mail.addImage(entry.getKey(), entry.getValue());
// 关闭流
IoUtil.close(entry.getValue());
}
}
return mail.send();
}
/**
* 将多个联系人转为列表分隔符为逗号或者分号
*
* @param addresses 多个联系人如果为空返回null
* @return 联系人列表
*/
private static List<String> splitAddress(String addresses) {
if (StrUtil.isBlank(addresses)) {
return null;
}
List<String> result;
if (StrUtil.contains(addresses, CharUtil.COMMA)) {
result = StrUtil.splitTrim(addresses, CharUtil.COMMA);
} else if (StrUtil.contains(addresses, ';')) {
result = StrUtil.splitTrim(addresses, ';');
} else {
result = CollUtil.newArrayList(addresses);
}
return result;
}
// ------------------------------------------------------------------------------------------------------------------------ Private method end
}

View File

@ -103,7 +103,7 @@ public class ExcelUtil {
String[] convertSource = converterExp.split(","); String[] convertSource = converterExp.split(",");
for (String item : convertSource) { for (String item : convertSource) {
String[] itemArray = item.split("="); String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue)) { if (StringUtils.containsAny(propertyValue, separator)) {
for (String value : propertyValue.split(separator)) { for (String value : propertyValue.split(separator)) {
if (itemArray[0].equals(value)) { if (itemArray[0].equals(value)) {
propertyString.append(itemArray[1] + separator); propertyString.append(itemArray[1] + separator);
@ -132,7 +132,7 @@ public class ExcelUtil {
String[] convertSource = converterExp.split(","); String[] convertSource = converterExp.split(",");
for (String item : convertSource) { for (String item : convertSource) {
String[] itemArray = item.split("="); String[] itemArray = item.split("=");
if (StringUtils.containsAny(separator, propertyValue)) { if (StringUtils.containsAny(propertyValue, separator)) {
for (String value : propertyValue.split(separator)) { for (String value : propertyValue.split(separator)) {
if (itemArray[1].equals(value)) { if (itemArray[1].equals(value)) {
propertyString.append(itemArray[0] + separator); propertyString.append(itemArray[0] + separator);

View File

@ -6,11 +6,11 @@ import lombok.AccessLevel;
import lombok.NoArgsConstructor; import lombok.NoArgsConstructor;
import org.redisson.api.*; import org.redisson.api.*;
import java.time.Duration;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer; import java.util.function.Consumer;
/** /**
@ -107,7 +107,7 @@ public class RedisUtils {
} catch (Exception e) { } catch (Exception e) {
long timeToLive = bucket.remainTimeToLive(); long timeToLive = bucket.remainTimeToLive();
bucket.set(value); bucket.set(value);
bucket.expire(timeToLive, TimeUnit.MILLISECONDS); bucket.expire(Duration.ofMillis(timeToLive));
} }
} else { } else {
bucket.set(value); bucket.set(value);
@ -119,13 +119,12 @@ public class RedisUtils {
* *
* @param key 缓存的键值 * @param key 缓存的键值
* @param value 缓存的值 * @param value 缓存的值
* @param timeout 时间 * @param duration 时间
* @param timeUnit 时间颗粒度
*/ */
public static <T> void setCacheObject(final String key, final T value, final long timeout, final TimeUnit timeUnit) { public static <T> void setCacheObject(final String key, final T value, final Duration duration) {
RBucket<T> result = CLIENT.getBucket(key); RBucket<T> result = CLIENT.getBucket(key);
result.set(value); result.set(value);
result.expire(timeout, timeUnit); result.expire(duration);
} }
/** /**
@ -149,20 +148,19 @@ public class RedisUtils {
* @return true=设置成功false=设置失败 * @return true=设置成功false=设置失败
*/ */
public static boolean expire(final String key, final long timeout) { public static boolean expire(final String key, final long timeout) {
return expire(key, timeout, TimeUnit.SECONDS); return expire(key, Duration.ofSeconds(timeout));
} }
/** /**
* 设置有效时间 * 设置有效时间
* *
* @param key Redis键 * @param key Redis键
* @param timeout 超时时间 * @param duration 超时时间
* @param unit 时间单位
* @return true=设置成功false=设置失败 * @return true=设置成功false=设置失败
*/ */
public static boolean expire(final String key, final long timeout, final TimeUnit unit) { public static boolean expire(final String key, final Duration duration) {
RBucket rBucket = CLIENT.getBucket(key); RBucket rBucket = CLIENT.getBucket(key);
return rBucket.expire(timeout, unit); return rBucket.expire(duration);
} }
/** /**

View File

@ -0,0 +1,56 @@
package com.ruoyi.demo.controller;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.utils.email.MailUtils;
import io.swagger.annotations.Api;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
/**
* 测试邮件发送 Controller
*
* @author Michelle.Chung
*/
@Validated
@Api(value = "邮件控制器", tags = {"测试邮件发送"})
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@RequestMapping("/demo/mail")
@RestController
public class MailController {
/**
* 发送邮件
*
* @param to 接收人
* @param subject 标题
* @param text 内容
*/
@GetMapping("/sendSimpleMessage")
public R<Void> sendSimpleMessage(String to, String subject, String text) {
MailUtils.send(to, subject, text, false);
return R.ok("操作成功");
}
/**
* 发送邮件带附件
*
* @param to 接收人
* @param subject 标题
* @param text 内容
*/
@GetMapping("/sendMessageWithAttachment")
public R<Void> sendMessageWithAttachment(String to, String subject, String text, String filePath) {
MailUtils.send(to, subject, text, false, new File(filePath));
return R.ok("操作成功");
}
}

View File

@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.TimeUnit; import java.time.Duration;
/** /**
* spring-cache 演示案例 * spring-cache 演示案例
@ -87,7 +87,7 @@ public class RedisCacheController {
@GetMapping("/test6") @GetMapping("/test6")
public R<Boolean> test6(String key, String value) { public R<Boolean> test6(String key, String value) {
RedisUtils.setCacheObject(key, value); RedisUtils.setCacheObject(key, value);
boolean flag = RedisUtils.expire(key, 10, TimeUnit.SECONDS); boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10));
System.out.println("***********" + flag); System.out.println("***********" + flag);
try { try {
Thread.sleep(11 * 1000); Thread.sleep(11 * 1000);

View File

@ -25,9 +25,9 @@ import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.time.Duration;
import java.util.Collection; import java.util.Collection;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit;
/** /**
* 防止重复提交(参考美团GTIS防重系统) * 防止重复提交(参考美团GTIS防重系统)
@ -66,7 +66,7 @@ public class RepeatSubmitAspect {
String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + url + submitKey; String cacheRepeatKey = Constants.REPEAT_SUBMIT_KEY + url + submitKey;
String key = RedisUtils.getCacheObject(cacheRepeatKey); String key = RedisUtils.getCacheObject(cacheRepeatKey);
if (key == null) { if (key == null) {
RedisUtils.setCacheObject(cacheRepeatKey, "", interval, TimeUnit.MILLISECONDS); RedisUtils.setCacheObject(cacheRepeatKey, "", Duration.ofMillis(interval));
KEY_CACHE.set(cacheRepeatKey); KEY_CACHE.set(cacheRepeatKey);
} else { } else {
String message = repeatSubmit.message(); String message = repeatSubmit.message();

View File

@ -0,0 +1,40 @@
package com.ruoyi.framework.config;
import cn.hutool.extra.mail.MailAccount;
import com.ruoyi.framework.config.properties.MailProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.annotation.Resource;
/**
* JavaMail 配置
*
* @author Michelle.Chung
*/
@Configuration
public class MailConfig {
@Resource
private MailProperties mailProperties;
/**
* 初始化 MailAccount
*/
@Bean
@ConditionalOnProperty(value = "spring.mail.enabled", havingValue = "true")
public MailAccount mailAccount() {
MailAccount account = new MailAccount();
account.setUser(mailProperties.getUsername());
account.setFrom(mailProperties.getUsername());
account.setPass(mailProperties.getPassword());
account.setHost(mailProperties.getHost());
account.setPort(mailProperties.getPort());
account.setAuth(mailProperties.getAuth());
account.setDebug(mailProperties.getDebug());
account.setStarttlsEnable(mailProperties.getStarttlsEnable());
return account;
}
}

View File

@ -1,6 +1,7 @@
package com.ruoyi.framework.config; package com.ruoyi.framework.config;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import com.ruoyi.common.utils.JsonUtils;
import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.config.properties.RedissonProperties; import com.ruoyi.framework.config.properties.RedissonProperties;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -53,7 +54,7 @@ public class RedisConfig extends CachingConfigurerSupport {
Config config = new Config(); Config config = new Config();
config.setThreads(redissonProperties.getThreads()) config.setThreads(redissonProperties.getThreads())
.setNettyThreads(redissonProperties.getNettyThreads()) .setNettyThreads(redissonProperties.getNettyThreads())
.setCodec(JsonJacksonCodec.INSTANCE); .setCodec(new JsonJacksonCodec(JsonUtils.getObjectMapper()));
RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig(); RedissonProperties.SingleServerConfig singleServerConfig = redissonProperties.getSingleServerConfig();
if (ObjectUtil.isNotNull(singleServerConfig)) { if (ObjectUtil.isNotNull(singleServerConfig)) {

View File

@ -109,7 +109,7 @@ public class SwaggerConfig {
* 安全模式这里指定token通过Authorization头请求头传递 * 安全模式这里指定token通过Authorization头请求头传递
*/ */
private List<SecurityScheme> securitySchemes() { private List<SecurityScheme> securitySchemes() {
List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>(); List<SecurityScheme> apiKeyList = new ArrayList<>();
String header = saTokenConfig.getTokenName(); String header = saTokenConfig.getTokenName();
apiKeyList.add(new ApiKey(header, header, In.HEADER.toValue())); apiKeyList.add(new ApiKey(header, header, In.HEADER.toValue()));
return apiKeyList; return apiKeyList;

View File

@ -33,8 +33,8 @@ public class ThreadPoolConfig {
@ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true") @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
public ThreadPoolTaskExecutor threadPoolTaskExecutor() { public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setMaxPoolSize(core); executor.setCorePoolSize(core);
executor.setCorePoolSize(core * 2); executor.setMaxPoolSize(core * 2);
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity()); executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds()); executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

View File

@ -0,0 +1,65 @@
package com.ruoyi.framework.config.properties;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* JavaMail 配置属性
*
* @author Michelle.Chung
*/
@Data
@Component
@ConfigurationProperties(prefix = "spring.mail")
public class MailProperties {
/**
* 过滤开关
*/
private String enabled;
/**
* 邮件服务地址
*/
private String host;
/**
* 用户名
*/
private String username;
/**
* 授权码 (设置 - 账户 - POP3/SMTP服务)
*/
private String password;
/**
* 邮箱加密端口不同邮箱的端口不一样
*/
private Integer port;
/**
* 是否需要用户认证
*/
@Value("${spring.mail.properties.mail.smtp.auth}")
private Boolean auth;
/**
* 是否启用TLS加密
*/
@Value("${spring.mail.properties.mail.smtp.starttls.enable}")
private Boolean starttlsEnable;
@Value("${spring.mail.properties.mail.smtp.ssl.trust}")
private String sslTrust;
private Boolean debug;
/**
* 传输协议 starttls.enable = true 时为 smtps
*/
private String protocol;
}

View File

@ -18,7 +18,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit; import java.time.Duration;
/** /**
* 用户行为 侦听器的实现 * 用户行为 侦听器的实现
@ -52,7 +52,7 @@ public class UserActionListener implements SaTokenListener {
dto.setTokenId(tokenValue); dto.setTokenId(tokenValue);
dto.setUserName(user.getUsername()); dto.setUserName(user.getUsername());
dto.setDeptName(user.getDeptName()); dto.setDeptName(user.getDeptName());
RedisUtils.setCacheObject(Constants.ONLINE_TOKEN_KEY + tokenValue, dto, tokenConfig.getTimeout(), TimeUnit.SECONDS); RedisUtils.setCacheObject(Constants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout()));
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue); log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
} else if (userType == UserType.APP_USER) { } else if (userType == UserType.APP_USER) {
// app端 自行根据业务编写 // app端 自行根据业务编写

View File

@ -5,10 +5,10 @@ import cn.dev33.satoken.util.SaFoxUtil;
import com.ruoyi.common.utils.redis.RedisUtils; import com.ruoyi.common.utils.redis.RedisUtils;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
/** /**
* Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一) * Sa-Token持久层接口(使用框架自带RedisUtils实现 协议统一)
@ -38,7 +38,7 @@ public class PlusSaTokenDao implements SaTokenDao {
if (timeout == SaTokenDao.NEVER_EXPIRE) { if (timeout == SaTokenDao.NEVER_EXPIRE) {
RedisUtils.setCacheObject(key, value); RedisUtils.setCacheObject(key, value);
} else { } else {
RedisUtils.setCacheObject(key, value, timeout, TimeUnit.SECONDS); RedisUtils.setCacheObject(key, value, Duration.ofSeconds(timeout));
} }
} }
@ -87,7 +87,7 @@ public class PlusSaTokenDao implements SaTokenDao {
} }
return; return;
} }
RedisUtils.expire(key, timeout, TimeUnit.SECONDS); RedisUtils.expire(key, Duration.ofSeconds(timeout));
} }
@ -111,7 +111,7 @@ public class PlusSaTokenDao implements SaTokenDao {
if (timeout == SaTokenDao.NEVER_EXPIRE) { if (timeout == SaTokenDao.NEVER_EXPIRE) {
RedisUtils.setCacheObject(key, object); RedisUtils.setCacheObject(key, object);
} else { } else {
RedisUtils.setCacheObject(key, object, timeout, TimeUnit.SECONDS); RedisUtils.setCacheObject(key, object, Duration.ofSeconds(timeout));
} }
} }
@ -160,7 +160,7 @@ public class PlusSaTokenDao implements SaTokenDao {
} }
return; return;
} }
RedisUtils.expire(key, timeout, TimeUnit.SECONDS); RedisUtils.expire(key, Duration.ofSeconds(timeout));
} }

View File

@ -27,8 +27,8 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.time.Duration;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
@ -248,7 +248,7 @@ public class SysLoginService {
errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1; errorNumber = ObjectUtil.isNull(errorNumber) ? 1 : errorNumber + 1;
// 达到规定错误次数 则锁定登录 // 达到规定错误次数 则锁定登录
if (errorNumber.equals(setErrorNumber)) { if (errorNumber.equals(setErrorNumber)) {
RedisUtils.setCacheObject(errorKey, errorNumber, errorLimitTime, TimeUnit.MINUTES); RedisUtils.setCacheObject(errorKey, errorNumber, Duration.ofMinutes(errorLimitTime));
asyncService.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), errorLimitTime), request); asyncService.recordLogininfor(username, loginFail, MessageUtils.message(loginType.getRetryLimitExceed(), errorLimitTime), request);
throw new UserException(loginType.getRetryLimitExceed(), errorLimitTime); throw new UserException(loginType.getRetryLimitExceed(), errorLimitTime);
} else { } else {

View File

@ -115,11 +115,11 @@ public class SysUserServiceImpl implements ISysUserService {
*/ */
@Override @Override
public TableDataInfo<SysUser> selectUnallocatedList(SysUser user, PageQuery pageQuery) { public TableDataInfo<SysUser> selectUnallocatedList(SysUser user, PageQuery pageQuery) {
List<Long> userId = userRoleMapper.selectUserIdsByRoleId(user.getRoleId()); List<Long> userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId());
QueryWrapper<SysUser> wrapper = Wrappers.query(); QueryWrapper<SysUser> wrapper = Wrappers.query();
wrapper.eq("u.del_flag", UserConstants.USER_NORMAL) wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
.and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id")) .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id"))
.notIn("u.user_id", userId) .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds)
.like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName()) .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
.like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber()); .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber());
Page<SysUser> page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper); Page<SysUser> page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper);