diff --git a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java index 07595e092..a958de62d 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/listener/UserActionListener.java @@ -71,7 +71,6 @@ public class UserActionListener implements SaTokenListener { logininforEvent.setUsername(username); logininforEvent.setStatus(Constants.LOGIN_SUCCESS); logininforEvent.setMessage(MessageUtils.message("user.login.success")); - logininforEvent.setRequest(ServletUtils.getRequest()); SpringUtils.context().publishEvent(logininforEvent); // 更新登录信息 loginService.recordLoginInfo((Long) loginModel.getExtra(LoginHelper.USER_KEY), ip); diff --git a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java index 52803663c..3ee67630b 100644 --- a/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java +++ b/ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java @@ -139,7 +139,6 @@ public class SysLoginService { logininforEvent.setUsername(username); logininforEvent.setStatus(status); logininforEvent.setMessage(message); - logininforEvent.setRequest(ServletUtils.getRequest()); SpringUtils.context().publishEvent(logininforEvent); } 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-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);