diff --git a/magic-api-plugins/magic-api-plugin-springdoc/pom.xml b/magic-api-plugins/magic-api-plugin-springdoc/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a83036ed5366f69f5b9fc8ce3e2f400220af45ad
--- /dev/null
+++ b/magic-api-plugins/magic-api-plugin-springdoc/pom.xml
@@ -0,0 +1,50 @@
+
+
+ 4.0.0
+
+ org.ssssssss
+ magic-api-plugins
+ 2.0.2
+
+ magic-api-plugin-springdoc
+ jar
+ magic-api-plugin-springdoc
+ magic-api-plugin-springdoc
+
+ 2.0.4
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ true
+
+
+ org.springdoc
+ springdoc-openapi-starter-webmvc-ui
+ ${springdoc.version}
+ provided
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ provided
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.10.1
+
+
+ 17
+ UTF-8
+
+
+
+
+
diff --git a/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/MagicSpringDocConfiguration.java b/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/MagicSpringDocConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..b071e758005161fba0ab841740216583760266aa
--- /dev/null
+++ b/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/MagicSpringDocConfiguration.java
@@ -0,0 +1,137 @@
+package org.ssssssss.magicapi.springdoc;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springdoc.core.properties.SwaggerUiConfigParameters;
+import org.springdoc.core.properties.SwaggerUiConfigProperties;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.context.annotation.Primary;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import org.ssssssss.magicapi.core.config.MagicAPIProperties;
+import org.ssssssss.magicapi.core.config.MagicPluginConfiguration;
+import org.ssssssss.magicapi.core.model.Plugin;
+import org.ssssssss.magicapi.core.service.MagicResourceService;
+import org.ssssssss.magicapi.core.service.impl.RequestMagicDynamicRegistry;
+import org.ssssssss.magicapi.springdoc.entity.SwaggerEntity;
+import org.ssssssss.magicapi.springdoc.entity.SwaggerProvider;
+import org.ssssssss.magicapi.utils.Mapping;
+
+import jakarta.servlet.ServletContext;
+
+import java.util.*;
+
+@Configuration
+@EnableConfigurationProperties(SpringDocConfig.class)
+@ConditionalOnProperty(
+ name = {"springdoc.api-docs.enabled"},
+ matchIfMissing = true
+)
+public class MagicSpringDocConfiguration implements MagicPluginConfiguration {
+
+ private final MagicAPIProperties properties;
+ private final SpringDocConfig springDocConfig;
+ @Autowired
+ @Lazy
+ private RequestMappingHandlerMapping requestMappingHandlerMapping;
+
+ private final ObjectProvider requestMagicDynamicRegistryObjectProvider;
+ private final MagicResourceService magicResourceService;
+ private final ServletContext servletContext;
+
+ private boolean createdMapping = false;
+
+ private static Logger logger = LoggerFactory.getLogger(MagicSpringDocConfiguration.class);
+
+ public MagicSpringDocConfiguration(MagicAPIProperties properties, SpringDocConfig springDocConfig, ObjectProvider requestMagicDynamicRegistryObjectProvider, MagicResourceService magicResourceService, ServletContext servletContext) {
+ this.properties = properties;
+ this.springDocConfig = springDocConfig;
+ this.requestMagicDynamicRegistryObjectProvider = requestMagicDynamicRegistryObjectProvider;
+ this.magicResourceService = magicResourceService;
+ this.servletContext = servletContext;
+ }
+
+ @Override
+ public Plugin plugin() {
+ return new Plugin("SpringDoc");
+ }
+
+ @Bean
+ @Primary
+ @Lazy
+ public SwaggerUiConfigParameters magicSwaggerUiConfigParameters(SwaggerUiConfigProperties swaggerUiConfigProperties) {
+ return new SwaggerUiConfigParameters(swaggerUiConfigProperties) {
+ @Override
+ public Map getConfigParameters() {
+ Map params = super.getConfigParameters();
+ if (!createdMapping) {
+ createdMapping = true;
+ try {
+ createSwaggerProvider(requestMagicDynamicRegistryObjectProvider, magicResourceService, servletContext);
+ } catch (NoSuchMethodException e) {
+ logger.error("注册springdoc接口失败", e);
+ return params;
+ }
+ }
+ Set urls = (Set) params.get("urls");
+ if (urls == null) {
+ urls = new HashSet<>();
+ SwaggerUrl url = new SwaggerUrl("default", (String) params.remove("url"), null);
+ urls.add(url);
+ } else {
+ urls = new HashSet<>(urls);
+ }
+ urls.add(new SwaggerUrl(springDocConfig.getGroupName(), springDocConfig.getLocation(), null));
+ params.put("urls", urls);
+ return params;
+ }
+ };
+ }
+
+
+ private void createSwaggerProvider(ObjectProvider requestMagicDynamicRegistryObjectProvider, MagicResourceService magicResourceService, ServletContext servletContext) throws NoSuchMethodException {
+
+ Mapping mapping = Mapping.create(requestMappingHandlerMapping);
+ RequestMappingInfo requestMappingInfo = mapping.paths(springDocConfig.getLocation()).build();
+ SwaggerEntity.License license = new SwaggerEntity.License("MIT", "https://gitee.com/ssssssss-team/magic-api/blob/master/LICENSE");
+ SwaggerEntity.Info info = new SwaggerEntity.Info(springDocConfig.getDescription(), springDocConfig.getVersion(), springDocConfig.getTitle(), license, springDocConfig.getConcat());
+
+ //具体参考:https://swagger.io/docs/specification/2-0/authentication/
+ Map securityDefinitionMap = new HashMap<>();
+ Map securityMap = new HashMap<>();
+
+ if (springDocConfig.getBasicAuth() != null) {
+ securityDefinitionMap.put(SwaggerEntity.BasicAuth.KEY_NAME, springDocConfig.getBasicAuth());
+
+ //the Basic and API key security items use an empty array instead.
+ securityMap.put(SwaggerEntity.BasicAuth.KEY_NAME, new String[]{});
+ }
+ if (springDocConfig.getApiKeyAuth() != null) {
+ securityDefinitionMap.put(SwaggerEntity.ApiKeyAuth.KEY_NAME, springDocConfig.getApiKeyAuth());
+
+ //the Basic and API key security items use an empty array instead.
+ securityMap.put(SwaggerEntity.ApiKeyAuth.KEY_NAME, new String[]{});
+ }
+ if (springDocConfig.getOauth2() != null) {
+ SwaggerEntity.OAuth2 oAuth2 = springDocConfig.getOauth2();
+ securityDefinitionMap.put(SwaggerEntity.OAuth2.KEY_NAME, oAuth2);
+
+ Map scopes = oAuth2.getScopes();
+ if (scopes != null) {
+ Set strings = scopes.keySet();
+ securityMap.put(SwaggerEntity.OAuth2.KEY_NAME, strings);
+ }
+ }
+ // 构建文档信息
+ SwaggerProvider swaggerProvider = new SwaggerProvider(requestMagicDynamicRegistryObjectProvider.getObject(), magicResourceService, servletContext.getContextPath(),
+ info, properties.isPersistenceResponseBody(), properties.getPrefix(), securityDefinitionMap, securityMap);
+ // 注册swagger.json
+ mapping.register(requestMappingInfo, swaggerProvider, SwaggerProvider.class.getDeclaredMethod("swaggerJson"));
+ }
+}
diff --git a/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/SpringDocConfig.java b/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/SpringDocConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..cfa67f651ca2e97a810eec77c5e7780318e47310
--- /dev/null
+++ b/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/SpringDocConfig.java
@@ -0,0 +1,145 @@
+package org.ssssssss.magicapi.springdoc;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.context.properties.NestedConfigurationProperty;
+import org.ssssssss.magicapi.springdoc.entity.SwaggerEntity;
+
+/**
+ * Swagger 配置
+ *
+ * @author mxd
+ */
+@ConfigurationProperties(prefix = "magic-api.swagger")
+public class SpringDocConfig {
+
+ /**
+ * 资源名称
+ */
+ private String name = "MagicAPI接口";
+
+ /**
+ * 资源位置
+ */
+ private String location = "/v2/api-docs/magic-api/swagger2.json";
+
+ /**
+ * 分组名称
+ */
+ private String groupName = "magic-api";
+
+ /**
+ * 文档标题
+ */
+ private String title = "MagicAPI Swagger Docs";
+
+ /**
+ * 文档描述
+ */
+ private String description = "MagicAPI 接口信息";
+
+ @NestedConfigurationProperty
+ private SwaggerEntity.Concat concat = new SwaggerEntity.Concat();
+
+ /**
+ * 基本认证
+ */
+ @NestedConfigurationProperty
+ private SwaggerEntity.BasicAuth basicAuth;
+
+ /**
+ * api密钥认证
+ */
+ @NestedConfigurationProperty
+ private SwaggerEntity.ApiKeyAuth apiKeyAuth;
+
+ /**
+ * oauth2认证
+ */
+ @NestedConfigurationProperty
+ private SwaggerEntity.OAuth2 oauth2;
+
+ /**
+ * 文档版本
+ */
+ private String version = "1.0";
+
+ public String getGroupName() {
+ return groupName;
+ }
+
+ public void setGroupName(String groupName) {
+ this.groupName = groupName;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getLocation() {
+ return location;
+ }
+
+ public void setLocation(String location) {
+ this.location = location;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ public SwaggerEntity.Concat getConcat() {
+ return concat;
+ }
+
+ public void setConcat(SwaggerEntity.Concat concat) {
+ this.concat = concat;
+ }
+
+ public SwaggerEntity.ApiKeyAuth getApiKeyAuth() {
+ return apiKeyAuth;
+ }
+
+ public void setApiKeyAuth(SwaggerEntity.ApiKeyAuth apiKeyAuth) {
+ this.apiKeyAuth = apiKeyAuth;
+ }
+
+ public SwaggerEntity.BasicAuth getBasicAuth() {
+ return basicAuth;
+ }
+
+ public void setBasicAuth(SwaggerEntity.BasicAuth basicAuth) {
+ this.basicAuth = basicAuth;
+ }
+
+ public SwaggerEntity.OAuth2 getOauth2() {
+ return oauth2;
+ }
+
+ public void setOauth2(SwaggerEntity.OAuth2 oauth2) {
+ this.oauth2 = oauth2;
+ }
+}
diff --git a/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/entity/SwaggerEntity.java b/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/entity/SwaggerEntity.java
new file mode 100644
index 0000000000000000000000000000000000000000..ec00eecc9a7600fda57fbe1842851ec95bfc8cdd
--- /dev/null
+++ b/magic-api-plugins/magic-api-plugin-springdoc/src/main/java/org/ssssssss/magicapi/springdoc/entity/SwaggerEntity.java
@@ -0,0 +1,637 @@
+package org.ssssssss.magicapi.springdoc.entity;
+
+import java.util.*;
+
+/**
+ * Swagger接口信息
+ *
+ * @author mxd
+ */
+public class SwaggerEntity {
+
+ private String swagger = "2.0";
+
+ private String host;
+
+ private String basePath;
+
+ private Info info;
+
+ private final Map securityDefinitions = new HashMap<>();
+
+ private final List