feat: 增加演示模式

This commit is contained in:
ageerle
2025-07-31 14:58:29 +08:00
parent 3c60f43daa
commit cdef9e1c89
4 changed files with 132 additions and 6 deletions

View File

@@ -17,8 +17,8 @@ spring:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: ruoyi-ai
password: ruoyi-ai
username: root
password: root
hikari:
# 最大连接池数量

View File

@@ -2,15 +2,13 @@
# 项目相关配置
ruoyi:
# 名称
name: "ruoyi"
name: "ruoyi-ai"
# 版本
version: ${revision}
# 版权年份
copyrightYear: 2025
# 实例演示开关
demoEnabled: true
# 获取ip地址开关
addressEnabled: false
demoEnabled: false
captcha:
enable: false

View File

@@ -1,6 +1,9 @@
package org.ruoyi.common.web.config;
import org.ruoyi.common.web.interceptor.DemoModeInterceptor;
import org.ruoyi.common.web.interceptor.PlusWebInvokeTimeInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.web.cors.CorsConfiguration;
@@ -18,10 +21,35 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@AutoConfiguration
public class ResourcesConfig implements WebMvcConfigurer {
@Autowired(required = false)
private DemoModeInterceptor demoModeInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 全局访问性能拦截
registry.addInterceptor(new PlusWebInvokeTimeInterceptor());
// 演示模式拦截器
if (demoModeInterceptor != null) {
registry.addInterceptor(demoModeInterceptor)
.addPathPatterns("/**") // 拦截所有路径
.excludePathPatterns(
// 排除静态资源
"/css/**",
"/js/**",
"/images/**",
"/fonts/**",
"/favicon.ico",
// 排除错误页面
"/error",
// 排除API文档
"/*/api-docs/**",
"/swagger-ui/**",
"/webjars/**",
// 排除监控端点
"/actuator/**"
);
}
}
@Override

View File

@@ -0,0 +1,100 @@
package org.ruoyi.common.web.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.core.config.RuoYiConfig;
import org.ruoyi.common.core.exception.DemoModeException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* 演示模式拦截器
* 全局拦截所有编辑操作POST、PUT、DELETE、PATCH
*
* @author ruoyi
*/
@Slf4j
@Component
public class DemoModeInterceptor implements HandlerInterceptor {
@Autowired
private RuoYiConfig ruoYiConfig;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 如果演示模式未开启,直接放行
if (!ruoYiConfig.isDemoEnabled()) {
return true;
}
String method = request.getMethod();
String requestURI = request.getRequestURI();
// 拦截所有编辑操作
if (isEditOperation(method)) {
// 排除一些特殊的只读操作
if (isExcludedPath(requestURI)) {
return true;
}
log.warn("演示模式拦截: {} {}", method, requestURI);
throw new DemoModeException();
}
return true;
}
/**
* 判断是否为编辑操作
*/
private boolean isEditOperation(String method) {
return "POST".equalsIgnoreCase(method)
|| "PUT".equalsIgnoreCase(method)
|| "DELETE".equalsIgnoreCase(method)
|| "PATCH".equalsIgnoreCase(method);
}
/**
* 判断是否为排除的路径这些路径即使是POST等方法也不拦截
*/
private boolean isExcludedPath(String requestURI) {
// 排除登录相关
if (requestURI.contains("/auth/login") || requestURI.contains("/auth/logout")) {
return true;
}
// 排除导出操作虽然是POST但是只读操作
if (requestURI.contains("/export")) {
return true;
}
// 排除查询操作一些复杂查询使用POST
if (requestURI.contains("/list") || requestURI.contains("/query")) {
return true;
}
// 排除聊天接口(核心功能)
if (requestURI.contains("/chat/send") || requestURI.contains("/chat/upload")) {
return true;
}
// 排除文件上传预览等只读操作
if (requestURI.contains("/upload") || requestURI.contains("/preview")) {
return true;
}
// 排除支付回调
if (requestURI.contains("/pay/returnUrl") || requestURI.contains("/pay/notifyUrl")) {
return true;
}
// 排除重置密码(用户自己的操作)
if (requestURI.contains("/auth/reset/password")) {
return true;
}
return false;
}
}