mirror of https://github.com/jeecgboot/jeecg-boot
Merge 016ab6e5ba
into c4a87d7c58
commit
2a370d746a
|
@ -16,10 +16,10 @@ public class WebSocketConfig {
|
||||||
* 注入ServerEndpointExporter,
|
* 注入ServerEndpointExporter,
|
||||||
* 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
|
* 这个bean会自动注册使用了@ServerEndpoint注解声明的Websocket endpoint
|
||||||
*/
|
*/
|
||||||
@Bean
|
// @Bean
|
||||||
public ServerEndpointExporter serverEndpointExporter() {
|
// public ServerEndpointExporter serverEndpointExporter() {
|
||||||
return new ServerEndpointExporter();
|
// return new ServerEndpointExporter();
|
||||||
}
|
// }
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public WebsocketFilter websocketFilter(){
|
public WebsocketFilter websocketFilter(){
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
package org.jeecg.config.security;
|
package org.jeecg.config.security;
|
||||||
|
|
||||||
import io.undertow.servlet.spec.HttpServletRequestImpl;
|
|
||||||
import io.undertow.util.HttpString;
|
|
||||||
import jakarta.servlet.FilterChain;
|
import jakarta.servlet.FilterChain;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletRequestWrapper;
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.springframework.core.annotation.Order;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -12,34 +11,100 @@ import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.filter.OncePerRequestFilter;
|
import org.springframework.web.filter.OncePerRequestFilter;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 复制仪盘表请求query体携带的token
|
* 复制仪盘表请求query体携带的token
|
||||||
* @author eightmonth
|
* 注意:改为容器无关实现,避免 Undertow 专有类型转换导致在 Tomcat 下 ClassCastException。
|
||||||
* @date 2024/7/3 14:04
|
*
|
||||||
|
* 来源优先级:
|
||||||
|
* 1. Authorization 头(若存在则规范为 Bearer <token> 格式)
|
||||||
|
* 2. 查询参数 token
|
||||||
|
* 3. 自定义头 X-Access-Token
|
||||||
|
*
|
||||||
|
* 若最终获得 token,则通过请求包装器注入 Authorization 头,保持对下游过滤器/安全链可见。
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Order(value = Integer.MIN_VALUE)
|
@Order(value = Integer.MIN_VALUE)
|
||||||
public class CopyTokenFilter extends OncePerRequestFilter {
|
public class CopyTokenFilter extends OncePerRequestFilter {
|
||||||
@Override
|
@Override
|
||||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||||
// 以下为undertow定制代码,如切换其它servlet容器,需要同步更换
|
// 容器无关实现:根据 header/参数提取 token,并以 Authorization 注入
|
||||||
HttpServletRequestImpl undertowRequest = (HttpServletRequestImpl) request;
|
String tokenHeader = request.getHeader("Authorization");
|
||||||
String token = request.getHeader("Authorization");
|
String candidate = null;
|
||||||
if (StringUtils.hasText(token)) {
|
if (StringUtils.hasText(tokenHeader)) {
|
||||||
undertowRequest.getExchange().getRequestHeaders().remove("Authorization");
|
String trimmed = tokenHeader.trim();
|
||||||
undertowRequest.getExchange().getRequestHeaders().add(new HttpString("Authorization"), "bearer " + token);
|
if (startsWithIgnoreCase(trimmed, "Bearer ")) {
|
||||||
|
candidate = trimmed;
|
||||||
|
} else if (!trimmed.contains(" ")) { // 纯 token,无空格,视为需要规范化
|
||||||
|
candidate = trimmed;
|
||||||
|
} // 其他认证方案(如 Basic ...)保持不处理
|
||||||
} else {
|
} else {
|
||||||
String bearerToken = request.getParameter("token");
|
String bearerToken = request.getParameter("token");
|
||||||
String headerBearerToken = request.getHeader("X-Access-Token");
|
String headerBearerToken = request.getHeader("X-Access-Token");
|
||||||
if (StringUtils.hasText(bearerToken)) {
|
if (StringUtils.hasText(bearerToken)) {
|
||||||
undertowRequest.getExchange().getRequestHeaders().add(new HttpString("Authorization"), "bearer " + bearerToken);
|
candidate = bearerToken.trim();
|
||||||
} else if (StringUtils.hasText(headerBearerToken)) {
|
} else if (StringUtils.hasText(headerBearerToken)) {
|
||||||
undertowRequest.getExchange().getRequestHeaders().add(new HttpString("Authorization"), "bearer " + headerBearerToken);
|
candidate = headerBearerToken.trim();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
filterChain.doFilter(undertowRequest, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
if (StringUtils.hasText(candidate)) {
|
||||||
|
final String authValue = startsWithIgnoreCase(candidate, "Bearer ") ? candidate : ("Bearer " + candidate);
|
||||||
|
HttpServletRequest wrapped = new AuthorizationHeaderRequestWrapper(request, authValue);
|
||||||
|
filterChain.doFilter(wrapped, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
filterChain.doFilter(request, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean startsWithIgnoreCase(String str, String prefix) {
|
||||||
|
if (str == null || prefix == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (prefix.length() > str.length()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return str.regionMatches(true, 0, prefix, 0, prefix.length());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class AuthorizationHeaderRequestWrapper extends HttpServletRequestWrapper {
|
||||||
|
private final String authorization;
|
||||||
|
|
||||||
|
AuthorizationHeaderRequestWrapper(HttpServletRequest request, String authorization) {
|
||||||
|
super(request);
|
||||||
|
this.authorization = authorization;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getHeader(String name) {
|
||||||
|
if ("Authorization".equalsIgnoreCase(name)) {
|
||||||
|
return authorization;
|
||||||
|
}
|
||||||
|
return super.getHeader(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> getHeaders(String name) {
|
||||||
|
if ("Authorization".equalsIgnoreCase(name)) {
|
||||||
|
return Collections.enumeration(Collections.singletonList(authorization));
|
||||||
|
}
|
||||||
|
return super.getHeaders(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Enumeration<String> getHeaderNames() {
|
||||||
|
Set<String> names = new LinkedHashSet<>();
|
||||||
|
Enumeration<String> e = super.getHeaderNames();
|
||||||
|
while (e.hasMoreElements()) {
|
||||||
|
names.add(e.nextElement());
|
||||||
|
}
|
||||||
|
names.add("Authorization");
|
||||||
|
return Collections.enumeration(names);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -207,6 +207,9 @@ public class SecurityConfig {
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/openapi/call/**")).permitAll()
|
.requestMatchers(AntPathRequestMatcher.antMatcher("/openapi/call/**")).permitAll()
|
||||||
// APP版本信息
|
// APP版本信息
|
||||||
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/version/app3version")).permitAll()
|
.requestMatchers(AntPathRequestMatcher.antMatcher("/sys/version/app3version")).permitAll()
|
||||||
|
// mcp接口
|
||||||
|
.requestMatchers(AntPathRequestMatcher.antMatcher("/sse")).permitAll()
|
||||||
|
.requestMatchers(AntPathRequestMatcher.antMatcher("/mcp/message")).permitAll()
|
||||||
.anyRequest().authenticated()
|
.anyRequest().authenticated()
|
||||||
)
|
)
|
||||||
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::disable))
|
||||||
|
|
|
@ -22,7 +22,7 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@Component
|
@Component
|
||||||
@ServerEndpoint("/vxeSocket/{userId}/{pageId}")
|
//@ServerEndpoint("/vxeSocket/{userId}/{pageId}")
|
||||||
public class VxeSocket {
|
public class VxeSocket {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
<parent>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-boot-parent</artifactId>
|
||||||
|
<version>3.8.2</version>
|
||||||
|
<relativePath>../../pom.xml</relativePath>
|
||||||
|
</parent>
|
||||||
|
|
||||||
|
<artifactId>jeecg-module-mcp-server</artifactId>
|
||||||
|
|
||||||
|
<properties>
|
||||||
|
<maven.compiler.source>17</maven.compiler.source>
|
||||||
|
<maven.compiler.target>17</maven.compiler.target>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
</properties>
|
||||||
|
|
||||||
|
|
||||||
|
<dependencies>
|
||||||
|
<!-- SYSTEM 系统管理模块 -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-system-biz</artifactId>
|
||||||
|
<version>${jeecgboot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
<!-- MCP-Server -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.ai</groupId>
|
||||||
|
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
|
||||||
|
</dependency>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
</project>
|
|
@ -0,0 +1,130 @@
|
||||||
|
package org.jeecg.modules.mcp;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import dev.langchain4j.agent.tool.ToolSpecification;
|
||||||
|
import dev.langchain4j.mcp.McpToolProvider;
|
||||||
|
import dev.langchain4j.mcp.client.DefaultMcpClient;
|
||||||
|
import dev.langchain4j.mcp.client.McpClient;
|
||||||
|
import dev.langchain4j.mcp.client.transport.McpTransport;
|
||||||
|
import dev.langchain4j.mcp.client.transport.http.HttpMcpTransport;
|
||||||
|
import dev.langchain4j.model.chat.ChatModel;
|
||||||
|
import dev.langchain4j.model.chat.request.json.JsonObjectSchema;
|
||||||
|
import dev.langchain4j.model.chat.request.json.JsonStringSchema;
|
||||||
|
import dev.langchain4j.service.AiServices;
|
||||||
|
import dev.langchain4j.service.tool.ToolExecutor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.jeecg.ai.assistant.AiChatAssistant;
|
||||||
|
import org.jeecg.ai.factory.AiModelFactory;
|
||||||
|
import org.jeecg.ai.factory.AiModelOptions;
|
||||||
|
import org.jeecg.common.api.vo.Result;
|
||||||
|
import org.jeecg.common.system.api.ISysBaseAPI;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: llm工具调用测试接口
|
||||||
|
* @Author: chenrui
|
||||||
|
* @Date: 2025/8/22 14:13
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/ai/tools/test")
|
||||||
|
@Slf4j
|
||||||
|
public class LlmToolsTestController {
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ISysBaseAPI sysBaseAPI;
|
||||||
|
|
||||||
|
// 根据环境构建模型配置;缺少关键项则返回 null 以便测试跳过
|
||||||
|
private static AiModelOptions buildModelOptionsFromEnv() {
|
||||||
|
String baseUrl = "https://api.gpt.ge";
|
||||||
|
String apiKey = "sk-ZLhvUUGPGyERkPya632f3f18209946F7A51d4479081a3dFb";
|
||||||
|
String modelName = "gpt-4.1-mini";
|
||||||
|
return AiModelOptions.builder()
|
||||||
|
.provider(AiModelFactory.AIMODEL_TYPE_OPENAI)
|
||||||
|
.modelName(modelName)
|
||||||
|
.baseUrl(baseUrl)
|
||||||
|
.apiKey(apiKey)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping(value = "/queryUser")
|
||||||
|
public Result<?> queryUser(@RequestParam(value = "prompt", required = true) String prompt) {
|
||||||
|
AiModelOptions modelOp = buildModelOptionsFromEnv();
|
||||||
|
ToolSpecification toolSpecification = ToolSpecification.builder()
|
||||||
|
.name("query_user_by_name")
|
||||||
|
.description("通过通过用户名查询用户信息,返回用户信息列表")
|
||||||
|
.parameters(JsonObjectSchema.builder()
|
||||||
|
.addProperties(Map.of(
|
||||||
|
"username", JsonStringSchema.builder()
|
||||||
|
.description("用户名,多个可以使用逗号分隔")
|
||||||
|
.build()
|
||||||
|
))
|
||||||
|
.build())
|
||||||
|
.build();
|
||||||
|
ToolExecutor toolExecutor = (toolExecutionRequest, memoryId) -> {
|
||||||
|
Map<String, Object> arguments = JSONObject.parseObject(toolExecutionRequest.arguments());
|
||||||
|
String username = arguments.get("username").toString();
|
||||||
|
List<JSONObject> users = sysBaseAPI.queryUsersByUsernames(username);
|
||||||
|
return JSONObject.toJSONString(users);
|
||||||
|
};
|
||||||
|
|
||||||
|
// 构建同步聊天模型并通过 AiChatAssistant 发起一次非流式对话
|
||||||
|
ChatModel chatModel = AiModelFactory.createChatModel(modelOp);
|
||||||
|
AiChatAssistant bot = AiServices.builder(AiChatAssistant.class)
|
||||||
|
.chatModel(chatModel)
|
||||||
|
.tools(Map.of(toolSpecification, toolExecutor))
|
||||||
|
.tools()
|
||||||
|
.build();
|
||||||
|
String chat = bot.chat(prompt);
|
||||||
|
log.info("聊天回复: " + chat);
|
||||||
|
return Result.OK(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据环境构建 MCP 工具提供者;缺少 URL 则返回 null 以便测试跳过
|
||||||
|
private static McpToolProvider buildMcpTool(String sseUrl) {
|
||||||
|
McpTransport transport = new HttpMcpTransport.Builder()
|
||||||
|
.sseUrl(sseUrl)
|
||||||
|
.logRequests(true)
|
||||||
|
.logResponses(true)
|
||||||
|
.build();
|
||||||
|
McpClient mcpClient = new DefaultMcpClient.Builder()
|
||||||
|
.transport(transport)
|
||||||
|
.build();
|
||||||
|
return McpToolProvider.builder()
|
||||||
|
.mcpClients(List.of(mcpClient))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试JeecgMcp
|
||||||
|
* @author chenrui
|
||||||
|
* @date 2025/8/22 10:10
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/queryUserByMcp")
|
||||||
|
public Result<?> testJeecgToolProvider(@RequestParam(value = "prompt", required = true) String prompt) {
|
||||||
|
// prompt = "查询一下有没有用户名是admin的用户信息";
|
||||||
|
// prompt = "新建一个顶级部门,部门名称是:测试部门,机构类别是公司";
|
||||||
|
AiModelOptions modelOp = buildModelOptionsFromEnv();
|
||||||
|
McpToolProvider toolProvider = buildMcpTool("http://localhost:8080/jeecgboot/sse");
|
||||||
|
|
||||||
|
// 构建同步聊天模型并通过 AiChatAssistant 发起一次非流式对话
|
||||||
|
ChatModel chatModel = AiModelFactory.createChatModel(modelOp);
|
||||||
|
AiChatAssistant bot = AiServices.builder(AiChatAssistant.class)
|
||||||
|
.chatModel(chatModel)
|
||||||
|
.toolProvider(toolProvider)
|
||||||
|
.build();
|
||||||
|
String chat = bot.chat(prompt);
|
||||||
|
log.info("聊天回复: " + chat);
|
||||||
|
return Result.OK(chat);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
package org.jeecg.modules.mcp;
|
||||||
|
|
||||||
|
import org.springframework.ai.tool.ToolCallbackProvider;
|
||||||
|
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description:
|
||||||
|
* @Author: chenrui
|
||||||
|
* @Date: 2025/8/21 17:19
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class McpConfiguration {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ToolCallbackProvider weatherTools(UserMcpTool userMcpTool) {
|
||||||
|
return MethodToolCallbackProvider.builder().toolObjects(userMcpTool).build();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package org.jeecg.modules.mcp;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import org.jeecg.common.system.api.ISysBaseAPI;
|
||||||
|
import org.jeecg.modules.system.entity.SysDepart;
|
||||||
|
import org.jeecg.modules.system.service.ISysDepartService;
|
||||||
|
import org.springframework.ai.tool.annotation.Tool;
|
||||||
|
import org.springframework.ai.tool.annotation.ToolParam;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description:
|
||||||
|
* @Author: chenrui
|
||||||
|
* @Date: 2025/8/21 17:10
|
||||||
|
*/
|
||||||
|
@Service("userMcpService")
|
||||||
|
public class UserMcpTool {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ISysBaseAPI sysBaseAPI;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
ISysDepartService sysDepartmentService;
|
||||||
|
|
||||||
|
@Tool(name = "query_user_by_name", description = "通过通过用户名查询用户信息,返回用户信息列表")
|
||||||
|
public String queryUserByUsername(@ToolParam(description = "用户名,多个可以使用逗号分隔", required = true) String username) {
|
||||||
|
if (username == null || username.isEmpty()) {
|
||||||
|
return "Username cannot be null or empty";
|
||||||
|
}
|
||||||
|
List<JSONObject> users = sysBaseAPI.queryUsersByUsernames(username);
|
||||||
|
return JSONObject.toJSONString(users);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Tool(name = "add_depart", description = "新增部门信息,返回操作结果")
|
||||||
|
public String saveDepartData(@ToolParam(description = "部门信息,departName(部门名称,必填),orgCategory(机构类别,必填, 1=公司,2=组织机构,3=岗位),parentId(父部门:父级部门的id,非必填)", required = true) SysDepart sysDepart){
|
||||||
|
try {
|
||||||
|
sysDepartmentService.saveDepartData(sysDepart, "mcpService");
|
||||||
|
} catch (Exception e) {
|
||||||
|
return "创建部门失败,原因:"+e.getMessage();
|
||||||
|
}
|
||||||
|
return "创建部门成功";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -21,7 +21,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@Slf4j
|
@Slf4j
|
||||||
@ServerEndpoint("/websocket/{userId}")
|
//@ServerEndpoint("/websocket/{userId}")
|
||||||
public class WebSocket {
|
public class WebSocket {
|
||||||
|
|
||||||
/**线程安全Map*/
|
/**线程安全Map*/
|
||||||
|
|
|
@ -25,6 +25,12 @@
|
||||||
<version>${jeecgboot.version}</version>
|
<version>${jeecgboot.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
|
<artifactId>jeecg-module-mcp-server</artifactId>
|
||||||
|
<version>${jeecgboot.version}</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- flyway 数据库自动升级
|
<!-- flyway 数据库自动升级
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.flywaydb</groupId>
|
<groupId>org.flywaydb</groupId>
|
||||||
|
|
|
@ -25,6 +25,12 @@ management:
|
||||||
include: metrics,httpexchanges,jeecghttptrace
|
include: metrics,httpexchanges,jeecghttptrace
|
||||||
|
|
||||||
spring:
|
spring:
|
||||||
|
ai:
|
||||||
|
mcp:
|
||||||
|
server:
|
||||||
|
name: jeecg-mcp-server
|
||||||
|
version: 1.0.0
|
||||||
|
base-url: /jeecgboot
|
||||||
flyway:
|
flyway:
|
||||||
# 是否启用flyway
|
# 是否启用flyway
|
||||||
enabled: true
|
enabled: true
|
||||||
|
@ -151,7 +157,7 @@ spring:
|
||||||
slow-sql-millis: 5000
|
slow-sql-millis: 5000
|
||||||
datasource:
|
datasource:
|
||||||
master:
|
master:
|
||||||
url: jdbc:mysql://127.0.0.1:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
|
url: jdbc:mysql://jeecg-boot-mysql:3306/jeecg-boot?characterEncoding=UTF-8&useUnicode=true&useSSL=false&tinyInt1isBit=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai
|
||||||
username: root
|
username: root
|
||||||
password: root
|
password: root
|
||||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||||
|
@ -165,7 +171,7 @@ spring:
|
||||||
data:
|
data:
|
||||||
redis:
|
redis:
|
||||||
database: 0
|
database: 0
|
||||||
host: 127.0.0.1
|
host: jeecg-boot-redis
|
||||||
port: 6379
|
port: 6379
|
||||||
password:
|
password:
|
||||||
#mybatis plus 设置
|
#mybatis plus 设置
|
||||||
|
|
|
@ -167,6 +167,14 @@
|
||||||
<type>pom</type>
|
<type>pom</type>
|
||||||
<scope>import</scope>
|
<scope>import</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<!-- spring-ai -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.ai</groupId>
|
||||||
|
<artifactId>spring-ai-bom</artifactId>
|
||||||
|
<version>1.0.1</version>
|
||||||
|
<type>pom</type>
|
||||||
|
<scope>import</scope>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- system 模块-->
|
<!-- system 模块-->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -481,7 +489,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.jeecgframework.boot</groupId>
|
<groupId>org.jeecgframework.boot</groupId>
|
||||||
<artifactId>jeecg-boot-starter3-chatgpt</artifactId>
|
<artifactId>jeecg-boot-starter3-chatgpt</artifactId>
|
||||||
<version>${jeecgboot.version}</version>
|
<version>3.8.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--flyway 支持 mysql5.7+、MariaDB10.3.16-->
|
<!--flyway 支持 mysql5.7+、MariaDB10.3.16-->
|
||||||
<!--mysql5.6,需要把版本号改成5.2.1-->
|
<!--mysql5.6,需要把版本号改成5.2.1-->
|
||||||
|
|
Loading…
Reference in New Issue