roles = roleService.selectRolesByUserId(user.getUserId());
loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
return loginUser;
diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
index ddab279bc..c7545fa65 100644
--- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
+++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysRegisterService.java
@@ -11,7 +11,6 @@ import org.dromara.common.core.exception.user.CaptchaException;
import org.dromara.common.core.exception.user.CaptchaExpireException;
import org.dromara.common.core.exception.user.UserException;
import org.dromara.common.core.utils.MessageUtils;
-import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.log.event.LogininforEvent;
@@ -108,7 +107,6 @@ public class SysRegisterService {
logininforEvent.setUsername(username);
logininforEvent.setStatus(status);
logininforEvent.setMessage(message);
- logininforEvent.setRequest(ServletUtils.getRequest());
SpringUtils.context().publishEvent(logininforEvent);
}
diff --git a/ruoyi-common/ruoyi-common-core/pom.xml b/ruoyi-common/ruoyi-common-core/pom.xml
index 5925c9b3c..f6f8c2556 100644
--- a/ruoyi-common/ruoyi-common-core/pom.xml
+++ b/ruoyi-common/ruoyi-common-core/pom.xml
@@ -99,6 +99,13 @@
transmittable-thread-local
+
+ jakarta.faces
+ jakarta.faces-api
+ 4.1.0
+ true
+
+
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/org/springframework/web/context/request/RequestContextHolder.java b/ruoyi-common/ruoyi-common-core/src/main/java/org/springframework/web/context/request/RequestContextHolder.java
new file mode 100644
index 000000000..7f9622dbc
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/org/springframework/web/context/request/RequestContextHolder.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2002-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.context.request;
+
+import com.alibaba.ttl.TransmittableThreadLocal;
+import jakarta.faces.context.FacesContext;
+import org.springframework.lang.Nullable;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Holder class to expose the web request in the form of a thread-bound
+ * {@link RequestAttributes} object. The request will be inherited
+ * by any child threads spawned by the current thread if the
+ * {@code inheritable} flag is set to {@code true}.
+ *
+ * Use {@link RequestContextListener} or
+ * {@link org.springframework.web.filter.RequestContextFilter} to expose
+ * the current web request. Note that
+ * already exposes the current request by default.
+ *
+ * 修改 spring 上下文存储方式 将 ThreadLocal 替换为 TransmittableThreadLocal
+ * 支持线程上下文切换变量传递 异步获取 spring 上下文
+ *
+ * @author Juergen Hoeller
+ * @author Rod Johnson
+ * @since 2.0
+ * @see RequestContextListener
+ * @see org.springframework.web.filter.RequestContextFilter
+ */
+public abstract class RequestContextHolder {
+
+ private static final boolean jsfPresent =
+ ClassUtils.isPresent("jakarta.faces.context.FacesContext", RequestContextHolder.class.getClassLoader());
+
+ // ThreadLocal 替换为 TransmittableThreadLocal
+ private static final ThreadLocal requestAttributesHolder =
+ new TransmittableThreadLocal<>();
+
+ private static final ThreadLocal inheritableRequestAttributesHolder =
+ new TransmittableThreadLocal<>();
+
+
+ /**
+ * Reset the RequestAttributes for the current thread.
+ */
+ public static void resetRequestAttributes() {
+ requestAttributesHolder.remove();
+ inheritableRequestAttributesHolder.remove();
+ }
+
+ /**
+ * Bind the given RequestAttributes to the current thread,
+ * not exposing it as inheritable for child threads.
+ * @param attributes the RequestAttributes to expose
+ * @see #setRequestAttributes(RequestAttributes, boolean)
+ */
+ public static void setRequestAttributes(@Nullable RequestAttributes attributes) {
+ setRequestAttributes(attributes, false);
+ }
+
+ /**
+ * Bind the given RequestAttributes to the current thread.
+ * @param attributes the RequestAttributes to expose,
+ * or {@code null} to reset the thread-bound context
+ * @param inheritable whether to expose the RequestAttributes as inheritable
+ * for child threads (using an {@link InheritableThreadLocal})
+ */
+ public static void setRequestAttributes(@Nullable RequestAttributes attributes, boolean inheritable) {
+ if (attributes == null) {
+ resetRequestAttributes();
+ }
+ else {
+ if (inheritable) {
+ inheritableRequestAttributesHolder.set(attributes);
+ requestAttributesHolder.remove();
+ }
+ else {
+ requestAttributesHolder.set(attributes);
+ inheritableRequestAttributesHolder.remove();
+ }
+ }
+ }
+
+ /**
+ * Return the RequestAttributes currently bound to the thread.
+ * @return the RequestAttributes currently bound to the thread,
+ * or {@code null} if none bound
+ */
+ @Nullable
+ public static RequestAttributes getRequestAttributes() {
+ RequestAttributes attributes = requestAttributesHolder.get();
+ if (attributes == null) {
+ attributes = inheritableRequestAttributesHolder.get();
+ }
+ return attributes;
+ }
+
+ /**
+ * Return the RequestAttributes currently bound to the thread.
+ * Exposes the previously bound RequestAttributes instance, if any.
+ * Falls back to the current JSF FacesContext, if any.
+ * @return the RequestAttributes currently bound to the thread
+ * @throws IllegalStateException if no RequestAttributes object
+ * is bound to the current thread
+ * @see #setRequestAttributes
+ * @see ServletRequestAttributes
+ * @see FacesRequestAttributes
+ * @see jakarta.faces.context.FacesContext#getCurrentInstance()
+ */
+ public static RequestAttributes currentRequestAttributes() throws IllegalStateException {
+ RequestAttributes attributes = getRequestAttributes();
+ if (attributes == null) {
+ if (jsfPresent) {
+ attributes = FacesRequestAttributesFactory.getFacesRequestAttributes();
+ }
+ if (attributes == null) {
+ throw new IllegalStateException("No thread-bound request found: " +
+ "Are you referring to request attributes outside of an actual web request, " +
+ "or processing a request outside of the originally receiving thread? " +
+ "If you are actually operating within a web request and still receive this message, " +
+ "your code is probably running outside of DispatcherServlet: " +
+ "In this case, use RequestContextListener or RequestContextFilter to expose the current request.");
+ }
+ }
+ return attributes;
+ }
+
+
+ /**
+ * Inner class to avoid hard-coded JSF dependency.
+ */
+ private static class FacesRequestAttributesFactory {
+
+ @Nullable
+ public static RequestAttributes getFacesRequestAttributes() {
+ try {
+ FacesContext facesContext = FacesContext.getCurrentInstance();
+ return (facesContext != null ? new FacesRequestAttributes(facesContext) : null);
+ }
+ catch (NoClassDefFoundError err) {
+ // typically for com/sun/faces/util/Util if only the JSF API jar is present
+ return null;
+ }
+ }
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
index cdbd00f09..8e257a23c 100644
--- a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
+++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/aspect/LogAspect.java
@@ -13,7 +13,6 @@ import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
-import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
@@ -21,7 +20,6 @@ import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessStatus;
import org.dromara.common.log.event.OperLogEvent;
-import org.dromara.common.satoken.utils.LoginHelper;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.http.HttpMethod;
import org.springframework.validation.BindingResult;
@@ -88,16 +86,6 @@ public class LogAspect {
// *========数据库日志=========*//
OperLogEvent operLog = new OperLogEvent();
- operLog.setTenantId(LoginHelper.getTenantId());
- operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
- // 请求的地址
- String ip = ServletUtils.getClientIP();
- operLog.setOperIp(ip);
- operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
- LoginUser loginUser = LoginHelper.getLoginUser();
- operLog.setOperName(loginUser.getUsername());
- operLog.setDeptName(loginUser.getDeptName());
-
if (e != null) {
operLog.setStatus(BusinessStatus.FAIL.ordinal());
operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
@@ -106,8 +94,6 @@ public class LogAspect {
String className = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
operLog.setMethod(className + "." + methodName + "()");
- // 设置请求方式
- operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
// 处理设置注解上的参数
getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
// 设置消耗时间
diff --git a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java
index 938eaadde..212bf18b5 100644
--- a/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java
+++ b/ruoyi-common/ruoyi-common-log/src/main/java/org/dromara/common/log/event/LogininforEvent.java
@@ -2,8 +2,6 @@ package org.dromara.common.log.event;
import lombok.Data;
-import jakarta.servlet.http.HttpServletRequest;
-
import java.io.Serial;
import java.io.Serializable;
@@ -39,11 +37,6 @@ public class LogininforEvent implements Serializable {
*/
private String message;
- /**
- * 请求体
- */
- private HttpServletRequest request;
-
/**
* 其他参数
*/
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java
index 1b51c272c..0ea3007b9 100644
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/MailConfig.java
@@ -1,7 +1,7 @@
package org.dromara.common.mail.config;
+import cn.hutool.extra.mail.MailAccount;
import org.dromara.common.mail.config.properties.MailProperties;
-import org.dromara.common.mail.utils.MailAccount;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java
deleted file mode 100644
index fdae86975..000000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/GlobalMailAccount.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.io.IORuntimeException;
-
-/**
- * 全局邮件帐户,依赖于邮件配置文件{@link MailAccount#MAIL_SETTING_PATHS}
- *
- * @author looly
- */
-public enum GlobalMailAccount {
- INSTANCE;
-
- private final MailAccount mailAccount;
-
- /**
- * 构造
- */
- GlobalMailAccount() {
- mailAccount = createDefaultAccount();
- }
-
- /**
- * 获得邮件帐户
- *
- * @return 邮件帐户
- */
- public MailAccount getAccount() {
- return this.mailAccount;
- }
-
- /**
- * 创建默认帐户
- *
- * @return MailAccount
- */
- private MailAccount createDefaultAccount() {
- for (String mailSettingPath : MailAccount.MAIL_SETTING_PATHS) {
- try {
- return new MailAccount(mailSettingPath);
- } catch (IORuntimeException ignore) {
- //ignore
- }
- }
- return null;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java
deleted file mode 100644
index b755e7370..000000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/InternalMailUtil.java
+++ /dev/null
@@ -1,108 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.util.ArrayUtil;
-import jakarta.mail.internet.AddressException;
-import jakarta.mail.internet.InternetAddress;
-import jakarta.mail.internet.MimeUtility;
-
-import java.io.UnsupportedEncodingException;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * 邮件内部工具类
- *
- * @author looly
- * @since 3.2.3
- */
-public class InternalMailUtil {
-
- /**
- * 将多个字符串邮件地址转为{@link InternetAddress}列表
- * 单个字符串地址可以是多个地址合并的字符串
- *
- * @param addrStrs 地址数组
- * @param charset 编码(主要用于中文用户名的编码)
- * @return 地址数组
- * @since 4.0.3
- */
- public static InternetAddress[] parseAddressFromStrs(String[] addrStrs, Charset charset) {
- final List resultList = new ArrayList<>(addrStrs.length);
- InternetAddress[] addrs;
- for (String addrStr : addrStrs) {
- addrs = parseAddress(addrStr, charset);
- if (ArrayUtil.isNotEmpty(addrs)) {
- Collections.addAll(resultList, addrs);
- }
- }
- return resultList.toArray(new InternetAddress[0]);
- }
-
- /**
- * 解析第一个地址
- *
- * @param address 地址字符串
- * @param charset 编码,{@code null}表示使用系统属性定义的编码或系统编码
- * @return 地址列表
- */
- public static InternetAddress parseFirstAddress(String address, Charset charset) {
- final InternetAddress[] internetAddresses = parseAddress(address, charset);
- if (ArrayUtil.isEmpty(internetAddresses)) {
- try {
- return new InternetAddress(address);
- } catch (AddressException e) {
- throw new MailException(e);
- }
- }
- return internetAddresses[0];
- }
-
- /**
- * 将一个地址字符串解析为多个地址
- * 地址间使用" "、","、";"分隔
- *
- * @param address 地址字符串
- * @param charset 编码,{@code null}表示使用系统属性定义的编码或系统编码
- * @return 地址列表
- */
- public static InternetAddress[] parseAddress(String address, Charset charset) {
- InternetAddress[] addresses;
- try {
- addresses = InternetAddress.parse(address);
- } catch (AddressException e) {
- throw new MailException(e);
- }
- //编码用户名
- if (ArrayUtil.isNotEmpty(addresses)) {
- final String charsetStr = null == charset ? null : charset.name();
- for (InternetAddress internetAddress : addresses) {
- try {
- internetAddress.setPersonal(internetAddress.getPersonal(), charsetStr);
- } catch (UnsupportedEncodingException e) {
- throw new MailException(e);
- }
- }
- }
-
- return addresses;
- }
-
- /**
- * 编码中文字符
- * 编码失败返回原字符串
- *
- * @param text 被编码的文本
- * @param charset 编码
- * @return 编码后的结果
- */
- public static String encodeText(String text, Charset charset) {
- try {
- return MimeUtility.encodeText(text, charset.name(), null);
- } catch (UnsupportedEncodingException e) {
- // ignore
- }
- return text;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java
deleted file mode 100644
index 6ca4b69ec..000000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/Mail.java
+++ /dev/null
@@ -1,483 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.builder.Builder;
-import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.io.IORuntimeException;
-import cn.hutool.core.io.IoUtil;
-import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import jakarta.activation.DataHandler;
-import jakarta.activation.DataSource;
-import jakarta.activation.FileDataSource;
-import jakarta.activation.FileTypeMap;
-import jakarta.mail.*;
-import jakarta.mail.internet.MimeBodyPart;
-import jakarta.mail.internet.MimeMessage;
-import jakarta.mail.internet.MimeMultipart;
-import jakarta.mail.internet.MimeUtility;
-import jakarta.mail.util.ByteArrayDataSource;
-
-import java.io.*;
-import java.nio.charset.Charset;
-import java.util.Date;
-
-/**
- * 邮件发送客户端
- *
- * @author looly
- * @since 3.2.0
- */
-public class Mail implements Builder {
- @Serial
- private static final long serialVersionUID = 1L;
-
- /**
- * 邮箱帐户信息以及一些客户端配置信息
- */
- private final MailAccount mailAccount;
- /**
- * 收件人列表
- */
- private String[] tos;
- /**
- * 抄送人列表(carbon copy)
- */
- private String[] ccs;
- /**
- * 密送人列表(blind carbon copy)
- */
- private String[] bccs;
- /**
- * 回复地址(reply-to)
- */
- private String[] reply;
- /**
- * 标题
- */
- private String title;
- /**
- * 内容
- */
- private String content;
- /**
- * 是否为HTML
- */
- private boolean isHtml;
- /**
- * 正文、附件和图片的混合部分
- */
- private final Multipart multipart = new MimeMultipart();
- /**
- * 是否使用全局会话,默认为false
- */
- private boolean useGlobalSession = false;
-
- /**
- * debug输出位置,可以自定义debug日志
- */
- private PrintStream debugOutput;
-
- /**
- * 创建邮件客户端
- *
- * @param mailAccount 邮件帐号
- * @return Mail
- */
- public static Mail create(MailAccount mailAccount) {
- return new Mail(mailAccount);
- }
-
- /**
- * 创建邮件客户端,使用全局邮件帐户
- *
- * @return Mail
- */
- public static Mail create() {
- return new Mail();
- }
-
- // --------------------------------------------------------------- Constructor start
-
- /**
- * 构造,使用全局邮件帐户
- */
- public Mail() {
- this(GlobalMailAccount.INSTANCE.getAccount());
- }
-
- /**
- * 构造
- *
- * @param mailAccount 邮件帐户,如果为null使用默认配置文件的全局邮件配置
- */
- public Mail(MailAccount mailAccount) {
- mailAccount = (null != mailAccount) ? mailAccount : GlobalMailAccount.INSTANCE.getAccount();
- this.mailAccount = mailAccount.defaultIfEmpty();
- }
- // --------------------------------------------------------------- Constructor end
-
- // --------------------------------------------------------------- Getters and Setters start
-
- /**
- * 设置收件人
- *
- * @param tos 收件人列表
- * @return this
- * @see #setTos(String...)
- */
- public Mail to(String... tos) {
- return setTos(tos);
- }
-
- /**
- * 设置多个收件人
- *
- * @param tos 收件人列表
- * @return this
- */
- public Mail setTos(String... tos) {
- this.tos = tos;
- return this;
- }
-
- /**
- * 设置多个抄送人(carbon copy)
- *
- * @param ccs 抄送人列表
- * @return this
- * @since 4.0.3
- */
- public Mail setCcs(String... ccs) {
- this.ccs = ccs;
- return this;
- }
-
- /**
- * 设置多个密送人(blind carbon copy)
- *
- * @param bccs 密送人列表
- * @return this
- * @since 4.0.3
- */
- public Mail setBccs(String... bccs) {
- this.bccs = bccs;
- return this;
- }
-
- /**
- * 设置多个回复地址(reply-to)
- *
- * @param reply 回复地址(reply-to)列表
- * @return this
- * @since 4.6.0
- */
- public Mail setReply(String... reply) {
- this.reply = reply;
- return this;
- }
-
- /**
- * 设置标题
- *
- * @param title 标题
- * @return this
- */
- public Mail setTitle(String title) {
- this.title = title;
- return this;
- }
-
- /**
- * 设置正文
- * 正文可以是普通文本也可以是HTML(默认普通文本),可以通过调用{@link #setHtml(boolean)} 设置是否为HTML
- *
- * @param content 正文
- * @return this
- */
- public Mail setContent(String content) {
- this.content = content;
- return this;
- }
-
- /**
- * 设置是否是HTML
- *
- * @param isHtml 是否为HTML
- * @return this
- */
- public Mail setHtml(boolean isHtml) {
- this.isHtml = isHtml;
- return this;
- }
-
- /**
- * 设置正文
- *
- * @param content 正文内容
- * @param isHtml 是否为HTML
- * @return this
- */
- public Mail setContent(String content, boolean isHtml) {
- setContent(content);
- return setHtml(isHtml);
- }
-
- /**
- * 设置文件类型附件,文件可以是图片文件,此时自动设置cid(正文中引用图片),默认cid为文件名
- *
- * @param files 附件文件列表
- * @return this
- */
- public Mail setFiles(File... files) {
- if (ArrayUtil.isEmpty(files)) {
- return this;
- }
-
- final DataSource[] attachments = new DataSource[files.length];
- for (int i = 0; i < files.length; i++) {
- attachments[i] = new FileDataSource(files[i]);
- }
- return setAttachments(attachments);
- }
-
- /**
- * 增加附件或图片,附件使用{@link DataSource} 形式表示,可以使用{@link FileDataSource}包装文件表示文件附件
- *
- * @param attachments 附件列表
- * @return this
- * @since 4.0.9
- */
- public Mail setAttachments(DataSource... attachments) {
- if (ArrayUtil.isNotEmpty(attachments)) {
- final Charset charset = this.mailAccount.getCharset();
- MimeBodyPart bodyPart;
- String nameEncoded;
- try {
- for (DataSource attachment : attachments) {
- bodyPart = new MimeBodyPart();
- bodyPart.setDataHandler(new DataHandler(attachment));
- nameEncoded = attachment.getName();
- if (this.mailAccount.isEncodefilename()) {
- nameEncoded = InternalMailUtil.encodeText(nameEncoded, charset);
- }
- // 普通附件文件名
- bodyPart.setFileName(nameEncoded);
- if (StrUtil.startWith(attachment.getContentType(), "image/")) {
- // 图片附件,用于正文中引用图片
- bodyPart.setContentID(nameEncoded);
- }
- this.multipart.addBodyPart(bodyPart);
- }
- } catch (MessagingException e) {
- throw new MailException(e);
- }
- }
- return this;
- }
-
- /**
- * 增加图片,图片的键对应到邮件模板中的占位字符串,图片类型默认为"image/jpeg"
- *
- * @param cid 图片与占位符,占位符格式为cid:${cid}
- * @param imageStream 图片文件
- * @return this
- * @since 4.6.3
- */
- public Mail addImage(String cid, InputStream imageStream) {
- return addImage(cid, imageStream, null);
- }
-
- /**
- * 增加图片,图片的键对应到邮件模板中的占位字符串
- *
- * @param cid 图片与占位符,占位符格式为cid:${cid}
- * @param imageStream 图片流,不关闭
- * @param contentType 图片类型,null赋值默认的"image/jpeg"
- * @return this
- * @since 4.6.3
- */
- public Mail addImage(String cid, InputStream imageStream, String contentType) {
- ByteArrayDataSource imgSource;
- try {
- imgSource = new ByteArrayDataSource(imageStream, ObjectUtil.defaultIfNull(contentType, "image/jpeg"));
- } catch (IOException e) {
- throw new IORuntimeException(e);
- }
- imgSource.setName(cid);
- return setAttachments(imgSource);
- }
-
- /**
- * 增加图片,图片的键对应到邮件模板中的占位字符串
- *
- * @param cid 图片与占位符,占位符格式为cid:${cid}
- * @param imageFile 图片文件
- * @return this
- * @since 4.6.3
- */
- public Mail addImage(String cid, File imageFile) {
- InputStream in = null;
- try {
- in = FileUtil.getInputStream(imageFile);
- return addImage(cid, in, FileTypeMap.getDefaultFileTypeMap().getContentType(imageFile));
- } finally {
- IoUtil.close(in);
- }
- }
-
- /**
- * 设置字符集编码
- *
- * @param charset 字符集编码
- * @return this
- * @see MailAccount#setCharset(Charset)
- */
- public Mail setCharset(Charset charset) {
- this.mailAccount.setCharset(charset);
- return this;
- }
-
- /**
- * 设置是否使用全局会话,默认为true
- *
- * @param isUseGlobalSession 是否使用全局会话,默认为true
- * @return this
- * @since 4.0.2
- */
- public Mail setUseGlobalSession(boolean isUseGlobalSession) {
- this.useGlobalSession = isUseGlobalSession;
- return this;
- }
-
- /**
- * 设置debug输出位置,可以自定义debug日志
- *
- * @param debugOutput debug输出位置
- * @return this
- * @since 5.5.6
- */
- public Mail setDebugOutput(PrintStream debugOutput) {
- this.debugOutput = debugOutput;
- return this;
- }
- // --------------------------------------------------------------- Getters and Setters end
-
- @Override
- public MimeMessage build() {
- try {
- return buildMsg();
- } catch (MessagingException e) {
- throw new MailException(e);
- }
- }
-
- /**
- * 发送
- *
- * @return message-id
- * @throws MailException 邮件发送异常
- */
- public String send() throws MailException {
- try {
- return doSend();
- } catch (MessagingException e) {
- if (e instanceof SendFailedException) {
- // 当地址无效时,显示更加详细的无效地址信息
- final Address[] invalidAddresses = ((SendFailedException) e).getInvalidAddresses();
- final String msg = StrUtil.format("Invalid Addresses: {}", ArrayUtil.toString(invalidAddresses));
- throw new MailException(msg, e);
- }
- throw new MailException(e);
- }
- }
-
- // --------------------------------------------------------------- Private method start
-
- /**
- * 执行发送
- *
- * @return message-id
- * @throws MessagingException 发送异常
- */
- private String doSend() throws MessagingException {
- final MimeMessage mimeMessage = buildMsg();
- Transport.send(mimeMessage);
- return mimeMessage.getMessageID();
- }
-
- /**
- * 构建消息
- *
- * @return {@link MimeMessage}消息
- * @throws MessagingException 消息异常
- */
- private MimeMessage buildMsg() throws MessagingException {
- final Charset charset = this.mailAccount.getCharset();
- final MimeMessage msg = new MimeMessage(getSession());
- // 发件人
- final String from = this.mailAccount.getFrom();
- if (StrUtil.isEmpty(from)) {
- // 用户未提供发送方,则从Session中自动获取
- msg.setFrom();
- } else {
- msg.setFrom(InternalMailUtil.parseFirstAddress(from, charset));
- }
- // 标题
- msg.setSubject(this.title, (null == charset) ? null : charset.name());
- // 发送时间
- msg.setSentDate(new Date());
- // 内容和附件
- msg.setContent(buildContent(charset));
- // 收件人
- msg.setRecipients(MimeMessage.RecipientType.TO, InternalMailUtil.parseAddressFromStrs(this.tos, charset));
- // 抄送人
- if (ArrayUtil.isNotEmpty(this.ccs)) {
- msg.setRecipients(MimeMessage.RecipientType.CC, InternalMailUtil.parseAddressFromStrs(this.ccs, charset));
- }
- // 密送人
- if (ArrayUtil.isNotEmpty(this.bccs)) {
- msg.setRecipients(MimeMessage.RecipientType.BCC, InternalMailUtil.parseAddressFromStrs(this.bccs, charset));
- }
- // 回复地址(reply-to)
- if (ArrayUtil.isNotEmpty(this.reply)) {
- msg.setReplyTo(InternalMailUtil.parseAddressFromStrs(this.reply, charset));
- }
-
- return msg;
- }
-
- /**
- * 构建邮件信息主体
- *
- * @param charset 编码,{@code null}则使用{@link MimeUtility#getDefaultJavaCharset()}
- * @return 邮件信息主体
- * @throws MessagingException 消息异常
- */
- private Multipart buildContent(Charset charset) throws MessagingException {
- final String charsetStr = null != charset ? charset.name() : MimeUtility.getDefaultJavaCharset();
- // 正文
- final MimeBodyPart body = new MimeBodyPart();
- body.setContent(content, StrUtil.format("text/{}; charset={}", isHtml ? "html" : "plain", charsetStr));
- this.multipart.addBodyPart(body);
-
- return this.multipart;
- }
-
- /**
- * 获取默认邮件会话
- * 如果为全局单例的会话,则全局只允许一个邮件帐号,否则每次发送邮件会新建一个新的会话
- *
- * @return 邮件会话 {@link Session}
- */
- private Session getSession() {
- final Session session = MailUtils.getSession(this.mailAccount, this.useGlobalSession);
-
- if (null != this.debugOutput) {
- session.setDebugOut(debugOutput);
- }
-
- return session;
- }
- // --------------------------------------------------------------- Private method end
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java
deleted file mode 100644
index 2a732a1a9..000000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailAccount.java
+++ /dev/null
@@ -1,659 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.util.CharsetUtil;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import cn.hutool.setting.Setting;
-
-import java.io.Serial;
-import java.io.Serializable;
-import java.nio.charset.Charset;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-
-/**
- * 邮件账户对象
- *
- * @author Luxiaolei
- */
-public class MailAccount implements Serializable {
- @Serial
- private static final long serialVersionUID = -6937313421815719204L;
-
- private static final String MAIL_PROTOCOL = "mail.transport.protocol";
- private static final String SMTP_HOST = "mail.smtp.host";
- private static final String SMTP_PORT = "mail.smtp.port";
- private static final String SMTP_AUTH = "mail.smtp.auth";
- private static final String SMTP_TIMEOUT = "mail.smtp.timeout";
- private static final String SMTP_CONNECTION_TIMEOUT = "mail.smtp.connectiontimeout";
- private static final String SMTP_WRITE_TIMEOUT = "mail.smtp.writetimeout";
-
- // SSL
- private static final String STARTTLS_ENABLE = "mail.smtp.starttls.enable";
- private static final String SSL_ENABLE = "mail.smtp.ssl.enable";
- private static final String SSL_PROTOCOLS = "mail.smtp.ssl.protocols";
- private static final String SOCKET_FACTORY = "mail.smtp.socketFactory.class";
- private static final String SOCKET_FACTORY_FALLBACK = "mail.smtp.socketFactory.fallback";
- private static final String SOCKET_FACTORY_PORT = "smtp.socketFactory.port";
-
- // System Properties
- private static final String SPLIT_LONG_PARAMS = "mail.mime.splitlongparameters";
- //private static final String ENCODE_FILE_NAME = "mail.mime.encodefilename";
- //private static final String CHARSET = "mail.mime.charset";
-
- // 其他
- private static final String MAIL_DEBUG = "mail.debug";
-
- public static final String[] MAIL_SETTING_PATHS = new String[]{"config/mail.setting", "config/mailAccount.setting", "mail.setting"};
-
- /**
- * SMTP服务器域名
- */
- private String host;
- /**
- * SMTP服务端口
- */
- private Integer port;
- /**
- * 是否需要用户名密码验证
- */
- private Boolean auth;
- /**
- * 用户名
- */
- private String user;
- /**
- * 密码
- */
- private String pass;
- /**
- * 发送方,遵循RFC-822标准
- */
- private String from;
-
- /**
- * 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- */
- private boolean debug;
- /**
- * 编码用于编码邮件正文和发送人、收件人等中文
- */
- private Charset charset = CharsetUtil.CHARSET_UTF_8;
- /**
- * 对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名)
- */
- private boolean splitlongparameters = false;
- /**
- * 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
- */
- private boolean encodefilename = true;
-
- /**
- * 使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
- */
- private boolean starttlsEnable = false;
- /**
- * 使用 SSL安全连接
- */
- private Boolean sslEnable;
-
- /**
- * SSL协议,多个协议用空格分隔
- */
- private String sslProtocols;
-
- /**
- * 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
- */
- private String socketFactoryClass = "javax.net.ssl.SSLSocketFactory";
- /**
- * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- */
- private boolean socketFactoryFallback;
- /**
- * 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- */
- private int socketFactoryPort = 465;
-
- /**
- * SMTP超时时长,单位毫秒,缺省值不超时
- */
- private long timeout;
- /**
- * Socket连接超时值,单位毫秒,缺省值不超时
- */
- private long connectionTimeout;
- /**
- * Socket写出超时值,单位毫秒,缺省值不超时
- */
- private long writeTimeout;
-
- /**
- * 自定义的其他属性,此自定义属性会覆盖默认属性
- */
- private final Map customProperty = new HashMap<>();
-
- // -------------------------------------------------------------- Constructor start
-
- /**
- * 构造,所有参数需自行定义或保持默认值
- */
- public MailAccount() {
- }
-
- /**
- * 构造
- *
- * @param settingPath 配置文件路径
- */
- public MailAccount(String settingPath) {
- this(new Setting(settingPath));
- }
-
- /**
- * 构造
- *
- * @param setting 配置文件
- */
- public MailAccount(Setting setting) {
- setting.toBean(this);
- }
-
- // -------------------------------------------------------------- Constructor end
-
- /**
- * 获得SMTP服务器域名
- *
- * @return SMTP服务器域名
- */
- public String getHost() {
- return host;
- }
-
- /**
- * 设置SMTP服务器域名
- *
- * @param host SMTP服务器域名
- * @return this
- */
- public MailAccount setHost(String host) {
- this.host = host;
- return this;
- }
-
- /**
- * 获得SMTP服务端口
- *
- * @return SMTP服务端口
- */
- public Integer getPort() {
- return port;
- }
-
- /**
- * 设置SMTP服务端口
- *
- * @param port SMTP服务端口
- * @return this
- */
- public MailAccount setPort(Integer port) {
- this.port = port;
- return this;
- }
-
- /**
- * 是否需要用户名密码验证
- *
- * @return 是否需要用户名密码验证
- */
- public Boolean isAuth() {
- return auth;
- }
-
- /**
- * 设置是否需要用户名密码验证
- *
- * @param isAuth 是否需要用户名密码验证
- * @return this
- */
- public MailAccount setAuth(boolean isAuth) {
- this.auth = isAuth;
- return this;
- }
-
- /**
- * 获取用户名
- *
- * @return 用户名
- */
- public String getUser() {
- return user;
- }
-
- /**
- * 设置用户名
- *
- * @param user 用户名
- * @return this
- */
- public MailAccount setUser(String user) {
- this.user = user;
- return this;
- }
-
- /**
- * 获取密码
- *
- * @return 密码
- */
- public String getPass() {
- return pass;
- }
-
- /**
- * 设置密码
- *
- * @param pass 密码
- * @return this
- */
- public MailAccount setPass(String pass) {
- this.pass = pass;
- return this;
- }
-
- /**
- * 获取发送方,遵循RFC-822标准
- *
- * @return 发送方,遵循RFC-822标准
- */
- public String getFrom() {
- return from;
- }
-
- /**
- * 设置发送方,遵循RFC-822标准
- * 发件人可以是以下形式:
- *
- *
- * 1. user@xxx.xx
- * 2. name <user@xxx.xx>
- *
- *
- * @param from 发送方,遵循RFC-822标准
- * @return this
- */
- public MailAccount setFrom(String from) {
- this.from = from;
- return this;
- }
-
- /**
- * 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- *
- * @return 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- * @since 4.0.2
- */
- public boolean isDebug() {
- return debug;
- }
-
- /**
- * 设置是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- *
- * @param debug 是否打开调试模式,调试模式会显示与邮件服务器通信过程,默认不开启
- * @return this
- * @since 4.0.2
- */
- public MailAccount setDebug(boolean debug) {
- this.debug = debug;
- return this;
- }
-
- /**
- * 获取字符集编码
- *
- * @return 编码,可能为{@code null}
- */
- public Charset getCharset() {
- return charset;
- }
-
- /**
- * 设置字符集编码,此选项不会修改全局配置,若修改全局配置,请设置此项为{@code null}并设置:
- *
- * System.setProperty("mail.mime.charset", charset);
- *
- *
- * @param charset 字符集编码,{@code null} 则表示使用全局设置的默认编码,全局编码为mail.mime.charset系统属性
- * @return this
- */
- public MailAccount setCharset(Charset charset) {
- this.charset = charset;
- return this;
- }
-
- /**
- * 对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名)
- *
- * @return 对于超长参数是否切分为多份
- */
- public boolean isSplitlongparameters() {
- return splitlongparameters;
- }
-
- /**
- * 设置对于超长参数是否切分为多份,默认为false(国内邮箱附件不支持切分的附件名)
- * 注意此项为全局设置,此项会调用
- *
- * System.setProperty("mail.mime.splitlongparameters", true)
- *
- *
- * @param splitlongparameters 对于超长参数是否切分为多份
- */
- public void setSplitlongparameters(boolean splitlongparameters) {
- this.splitlongparameters = splitlongparameters;
- }
-
- /**
- * 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
- *
- * @return 对于文件名是否使用{@link #charset}编码,默认为 {@code true}
- * @since 5.7.16
- */
- public boolean isEncodefilename() {
-
- return encodefilename;
- }
-
- /**
- * 设置对于文件名是否使用{@link #charset}编码,此选项不会修改全局配置
- * 如果此选项设置为{@code false},则是否编码取决于两个系统属性:
- *
- * - mail.mime.encodefilename 是否编码附件文件名
- * - mail.mime.charset 编码文件名的编码
- *
- *
- * @param encodefilename 对于文件名是否使用{@link #charset}编码
- * @since 5.7.16
- */
- public void setEncodefilename(boolean encodefilename) {
- this.encodefilename = encodefilename;
- }
-
- /**
- * 是否使用 STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
- *
- * @return 是否使用 STARTTLS安全连接
- */
- public boolean isStarttlsEnable() {
- return this.starttlsEnable;
- }
-
- /**
- * 设置是否使用STARTTLS安全连接,STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
- *
- * @param startttlsEnable 是否使用STARTTLS安全连接
- * @return this
- */
- public MailAccount setStarttlsEnable(boolean startttlsEnable) {
- this.starttlsEnable = startttlsEnable;
- return this;
- }
-
- /**
- * 是否使用 SSL安全连接
- *
- * @return 是否使用 SSL安全连接
- */
- public Boolean isSslEnable() {
- return this.sslEnable;
- }
-
- /**
- * 设置是否使用SSL安全连接
- *
- * @param sslEnable 是否使用SSL安全连接
- * @return this
- */
- public MailAccount setSslEnable(Boolean sslEnable) {
- this.sslEnable = sslEnable;
- return this;
- }
-
- /**
- * 获取SSL协议,多个协议用空格分隔
- *
- * @return SSL协议,多个协议用空格分隔
- * @since 5.5.7
- */
- public String getSslProtocols() {
- return sslProtocols;
- }
-
- /**
- * 设置SSL协议,多个协议用空格分隔
- *
- * @param sslProtocols SSL协议,多个协议用空格分隔
- * @since 5.5.7
- */
- public void setSslProtocols(String sslProtocols) {
- this.sslProtocols = sslProtocols;
- }
-
- /**
- * 获取指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
- *
- * @return 指定实现javax.net.SocketFactory接口的类的名称, 这个类将被用于创建SMTP的套接字
- */
- public String getSocketFactoryClass() {
- return socketFactoryClass;
- }
-
- /**
- * 设置指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
- *
- * @param socketFactoryClass 指定实现javax.net.SocketFactory接口的类的名称,这个类将被用于创建SMTP的套接字
- * @return this
- */
- public MailAccount setSocketFactoryClass(String socketFactoryClass) {
- this.socketFactoryClass = socketFactoryClass;
- return this;
- }
-
- /**
- * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- *
- * @return 如果设置为true, 未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- */
- public boolean isSocketFactoryFallback() {
- return socketFactoryFallback;
- }
-
- /**
- * 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- *
- * @param socketFactoryFallback 如果设置为true,未能创建一个套接字使用指定的套接字工厂类将导致使用java.net.Socket创建的套接字类, 默认值为true
- * @return this
- */
- public MailAccount setSocketFactoryFallback(boolean socketFactoryFallback) {
- this.socketFactoryFallback = socketFactoryFallback;
- return this;
- }
-
- /**
- * 获取指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- *
- * @return 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- */
- public int getSocketFactoryPort() {
- return socketFactoryPort;
- }
-
- /**
- * 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- *
- * @param socketFactoryPort 指定的端口连接到在使用指定的套接字工厂。如果没有设置,将使用默认端口
- * @return this
- */
- public MailAccount setSocketFactoryPort(int socketFactoryPort) {
- this.socketFactoryPort = socketFactoryPort;
- return this;
- }
-
- /**
- * 设置SMTP超时时长,单位毫秒,缺省值不超时
- *
- * @param timeout SMTP超时时长,单位毫秒,缺省值不超时
- * @return this
- * @since 4.1.17
- */
- public MailAccount setTimeout(long timeout) {
- this.timeout = timeout;
- return this;
- }
-
- /**
- * 设置Socket连接超时值,单位毫秒,缺省值不超时
- *
- * @param connectionTimeout Socket连接超时值,单位毫秒,缺省值不超时
- * @return this
- * @since 4.1.17
- */
- public MailAccount setConnectionTimeout(long connectionTimeout) {
- this.connectionTimeout = connectionTimeout;
- return this;
- }
-
- /**
- * 设置Socket写出超时值,单位毫秒,缺省值不超时
- *
- * @param writeTimeout Socket写出超时值,单位毫秒,缺省值不超时
- * @return this
- * @since 5.8.3
- */
- public MailAccount setWriteTimeout(long writeTimeout) {
- this.writeTimeout = writeTimeout;
- return this;
- }
-
- /**
- * 获取自定义属性列表
- *
- * @return 自定义参数列表
- * @since 5.6.4
- */
- public Map getCustomProperty() {
- return customProperty;
- }
-
- /**
- * 设置自定义属性,如mail.smtp.ssl.socketFactory
- *
- * @param key 属性名,空白被忽略
- * @param value 属性值, null被忽略
- * @return this
- * @since 5.6.4
- */
- public MailAccount setCustomProperty(String key, Object value) {
- if (StrUtil.isNotBlank(key) && ObjectUtil.isNotNull(value)) {
- this.customProperty.put(key, value);
- }
- return this;
- }
-
- /**
- * 获得SMTP相关信息
- *
- * @return {@link Properties}
- */
- public Properties getSmtpProps() {
- //全局系统参数
- System.setProperty(SPLIT_LONG_PARAMS, String.valueOf(this.splitlongparameters));
-
- final Properties p = new Properties();
- p.put(MAIL_PROTOCOL, "smtp");
- p.put(SMTP_HOST, this.host);
- p.put(SMTP_PORT, String.valueOf(this.port));
- p.put(SMTP_AUTH, String.valueOf(this.auth));
- if (this.timeout > 0) {
- p.put(SMTP_TIMEOUT, String.valueOf(this.timeout));
- }
- if (this.connectionTimeout > 0) {
- p.put(SMTP_CONNECTION_TIMEOUT, String.valueOf(this.connectionTimeout));
- }
- // issue#2355
- if (this.writeTimeout > 0) {
- p.put(SMTP_WRITE_TIMEOUT, String.valueOf(this.writeTimeout));
- }
-
- p.put(MAIL_DEBUG, String.valueOf(this.debug));
-
- if (this.starttlsEnable) {
- //STARTTLS是对纯文本通信协议的扩展。它将纯文本连接升级为加密连接(TLS或SSL), 而不是使用一个单独的加密通信端口。
- p.put(STARTTLS_ENABLE, "true");
-
- if (null == this.sslEnable) {
- //为了兼容旧版本,当用户没有此项配置时,按照starttlsEnable开启状态时对待
- this.sslEnable = true;
- }
- }
-
- // SSL
- if (null != this.sslEnable && this.sslEnable) {
- p.put(SSL_ENABLE, "true");
- p.put(SOCKET_FACTORY, socketFactoryClass);
- p.put(SOCKET_FACTORY_FALLBACK, String.valueOf(this.socketFactoryFallback));
- p.put(SOCKET_FACTORY_PORT, String.valueOf(this.socketFactoryPort));
- // issue#IZN95@Gitee,在Linux下需自定义SSL协议版本
- if (StrUtil.isNotBlank(this.sslProtocols)) {
- p.put(SSL_PROTOCOLS, this.sslProtocols);
- }
- }
-
- // 补充自定义属性,允许自定属性覆盖已经设置的值
- p.putAll(this.customProperty);
-
- return p;
- }
-
- /**
- * 如果某些值为null,使用默认值
- *
- * @return this
- */
- public MailAccount defaultIfEmpty() {
- // 去掉发件人的姓名部分
- final String fromAddress = InternalMailUtil.parseFirstAddress(this.from, this.charset).getAddress();
-
- if (StrUtil.isBlank(this.host)) {
- // 如果SMTP地址为空,默认使用smtp.<发件人邮箱后缀>
- this.host = StrUtil.format("smtp.{}", StrUtil.subSuf(fromAddress, fromAddress.indexOf('@') + 1));
- }
- if (StrUtil.isBlank(user)) {
- // 如果用户名为空,默认为发件人(issue#I4FYVY@Gitee)
- //this.user = StrUtil.subPre(fromAddress, fromAddress.indexOf('@'));
- this.user = fromAddress;
- }
- if (null == this.auth) {
- // 如果密码非空白,则使用认证模式
- this.auth = (false == StrUtil.isBlank(this.pass));
- }
- if (null == this.port) {
- // 端口在SSL状态下默认与socketFactoryPort一致,非SSL状态下默认为25
- this.port = (null != this.sslEnable && this.sslEnable) ? this.socketFactoryPort : 25;
- }
- if (null == this.charset) {
- // 默认UTF-8编码
- this.charset = CharsetUtil.CHARSET_UTF_8;
- }
-
- return this;
- }
-
- @Override
- public String toString() {
- return "MailAccount [host=" + host + ", port=" + port + ", auth=" + auth + ", user=" + user + ", pass=" + (StrUtil.isEmpty(this.pass) ? "" : "******") + ", from=" + from + ", startttlsEnable="
- + starttlsEnable + ", socketFactoryClass=" + socketFactoryClass + ", socketFactoryFallback=" + socketFactoryFallback + ", socketFactoryPort=" + socketFactoryPort + "]";
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java
deleted file mode 100644
index cc199d455..000000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailException.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import cn.hutool.core.exceptions.ExceptionUtil;
-import cn.hutool.core.util.StrUtil;
-
-import java.io.Serial;
-
-/**
- * 邮件异常
- *
- * @author xiaoleilu
- */
-public class MailException extends RuntimeException {
- @Serial
- private static final long serialVersionUID = 8247610319171014183L;
-
- public MailException(Throwable e) {
- super(ExceptionUtil.getMessage(e), e);
- }
-
- public MailException(String message) {
- super(message);
- }
-
- public MailException(String messageTemplate, Object... params) {
- super(StrUtil.format(messageTemplate, params));
- }
-
- public MailException(String message, Throwable throwable) {
- super(message, throwable);
- }
-
- public MailException(String message, Throwable throwable, boolean enableSuppression, boolean writableStackTrace) {
- super(message, throwable, enableSuppression, writableStackTrace);
- }
-
- public MailException(Throwable throwable, String messageTemplate, Object... params) {
- super(StrUtil.format(messageTemplate, params), throwable);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
index 040cc572a..a28701fbc 100644
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
+++ b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/MailUtils.java
@@ -5,6 +5,9 @@ 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.JakartaMail;
+import cn.hutool.extra.mail.JakartaUserPassAuthenticator;
+import cn.hutool.extra.mail.MailAccount;
import jakarta.mail.Authenticator;
import jakarta.mail.Session;
import lombok.AccessLevel;
@@ -17,7 +20,7 @@ import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;
-
+import java.util.Map.Entry;
/**
* 邮件工具类
@@ -385,7 +388,7 @@ public class MailUtils {
public static Session getSession(MailAccount mailAccount, boolean isSingleton) {
Authenticator authenticator = null;
if (mailAccount.isAuth()) {
- authenticator = new UserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
+ authenticator = new JakartaUserPassAuthenticator(mailAccount.getUser(), mailAccount.getPass());
}
return isSingleton ? Session.getDefaultInstance(mailAccount.getSmtpProps(), authenticator) //
@@ -412,7 +415,7 @@ public class MailUtils {
*/
private static String send(MailAccount mailAccount, boolean useGlobalSession, Collection tos, Collection ccs, Collection bccs, String subject, String content,
Map imageMap, boolean isHtml, File... files) {
- final Mail mail = Mail.create(mailAccount).setUseGlobalSession(useGlobalSession);
+ final JakartaMail mail = JakartaMail.create(mailAccount).setUseGlobalSession(useGlobalSession);
// 可选抄送人
if (CollUtil.isNotEmpty(ccs)) {
@@ -431,7 +434,7 @@ public class MailUtils {
// 图片
if (MapUtil.isNotEmpty(imageMap)) {
- for (Map.Entry entry : imageMap.entrySet()) {
+ for (Entry entry : imageMap.entrySet()) {
mail.addImage(entry.getKey(), entry.getValue());
// 关闭流
IoUtil.close(entry.getValue());
@@ -463,5 +466,4 @@ public class MailUtils {
return result;
}
// ------------------------------------------------------------------------------------------------------------------------ Private method end
-
}
diff --git a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java b/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java
deleted file mode 100644
index fbbe5e371..000000000
--- a/ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/utils/UserPassAuthenticator.java
+++ /dev/null
@@ -1,33 +0,0 @@
-package org.dromara.common.mail.utils;
-
-import jakarta.mail.Authenticator;
-import jakarta.mail.PasswordAuthentication;
-
-/**
- * 用户名密码验证器
- *
- * @author looly
- * @since 3.1.2
- */
-public class UserPassAuthenticator extends Authenticator {
-
- private final String user;
- private final String pass;
-
- /**
- * 构造
- *
- * @param user 用户名
- * @param pass 密码
- */
- public UserPassAuthenticator(String user, String pass) {
- this.user = user;
- this.pass = pass;
- }
-
- @Override
- protected PasswordAuthentication getPasswordAuthentication() {
- return new PasswordAuthentication(this.user, this.pass);
- }
-
-}
diff --git a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
index 455cecb2e..981bd421b 100644
--- a/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
+++ b/ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/enums/DataScopeType.java
@@ -13,9 +13,9 @@ import org.dromara.common.mybatis.helper.DataPermissionHelper;
* 内置数据:
* - {@code user}: 当前登录用户信息,参考 {@link LoginUser}
* 内置服务:
- * - {@code sdss}: 系统数据权限服务,参考 {@link ISysDataScopeService}
+ * - {@code sdss}: 系统数据权限服务,参考 ISysDataScopeService
* 如需扩展数据,可以通过 {@link DataPermissionHelper} 进行操作
- * 如需扩展服务,可以通过 {@link ISysDataScopeService} 自行编写
+ * 如需扩展服务,可以通过 ISysDataScopeService 自行编写
*
*
* @author Lion Li
@@ -32,29 +32,21 @@ public enum DataScopeType {
/**
* 自定数据权限
- * 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} )`
- * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
*/
CUSTOM("2", " #{#deptName} IN ( #{@sdss.getRoleCustom( #user.roleId )} ) ", " 1 = 0 "),
/**
* 部门数据权限
- * 使用 SpEL 表达式:`#{#deptName} = #{#user.deptId}`
- * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
*/
DEPT("3", " #{#deptName} = #{#user.deptId} ", " 1 = 0 "),
/**
* 部门及以下数据权限
- * 使用 SpEL 表达式:`#{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )}`
- * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
*/
DEPT_AND_CHILD("4", " #{#deptName} IN ( #{@sdss.getDeptAndChild( #user.deptId )} )", " 1 = 0 "),
/**
* 仅本人数据权限
- * 使用 SpEL 表达式:`#{#userName} = #{#user.userId}`
- * 如果不满足条件,则使用默认 SQL 表达式:`1 = 0`
*/
SELF("5", " #{#userName} = #{#user.userId} ", " 1 = 0 ");
diff --git a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
index f5db391b8..6e111e3a8 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
+++ b/ruoyi-modules/ruoyi-generator/src/main/java/org/dromara/generator/util/VelocityUtils.java
@@ -215,6 +215,9 @@ public class VelocityUtils {
importList.add("com.fasterxml.jackson.annotation.JsonFormat");
} else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) {
importList.add("java.math.BigDecimal");
+ } else if (!column.isSuperColumn() && "imageUpload".equals(column.getHtmlType())) {
+ importList.add("org.dromara.common.translation.annotation.Translation");
+ importList.add("org.dromara.common.translation.constant.TransConstant");
}
}
return importList;
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
index f99a2ed9a..c896afbe8 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/java/vo.java.vm
@@ -53,6 +53,13 @@ public class ${ClassName}Vo implements Serializable {
#end
private $column.javaType $column.javaField;
+#if($column.htmlType == "imageUpload")
+ /**
+ * ${column.columnComment}Url
+ */
+ @Translation(type = TransConstant.OSS_ID_TO_URL, mapper = "${column.javaField}")
+ private String ${column.javaField}Url";
+#end
#end
#end
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
index c3f6ed1f8..35a468e80 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/ts/types.ts.vm
@@ -9,6 +9,12 @@ export interface ${BusinessName}VO {
#elseif($column.javaType == 'Boolean') boolean;
#else string;
#end
+#if($column.htmlType == "imageUpload")
+ /**
+ * ${column.columnComment}Url
+ */
+ ${column.javaField}Url: string;
+#end
#end
#end
#if ($table.tree)
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
index d13ef2f27..caf3472e1 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -99,9 +99,9 @@
#elseif($column.list && $column.htmlType == "imageUpload")
-
+
-
+
#elseif($column.list && $column.dictType && "" != $column.dictType)
diff --git a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
index 886f4ab71..a92d19adc 100644
--- a/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
+++ b/ruoyi-modules/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -101,9 +101,9 @@
#elseif($column.list && $column.htmlType == "imageUpload")
-
+
-
+
#elseif($column.list && $column.dictType && "" != $column.dictType)
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
index 4f5f23f32..968bbe906 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
@@ -12,6 +12,7 @@ import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysDeptBo;
import org.dromara.system.domain.vo.SysDeptVo;
import org.dromara.system.service.ISysDeptService;
+import org.dromara.system.service.ISysPostService;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@@ -29,6 +30,7 @@ import java.util.List;
public class SysDeptController extends BaseController {
private final ISysDeptService deptService;
+ private final ISysPostService postService;
/**
* 获取部门列表
@@ -117,6 +119,9 @@ public class SysDeptController extends BaseController {
if (deptService.checkDeptExistUser(deptId)) {
return R.warn("部门存在用户,不允许删除");
}
+ if (postService.countPostByDeptId(deptId) > 0) {
+ return R.warn("部门存在岗位,不允许删除");
+ }
deptService.checkDeptDataScope(deptId);
return toAjax(deptService.deleteDeptById(deptId));
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
index 559e1d59b..893b381e3 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
@@ -11,6 +11,7 @@ import org.dromara.common.encrypt.annotation.ApiEncrypt;
import org.dromara.common.idempotent.annotation.RepeatSubmit;
import org.dromara.common.log.annotation.Log;
import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.helper.DataPermissionHelper;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysUserBo;
@@ -72,7 +73,8 @@ public class SysProfileController extends BaseController {
if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
return R.fail("修改用户'" + username + "'失败,邮箱账号已存在");
}
- if (userService.updateUserProfile(user) > 0) {
+ int rows = DataPermissionHelper.ignore(() -> userService.updateUserProfile(user));
+ if (rows > 0) {
return R.ok();
}
return R.fail("修改个人信息异常,请联系管理员");
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
index 7d99916d0..acaf5f83c 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
@@ -92,6 +92,9 @@ public class SysTenantPackageController extends BaseController {
@RepeatSubmit()
@PostMapping()
public R add(@Validated(AddGroup.class) @RequestBody SysTenantPackageBo bo) {
+ if (!tenantPackageService.checkPackageNameUnique(bo)) {
+ return R.fail("新增套餐'" + bo.getPackageName() + "'失败,套餐名称已存在");
+ }
return toAjax(tenantPackageService.insertByBo(bo));
}
@@ -104,6 +107,9 @@ public class SysTenantPackageController extends BaseController {
@RepeatSubmit()
@PutMapping()
public R edit(@Validated(EditGroup.class) @RequestBody SysTenantPackageBo bo) {
+ if (!tenantPackageService.checkPackageNameUnique(bo)) {
+ return R.fail("修改套餐'" + bo.getPackageName() + "'失败,套餐名称已存在");
+ }
return toAjax(tenantPackageService.updateByBo(bo));
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
index d1f405919..86249d20e 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
@@ -61,13 +61,13 @@ public class SysUserVo implements Serializable {
/**
* 用户邮箱
*/
- @Sensitive(strategy = SensitiveStrategy.EMAIL)
+ @Sensitive(strategy = SensitiveStrategy.EMAIL, perms = "system:user:edit")
private String email;
/**
* 手机号码
*/
- @Sensitive(strategy = SensitiveStrategy.PHONE)
+ @Sensitive(strategy = SensitiveStrategy.PHONE, perms = "system:user:edit")
private String phonenumber;
/**
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
index c43f0395c..3751b23be 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
@@ -80,6 +80,14 @@ public interface ISysPostService {
*/
long countUserPostById(Long postId);
+ /**
+ * 通过部门ID查询岗位使用数量
+ *
+ * @param deptId 部门id
+ * @return 结果
+ */
+ long countPostByDeptId(Long deptId);
+
/**
* 删除岗位信息
*
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
index cdb887ca6..d060b68cd 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
@@ -1,9 +1,9 @@
package org.dromara.system.service;
-import org.dromara.system.domain.vo.SysTenantPackageVo;
-import org.dromara.system.domain.bo.SysTenantPackageBo;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysTenantPackageBo;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
import java.util.Collection;
import java.util.List;
@@ -45,6 +45,11 @@ public interface ISysTenantPackageService {
*/
Boolean updateByBo(SysTenantPackageBo bo);
+ /**
+ * 校验套餐名称是否唯一
+ */
+ boolean checkPackageNameUnique(SysTenantPackageBo bo);
+
/**
* 修改套餐状态
*/
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
index a31c42635..018f9a07a 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
@@ -2,6 +2,7 @@ package org.dromara.system.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.StreamUtils;
@@ -38,6 +39,9 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
*/
@Override
public String getRoleCustom(Long roleId) {
+ if (ObjectUtil.isNull(roleId)) {
+ return "-1";
+ }
List list = roleDeptMapper.selectList(
new LambdaQueryWrapper()
.select(SysRoleDept::getDeptId)
@@ -45,7 +49,7 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
if (CollUtil.isNotEmpty(list)) {
return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId()));
}
- return null;
+ return "-1";
}
/**
@@ -56,6 +60,9 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
*/
@Override
public String getDeptAndChild(Long deptId) {
+ if (ObjectUtil.isNull(deptId)) {
+ return "-1";
+ }
List deptList = deptMapper.selectList(new LambdaQueryWrapper()
.select(SysDept::getDeptId)
.apply(DataBaseHelper.findInSet(deptId, "ancestors")));
@@ -64,7 +71,7 @@ public class SysDataScopeServiceImpl implements ISysDataScopeService {
if (CollUtil.isNotEmpty(ids)) {
return StreamUtils.join(ids, Convert::toStr);
}
- return null;
+ return "-1";
}
}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
index b95baf44b..dfd490ae9 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
@@ -55,7 +55,7 @@ public class SysLogininforServiceImpl implements ISysLogininforService {
@Async
@EventListener
public void recordLogininfor(LogininforEvent logininforEvent) {
- HttpServletRequest request = logininforEvent.getRequest();
+ HttpServletRequest request = ServletUtils.getRequest();
final UserAgent userAgent = UserAgentUtil.parse(request.getHeader("User-Agent"));
final String ip = ServletUtils.getClientIP(request);
// 客户端信息
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
index b78b9dcc8..45f263839 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
@@ -3,18 +3,23 @@ package org.dromara.system.service.impl;
import cn.hutool.core.util.ArrayUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import jakarta.servlet.http.HttpServletRequest;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.utils.MapstructUtils;
-import org.dromara.common.mybatis.core.page.PageQuery;
-import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.core.utils.ip.AddressUtils;
+import org.dromara.common.log.enums.BusinessStatus;
import org.dromara.common.log.event.OperLogEvent;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysOperLog;
import org.dromara.system.domain.bo.SysOperLogBo;
import org.dromara.system.domain.vo.SysOperLogVo;
import org.dromara.system.mapper.SysOperLogMapper;
import org.dromara.system.service.ISysOperLogService;
-import lombok.RequiredArgsConstructor;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
@@ -44,6 +49,18 @@ public class SysOperLogServiceImpl implements ISysOperLogService {
@EventListener
public void recordOper(OperLogEvent operLogEvent) {
SysOperLogBo operLog = MapstructUtils.convert(operLogEvent, SysOperLogBo.class);
+ operLog.setTenantId(LoginHelper.getTenantId());
+ operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
+ // 请求的地址
+ String ip = ServletUtils.getClientIP();
+ operLog.setOperIp(ip);
+ HttpServletRequest request = ServletUtils.getRequest();
+ operLog.setOperUrl(StringUtils.substring(request.getRequestURI(), 0, 255));
+ LoginUser loginUser = LoginHelper.getLoginUser();
+ operLog.setOperName(loginUser.getUsername());
+ operLog.setDeptName(loginUser.getDeptName());
+ // 设置请求方式
+ operLog.setRequestMethod(request.getMethod());
// 远程查询操作地点
operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
insertOperlog(operLog);
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
index b8a7e607a..2c38129ac 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
@@ -177,6 +177,17 @@ public class SysPostServiceImpl implements ISysPostService {
return userPostMapper.selectCount(new LambdaQueryWrapper().eq(SysUserPost::getPostId, postId));
}
+ /**
+ * 通过部门ID查询岗位使用数量
+ *
+ * @param deptId 部门id
+ * @return 结果
+ */
+ @Override
+ public long countPostByDeptId(Long deptId) {
+ return baseMapper.selectCount(new LambdaQueryWrapper().eq(SysPost::getDeptId, deptId));
+ }
+
/**
* 删除岗位信息
*
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
index 31f949836..9b8b0ecbe 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
@@ -293,6 +293,10 @@ public class SysRoleServiceImpl implements ISysRoleService {
@Transactional(rollbackFor = Exception.class)
public int updateRole(SysRoleBo bo) {
SysRole role = MapstructUtils.convert(bo, SysRole.class);
+
+ if (UserConstants.ROLE_DISABLE.equals(role.getStatus()) && this.countUserRoleByRoleId(role.getRoleId()) > 0) {
+ throw new ServiceException("角色已分配,不能禁用!");
+ }
// 修改角色信息
baseMapper.updateById(role);
// 删除角色与菜单关联
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
index 5fd04af8e..d2a72f611 100644
--- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
@@ -1,6 +1,7 @@
package org.dromara.system.service.impl;
import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -116,6 +117,17 @@ public class SysTenantPackageServiceImpl implements ISysTenantPackageService {
return baseMapper.updateById(update) > 0;
}
+ /**
+ * 校验套餐名称是否唯一
+ */
+ @Override
+ public boolean checkPackageNameUnique(SysTenantPackageBo bo) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper()
+ .eq(SysTenantPackage::getPackageName, bo.getPackageName())
+ .ne(ObjectUtil.isNotNull(bo.getPackageId()), SysTenantPackage::getPackageId, bo.getPackageId()));
+ return !exist;
+ }
+
/**
* 修改套餐状态
*