2.0 first commit

This commit is contained in:
mxd
2021-12-30 21:33:50 +08:00
parent 9903ab6b79
commit 052e43ffb1
124 changed files with 67 additions and 24682 deletions

View File

@@ -6,7 +6,7 @@
<parent>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api-parent</artifactId>
<version>1.7.2</version>
<version>2.0.0-alpha.1</version>
</parent>
<artifactId>magic-api-spring-boot-starter</artifactId>
<packaging>jar</packaging>

View File

@@ -22,6 +22,7 @@ import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;
@@ -29,7 +30,6 @@ import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
@@ -50,13 +50,16 @@ import org.ssssssss.magicapi.interceptor.*;
import org.ssssssss.magicapi.logging.LoggerManager;
import org.ssssssss.magicapi.model.Constants;
import org.ssssssss.magicapi.model.DataType;
import org.ssssssss.magicapi.model.MagicEntity;
import org.ssssssss.magicapi.model.Options;
import org.ssssssss.magicapi.modules.*;
import org.ssssssss.magicapi.provider.*;
import org.ssssssss.magicapi.provider.impl.*;
import org.ssssssss.magicapi.service.MagicDynamicRegistry;
import org.ssssssss.magicapi.service.MagicResourceService;
import org.ssssssss.magicapi.service.impl.*;
import org.ssssssss.magicapi.utils.ClassScanner;
import org.ssssssss.magicapi.utils.Mapping;
import org.ssssssss.magicapi.utils.PathUtils;
import org.ssssssss.script.MagicResourceLoader;
import org.ssssssss.script.MagicScript;
import org.ssssssss.script.MagicScriptEngine;
@@ -70,7 +73,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -85,7 +87,7 @@ import java.util.function.BiFunction;
@Configuration
@ConditionalOnClass({RequestMappingHandlerMapping.class})
@EnableConfigurationProperties(MagicAPIProperties.class)
@Import({MagicRedisAutoConfiguration.class, MagicMongoAutoConfiguration.class, MagicSwaggerConfiguration.class, MagicJsonAutoConfiguration.class, ApplicationUriPrinter.class})
@Import({MagicRedisAutoConfiguration.class, MagicMongoAutoConfiguration.class, MagicJsonAutoConfiguration.class, ApplicationUriPrinter.class})
@EnableWebSocket
public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketConfigurer {
@@ -136,6 +138,10 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
private final ObjectProvider<MagicNotifyService> magicNotifyServiceProvider;
private final ObjectProvider<List<MagicDynamicRegistry<? extends MagicEntity>>> magicDynamicRegistriesProvider;
private final ObjectProvider<List<MagicResourceStorage<? extends MagicEntity>>> magicResourceStoragesProvider;
private final ObjectProvider<DataSourceEncryptProvider> dataSourceEncryptProvider;
private final Environment environment;
@@ -174,6 +180,8 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
ObjectProvider<AuthorizationInterceptor> authorizationInterceptorProvider,
ObjectProvider<List<NamedTableInterceptor>> namedTableInterceptorsProvider,
ObjectProvider<DataSourceEncryptProvider> dataSourceEncryptProvider,
ObjectProvider<List<MagicDynamicRegistry<? extends MagicEntity>>> magicDynamicRegistriesProvider,
ObjectProvider<List<MagicResourceStorage<? extends MagicEntity>>> magicResourceStoragesProvider,
Environment environment,
ApplicationContext applicationContext
) {
@@ -189,6 +197,8 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
this.authorizationInterceptorProvider = authorizationInterceptorProvider;
this.namedTableInterceptorsProvider = namedTableInterceptorsProvider;
this.dataSourceEncryptProvider = dataSourceEncryptProvider;
this.magicDynamicRegistriesProvider = magicDynamicRegistriesProvider;
this.magicResourceStoragesProvider = magicResourceStoragesProvider;
this.environment = environment;
this.applicationContext = applicationContext;
}
@@ -278,13 +288,13 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
// 配置静态资源路径
registry.addResourceHandler(web + "/**").addResourceLocations("classpath:/magic-editor/");
try {
Mapping mapping = Mapping.create(requestMappingHandlerMapping);
// 默认首页设置
mapping.register(mapping.paths(web).build(), this, MagicAPIAutoConfiguration.class.getDeclaredMethod("redirectIndex", HttpServletRequest.class))
// 读取配置
.register(mapping.paths(web + "/config.json").build(), this, MagicAPIAutoConfiguration.class.getDeclaredMethod("readConfig"))
// 读取配置
.register(mapping.paths(web + "/classes.txt").produces("text/plain").build(), this, MagicAPIAutoConfiguration.class.getDeclaredMethod("readClass"));
Mapping mapping = Mapping.create(requestMappingHandlerMapping, web, properties.getPrefix());
// 默认首页设置
mapping.register(mapping.paths(web).build(), this, MagicAPIAutoConfiguration.class.getDeclaredMethod("redirectIndex", HttpServletRequest.class));
// 读取配置
mapping.register("GET", web + "/config.json", this, MagicAPIAutoConfiguration.class.getDeclaredMethod("readConfig"));
// 读取配置
mapping.register(mapping.paths(web + "/classes.txt").methods(RequestMethod.GET).produces("text/plain").build(), this, MagicAPIAutoConfiguration.class.getDeclaredMethod("readClass"));
} catch (NoSuchMethodException ignored) {
}
}
@@ -337,39 +347,49 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
return new DefaultSqlCache(cacheConfig.getCapacity(), cacheConfig.getTtl());
}
/**
* 注入接口映射
*/
@Bean
public MappingHandlerMapping mappingHandlerMapping() throws NoSuchMethodException {
String prefix = StringUtils.isNotBlank(properties.getPrefix()) ? PathUtils.replaceSlash("/" + properties.getPrefix() + "/") : null;
return new MappingHandlerMapping(prefix, properties.isAllowOverride());
@ConditionalOnMissingBean
public MagicResourceService magicResourceService(Resource workspace) {
return new DefaultMagicResourceService(workspace, magicResourceStoragesProvider.getObject(), applicationContext);
}
@Bean
@ConditionalOnMissingBean(FunctionServiceProvider.class)
public FunctionServiceProvider functionServiceProvider(GroupServiceProvider groupServiceProvider, Resource magicResource) {
return new DefaultFunctionServiceProvider(groupServiceProvider, magicResource);
@ConditionalOnMissingBean
public ApiInfoMagicResourceStorage apiInfoMagicResourceStorage() {
return new ApiInfoMagicResourceStorage();
}
/**
* 注入分组存储service
*/
@Bean
@ConditionalOnMissingBean(GroupServiceProvider.class)
public GroupServiceProvider groupServiceProvider(Resource magicResource) {
return new DefaultGroupServiceProvider(magicResource);
@ConditionalOnMissingBean
public RequestMagicDynamicRegistry magicRequestMagicDynamicRegistry(ApiInfoMagicResourceStorage apiInfoMagicResourceStorage) throws NoSuchMethodException {
return new RequestMagicDynamicRegistry(apiInfoMagicResourceStorage, Mapping.create(requestMappingHandlerMapping, properties.getWeb(), properties.getPrefix()));
}
/**
* 注入接口存储service
*/
@Bean
@ConditionalOnMissingBean(ApiServiceProvider.class)
public ApiServiceProvider apiServiceProvider(GroupServiceProvider groupServiceProvider, Resource magicResource) {
return new DefaultApiServiceProvider(groupServiceProvider, magicResource);
@ConditionalOnMissingBean
public FunctionInfoMagicResourceStorage functionInfoMagicResourceStorage() {
return new FunctionInfoMagicResourceStorage();
}
@Bean
@ConditionalOnMissingBean
public FunctionMagicDynamicRegistry functionMagicDynamicRegistry(FunctionInfoMagicResourceStorage functionInfoMagicResourceStorage) {
return new FunctionMagicDynamicRegistry(functionInfoMagicResourceStorage);
}
@Bean
@ConditionalOnMissingBean
public DataSourceInfoMagicResourceStorage dataSourceInfoMagicResourceStorage() {
return new DataSourceInfoMagicResourceStorage();
}
@Bean
@ConditionalOnMissingBean
public DataSourceMagicDynamicRegistry dataSourceMagicDynamicRegistry(DataSourceInfoMagicResourceStorage dataSourceInfoMagicResourceStorage) {
return new DataSourceMagicDynamicRegistry(dataSourceInfoMagicResourceStorage);
}
@Bean
@ConditionalOnMissingBean(MagicNotifyService.class)
public MagicNotifyService magicNotifyService() {
@@ -385,26 +405,13 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
return new MagicFileBackupService(new File(properties.getBackupConfig().getLocation()));
}
@Bean
public MagicFunctionManager magicFunctionManager(GroupServiceProvider groupServiceProvider, FunctionServiceProvider functionServiceProvider) {
return new MagicFunctionManager(groupServiceProvider, functionServiceProvider);
}
/**
* 注入API调用Service
*/
@Bean
@ConditionalOnMissingBean
public MagicAPIService magicAPIService(MappingHandlerMapping mappingHandlerMapping,
ApiServiceProvider apiServiceProvider,
FunctionServiceProvider functionServiceProvider,
GroupServiceProvider groupServiceProvider,
ResultProvider resultProvider,
MagicDynamicDataSource magicDynamicDataSource,
MagicFunctionManager magicFunctionManager,
Resource workspace,
MagicBackupService magicBackupService) {
return new DefaultMagicAPIService(mappingHandlerMapping, apiServiceProvider, functionServiceProvider, groupServiceProvider, resultProvider, magicDynamicDataSource, magicFunctionManager, magicNotifyServiceProvider.getObject(), properties.getClusterConfig().getInstanceId(), workspace, magicBackupService, dataSourceEncryptProvider.getIfAvailable() , properties.isThrowException());
public MagicAPIService magicAPIService(ResultProvider resultProvider, MagicResourceService magicResourceService) {
return new DefaultMagicAPIService(resultProvider, properties.getClusterConfig().getInstanceId(), magicResourceService, properties.isThrowException());
}
/**
@@ -522,18 +529,15 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
@Bean
public MagicConfiguration magicConfiguration(MagicDynamicDataSource dynamicDataSource,
SQLModule sqlModule,
List<MagicModule> magicModules,
SQLModule sqlModule,
List<MagicModule> magicModules,
List<LanguageProvider> languageProviders,
Resource magicResource,
ResultProvider resultProvider,
MagicResourceService magicResourceService,
MagicAPIService magicAPIService,
ApiServiceProvider apiServiceProvider,
GroupServiceProvider groupServiceProvider,
MappingHandlerMapping mappingHandlerMapping,
FunctionServiceProvider functionServiceProvider,
MagicNotifyService magicNotifyService,
MagicFunctionManager magicFunctionManager,
RequestMagicDynamicRegistry requestMagicDynamicRegistry,
MagicBackupService magicBackupService) throws NoSuchMethodException {
logger.info("magic-api工作目录:{}", magicResource);
AsyncCall.setThreadPoolExecutorSize(properties.getThreadPoolExecutorSize());
@@ -550,10 +554,8 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
configuration.setMagicAPIService(magicAPIService);
configuration.setMagicNotifyService(magicNotifyService);
configuration.setInstanceId(properties.getClusterConfig().getInstanceId());
configuration.setApiServiceProvider(apiServiceProvider);
configuration.setGroupServiceProvider(groupServiceProvider);
configuration.setMappingHandlerMapping(mappingHandlerMapping);
configuration.setFunctionServiceProvider(functionServiceProvider);
configuration.setMagicResourceService(magicResourceService);
configuration.setMagicDynamicRegistries(magicDynamicRegistriesProvider.getObject());
configuration.setMagicBackupService(magicBackupService);
SecurityConfig securityConfig = properties.getSecurityConfig();
configuration.setDebugTimeout(properties.getDebugConfig().getTimeout());
@@ -568,32 +570,19 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
// 向页面传递配置信息时不传递用户名密码,增强安全性
securityConfig.setUsername(null);
securityConfig.setPassword(null);
requestMagicDynamicRegistry.setHandler(new RequestHandler(configuration, requestMagicDynamicRegistry));
// 构建UI请求处理器
String base = properties.getWeb();
mappingHandlerMapping.setRequestMappingHandlerMapping(requestMappingHandlerMapping);
MagicDataSourceController dataSourceController = new MagicDataSourceController(configuration);
Mapping mapping = Mapping.create(requestMappingHandlerMapping, base, properties.getPrefix());
MagicWorkbenchController magicWorkbenchController = new MagicWorkbenchController(configuration, properties.getSecretKey());
if (base != null) {
configuration.setEnableWeb(true);
List<MagicController> controllers = new ArrayList<>(Arrays.asList(
new MagicAPIController(configuration),
dataSourceController,
magicWorkbenchController,
new MagicGroupController(configuration),
new MagicFunctionController(configuration)
));
controllers.forEach(item -> mappingHandlerMapping.registerController(item, base));
mapping.registerController(magicWorkbenchController).registerController(new MagicResourceController(configuration));
}
// 注册接收推送的接口
if (StringUtils.isNotBlank(properties.getSecretKey())) {
Mapping mapping = Mapping.create(requestMappingHandlerMapping);
RequestMappingInfo requestMappingInfo = mapping.paths(properties.getPushPath()).build();
Method method = MagicWorkbenchController.class.getDeclaredMethod("receivePush", MultipartFile.class, String.class, Long.class, String.class);
mapping.register(requestMappingInfo, magicWorkbenchController, method);
mapping.register(mapping.paths(properties.getPushPath()).methods(RequestMethod.POST).build(), magicWorkbenchController, MagicWorkbenchController.class.getDeclaredMethod("receivePush", MultipartFile.class, String.class, Long.class, String.class));
}
// 注册数据源
magicAPIService.registerAllDataSource();
// 设置拦截器信息
this.requestInterceptorsProvider.getIfAvailable(Collections::emptyList).forEach(interceptor -> {
logger.info("注册请求拦截器:{}", interceptor.getClass());
@@ -603,16 +592,6 @@ public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketCon
if (this.properties.isBanner()) {
configuration.printBanner();
}
configuration.setMagicFunctionManager(magicFunctionManager);
// 注册函数加载器
magicFunctionManager.registerFunctionLoader();
// 注册所有函数
magicFunctionManager.registerAllFunction();
mappingHandlerMapping.setHandler(new RequestHandler(configuration));
mappingHandlerMapping.setMagicApiService(apiServiceProvider);
mappingHandlerMapping.setGroupServiceProvider(groupServiceProvider);
// 注册所有映射
mappingHandlerMapping.registerAllMapping();
// 备份清理
if (properties.getBackupConfig().getMaxHistory() > 0) {
long interval = properties.getBackupConfig().getMaxHistory() * 86400000L;

View File

@@ -147,9 +147,6 @@ public class MagicAPIProperties {
@NestedConfigurationProperty
private DebugConfig debugConfig = new DebugConfig();
@NestedConfigurationProperty
private SwaggerConfig swaggerConfig = new SwaggerConfig();
@NestedConfigurationProperty
private ResourceConfig resource = new ResourceConfig();
@@ -265,14 +262,6 @@ public class MagicAPIProperties {
this.prefix = prefix;
}
public SwaggerConfig getSwaggerConfig() {
return swaggerConfig;
}
public void setSwaggerConfig(SwaggerConfig swaggerConfig) {
this.swaggerConfig = swaggerConfig;
}
public String getAutoImportModule() {
return autoImportModule;
}

View File

@@ -1,98 +0,0 @@
package org.ssssssss.magicapi.spring.boot.starter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
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.config.MappingHandlerMapping;
import org.ssssssss.magicapi.provider.GroupServiceProvider;
import org.ssssssss.magicapi.swagger.SwaggerEntity;
import org.ssssssss.magicapi.swagger.SwaggerProvider;
import org.ssssssss.magicapi.utils.Mapping;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.SwaggerResourcesProvider;
import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Swagger配置类
*
* @author mxd
*/
@Configuration
@AutoConfigureAfter({MagicAPIAutoConfiguration.class})
@EnableConfigurationProperties(MagicAPIProperties.class)
@ConditionalOnClass(name = "springfox.documentation.swagger.web.SwaggerResourcesProvider")
public class MagicSwaggerConfiguration {
private final MagicAPIProperties properties;
private final ApplicationContext applicationContext;
@Autowired
@Lazy
private RequestMappingHandlerMapping requestMappingHandlerMapping;
public MagicSwaggerConfiguration(MagicAPIProperties properties, ApplicationContext applicationContext) {
this.properties = properties;
this.applicationContext = applicationContext;
}
@Bean
@Primary
public SwaggerResourcesProvider magicSwaggerResourcesProvider(MappingHandlerMapping handlerMapping, GroupServiceProvider groupServiceProvider, ServletContext servletContext) throws NoSuchMethodException {
SwaggerConfig config = properties.getSwaggerConfig();
Mapping mapping = Mapping.create(requestMappingHandlerMapping);
RequestMappingInfo requestMappingInfo = mapping.paths(config.getLocation()).build();
// 构建文档信息
SwaggerProvider swaggerProvider = new SwaggerProvider();
swaggerProvider.setGroupServiceProvider(groupServiceProvider);
swaggerProvider.setMappingHandlerMapping(handlerMapping);
swaggerProvider.setPersistenceResponseBody(properties.isPersistenceResponseBody());
SwaggerEntity.License license = new SwaggerEntity.License("MIT", "https://gitee.com/ssssssss-team/magic-api/blob/master/LICENSE");
swaggerProvider.setInfo(new SwaggerEntity.Info(config.getDescription(), config.getVersion(), config.getTitle(), license, config.getConcat()));
swaggerProvider.setBasePath(servletContext.getContextPath());
// 注册swagger.json
mapping.register(requestMappingInfo, swaggerProvider, SwaggerProvider.class.getDeclaredMethod("swaggerJson"));
return () -> {
List<SwaggerResource> resources = new ArrayList<>();
// 追加Magic Swagger信息
resources.add(swaggerResource(config.getName(), config.getLocation()));
Map<String, SwaggerResourcesProvider> beans = applicationContext.getBeansOfType(SwaggerResourcesProvider.class);
// 获取已定义的文档信息
for (Map.Entry<String, SwaggerResourcesProvider> entry : beans.entrySet()) {
if (!"magicSwaggerResourcesProvider".equalsIgnoreCase(entry.getKey())) {
resources.addAll(entry.getValue().get());
}
}
return resources;
};
}
/**
* 构建 SwaggerResource
*
* @param name 名字
* @param location 位置
*/
private SwaggerResource swaggerResource(String name, String location) {
SwaggerResource resource = new SwaggerResource();
resource.setName(name);
resource.setLocation(location);
resource.setSwaggerVersion("2.0");
return resource;
}
}

View File

@@ -1,88 +0,0 @@
package org.ssssssss.magicapi.spring.boot.starter;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
import org.ssssssss.magicapi.swagger.SwaggerEntity;
/**
* Swagger 配置
*
* @author mxd
*/
public class SwaggerConfig {
/**
* 资源名称
*/
private String name = "MagicAPI接口";
/**
* 资源位置
*/
private String location = "/v2/api-docs/magic-api/swagger2.json";
/**
* 文档标题
*/
private String title = "MagicAPI Swagger Docs";
/**
* 文档描述
*/
private String description = "MagicAPI 接口信息";
@NestedConfigurationProperty
private SwaggerEntity.Concat concat = new SwaggerEntity.Concat();
/**
* 文档版本
*/
private String version = "1.0";
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;
}
}