Commit 02897568 authored by liang.tang's avatar liang.tang
Browse files

magic-api

parents
Pipeline #222 failed with stages
in 0 seconds
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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.ssssssss</groupId>
<artifactId>magic-api-servlet</artifactId>
<version>2.1.1</version>
</parent>
<artifactId>magic-api-servlet-javaee</artifactId>
<packaging>jar</packaging>
<name>magic-api-servlet-javaee</name>
<description>auto generate http api</description>
<dependencies>
</dependencies>
</project>
package org.ssssssss.magicapi.servlet.javaee;
import org.ssssssss.magicapi.core.servlet.MagicCookie;
import javax.servlet.http.Cookie;
public class MagicJavaEECookie implements MagicCookie {
private final Cookie cookie;
public MagicJavaEECookie(Cookie cookie) {
this.cookie = cookie;
}
@Override
public String getName() {
return cookie.getName();
}
@Override
public String getValue() {
return cookie.getValue();
}
@Override
public <T> T getCookie() {
return (T) cookie;
}
}
package org.ssssssss.magicapi.servlet.javaee;
import org.ssssssss.magicapi.core.config.MagicCorsFilter;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MagicJavaEECorsFilter extends MagicCorsFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
super.process(new MagicJavaEEHttpServletRequest((HttpServletRequest) request, null), new MagicJavaEEHttpServletResponse((HttpServletResponse) response));
chain.doFilter(request, response);
}
}
package org.ssssssss.magicapi.servlet.javaee;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartRequest;
import org.springframework.web.multipart.MultipartResolver;
import org.ssssssss.magicapi.core.servlet.MagicCookie;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest;
import org.ssssssss.magicapi.core.servlet.MagicHttpSession;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.io.InputStream;
import java.security.Principal;
import java.util.Arrays;
import java.util.Enumeration;
public class MagicJavaEEHttpServletRequest implements MagicHttpServletRequest {
private final HttpServletRequest request;
private final MultipartResolver multipartResolver;
public MagicJavaEEHttpServletRequest(HttpServletRequest request, MultipartResolver multipartResolver) {
this.request = request;
this.multipartResolver = multipartResolver;
}
@Override
public String getHeader(String name) {
return request.getHeader(name);
}
@Override
public Enumeration<String> getHeaders(String name) {
return request.getHeaders(name);
}
@Override
public String getRequestURI() {
return request.getRequestURI();
}
@Override
public String getMethod() {
return request.getMethod();
}
@Override
public void setAttribute(String key, Object value) {
request.setAttribute(key, value);
}
@Override
public String[] getParameterValues(String name) {
return request.getParameterValues(name);
}
@Override
public Object getAttribute(String name) {
return request.getAttribute(name);
}
@Override
public HttpInputMessage getHttpInputMessage() {
return new ServletServerHttpRequest(request);
}
@Override
public String getContentType() {
return request.getContentType();
}
@Override
public MagicHttpSession getSession() {
return new MagicJavaEEHttpSession(request.getSession());
}
@Override
public MagicCookie[] getCookies() {
Cookie[] cookies = request.getCookies();
if (cookies == null) {
return new MagicJavaEECookie[0];
}
return Arrays.stream(request.getCookies()).map(MagicJavaEECookie::new).toArray(MagicJavaEECookie[]::new);
}
@Override
public InputStream getInputStream() throws IOException {
return request.getInputStream();
}
@Override
public boolean isMultipart() {
return multipartResolver.isMultipart(request);
}
@Override
public String getRemoteAddr() {
return request.getRemoteAddr();
}
@Override
public MultipartRequest resolveMultipart() {
return multipartResolver.resolveMultipart(request);
}
@Override
public Principal getUserPrincipal() {
return request.getUserPrincipal();
}
@Override
public <T> T getRequest() {
return (T) request;
}
public static class ArgumentsResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType() == MagicHttpServletRequest.class;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return new MagicJavaEEHttpServletRequest(webRequest.getNativeRequest(HttpServletRequest.class), null);
}
}
}
package org.ssssssss.magicapi.servlet.javaee;
import org.springframework.core.MethodParameter;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.ssssssss.magicapi.core.servlet.MagicCookie;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletResponse;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
public class MagicJavaEEHttpServletResponse implements MagicHttpServletResponse {
private final HttpServletResponse response;
public MagicJavaEEHttpServletResponse(HttpServletResponse response) {
this.response = response;
}
@Override
public void setHeader(String name, String value) {
response.setHeader(name, value);
}
@Override
public void addHeader(String name, String value) {
response.addHeader(name, value);
}
@Override
public void sendRedirect(String location) throws IOException {
response.sendRedirect(location);
}
@Override
public void addCookie(MagicCookie cookie) {
response.addCookie(cookie.getCookie());
}
@Override
public void setContentType(String contentType) {
response.setContentType(contentType);
}
@Override
public void setCharacterEncoding(String characterEncoding) {
response.setCharacterEncoding(characterEncoding);
}
@Override
public OutputStream getOutputStream() throws IOException {
return response.getOutputStream();
}
@Override
public Collection<String> getHeaderNames() {
return response.getHeaderNames();
}
@Override
public <T> T getResponse() {
return (T) response;
}
public static class ArgumentsResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType() == MagicHttpServletResponse.class;
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
return new MagicJavaEEHttpServletResponse(webRequest.getNativeResponse(HttpServletResponse.class));
}
}
}
package org.ssssssss.magicapi.servlet.javaee;
import org.ssssssss.magicapi.core.servlet.MagicHttpSession;
import javax.servlet.http.HttpSession;
public class MagicJavaEEHttpSession implements MagicHttpSession {
private final HttpSession session;
public MagicJavaEEHttpSession(HttpSession session) {
this.session = session;
}
@Override
public Object getAttribute(String key) {
return session.getAttribute(key);
}
@Override
public void setAttribute(String key, Object value) {
session.setAttribute(key, value);
}
@Override
public <T> T getSession() {
return (T) session;
}
}
package org.ssssssss.magicapi.servlet.javaee;
import org.springframework.web.multipart.MultipartResolver;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletRequest;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletResponse;
import org.ssssssss.magicapi.core.servlet.MagicRequestContextHolder;
public class MagicJavaEERequestContextHolder implements MagicRequestContextHolder {
private final MultipartResolver multipartResolver;
public MagicJavaEERequestContextHolder(MultipartResolver multipartResolver) {
this.multipartResolver = multipartResolver;
}
@Override
public MagicHttpServletRequest getRequest() {
return convert(servletRequestAttributes -> new MagicJavaEEHttpServletRequest(servletRequestAttributes.getRequest(), multipartResolver));
}
@Override
public MagicHttpServletResponse getResponse() {
return convert(servletRequestAttributes -> new MagicJavaEEHttpServletResponse(servletRequestAttributes.getResponse()));
}
}
package org.ssssssss.magicapi.servlet.javaee;
import org.apache.commons.lang3.StringUtils;
import org.ssssssss.magicapi.core.context.RequestContext;
import org.ssssssss.magicapi.core.servlet.MagicHttpServletResponse;
import org.ssssssss.magicapi.modules.servlet.ResponseModule;
import org.ssssssss.script.annotation.Comment;
import org.ssssssss.script.functions.ExtensionMethod;
import org.ssssssss.script.functions.ObjectConvertExtension;
import javax.servlet.http.Cookie;
import java.util.Map;
public class MagicJavaEEResponseExtension implements ExtensionMethod {
/**
* 添加cookie
*/
@Comment("添加Cookie")
public ResponseModule addCookie(ResponseModule module, @Comment(name = "cookie", value = "Cookie对象") Cookie cookie) {
if (cookie != null) {
MagicHttpServletResponse response = RequestContext.getHttpServletResponse();
if (response != null) {
response.addCookie(new MagicJavaEECookie(cookie));
}
}
return module;
}
/**
* 批量添加cookie
*/
@Comment("批量添加Cookie")
public ResponseModule addCookies(ResponseModule module, @Comment(name = "cookies", value = "Cookies") Map<String, String> cookies) {
return addCookies(module, cookies, null);
}
/**
* 添加cookie
*/
@Comment("添加Cookie")
public ResponseModule addCookie(ResponseModule module, @Comment(name = "name", value = "Cookie名") String name,
@Comment(name = "value", value = "Cookie值") String value,
@Comment(name = "options", value = "Cookie选项,如`path`、`httpOnly`、`domain`、`maxAge`") Map<String, Object> options) {
if (StringUtils.isNotBlank(name)) {
Cookie cookie = new Cookie(name, value);
if (options != null) {
Object path = options.get("path");
if (path != null) {
cookie.setPath(path.toString());
}
Object httpOnly = options.get("httpOnly");
if (httpOnly != null) {
cookie.setHttpOnly("true".equalsIgnoreCase(httpOnly.toString()));
}
Object domain = options.get("domain");
if (domain != null) {
cookie.setDomain(domain.toString());
}
Object maxAge = options.get("maxAge");
int age;
if (maxAge != null && (age = ObjectConvertExtension.asInt(maxAge, Integer.MIN_VALUE)) != Integer.MIN_VALUE) {
cookie.setMaxAge(age);
}
}
addCookie(module, cookie);
}
return module;
}
/**
* 添加cookie
*/
@Comment("添加Cookie")
public ResponseModule addCookie(ResponseModule module, @Comment(name = "name", value = "cookie名") String name,
@Comment(name = "value", value = "cookie值") String value) {
if (StringUtils.isNotBlank(name)) {
addCookie(module, new Cookie(name, value));
}
return module;
}
/**
* 批量添加cookie
*/
@Comment("批量添加Cookie")
public ResponseModule addCookies(ResponseModule module,
@Comment(name = "cookies", value = "Cookies") Map<String, String> cookies,
@Comment(name = "options", value = "Cookie选项,如`path`、`httpOnly`、`domain`、`maxAge`") Map<String, Object> options) {
if (cookies != null) {
for (Map.Entry<String, String> entry : cookies.entrySet()) {
addCookie(module, entry.getKey(), entry.getValue(), options);
}
}
return module;
}
@Override
public Class<?> support() {
return ResponseModule.class;
}
}
package org.ssssssss.magicapi.servlet.javaee;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.ssssssss.magicapi.core.config.MagicAPIProperties;
import org.ssssssss.magicapi.core.interceptor.AuthorizationInterceptor;
import org.ssssssss.magicapi.core.servlet.MagicRequestContextHolder;
import java.util.List;
@Configuration
public class MagicJavaEEServletConfiguration implements WebMvcConfigurer {
private final MagicAPIProperties properties;
private final ObjectProvider<MagicJavaEEWebRequestInterceptor> magicWebRequestInterceptorProvider;
public MagicJavaEEServletConfiguration(MagicAPIProperties properties, ObjectProvider<MagicJavaEEWebRequestInterceptor> magicWebRequestInterceptorProvider) {
this.properties = properties;
this.magicWebRequestInterceptorProvider = magicWebRequestInterceptorProvider;
}
private MagicJavaEECorsFilter magicCorsFilter = new MagicJavaEECorsFilter();
@Bean
public MagicRequestContextHolder magicRequestContextHolder(MultipartResolver multipartResolver){
return new MagicJavaEERequestContextHolder(multipartResolver);
}
@Bean
public MagicJavaEEWebRequestInterceptor magicWebRequestInterceptor(AuthorizationInterceptor authorizationInterceptor){
return new MagicJavaEEWebRequestInterceptor(properties.isSupportCrossDomain() ? magicCorsFilter : null, authorizationInterceptor);
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(magicWebRequestInterceptorProvider.getObject()).addPathPatterns("/**");
}
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(0, new MagicJavaEEHttpServletRequest.ArgumentsResolver());
resolvers.add(0, new MagicJavaEEHttpServletResponse.ArgumentsResolver());
}
@Bean
public MagicJavaEEResponseExtension magicJavaEEResponseExtension() {
return new MagicJavaEEResponseExtension();
}
@Bean
@ConditionalOnProperty(prefix = "magic-api", value = "support-cross-domain", havingValue = "true", matchIfMissing = true)
public FilterRegistrationBean<MagicJavaEECorsFilter> magicCorsFilterRegistrationBean() {
FilterRegistrationBean<MagicJavaEECorsFilter> registration = new FilterRegistrationBean<>(magicCorsFilter);
registration.addUrlPatterns("/*");
registration.setName("Magic Cors Filter");
registration.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registration;
}
}
package org.ssssssss.magicapi.servlet.javaee;
import org.springframework.web.servlet.HandlerInterceptor;
import org.ssssssss.magicapi.core.config.MagicCorsFilter;
import org.ssssssss.magicapi.core.interceptor.AuthorizationInterceptor;
import org.ssssssss.magicapi.core.interceptor.MagicWebRequestInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MagicJavaEEWebRequestInterceptor extends MagicWebRequestInterceptor implements HandlerInterceptor {
public MagicJavaEEWebRequestInterceptor(MagicCorsFilter magicCorsFilter, AuthorizationInterceptor authorizationInterceptor) {
super(magicCorsFilter, authorizationInterceptor);
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
super.handle(handler, new MagicJavaEEHttpServletRequest(request, null), new MagicJavaEEHttpServletResponse(response));
return true;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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.ssssssss</groupId>
<artifactId>magic-api-parent</artifactId>
<version>2.1.1</version>
</parent>
<artifactId>magic-api-servlet</artifactId>
<packaging>pom</packaging>
<name>magic-api-servlet</name>
<description>auto generate http api</description>
<modules>
<module>magic-api-servlet-jakarta</module>
<module>magic-api-servlet-javaee</module>
</modules>
<dependencies>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api</artifactId>
</dependency>
</dependencies>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
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.ssssssss</groupId>
<artifactId>magic-api-parent</artifactId>
<version>2.1.1</version>
</parent>
<artifactId>magic-api-spring-boot-starter</artifactId>
<packaging>jar</packaging>
<name>magic-api-spring-boot-starter</name>
<description>magic-api-spring-boot-starter</description>
<dependencies>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api</artifactId>
</dependency>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-script</artifactId>
</dependency>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-editor</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api-servlet-jakarta</artifactId>
</dependency>
<dependency>
<groupId>org.ssssssss</groupId>
<artifactId>magic-api-servlet-javaee</artifactId>
</dependency>
</dependencies>
</project>
package org.ssssssss.magicapi.spring.boot.starter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.ssssssss.magicapi.core.config.MagicAPIProperties;
import org.ssssssss.magicapi.utils.PathUtils;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Objects;
/**
* 输出服务访问地址
*
* @author 冰点
* @date 2021-6-3 12:08:59
* @since 1.2.1
*/
@Component
@ConditionalOnProperty(name = "magic-api.show-url", havingValue = "true", matchIfMissing = true)
@Order
public class ApplicationUriPrinter implements CommandLineRunner {
@Value("${server.port:8080}")
private int port;
@Value("${server.servlet.context-path:}")
private String contextPath;
@Autowired
private MagicAPIProperties properties;
@Override
public void run(String... args) throws Exception {
System.out.println("********************************************当前服务相关地址********************************************");
String ip = "IP";
try {
ip = InetAddress.getLocalHost().getHostAddress();
} catch (UnknownHostException e) {
System.out.println("当前服务地址获取失败");
}
String magicWebPath = properties.getWeb();
String schema = "http://";
String localUrl = schema + PathUtils.replaceSlash(String.format("localhost:%s/%s/%s/", port, contextPath, Objects.toString(properties.getPrefix(), "")));
String externUrl = schema + PathUtils.replaceSlash(String.format("%s:%s/%s/%s/", ip, port, contextPath, Objects.toString(properties.getPrefix(), "")));
System.out.printf(
"服务启动成功,magic-api已内置启动! Access URLs:" +
"\n\t接口本地地址: \t\t%s" +
"\n\t接口外部地址: \t\t%s\n"
, localUrl
, externUrl
);
if (!StringUtils.isEmpty(magicWebPath)) {
String webPath = schema + PathUtils.replaceSlash(String.format("%s:%s/%s/%s/index.html", ip, port, contextPath, magicWebPath));
System.out.println("\t接口配置平台: \t\t" + webPath);
}
System.out.println("\t可通过配置关闭输出: \tmagic-api.show-url=false");
System.out.println("********************************************当前服务相关地址********************************************");
}
}
package org.ssssssss.magicapi.spring.boot.starter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
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.Import;
import org.springframework.context.annotation.Lazy;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
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;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistration;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.ssssssss.magicapi.backup.service.MagicBackupService;
import org.ssssssss.magicapi.backup.service.MagicDatabaseBackupService;
import org.ssssssss.magicapi.backup.web.MagicBackupController;
import org.ssssssss.magicapi.core.annotation.MagicModule;
import org.ssssssss.magicapi.core.config.*;
import org.ssssssss.magicapi.core.exception.MagicAPIException;
import org.ssssssss.magicapi.core.handler.MagicCoordinationHandler;
import org.ssssssss.magicapi.core.handler.MagicDebugHandler;
import org.ssssssss.magicapi.core.handler.MagicWebSocketDispatcher;
import org.ssssssss.magicapi.core.handler.MagicWorkbenchHandler;
import org.ssssssss.magicapi.core.interceptor.AuthorizationInterceptor;
import org.ssssssss.magicapi.core.interceptor.DefaultAuthorizationInterceptor;
import org.ssssssss.magicapi.core.interceptor.RequestInterceptor;
import org.ssssssss.magicapi.core.interceptor.ResultProvider;
import org.ssssssss.magicapi.core.logging.LoggerManager;
import org.ssssssss.magicapi.core.model.DataType;
import org.ssssssss.magicapi.core.model.MagicEntity;
import org.ssssssss.magicapi.core.model.Plugin;
import org.ssssssss.magicapi.core.resource.DatabaseResource;
import org.ssssssss.magicapi.core.resource.ResourceAdapter;
import org.ssssssss.magicapi.core.service.*;
import org.ssssssss.magicapi.core.service.impl.DefaultMagicAPIService;
import org.ssssssss.magicapi.core.service.impl.DefaultMagicResourceService;
import org.ssssssss.magicapi.core.service.impl.RequestMagicDynamicRegistry;
import org.ssssssss.magicapi.core.servlet.MagicRequestContextHolder;
import org.ssssssss.magicapi.core.web.MagicResourceController;
import org.ssssssss.magicapi.core.web.MagicWorkbenchController;
import org.ssssssss.magicapi.core.web.RequestHandler;
import org.ssssssss.magicapi.datasource.model.MagicDynamicDataSource;
import org.ssssssss.magicapi.datasource.service.DataSourceEncryptProvider;
import org.ssssssss.magicapi.datasource.web.MagicDataSourceController;
import org.ssssssss.magicapi.function.service.FunctionMagicDynamicRegistry;
import org.ssssssss.magicapi.jsr223.LanguageProvider;
import org.ssssssss.magicapi.modules.DynamicModule;
import org.ssssssss.magicapi.utils.Mapping;
import org.ssssssss.magicapi.utils.WebUtils;
import org.ssssssss.script.MagicResourceLoader;
import org.ssssssss.script.MagicScript;
import org.ssssssss.script.MagicScriptEngine;
import org.ssssssss.script.exception.MagicScriptRuntimeException;
import org.ssssssss.script.functions.DynamicModuleImport;
import org.ssssssss.script.functions.ExtensionMethod;
import org.ssssssss.script.parsing.ast.statement.AsyncCall;
import org.ssssssss.script.reflection.JavaReflection;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.stream.Collectors;
/**
* magic-api自动配置类
*
* @author mxd
*/
@Configuration
@ConditionalOnClass({RequestMappingHandlerMapping.class})
@EnableConfigurationProperties(MagicAPIProperties.class)
@Import({MagicServletConfiguration.class, MagicJsonAutoConfiguration.class, ApplicationUriPrinter.class, MagicModuleConfiguration.class, MagicDynamicRegistryConfiguration.class})
@EnableWebSocket
@AutoConfigureAfter(MagicPluginConfiguration.class)
public class MagicAPIAutoConfiguration implements WebMvcConfigurer, WebSocketConfigurer {
private static final Logger logger = LoggerFactory.getLogger(MagicAPIAutoConfiguration.class);
/**
* 请求拦截器
*/
private final ObjectProvider<List<RequestInterceptor>> requestInterceptorsProvider;
/**
* 自定义的类型扩展
*/
private final ObjectProvider<List<ExtensionMethod>> extensionMethodsProvider;
/**
* 内置的消息转换
*/
private final ObjectProvider<List<HttpMessageConverter<?>>> httpMessageConvertersProvider;
private final ObjectProvider<AuthorizationInterceptor> authorizationInterceptorProvider;
/**
* 自定义的函数
*/
private final ObjectProvider<List<MagicFunction>> magicFunctionsProvider;
private final ObjectProvider<List<MagicPluginConfiguration>> magicPluginsProvider;
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 MagicAPIProperties properties;
private final ApplicationContext applicationContext;
private boolean registerMapping = false;
private boolean registerWebsocket = false;
@Autowired
@Lazy
private RequestMappingHandlerMapping requestMappingHandlerMapping;
public MagicAPIAutoConfiguration(MagicAPIProperties properties,
ObjectProvider<List<RequestInterceptor>> requestInterceptorsProvider,
ObjectProvider<List<ExtensionMethod>> extensionMethodsProvider,
ObjectProvider<List<HttpMessageConverter<?>>> httpMessageConvertersProvider,
ObjectProvider<List<MagicFunction>> magicFunctionsProvider,
ObjectProvider<List<MagicPluginConfiguration>> magicPluginsProvider,
ObjectProvider<MagicNotifyService> magicNotifyServiceProvider,
ObjectProvider<AuthorizationInterceptor> authorizationInterceptorProvider,
ObjectProvider<DataSourceEncryptProvider> dataSourceEncryptProvider,
ObjectProvider<List<MagicDynamicRegistry<? extends MagicEntity>>> magicDynamicRegistriesProvider,
ObjectProvider<List<MagicResourceStorage<? extends MagicEntity>>> magicResourceStoragesProvider,
ApplicationContext applicationContext
) {
this.properties = properties;
this.requestInterceptorsProvider = requestInterceptorsProvider;
this.extensionMethodsProvider = extensionMethodsProvider;
this.httpMessageConvertersProvider = httpMessageConvertersProvider;
this.magicFunctionsProvider = magicFunctionsProvider;
this.magicPluginsProvider = magicPluginsProvider;
this.magicNotifyServiceProvider = magicNotifyServiceProvider;
this.authorizationInterceptorProvider = authorizationInterceptorProvider;
this.dataSourceEncryptProvider = dataSourceEncryptProvider;
this.magicDynamicRegistriesProvider = magicDynamicRegistriesProvider;
this.magicResourceStoragesProvider = magicResourceStoragesProvider;
this.applicationContext = applicationContext;
}
@Bean
@ConditionalOnMissingBean(org.ssssssss.magicapi.core.resource.Resource.class)
@ConditionalOnProperty(prefix = "magic-api", name = "resource.type", havingValue = "database")
public org.ssssssss.magicapi.core.resource.Resource magicDatabaseResource(MagicDynamicDataSource magicDynamicDataSource) {
Resource resourceConfig = properties.getResource();
if (magicDynamicDataSource.isEmpty()) {
throw new MagicAPIException("当前未配置数据源,如已配置,请引入 spring-boot-starter-jdbc 后在试!");
}
MagicDynamicDataSource.DataSourceNode dataSourceNode = magicDynamicDataSource.getDataSource(resourceConfig.getDatasource());
return new DatabaseResource(new JdbcTemplate(dataSourceNode.getDataSource()), resourceConfig.getTableName(), resourceConfig.getPrefix(), resourceConfig.isReadonly());
}
@Bean
@ConditionalOnMissingBean(org.ssssssss.magicapi.core.resource.Resource.class)
@ConditionalOnProperty(prefix = "magic-api", name = "resource.type", havingValue = "file", matchIfMissing = true)
public org.ssssssss.magicapi.core.resource.Resource magicResource() throws IOException {
Resource resourceConfig = properties.getResource();
return ResourceAdapter.getResource(resourceConfig.getLocation(), resourceConfig.isReadonly());
}
@Bean
@ConditionalOnMissingBean(MagicBackupService.class)
@ConditionalOnProperty(prefix = "magic-api", name = "backup.enable", havingValue = "true")
public MagicBackupService magicDatabaseBackupService(MagicDynamicDataSource magicDynamicDataSource) {
Backup backupConfig = properties.getBackup();
MagicDynamicDataSource.DataSourceNode dataSourceNode = magicDynamicDataSource.getDataSource(backupConfig.getDatasource());
return new MagicDatabaseBackupService(new JdbcTemplate(dataSourceNode.getDataSource()), backupConfig.getTableName());
}
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
String web = properties.getWeb();
if (web != null && !registerMapping) {
registerMapping = true;
// 当开启了UI界面时,收集日志
LoggerManager.createMagicAppender();
// 配置静态资源路径
registry.addResourceHandler(web + "/**").addResourceLocations("classpath:/magic-editor/");
}
}
@Bean
@ConditionalOnMissingBean
public MagicResourceService magicResourceService(org.ssssssss.magicapi.core.resource.Resource workspace) {
return new DefaultMagicResourceService(workspace, magicResourceStoragesProvider.getObject(), applicationContext);
}
@Bean
@ConditionalOnMissingBean(MagicNotifyService.class)
public MagicNotifyService magicNotifyService() {
logger.info("未配置集群通知服务,本实例不会推送通知,集群环境下可能会有问题,如需开启,请引用magic-api-plugin-cluster插件");
return magicNotify -> {
};
}
/**
* 注入API调用Service
*/
@Bean
@ConditionalOnMissingBean
public MagicAPIService magicAPIService(ResultProvider resultProvider, MagicResourceService magicResourceService, MagicRequestContextHolder magicRequestContextHolder, RequestMagicDynamicRegistry requestMagicDynamicRegistry, FunctionMagicDynamicRegistry functionMagicDynamicRegistry) {
WebUtils.magicRequestContextHolder = magicRequestContextHolder;
return new DefaultMagicAPIService(resultProvider, properties.getInstanceId(), magicResourceService, requestMagicDynamicRegistry, functionMagicDynamicRegistry, properties.isThrowException(), properties.getPrefix() ,magicRequestContextHolder, applicationContext);
}
/**
* 注册模块、类型扩展
*/
private void setupMagicModules(List<ExtensionMethod> extensionMethods, List<LanguageProvider> languageProviders) {
// 设置脚本import时 class加载策略
MagicResourceLoader.setClassLoader((className) -> {
try {
return applicationContext.getBean(className);
} catch (Exception e) {
Class<?> clazz = null;
try {
clazz = Class.forName(className);
return applicationContext.getBean(clazz);
} catch (Exception ex) {
if (clazz == null) {
throw new MagicScriptRuntimeException(new ClassNotFoundException(className));
}
return clazz;
}
}
});
MagicResourceLoader.addScriptLanguageLoader(language -> languageProviders.stream()
.filter(it -> it.support(language))
.findFirst().<BiFunction<Map<String, Object>, String, Object>>map(languageProvider -> (context, script) -> {
try {
return languageProvider.execute(language, script, context);
} catch (Exception e) {
throw new MagicAPIException(e.getMessage(), e);
}
}).orElse(null)
);
logger.info("注册模块:{} -> {}", "log", Logger.class);
MagicResourceLoader.addModule("log", new DynamicModuleImport(Logger.class, context -> LoggerFactory.getLogger(Objects.toString(context.getScriptName(), "Unknown"))));
List<String> importModules = properties.getAutoImportModuleList();
applicationContext.getBeansWithAnnotation(MagicModule.class).values().forEach(module -> {
String moduleName = AnnotationUtils.findAnnotation(module.getClass(), MagicModule.class).value();
logger.info("注册模块:{} -> {}", moduleName, module.getClass());
if(module instanceof DynamicModule){
MagicResourceLoader.addModule(moduleName, new DynamicModuleImport(module.getClass(), ((DynamicModule<?>) module)::getDynamicModule));
} else {
MagicResourceLoader.addModule(moduleName, module);
}
});
MagicResourceLoader.getModuleNames().stream().filter(importModules::contains).forEach(moduleName -> {
logger.info("自动导入模块:{}", moduleName);
MagicScriptEngine.addDefaultImport(moduleName, MagicResourceLoader.loadModule(moduleName));
});
properties.getAutoImportPackageList().forEach(importPackage -> {
logger.info("自动导包:{}", importPackage);
MagicResourceLoader.addPackage(importPackage);
});
extensionMethods.forEach(extension -> extension.supports().forEach(support -> {
logger.info("注册扩展:{} -> {}", support, extension.getClass());
JavaReflection.registerMethodExtension(support, extension);
}));
}
@Bean
public MagicConfiguration magicConfiguration(List<LanguageProvider> languageProviders,
org.ssssssss.magicapi.core.resource.Resource magicResource,
ResultProvider resultProvider,
MagicResourceService magicResourceService,
MagicAPIService magicAPIService,
MagicNotifyService magicNotifyService,
RequestMagicDynamicRegistry requestMagicDynamicRegistry,
@Autowired(required = false) MagicBackupService magicBackupService) throws NoSuchMethodException {
logger.info("magic-api工作目录:{}", magicResource);
AsyncCall.setThreadPoolExecutorSize(properties.getThreadPoolExecutorSize());
DataType.DATE_PATTERNS = properties.getDatePattern();
MagicScript.setCompileCache(properties.getCompileCacheSize());
// 设置响应结果的code值
ResponseCode responseCodeConfig = properties.getResponseCode();
Constants.RESPONSE_CODE_SUCCESS = responseCodeConfig.getSuccess();
Constants.RESPONSE_CODE_INVALID = responseCodeConfig.getInvalid();
Constants.RESPONSE_CODE_EXCEPTION = responseCodeConfig.getException();
// 设置模块和扩展方法
setupMagicModules(extensionMethodsProvider.getIfAvailable(Collections::emptyList), languageProviders);
MagicConfiguration configuration = new MagicConfiguration();
configuration.setMagicAPIService(magicAPIService);
configuration.setMagicNotifyService(magicNotifyService);
configuration.setInstanceId(properties.getInstanceId());
configuration.setMagicResourceService(magicResourceService);
configuration.setMagicDynamicRegistries(magicDynamicRegistriesProvider.getObject());
configuration.setMagicBackupService(magicBackupService);
Security security = properties.getSecurity();
configuration.setDebugTimeout(properties.getDebug().getTimeout());
configuration.setHttpMessageConverters(httpMessageConvertersProvider.getIfAvailable(Collections::emptyList));
configuration.setResultProvider(resultProvider);
configuration.setThrowException(properties.isThrowException());
configuration.setEditorConfig(properties.getEditorConfig());
configuration.setWorkspace(magicResource);
configuration.setAuthorizationInterceptor(authorizationInterceptorProvider.getObject());
// 注册函数
this.magicFunctionsProvider.getIfAvailable(Collections::emptyList).forEach(JavaReflection::registerFunction);
// 向页面传递配置信息时不传递用户名密码,增强安全性
security.setUsername(null);
security.setPassword(null);
requestMagicDynamicRegistry.setHandler(new RequestHandler(configuration, requestMagicDynamicRegistry));
List<MagicPluginConfiguration> pluginConfigurations = magicPluginsProvider.getIfAvailable(Collections::emptyList);
List<Plugin> plugins = pluginConfigurations.stream().map(MagicPluginConfiguration::plugin).collect(Collectors.toList());
// 构建UI请求处理器
String base = properties.getWeb();
Mapping mapping = Mapping.create(requestMappingHandlerMapping, base);
MagicWorkbenchController magicWorkbenchController = new MagicWorkbenchController(configuration, properties, plugins);
if (base != null) {
configuration.setEnableWeb(true);
mapping.registerController(magicWorkbenchController)
.registerController(new MagicResourceController(configuration))
.registerController(new MagicDataSourceController(configuration))
.registerController(new MagicBackupController(configuration));
pluginConfigurations.forEach(it -> it.controllerRegister().register(mapping, configuration));
}
// 注册接收推送的接口
if (StringUtils.isNotBlank(properties.getSecretKey())) {
mapping.register(mapping.paths(properties.getPushPath()).methods(RequestMethod.POST).build(), magicWorkbenchController, MagicWorkbenchController.class.getDeclaredMethod("receivePush", MultipartFile.class, String.class, Long.class, String.class));
}
// 设置拦截器信息
this.requestInterceptorsProvider.getIfAvailable(Collections::emptyList).forEach(interceptor -> {
logger.info("注册请求拦截器:{}", interceptor.getClass());
configuration.addRequestInterceptor(interceptor);
});
// 打印banner
if (this.properties.isBanner()) {
configuration.printBanner(plugins.stream().map(Plugin::getName).collect(Collectors.toList()));
}
if (magicBackupService == null) {
logger.error("当前备份设置未配置,强烈建议配置备份设置,以免代码丢失。");
}
// 备份清理
if (properties.getBackup().isEnable() && properties.getBackup().getMaxHistory() > 0 && magicBackupService != null) {
long interval = properties.getBackup().getMaxHistory() * 86400000L;
// 1小时执行1次
new ScheduledThreadPoolExecutor(1, r -> new Thread(r, "magic-api-clean-task")).scheduleAtFixedRate(() -> {
try {
long count = magicBackupService.removeBackupByTimestamp(System.currentTimeMillis() - interval);
if (count > 0) {
logger.info("已删除备份记录{}条", count);
}
} catch (Exception e) {
logger.error("删除备份记录时出错", e);
}
}, 1, 1, TimeUnit.HOURS);
}
return configuration;
}
@Bean
@ConditionalOnMissingBean
public AuthorizationInterceptor authorizationInterceptor(MagicAPIProperties properties){
Security security = properties.getSecurity();
return new DefaultAuthorizationInterceptor(security.getUsername(), security.getPassword());
}
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry webSocketHandlerRegistry) {
String web = properties.getWeb();
MagicNotifyService magicNotifyService = magicNotifyServiceProvider.getObject();
WebSocketSessionManager.setMagicNotifyService(magicNotifyService);
if (web != null && !registerWebsocket) {
registerWebsocket = true;
MagicWebSocketDispatcher dispatcher = new MagicWebSocketDispatcher(properties.getInstanceId(), magicNotifyService, Arrays.asList(
new MagicDebugHandler(),
new MagicCoordinationHandler(),
new MagicWorkbenchHandler(authorizationInterceptorProvider.getObject())
));
WebSocketHandlerRegistration registration = webSocketHandlerRegistry.addHandler(dispatcher, web + "/console");
if (properties.isSupportCrossDomain()) {
registration.setAllowedOrigins("*");
}
}
}
}
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.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.ssssssss.magicapi.core.config.MagicAPIProperties;
import org.ssssssss.magicapi.core.interceptor.DefaultResultProvider;
import org.ssssssss.magicapi.core.interceptor.ResultProvider;
import org.ssssssss.magicapi.core.service.impl.ApiInfoMagicResourceStorage;
import org.ssssssss.magicapi.core.service.impl.RequestMagicDynamicRegistry;
import org.ssssssss.magicapi.datasource.model.MagicDynamicDataSource;
import org.ssssssss.magicapi.datasource.service.DataSourceInfoMagicResourceStorage;
import org.ssssssss.magicapi.datasource.service.DataSourceMagicDynamicRegistry;
import org.ssssssss.magicapi.function.service.FunctionInfoMagicResourceStorage;
import org.ssssssss.magicapi.function.service.FunctionMagicDynamicRegistry;
import org.ssssssss.magicapi.utils.Mapping;
@Configuration
@AutoConfigureAfter(MagicModuleConfiguration.class)
public class MagicDynamicRegistryConfiguration {
private final MagicAPIProperties properties;
@Autowired
@Lazy
private RequestMappingHandlerMapping requestMappingHandlerMapping;
public MagicDynamicRegistryConfiguration(MagicAPIProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public ApiInfoMagicResourceStorage apiInfoMagicResourceStorage() {
return new ApiInfoMagicResourceStorage(properties.getPrefix());
}
@Bean
@ConditionalOnMissingBean
public RequestMagicDynamicRegistry magicRequestMagicDynamicRegistry(ApiInfoMagicResourceStorage apiInfoMagicResourceStorage) throws NoSuchMethodException {
return new RequestMagicDynamicRegistry(apiInfoMagicResourceStorage, Mapping.create(requestMappingHandlerMapping, properties.getWeb()), properties.isAllowOverride(), properties.getPrefix());
}
@Bean
@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, MagicDynamicDataSource magicDynamicDataSource) {
return new DataSourceMagicDynamicRegistry(dataSourceInfoMagicResourceStorage, magicDynamicDataSource);
}
}
package org.ssssssss.magicapi.spring.boot.starter;
import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Configuration;
import org.ssssssss.magicapi.utils.IoUtils;
import org.ssssssss.script.exception.MagicScriptException;
import org.ssssssss.script.parsing.ast.statement.ClassConverter;
import java.io.IOException;
import java.io.InputStream;
import java.util.function.Function;
/**
* JSON自动配置
*
* @author mxd
*/
@Configuration
@AutoConfigureBefore(MagicAPIAutoConfiguration.class)
public class MagicJsonAutoConfiguration {
private static void register(Function<String, Object> processString, Function<byte[], Object> processBytes, Function<Object, String> stringify) {
register(processString, processBytes, IoUtils::bytes, stringify);
}
private static void register(Function<String, Object> processString, Function<byte[], Object> processBytes, Function<InputStream, Object> processInputStream, Function<Object, String> stringify) {
ClassConverter.register("json", (value, params) -> {
if (value == null) {
return params != null && params.length > 0 ? params[0] : null;
} else if (value instanceof CharSequence) {
return processString.apply(value.toString());
} else if (value instanceof byte[]) {
return processBytes.apply((byte[]) value);
} else if (value instanceof InputStream) {
return processInputStream.apply((InputStream) value);
}
throw new MagicScriptException(String.format("不支持的类型:%s", value.getClass()));
});
ClassConverter.register("stringify", (value, params) -> {
if (value == null) {
return params != null && params.length > 0 ? params[0] : null;
}
return stringify.apply(value);
});
}
@ConditionalOnBean({ObjectMapper.class})
@Configuration
static class MagicJacksonAutoConfiguration {
MagicJacksonAutoConfiguration(ObjectMapper objectMapper) {
register(str -> {
try {
return objectMapper.readValue(str, Object.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}, bytes -> {
try {
return objectMapper.readValue(bytes, Object.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}, is -> {
try {
return objectMapper.readValue(is, Object.class);
} catch (IOException e) {
throw new RuntimeException(e);
}
}, object -> {
try {
return objectMapper.writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
});
}
}
@ConditionalOnMissingBean({ObjectMapper.class})
@ConditionalOnClass(JSON.class)
@Configuration
static class MagicFastJsonAutoConfiguration {
MagicFastJsonAutoConfiguration() {
register(JSON::parse, JSON::parse, JSON::toJSONString);
}
}
}
package org.ssssssss.magicapi.spring.boot.starter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;
import org.springframework.http.MediaType;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartResolver;
import org.ssssssss.magicapi.core.config.Cache;
import org.ssssssss.magicapi.core.config.MagicAPIProperties;
import org.ssssssss.magicapi.core.config.Page;
import org.ssssssss.magicapi.core.interceptor.DefaultResultProvider;
import org.ssssssss.magicapi.core.interceptor.ResultProvider;
import org.ssssssss.magicapi.core.servlet.MagicRequestContextHolder;
import org.ssssssss.magicapi.datasource.model.MagicDynamicDataSource;
import org.ssssssss.magicapi.jsr223.JSR223LanguageProvider;
import org.ssssssss.magicapi.modules.db.ColumnMapperAdapter;
import org.ssssssss.magicapi.modules.db.SQLModule;
import org.ssssssss.magicapi.modules.db.cache.DefaultSqlCache;
import org.ssssssss.magicapi.modules.db.cache.SqlCache;
import org.ssssssss.magicapi.modules.db.dialect.Dialect;
import org.ssssssss.magicapi.modules.db.dialect.DialectAdapter;
import org.ssssssss.magicapi.modules.db.inteceptor.DefaultSqlInterceptor;
import org.ssssssss.magicapi.modules.db.inteceptor.NamedTableInterceptor;
import org.ssssssss.magicapi.modules.db.inteceptor.SQLInterceptor;
import org.ssssssss.magicapi.modules.db.provider.ColumnMapperProvider;
import org.ssssssss.magicapi.modules.db.provider.DefaultPageProvider;
import org.ssssssss.magicapi.modules.db.provider.PageProvider;
import org.ssssssss.magicapi.modules.http.HttpModule;
import org.ssssssss.magicapi.modules.servlet.RequestModule;
import org.ssssssss.magicapi.modules.servlet.ResponseModule;
import org.ssssssss.magicapi.modules.spring.EnvModule;
import javax.sql.DataSource;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MagicModuleConfiguration {
private static final Logger logger = LoggerFactory.getLogger(MagicModuleConfiguration.class);
private final MagicAPIProperties properties;
/**
* SQL拦截器
*/
private final ObjectProvider<List<SQLInterceptor>> sqlInterceptorsProvider;
/**
* 单表API拦截器
*/
private final ObjectProvider<List<NamedTableInterceptor>> namedTableInterceptorsProvider;
/**
* 自定义的方言
*/
private final ObjectProvider<List<Dialect>> dialectsProvider;
/**
* 自定义的列名转换
*/
private final ObjectProvider<List<ColumnMapperProvider>> columnMapperProvidersProvider;
private final Environment environment;
@Autowired(required = false)
private MultipartResolver multipartResolver;
public MagicModuleConfiguration(MagicAPIProperties properties,
ObjectProvider<List<SQLInterceptor>> sqlInterceptorsProvider,
ObjectProvider<List<NamedTableInterceptor>> namedTableInterceptorsProvider,
ObjectProvider<List<Dialect>> dialectsProvider,
ObjectProvider<List<ColumnMapperProvider>> columnMapperProvidersProvider,
Environment environment) {
this.properties = properties;
this.sqlInterceptorsProvider = sqlInterceptorsProvider;
this.namedTableInterceptorsProvider = namedTableInterceptorsProvider;
this.dialectsProvider = dialectsProvider;
this.columnMapperProvidersProvider = columnMapperProvidersProvider;
this.environment = environment;
}
/**
* 注入动态数据源
*/
@Bean
@ConditionalOnMissingBean(MagicDynamicDataSource.class)
public MagicDynamicDataSource magicDynamicDataSource(@Autowired(required = false) DataSource dataSource) {
MagicDynamicDataSource dynamicDataSource = new MagicDynamicDataSource();
if (dataSource != null) {
dynamicDataSource.put(dataSource);
} else {
logger.warn("当前数据源未配置");
}
return dynamicDataSource;
}
@Bean
@ConditionalOnMissingBean(PageProvider.class)
public PageProvider pageProvider() {
Page pageConfig = properties.getPage();
logger.info("未找到分页实现,采用默认分页实现,分页配置:(页码={},页大小={},默认首页={},默认页大小={},最大页大小={})", pageConfig.getPage(), pageConfig.getSize(), pageConfig.getDefaultPage(), pageConfig.getDefaultSize(), pageConfig.getMaxPageSize());
return new DefaultPageProvider(pageConfig.getPage(), pageConfig.getSize(), pageConfig.getDefaultPage(), pageConfig.getDefaultSize(), pageConfig.getMaxPageSize());
}
/**
* 注入SQL缓存实现
*/
@Bean
@ConditionalOnMissingBean(SqlCache.class)
public SqlCache sqlCache() {
Cache cacheConfig = properties.getCache();
logger.info("未找到SQL缓存实现,采用默认缓存实现(LRU+TTL),缓存配置:(容量={},TTL={})", cacheConfig.getCapacity(), cacheConfig.getTtl());
return new DefaultSqlCache(cacheConfig.getCapacity(), cacheConfig.getTtl());
}
/**
* 注入数据库查询模块
*/
@Bean
@ConditionalOnBean({MagicDynamicDataSource.class})
public SQLModule magicSqlModule(MagicDynamicDataSource dynamicDataSource,
ResultProvider resultProvider,
PageProvider pageProvider,
SqlCache sqlCache) {
SQLModule sqlModule = new SQLModule(dynamicDataSource);
if (!dynamicDataSource.isEmpty()) {
sqlModule.setDataSourceNode(dynamicDataSource.getDataSource());
}
sqlModule.setResultProvider(resultProvider);
sqlModule.setPageProvider(pageProvider);
List<SQLInterceptor> sqlInterceptors = sqlInterceptorsProvider.getIfAvailable(ArrayList::new);
if (properties.isShowSql()) {
sqlInterceptors.add(new DefaultSqlInterceptor());
}
sqlModule.setSqlInterceptors(sqlInterceptors);
sqlModule.setNamedTableInterceptors(namedTableInterceptorsProvider.getIfAvailable(Collections::emptyList));
ColumnMapperAdapter columnMapperAdapter = new ColumnMapperAdapter();
this.columnMapperProvidersProvider.getIfAvailable(Collections::emptyList).stream().filter(mapperProvider -> !"default".equals(mapperProvider.name())).forEach(columnMapperAdapter::add);
columnMapperAdapter.setDefault(properties.getSqlColumnCase());
sqlModule.setColumnMapperProvider(columnMapperAdapter);
sqlModule.setColumnMapRowMapper(columnMapperAdapter.getDefaultColumnMapRowMapper());
sqlModule.setRowMapColumnMapper(columnMapperAdapter.getDefaultRowMapColumnMapper());
sqlModule.setSqlCache(sqlCache);
DialectAdapter dialectAdapter = new DialectAdapter();
dialectsProvider.getIfAvailable(Collections::emptyList).forEach(dialectAdapter::add);
sqlModule.setDialectAdapter(dialectAdapter);
sqlModule.setLogicDeleteColumn(properties.getCrud().getLogicDeleteColumn());
sqlModule.setLogicDeleteValue(properties.getCrud().getLogicDeleteValue());
return sqlModule;
}
@Bean
public JSR223LanguageProvider jsr223LanguageProvider() {
return new JSR223LanguageProvider();
}
@Bean
@ConditionalOnMissingBean(HttpModule.class)
public HttpModule magicHttpModule() {
return new HttpModule(createRestTemplate());
}
@Bean
@ConditionalOnMissingBean
public EnvModule magicEnvModule(){
return new EnvModule(environment);
}
@Bean
@ConditionalOnMissingBean
public RequestModule magicRequestModule(MagicRequestContextHolder magicRequestContextHolder){
return new RequestModule(magicRequestContextHolder);
}
/**
* 注入结果构建方法
*/
@Bean
@ConditionalOnMissingBean(ResultProvider.class)
public ResultProvider resultProvider() {
return new DefaultResultProvider(properties.getResponse());
}
@Bean
@ConditionalOnMissingBean
public ResponseModule magicResponseModule(ResultProvider resultProvider){
return new ResponseModule(resultProvider);
}
private RestTemplate createRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new StringHttpMessageConverter(StandardCharsets.UTF_8) {
{
setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
}
@Override
public boolean supports(Class<?> clazz) {
return true;
}
});
return restTemplate;
}
}
package org.ssssssss.magicapi.spring.boot.starter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.ssssssss.magicapi.servlet.javaee.MagicJavaEEServletConfiguration;
@Configuration
@AutoConfigureBefore(MagicAPIAutoConfiguration.class)
public class MagicServletConfiguration {
public MagicServletConfiguration() {
}
static class JakartaConfigurationImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"org.ssssssss.magicapi.servlet.jakarta.MagicJakartaServletConfiguration"};
}
}
@Configuration
@ConditionalOnClass(name = "jakarta.servlet.http.HttpServletRequest")
@Import(JakartaConfigurationImportSelector.class)
static class JakartaEEConfiguration {
}
@Configuration
@ConditionalOnClass(name = "javax.servlet.http.HttpServletRequest")
@Import(MagicJavaEEServletConfiguration.class)
static class JavaEEConfiguration{
}
}
org.springframework.boot.autoconfigure.EnableAutoConfiguration=org.ssssssss.magicapi.spring.boot.starter.MagicAPIAutoConfiguration
\ No newline at end of file
org.ssssssss.magicapi.spring.boot.starter.MagicAPIAutoConfiguration
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment