+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.cloud.http;
+
+import org.springblade.core.cloud.props.BladeFeignHeadersProperties;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+
+/**
+ * http 配置
+ *
+ * @author L.cm
+ */
+@AutoConfiguration
+@EnableConfigurationProperties({BladeHttpProperties.class, BladeFeignHeadersProperties.class})
+public class BladeHttpConfiguration {
+}
diff --git a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/BladeHttpProperties.java b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/BladeHttpProperties.java
new file mode 100644
index 0000000..48d9e48
--- /dev/null
+++ b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/BladeHttpProperties.java
@@ -0,0 +1,64 @@
+/**
+ * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.cloud.http;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springblade.core.launch.log.BladeLogLevel;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * http 配置
+ *
+ * @author L.cm
+ */
+@Getter
+@Setter
+@RefreshScope
+@ConfigurationProperties("blade.http")
+public class BladeHttpProperties {
+ /**
+ * 最大连接数,默认:200
+ */
+ private int maxConnections = 200;
+ /**
+ * 连接存活时间,默认:900L
+ */
+ private long timeToLive = 900L;
+ /**
+ * 连接池存活时间单位,默认:秒
+ */
+ private TimeUnit timeUnit = TimeUnit.SECONDS;
+ /**
+ * 链接超时,默认:2000毫秒
+ */
+ private int connectionTimeout = 2000;
+ /**
+ * 是否支持重定向,默认:true
+ */
+ private boolean followRedirects = true;
+ /**
+ * 关闭证书校验
+ */
+ private boolean disableSslValidation = true;
+ /**
+ * 日志级别
+ */
+ private BladeLogLevel level = BladeLogLevel.NONE;
+}
diff --git a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/HttpLoggingInterceptor.java b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/HttpLoggingInterceptor.java
index 67eeb8a..5008593 100644
--- a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/HttpLoggingInterceptor.java
+++ b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/HttpLoggingInterceptor.java
@@ -17,10 +17,10 @@ package org.springblade.core.cloud.http;
import okhttp3.*;
import okhttp3.internal.http.HttpHeaders;
-import okhttp3.internal.platform.Platform;
import okio.Buffer;
import okio.BufferedSource;
import okio.GzipSource;
+import org.springblade.core.launch.log.BladeLogLevel;
import java.io.EOFException;
import java.io.IOException;
@@ -29,8 +29,6 @@ import java.nio.charset.StandardCharsets;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
-import static okhttp3.internal.platform.Platform.INFO;
-
/**
* An OkHttp interceptor which logs request and response information. Can be applied as an
* {@linkplain OkHttpClient#interceptors() application interceptor} or as a {@linkplain
@@ -42,121 +40,46 @@ import static okhttp3.internal.platform.Platform.INFO;
*/
public final class HttpLoggingInterceptor implements Interceptor {
private static final Charset UTF8 = StandardCharsets.UTF_8;
-
- public enum Level {
- /**
- * No logs.
- */
- NONE,
- /**
- * Logs request and response lines.
- *
- *
- */
- BODY
- }
+ private final Logger logger;
+ private volatile BladeLogLevel level = BladeLogLevel.NONE;
public interface Logger {
/**
* log
- *
* @param message message
*/
void log(String message);
-
- /**
- * A {@link Logger} defaults output appropriate for the current platform.
- */
- Logger DEFAULT = message -> Platform.get().log(message, INFO, null);
- }
-
- public HttpLoggingInterceptor() {
- this(Logger.DEFAULT);
}
public HttpLoggingInterceptor(Logger logger) {
this.logger = logger;
}
- private final Logger logger;
-
- private volatile Level level = Level.NONE;
-
/**
* Change the level at which this interceptor logs.
- *
* @param level log Level
* @return HttpLoggingInterceptor
*/
- public HttpLoggingInterceptor setLevel(Level level) {
- Objects.requireNonNull(level, "level == null. Use Level.NONE instead.");
- this.level = level;
+ public HttpLoggingInterceptor setLevel(BladeLogLevel level) {
+ this.level = Objects.requireNonNull(level, "level == null. Use Level.NONE instead.");
return this;
}
- public Level getLevel() {
+ public BladeLogLevel getLevel() {
return level;
}
- private String gzip = "gzip";
- private String contentEncoding = "Content-Encoding";
-
@Override
public Response intercept(Chain chain) throws IOException {
- Level level = this.level;
+ BladeLogLevel level = this.level;
Request request = chain.request();
- if (level == Level.NONE) {
+ if (level == BladeLogLevel.NONE) {
return chain.proceed(request);
}
- boolean logBody = level == Level.BODY;
- boolean logHeaders = logBody || level == Level.HEADERS;
+ boolean logBody = level == BladeLogLevel.BODY;
+ boolean logHeaders = logBody || level == BladeLogLevel.HEADERS;
RequestBody requestBody = request.body();
boolean hasRequestBody = requestBody != null;
@@ -239,7 +162,8 @@ public final class HttpLoggingInterceptor implements Interceptor {
if (logHeaders) {
Headers headers = response.headers();
- for (int i = 0, count = headers.size(); i < count; i++) {
+ int count = headers.size();
+ for (int i = 0; i < count; i++) {
logger.log(headers.name(i) + ": " + headers.value(i));
}
@@ -251,10 +175,10 @@ public final class HttpLoggingInterceptor implements Interceptor {
BufferedSource source = responseBody.source();
// Buffer the entire body.
source.request(Long.MAX_VALUE);
- Buffer buffer = source.buffer();
+ Buffer buffer = source.getBuffer();
Long gzippedLength = null;
- if (gzip.equalsIgnoreCase(headers.get(contentEncoding))) {
+ if ("gzip".equalsIgnoreCase(headers.get("Content-Encoding"))) {
gzippedLength = buffer.size();
GzipSource gzippedResponseBody = null;
try {
@@ -301,14 +225,12 @@ public final class HttpLoggingInterceptor implements Interceptor {
* Returns true if the body in question probably contains human readable text. Uses a small sample
* of code points to detect unicode control characters commonly used in binary file signatures.
*/
- private static int plainCnt = 16;
-
private static boolean isPlaintext(Buffer buffer) {
try {
Buffer prefix = new Buffer();
long byteCount = buffer.size() < 64 ? buffer.size() : 64;
buffer.copyTo(prefix, 0, byteCount);
- for (int i = 0; i < plainCnt; i++) {
+ for (int i = 0; i < 16; i++) {
if (prefix.exhausted()) {
break;
}
diff --git a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateConfiguration.java b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateConfiguration.java
index 140343a..6dd2ede 100644
--- a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateConfiguration.java
+++ b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/RestTemplateConfiguration.java
@@ -17,29 +17,38 @@ package org.springblade.core.cloud.http;
import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.AllArgsConstructor;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.ConnectionPool;
+import okhttp3.OkHttpClient;
import org.springblade.core.cloud.header.BladeFeignAccountGetter;
+import org.springblade.core.cloud.http.client.OkHttp3ClientHttpRequestFactory;
import org.springblade.core.cloud.props.BladeFeignHeadersProperties;
+import org.springblade.core.tool.ssl.DisableValidationTrustManager;
+import org.springblade.core.tool.ssl.TrustAllHostNames;
import org.springblade.core.tool.utils.Charsets;
+import org.springblade.core.tool.utils.Holder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
-import org.springframework.cloud.commons.httpclient.OkHttpClientConnectionPoolFactory;
-import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
-import org.springframework.cloud.openfeign.support.FeignHttpClientProperties;
+import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Profile;
-import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.lang.Nullable;
import org.springframework.web.client.RestTemplate;
-import java.util.Collections;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -48,84 +57,53 @@ import java.util.concurrent.TimeUnit;
*
* @author L.cm
*/
+@Slf4j
+@RequiredArgsConstructor
@AutoConfiguration
-@AllArgsConstructor
-@ConditionalOnClass(okhttp3.OkHttpClient.class)
-@EnableConfigurationProperties(BladeFeignHeadersProperties.class)
+@ConditionalOnClass(OkHttpClient.class)
+@ConditionalOnProperty(value = "blade.http.enabled", matchIfMissing = true)
public class RestTemplateConfiguration {
- private final ObjectMapper objectMapper;
+ private final BladeHttpProperties properties;
/**
- * dev, test 环境打印出BODY
+ * okhttp3 请求日志拦截器
+ *
* @return HttpLoggingInterceptor
*/
- @Bean("httpLoggingInterceptor")
- @Profile({"dev", "test"})
- public HttpLoggingInterceptor testLoggingInterceptor() {
+ @Bean
+ public HttpLoggingInterceptor loggingInterceptor() {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new OkHttpSlf4jLogger());
- interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
- return interceptor;
- }
-
- /**
- * ontest 环境 打印 请求头
- * @return HttpLoggingInterceptor
- */
- @Bean("httpLoggingInterceptor")
- @Profile("ontest")
- public HttpLoggingInterceptor onTestLoggingInterceptor() {
- HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new OkHttpSlf4jLogger());
- interceptor.setLevel(HttpLoggingInterceptor.Level.HEADERS);
- return interceptor;
- }
-
- /**
- * prod 环境只打印请求url
- * @return HttpLoggingInterceptor
- */
- @Bean("httpLoggingInterceptor")
- @Profile("prod")
- public HttpLoggingInterceptor prodLoggingInterceptor() {
- HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(new OkHttpSlf4jLogger());
- interceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
+ interceptor.setLevel(properties.getLevel());
return interceptor;
}
/**
* okhttp3 链接池配置
- * @param connectionPoolFactory 链接池配置
- * @param httpClientProperties httpClient配置
+ *
* @return okhttp3.ConnectionPool
*/
@Bean
- @ConditionalOnMissingBean(okhttp3.ConnectionPool.class)
- public okhttp3.ConnectionPool httpClientConnectionPool(
- FeignHttpClientProperties httpClientProperties,
- OkHttpClientConnectionPoolFactory connectionPoolFactory) {
- Integer maxTotalConnections = httpClientProperties.getMaxConnections();
- Long timeToLive = httpClientProperties.getTimeToLive();
- TimeUnit ttlUnit = httpClientProperties.getTimeToLiveUnit();
- return connectionPoolFactory.create(maxTotalConnections, timeToLive, ttlUnit);
+ @ConditionalOnMissingBean
+ public ConnectionPool httpClientConnectionPool() {
+ int maxTotalConnections = properties.getMaxConnections();
+ long timeToLive = properties.getTimeToLive();
+ TimeUnit ttlUnit = properties.getTimeUnit();
+ return new ConnectionPool(maxTotalConnections, timeToLive, ttlUnit);
}
/**
* 配置OkHttpClient
- * @param httpClientFactory httpClient 工厂
+ *
* @param connectionPool 链接池配置
- * @param httpClientProperties httpClient配置
- * @param interceptor 拦截器
+ * @param interceptor 拦截器
* @return OkHttpClient
*/
@Bean
- @ConditionalOnMissingBean(okhttp3.OkHttpClient.class)
- public okhttp3.OkHttpClient httpClient(
- OkHttpClientFactory httpClientFactory,
- okhttp3.ConnectionPool connectionPool,
- FeignHttpClientProperties httpClientProperties,
- HttpLoggingInterceptor interceptor) {
- Boolean followRedirects = httpClientProperties.isFollowRedirects();
- Integer connectTimeout = httpClientProperties.getConnectionTimeout();
- return httpClientFactory.createBuilder(httpClientProperties.isDisableSslValidation())
+ @ConditionalOnMissingBean
+ public OkHttpClient okHttpClient(ConnectionPool connectionPool, HttpLoggingInterceptor interceptor) {
+ boolean followRedirects = properties.isFollowRedirects();
+ int connectTimeout = properties.getConnectionTimeout();
+ return this.createBuilder(properties.isDisableSslValidation())
.connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
@@ -135,6 +113,24 @@ public class RestTemplateConfiguration {
.build();
}
+ private OkHttpClient.Builder createBuilder(boolean disableSslValidation) {
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ if (disableSslValidation) {
+ try {
+ X509TrustManager disabledTrustManager = DisableValidationTrustManager.INSTANCE;
+ TrustManager[] trustManagers = new TrustManager[]{disabledTrustManager};
+ SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, trustManagers, Holder.SECURE_RANDOM);
+ SSLSocketFactory disabledSslSocketFactory = sslContext.getSocketFactory();
+ builder.sslSocketFactory(disabledSslSocketFactory, disabledTrustManager);
+ builder.hostnameVerifier(TrustAllHostNames.INSTANCE);
+ } catch (NoSuchAlgorithmException | KeyManagementException e) {
+ log.warn("Error setting SSLSocketFactory in OKHttpClient", e);
+ }
+ }
+ return builder;
+ }
+
@Bean
public RestTemplateHeaderInterceptor requestHeaderInterceptor(
@Autowired(required = false) @Nullable BladeFeignAccountGetter accountGetter,
@@ -142,38 +138,57 @@ public class RestTemplateConfiguration {
return new RestTemplateHeaderInterceptor(accountGetter,properties);
}
- /**
- * 普通的 RestTemplate,不透传请求头,一般只做外部 http 调用
- * @param httpClient OkHttpClient
- * @return RestTemplate
- */
- @Bean
- @ConditionalOnMissingBean(RestTemplate.class)
- public RestTemplate restTemplate(okhttp3.OkHttpClient httpClient) {
- RestTemplate restTemplate = new RestTemplate(new OkHttp3ClientHttpRequestFactory(httpClient));
- configMessageConverters(restTemplate.getMessageConverters());
- return restTemplate;
+ @AutoConfiguration
+ @RequiredArgsConstructor
+ @ConditionalOnClass(OkHttpClient.class)
+ @ConditionalOnProperty(value = "blade.http.rest-template.enable")
+ public static class RestTemplateAutoConfiguration {
+ private final ApplicationContext context;
+
+ /**
+ * 普通的 RestTemplate,不透传请求头,一般只做外部 http 调用
+ *
+ * @param okHttpClient OkHttpClient
+ * @return RestTemplate
+ */
+ @Bean
+ @ConditionalOnMissingBean
+ public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder, OkHttpClient okHttpClient) {
+ restTemplateBuilder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient));
+ RestTemplate restTemplate = restTemplateBuilder.build();
+ configMessageConverters(context, restTemplate.getMessageConverters());
+ return restTemplate;
+ }
}
- /**
- * 支持负载均衡的 LbRestTemplate
- * @param httpClient OkHttpClient
- * @param interceptor RestTemplateHeaderInterceptor
- * @return LbRestTemplate
- */
- @Bean
- @LoadBalanced
- @ConditionalOnMissingBean(LbRestTemplate.class)
- public LbRestTemplate lbRestTemplate(okhttp3.OkHttpClient httpClient, RestTemplateHeaderInterceptor interceptor) {
- LbRestTemplate lbRestTemplate = new LbRestTemplate(new OkHttp3ClientHttpRequestFactory(httpClient));
- lbRestTemplate.setInterceptors(Collections.singletonList(interceptor));
- configMessageConverters(lbRestTemplate.getMessageConverters());
- return lbRestTemplate;
+ @AutoConfiguration
+ @RequiredArgsConstructor
+ @ConditionalOnClass(OkHttpClient.class)
+ @ConditionalOnProperty(value = "blade.http.lb-rest-template.enable")
+ public static class LbRestTemplateAutoConfiguration {
+ private final ApplicationContext context;
+
+ /**
+ * 支持负载均衡的 LbRestTemplate
+ *
+ * @param okHttpClient OkHttpClient
+ * @return LbRestTemplate
+ */
+ @Bean
+ @LoadBalanced
+ @ConditionalOnMissingBean
+ public LbRestTemplate lbRestTemplate(RestTemplateBuilder restTemplateBuilder, OkHttpClient okHttpClient) {
+ restTemplateBuilder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient));
+ LbRestTemplate restTemplate = restTemplateBuilder.build(LbRestTemplate.class);
+ restTemplate.getInterceptors().add(context.getBean(RestTemplateHeaderInterceptor.class));
+ configMessageConverters(context, restTemplate.getMessageConverters());
+ return restTemplate;
+ }
}
- private void configMessageConverters(List> converters) {
+ private static void configMessageConverters(ApplicationContext context, List> converters) {
converters.removeIf(x -> x instanceof StringHttpMessageConverter || x instanceof MappingJackson2HttpMessageConverter);
converters.add(new StringHttpMessageConverter(Charsets.UTF_8));
- converters.add(new MappingJackson2HttpMessageConverter(objectMapper));
+ converters.add(new MappingJackson2HttpMessageConverter(context.getBean(ObjectMapper.class)));
}
}
diff --git a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/AbstractStreamingClientHttpRequest.java b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/AbstractStreamingClientHttpRequest.java
new file mode 100644
index 0000000..3b362c6
--- /dev/null
+++ b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/AbstractStreamingClientHttpRequest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2002-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.cloud.http.client;
+
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.StreamingHttpOutputMessage;
+import org.springframework.http.client.AbstractClientHttpRequest;
+import org.springframework.http.client.ClientHttpRequest;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+import org.springframework.util.FastByteArrayOutputStream;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * Abstract base for {@link ClientHttpRequest} that also implement
+ * {@link StreamingHttpOutputMessage}. Ensures that headers and
+ * body are not written multiple times.
+ *
+ * @author Arjen Poutsma
+ * @since 6.1
+ */
+public abstract class AbstractStreamingClientHttpRequest extends AbstractClientHttpRequest
+ implements StreamingHttpOutputMessage {
+
+ @Nullable
+ private Body body;
+
+ @Nullable
+ private FastByteArrayOutputStream bodyStream;
+
+
+ @Override
+ protected final OutputStream getBodyInternal(HttpHeaders headers) {
+ Assert.state(this.body == null, "Invoke either getBody or setBody; not both");
+
+ if (this.bodyStream == null) {
+ this.bodyStream = new FastByteArrayOutputStream(1024);
+ }
+ return this.bodyStream;
+ }
+
+ @Override
+ public final void setBody(Body body) {
+ Assert.notNull(body, "Body must not be null");
+ assertNotExecuted();
+ Assert.state(this.bodyStream == null, "Invoke either getBody or setBody; not both");
+
+ this.body = body;
+ }
+
+ @Override
+ protected final ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
+ if (this.body == null && this.bodyStream != null) {
+ this.body = outputStream -> this.bodyStream.writeTo(outputStream);
+ }
+ return executeInternal(headers, this.body);
+ }
+
+
+ /**
+ * Abstract template method that writes the given headers and content to the HTTP request.
+ *
+ * @param headers the HTTP headers
+ * @param body the HTTP body, may be {@code null} if no body was {@linkplain #setBody(Body) set}
+ * @return the response object for the executed request
+ * @since 6.1
+ */
+ protected abstract ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException;
+
+}
diff --git a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpRequest.java b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpRequest.java
new file mode 100644
index 0000000..3b682a2
--- /dev/null
+++ b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpRequest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2002-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.cloud.http.client;
+
+import okhttp3.MediaType;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.RequestBody;
+import okio.BufferedSink;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.client.ClientHttpRequest;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.lang.Nullable;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * {@link ClientHttpRequest} implementation based on OkHttp 3.x.
+ *
+ *
Created via the {@link OkHttp3ClientHttpRequestFactory}.
+ *
+ * @author Luciano Leggieri
+ * @author Arjen Poutsma
+ * @author Roy Clarkson
+ * @since 4.3
+ */
+public class OkHttp3ClientHttpRequest extends AbstractStreamingClientHttpRequest {
+
+ private final OkHttpClient client;
+
+ private final URI uri;
+
+ private final HttpMethod method;
+
+
+ public OkHttp3ClientHttpRequest(OkHttpClient client, URI uri, HttpMethod method) {
+ this.client = client;
+ this.uri = uri;
+ this.method = method;
+ }
+
+
+ @Override
+ public HttpMethod getMethod() {
+ return this.method;
+ }
+
+ @Override
+ public URI getURI() {
+ return this.uri;
+ }
+
+ @Override
+ @SuppressWarnings("removal")
+ protected ClientHttpResponse executeInternal(HttpHeaders headers, @Nullable Body body) throws IOException {
+
+ RequestBody requestBody;
+ if (body != null) {
+ requestBody = new BodyRequestBody(headers, body);
+ } else if (okhttp3.internal.http.HttpMethod.requiresRequestBody(getMethod().name())) {
+ String header = headers.getFirst(HttpHeaders.CONTENT_TYPE);
+ MediaType contentType = (header != null) ? MediaType.parse(header) : null;
+ requestBody = RequestBody.create(contentType, new byte[0]);
+ } else {
+ requestBody = null;
+ }
+ Request.Builder builder = new Request.Builder()
+ .url(this.uri.toURL());
+ builder.method(this.method.name(), requestBody);
+ headers.forEach((headerName, headerValues) -> {
+ for (String headerValue : headerValues) {
+ builder.addHeader(headerName, headerValue);
+ }
+ });
+ Request request = builder.build();
+ return new OkHttp3ClientHttpResponse(this.client.newCall(request).execute());
+ }
+
+
+ private static class BodyRequestBody extends RequestBody {
+
+ private final HttpHeaders headers;
+
+ private final Body body;
+
+
+ public BodyRequestBody(HttpHeaders headers, Body body) {
+ this.headers = headers;
+ this.body = body;
+ }
+
+ @Override
+ public long contentLength() {
+ return this.headers.getContentLength();
+ }
+
+ @Nullable
+ @Override
+ public MediaType contentType() {
+ String contentType = this.headers.getFirst(HttpHeaders.CONTENT_TYPE);
+ if (StringUtils.hasText(contentType)) {
+ return MediaType.parse(contentType);
+ } else {
+ return null;
+ }
+ }
+
+ @Override
+ public void writeTo(BufferedSink sink) throws IOException {
+ this.body.writeTo(sink.outputStream());
+ }
+
+ @Override
+ public boolean isOneShot() {
+ return !this.body.repeatable();
+ }
+ }
+
+
+}
diff --git a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpRequestFactory.java b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpRequestFactory.java
new file mode 100644
index 0000000..ac162fb
--- /dev/null
+++ b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpRequestFactory.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2002-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.cloud.http.client;
+
+import okhttp3.Cache;
+import okhttp3.OkHttpClient;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.http.HttpMethod;
+import org.springframework.http.client.ClientHttpRequest;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.util.Assert;
+
+import java.io.IOException;
+import java.net.URI;
+import java.time.Duration;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * {@link ClientHttpRequestFactory} implementation that uses
+ * OkHttp 3.x to create requests.
+ *
+ * @author Luciano Leggieri
+ * @author Arjen Poutsma
+ * @author Roy Clarkson
+ * @since 4.3
+ */
+public class OkHttp3ClientHttpRequestFactory implements ClientHttpRequestFactory, DisposableBean {
+
+ private OkHttpClient client;
+
+ private final boolean defaultClient;
+
+
+ /**
+ * Create a factory with a default {@link OkHttpClient} instance.
+ */
+ public OkHttp3ClientHttpRequestFactory() {
+ this.client = new OkHttpClient();
+ this.defaultClient = true;
+ }
+
+ /**
+ * Create a factory with the given {@link OkHttpClient} instance.
+ *
+ * @param client the client to use
+ */
+ public OkHttp3ClientHttpRequestFactory(OkHttpClient client) {
+ Assert.notNull(client, "OkHttpClient must not be null");
+ this.client = client;
+ this.defaultClient = false;
+ }
+
+
+ /**
+ * Set the underlying read timeout in milliseconds.
+ * A value of 0 specifies an infinite timeout.
+ */
+ public void setReadTimeout(int readTimeout) {
+ this.client = this.client.newBuilder()
+ .readTimeout(readTimeout, TimeUnit.MILLISECONDS)
+ .build();
+ }
+
+ /**
+ * Set the underlying read timeout in milliseconds.
+ * A value of 0 specifies an infinite timeout.
+ *
+ * @since 6.1
+ */
+ public void setReadTimeout(Duration readTimeout) {
+ this.client = this.client.newBuilder()
+ .readTimeout(readTimeout)
+ .build();
+ }
+
+ /**
+ * Set the underlying write timeout in milliseconds.
+ * A value of 0 specifies an infinite timeout.
+ */
+ public void setWriteTimeout(int writeTimeout) {
+ this.client = this.client.newBuilder()
+ .writeTimeout(writeTimeout, TimeUnit.MILLISECONDS)
+ .build();
+ }
+
+ /**
+ * Set the underlying write timeout in milliseconds.
+ * A value of 0 specifies an infinite timeout.
+ *
+ * @since 6.1
+ */
+ public void setWriteTimeout(Duration writeTimeout) {
+ this.client = this.client.newBuilder()
+ .writeTimeout(writeTimeout)
+ .build();
+ }
+
+ /**
+ * Set the underlying connect timeout in milliseconds.
+ * A value of 0 specifies an infinite timeout.
+ */
+ public void setConnectTimeout(int connectTimeout) {
+ this.client = this.client.newBuilder()
+ .connectTimeout(connectTimeout, TimeUnit.MILLISECONDS)
+ .build();
+ }
+
+ /**
+ * Set the underlying connect timeout in milliseconds.
+ * A value of 0 specifies an infinite timeout.
+ *
+ * @since 6.1
+ */
+ public void setConnectTimeout(Duration connectTimeout) {
+ this.client = this.client.newBuilder()
+ .connectTimeout(connectTimeout)
+ .build();
+ }
+
+
+ @NotNull
+ @Override
+ public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
+ return new OkHttp3ClientHttpRequest(this.client, uri, httpMethod);
+ }
+
+
+ @Override
+ public void destroy() throws IOException {
+ if (this.defaultClient) {
+ // Clean up the client if we created it in the constructor
+ Cache cache = this.client.cache();
+ if (cache != null) {
+ cache.close();
+ }
+ this.client.dispatcher().executorService().shutdown();
+ this.client.connectionPool().evictAll();
+ }
+ }
+
+}
diff --git a/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpResponse.java b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpResponse.java
new file mode 100644
index 0000000..297cd35
--- /dev/null
+++ b/blade-core-cloud/src/main/java/org/springblade/core/cloud/http/client/OkHttp3ClientHttpResponse.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2002-2023 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springblade.core.cloud.http.client;
+
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatusCode;
+import org.springframework.http.client.ClientHttpResponse;
+import org.springframework.lang.Nullable;
+import org.springframework.util.Assert;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * {@link ClientHttpResponse} implementation based on OkHttp 3.x.
+ *
+ * @author Luciano Leggieri
+ * @author Arjen Poutsma
+ * @author Roy Clarkson
+ * @since 4.3
+ */
+public class OkHttp3ClientHttpResponse implements ClientHttpResponse {
+
+ private final Response response;
+
+ @Nullable
+ private volatile HttpHeaders headers;
+
+
+ public OkHttp3ClientHttpResponse(Response response) {
+ Assert.notNull(response, "Response must not be null");
+ this.response = response;
+ }
+
+
+ @Override
+ public HttpStatusCode getStatusCode() throws IOException {
+ return HttpStatusCode.valueOf(this.response.code());
+ }
+
+ @Override
+ public String getStatusText() {
+ return this.response.message();
+ }
+
+ @Override
+ public InputStream getBody() throws IOException {
+ ResponseBody body = this.response.body();
+ return (body != null ? body.byteStream() : InputStream.nullInputStream());
+ }
+
+ @Override
+ public HttpHeaders getHeaders() {
+ HttpHeaders headers = this.headers;
+ if (headers == null) {
+ headers = new HttpHeaders();
+ for (String headerName : this.response.headers().names()) {
+ for (String headerValue : this.response.headers(headerName)) {
+ headers.add(headerName, headerValue);
+ }
+ }
+ this.headers = headers;
+ }
+ return headers;
+ }
+
+ @Override
+ public void close() {
+ ResponseBody body = this.response.body();
+ if (body != null) {
+ body.close();
+ }
+ }
+
+}
diff --git a/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeBlockExceptionHandler.java b/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeBlockExceptionHandler.java
index 12ddec4..159373c 100644
--- a/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeBlockExceptionHandler.java
+++ b/blade-core-cloud/src/main/java/org/springblade/core/cloud/sentinel/BladeBlockExceptionHandler.java
@@ -7,8 +7,8 @@ import org.springblade.core.tool.jackson.JsonUtil;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
/**
* Sentinel统一限流策略
diff --git a/blade-core-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java b/blade-core-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java
index 8859a21..9a03fa5 100644
--- a/blade-core-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java
+++ b/blade-core-datascope/src/main/java/org/springblade/core/datascope/model/DataScopeModel.java
@@ -20,6 +20,7 @@ import lombok.NoArgsConstructor;
import org.springblade.core.datascope.constant.DataScopeConstant;
import org.springblade.core.datascope.enums.DataScopeEnum;
+import java.io.Serial;
import java.io.Serializable;
/**
@@ -31,6 +32,7 @@ import java.io.Serializable;
@NoArgsConstructor
public class DataScopeModel implements Serializable {
+ @Serial
private static final long serialVersionUID = 1L;
/**
diff --git a/blade-core-develop/pom.xml b/blade-core-develop/pom.xml
index 30bc426..ce6b870 100644
--- a/blade-core-develop/pom.xml
+++ b/blade-core-develop/pom.xml
@@ -23,12 +23,10 @@
com.baomidoumybatis-plus-generator
- ${mybatis.plus.generator.version}com.baomidoumybatis-plus-extension
- ${mybatis.plus.version}
diff --git a/blade-core-develop/src/main/resources/templates/controller.java.vm b/blade-core-develop/src/main/resources/templates/controller.java.vm
index 625090a..9471288 100644
--- a/blade-core-develop/src/main/resources/templates/controller.java.vm
+++ b/blade-core-develop/src/main/resources/templates/controller.java.vm
@@ -15,12 +15,12 @@
*/
package $!{package.Controller};
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.annotations.ApiParam;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;
-import javax.validation.Valid;
+import jakarta.validation.Valid;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
@@ -54,7 +54,7 @@ import $!{superControllerClassPackage};
@RestController
@AllArgsConstructor
@RequestMapping("#if($!{hasServiceName})/$!{serviceName}#end/$!{entityKey}")
-@Api(value = "$!{table.comment}", tags = "$!{table.comment}接口")
+@Tag(name = "$!{table.comment}", tags = "$!{table.comment}接口")
#if($!{superControllerClass})
public class $!{table.controllerName} extends $!{superControllerClass} {
#else
@@ -69,7 +69,7 @@ public class $!{table.controllerName} {
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
- @ApiOperation(value = "详情", notes = "传入$!{table.entityPath}")
+ @Operation(summary = "详情", description = "传入$!{table.entityPath}")
public R<$!{entity}VO> detail($!{entity} $!{table.entityPath}) {
$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
return R.data($!{entity}Wrapper.build().entityVO(detail));
@@ -80,7 +80,7 @@ public class $!{table.controllerName} {
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
- @ApiOperation(value = "分页", notes = "传入$!{table.entityPath}")
+ @Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R> list($!{entity} $!{table.entityPath}, Query query) {
IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath}));
return R.data($!{entity}Wrapper.build().pageVO(pages));
@@ -92,7 +92,7 @@ public class $!{table.controllerName} {
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
- @ApiOperation(value = "详情", notes = "传入$!{table.entityPath}")
+ @Operation(summary = "详情", description = "传入$!{table.entityPath}")
public R<$!{entity}> detail($!{entity} $!{table.entityPath}) {
$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
return R.data(detail);
@@ -103,7 +103,7 @@ public class $!{table.controllerName} {
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
- @ApiOperation(value = "分页", notes = "传入$!{table.entityPath}")
+ @Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R> list($!{entity} $!{table.entityPath}, Query query) {
IPage<$!{entity}> pages = $!{table.entityPath}Service.page(Condition.getPage(query), Condition.getQueryWrapper($!{table.entityPath}));
return R.data(pages);
@@ -115,7 +115,7 @@ public class $!{table.controllerName} {
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
- @ApiOperation(value = "分页", notes = "传入$!{table.entityPath}")
+ @Operation(summary = "分页", description = "传入$!{table.entityPath}")
public R> page($!{entity}VO $!{table.entityPath}, Query query) {
IPage<$!{entity}VO> pages = $!{table.entityPath}Service.select$!{entity}Page(Condition.getPage(query), $!{table.entityPath});
return R.data(pages);
@@ -126,7 +126,7 @@ public class $!{table.controllerName} {
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
- @ApiOperation(value = "新增", notes = "传入$!{table.entityPath}")
+ @Operation(summary = "新增", description = "传入$!{table.entityPath}")
public R save(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.save($!{table.entityPath}));
}
@@ -136,7 +136,7 @@ public class $!{table.controllerName} {
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
- @ApiOperation(value = "修改", notes = "传入$!{table.entityPath}")
+ @Operation(summary = "修改", description = "传入$!{table.entityPath}")
public R update(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.updateById($!{table.entityPath}));
}
@@ -146,7 +146,7 @@ public class $!{table.controllerName} {
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
- @ApiOperation(value = "新增或修改", notes = "传入$!{table.entityPath}")
+ @Operation(summary = "新增或修改", description = "传入$!{table.entityPath}")
public R submit(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.saveOrUpdate($!{table.entityPath}));
}
@@ -158,8 +158,8 @@ public class $!{table.controllerName} {
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
- @ApiOperation(value = "逻辑删除", notes = "传入ids")
- public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+ @Operation(summary = "逻辑删除", description = "传入ids")
+ public R remove(@Parameter(name = "主键集合", required = true) @RequestParam String ids) {
return R.status($!{table.entityPath}Service.deleteLogic(Func.toLongList(ids)));
}
@@ -170,8 +170,8 @@ public class $!{table.controllerName} {
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 8)
- @ApiOperation(value = "删除", notes = "传入ids")
- public R remove(@ApiParam(value = "主键集合", required = true) @RequestParam String ids) {
+ @Operation(summary = "删除", description = "传入ids")
+ public R remove(@Parameter(name = "主键集合", required = true) @RequestParam String ids) {
return R.status($!{table.entityPath}Service.removeByIds(Func.toLongList(ids)));
}
diff --git a/blade-core-develop/src/main/resources/templates/entity.java.vm b/blade-core-develop/src/main/resources/templates/entity.java.vm
index 08afc0b..fdc6772 100644
--- a/blade-core-develop/src/main/resources/templates/entity.java.vm
+++ b/blade-core-develop/src/main/resources/templates/entity.java.vm
@@ -23,9 +23,9 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
#end
#if($!{swagger})
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
#end
+import java.io.Serial;
/**
* $!{table.comment}实体类
@@ -43,7 +43,7 @@ import io.swagger.annotations.ApiModelProperty;
@EqualsAndHashCode(callSuper = true)
#end
#if($!{swagger})
-@ApiModel(value = "$!{entity}对象", description = #if ("$!{table.comment}"=="")"$!{entity}对象"#else"$!{table.comment}"#end)
+@Schema(description = #if ("$!{table.comment}"=="")"$!{entity}对象"#else"$!{table.comment}"#end)
#end
#if($!{superEntityClass})
public class $!{entity} extends $!{superEntityClass}#if($!{activeRecord})<$!{entity}>#end {
@@ -54,7 +54,8 @@ public class $!{entity} extends Model<$!{entity}> {
public class $!{entity} implements Serializable {
#end
- private static final long serialVersionUID = 1L;
+ @Serial
+ private static final long serialVersionUID = 1L;
## ---------- BEGIN 字段循环遍历 ----------
#foreach($field in $!{table.fields})
@@ -67,7 +68,7 @@ public class $!{entity} implements Serializable {
* $!{field.comment}
*/
#if($!{swagger})
- @ApiModelProperty(value = "$!{field.comment}")
+ @Schema(description = "$!{field.comment}")
#end
#end
#if($!{field.keyFlag})
diff --git a/blade-core-develop/src/main/resources/templates/entityDTO.java.vm b/blade-core-develop/src/main/resources/templates/entityDTO.java.vm
index a7f0512..8c31195 100644
--- a/blade-core-develop/src/main/resources/templates/entityDTO.java.vm
+++ b/blade-core-develop/src/main/resources/templates/entityDTO.java.vm
@@ -21,6 +21,7 @@ import $!{package.Entity}.$!{entity};
import lombok.Data;
import lombok.EqualsAndHashCode;
#end
+import java.io.Serial;
/**
* $!{table.comment}数据传输对象实体类
@@ -33,6 +34,7 @@ import lombok.EqualsAndHashCode;
@EqualsAndHashCode(callSuper = true)
#end
public class $!{entity}DTO extends $!{entity} {
+ @Serial
private static final long serialVersionUID = 1L;
}
diff --git a/blade-core-develop/src/main/resources/templates/entityVO.java.vm b/blade-core-develop/src/main/resources/templates/entityVO.java.vm
index ac0f812..e558e9a 100644
--- a/blade-core-develop/src/main/resources/templates/entityVO.java.vm
+++ b/blade-core-develop/src/main/resources/templates/entityVO.java.vm
@@ -22,8 +22,9 @@ import lombok.Data;
import lombok.EqualsAndHashCode;
#end
#if($!{swagger})
-import io.swagger.annotations.ApiModel;
+import io.swagger.v3.oas.annotations.media.Schema;
#end
+import java.io.Serial;
/**
* $!{table.comment}视图实体类
@@ -36,9 +37,10 @@ import io.swagger.annotations.ApiModel;
@EqualsAndHashCode(callSuper = true)
#end
#if($!{swagger})
-@ApiModel(value = "$!{entity}VO对象", description = #if ("$!{table.comment}"=="")"$!{entity}VO对象"#else"$!{table.comment}"#end)
+@Schema(description = #if ("$!{table.comment}"=="")"$!{entity}VO对象"#else"$!{table.comment}"#end)
#end
public class $!{entity}VO extends $!{entity} {
+ @Serial
private static final long serialVersionUID = 1L;
}
diff --git a/blade-core-develop/src/main/resources/templates/wrapper.java.vm b/blade-core-develop/src/main/resources/templates/wrapper.java.vm
index 64a8b01..3729f01 100644
--- a/blade-core-develop/src/main/resources/templates/wrapper.java.vm
+++ b/blade-core-develop/src/main/resources/templates/wrapper.java.vm
@@ -37,7 +37,7 @@ public class $!{entity}Wrapper extends BaseEntityWrapper<$!{entity}, $!{entity}V
@Override
public $!{entity}VO entityVO($!{entity} $!{table.entityPath}) {
- $!{entity}VO $!{table.entityPath}VO = BeanUtil.copy($!{table.entityPath}, $!{entity}VO.class);
+ $!{entity}VO $!{table.entityPath}VO = BeanUtil.copyProperties($!{table.entityPath}, $!{entity}VO.class);
return $!{table.entityPath}VO;
}
diff --git a/blade-core-launch/pom.xml b/blade-core-launch/pom.xml
index 064023b..b08338c 100644
--- a/blade-core-launch/pom.xml
+++ b/blade-core-launch/pom.xml
@@ -30,6 +30,28 @@
org.springframework.bootspring-boot-starter-undertow
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+
+
+
+ javax.xml.bind
+ jaxb-api
+
+
+ com.sun.xml.bind
+ jaxb-core
+
+
+ com.sun.xml.bind
+ jaxb-impl
+
+
+ javax.activation
+ activation
+
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/config/BladePropertyConfiguration.java b/blade-core-launch/src/main/java/org/springblade/core/launch/config/BladePropertyConfiguration.java
new file mode 100644
index 0000000..98f37dc
--- /dev/null
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/config/BladePropertyConfiguration.java
@@ -0,0 +1,42 @@
+/**
+ * Copyright (c) 2019-2029, DreamLu 卢春梦 (596392912@qq.com & www.dreamlu.net).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.launch.config;
+
+import org.springblade.core.launch.props.BladeProperties;
+import org.springblade.core.launch.props.BladePropertySourcePostProcessor;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.Order;
+
+/**
+ * blade property config
+ *
+ * @author L.cm
+ */
+@AutoConfiguration
+@Order(Ordered.HIGHEST_PRECEDENCE)
+@EnableConfigurationProperties(BladeProperties.class)
+public class BladePropertyConfiguration {
+
+ @Bean
+ public BladePropertySourcePostProcessor bladePropertySourcePostProcessor() {
+ return new BladePropertySourcePostProcessor();
+ }
+
+}
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java
index 141010b..c2e4dac 100644
--- a/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/constant/AppConstant.java
@@ -25,7 +25,7 @@ public interface AppConstant {
/**
* 应用版本
*/
- String APPLICATION_VERSION = "3.7.2";
+ String APPLICATION_VERSION = "4.0.0";
/**
* 基础包
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/log/BladeLogLevel.java b/blade-core-launch/src/main/java/org/springblade/core/launch/log/BladeLogLevel.java
new file mode 100644
index 0000000..f3588b4
--- /dev/null
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/log/BladeLogLevel.java
@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.launch.log;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * 请求日志级别,来源 okHttp
+ *
+ * @author L.cm
+ */
+@Getter
+@RequiredArgsConstructor
+public enum BladeLogLevel {
+ /**
+ * No logs.
+ */
+ NONE(0),
+
+ /**
+ * Logs request and response lines.
+ *
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.launch.props;
+
+import org.springframework.core.Ordered;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义资源文件读取,优先级最低
+ *
+ * @author L.cm
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface BladePropertySource {
+
+ /**
+ * Indicate the resource location(s) of the properties file to be loaded.
+ * for example, {@code "classpath:/com/example/app.yml"}
+ *
+ * @return location(s)
+ */
+ String value();
+
+ /**
+ * load app-{activeProfile}.yml
+ *
+ * @return {boolean}
+ */
+ boolean loadActiveProfile() default true;
+
+ /**
+ * Get the order value of this resource.
+ *
+ * @return order
+ */
+ int order() default Ordered.LOWEST_PRECEDENCE;
+
+}
diff --git a/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladePropertySourcePostProcessor.java b/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladePropertySourcePostProcessor.java
new file mode 100644
index 0000000..b85213b
--- /dev/null
+++ b/blade-core-launch/src/main/java/org/springblade/core/launch/props/BladePropertySourcePostProcessor.java
@@ -0,0 +1,178 @@
+/**
+ * Copyright (c) 2019-2029, DreamLu 卢春梦 (596392912@qq.com & www.dreamlu.net).
+ *
+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.gnu.org/licenses/lgpl.html
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springblade.core.launch.props;
+
+import lombok.EqualsAndHashCode;
+import lombok.Getter;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.boot.env.PropertySourceLoader;
+import org.springframework.core.Ordered;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.core.env.ConfigurableEnvironment;
+import org.springframework.core.env.MutablePropertySources;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.DefaultResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.core.io.support.SpringFactoriesLoader;
+import org.springframework.util.ClassUtils;
+import org.springframework.util.StringUtils;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 自定义资源文件读取,优先级最低
+ *
+ * @author L.cm
+ */
+@Slf4j
+public class BladePropertySourcePostProcessor implements BeanFactoryPostProcessor, InitializingBean, Ordered {
+ private final ResourceLoader resourceLoader;
+ private final List propertySourceLoaders;
+
+ public BladePropertySourcePostProcessor() {
+ this.resourceLoader = new DefaultResourceLoader();
+ this.propertySourceLoaders = SpringFactoriesLoader.loadFactories(PropertySourceLoader.class, getClass().getClassLoader());
+ }
+
+ @Override
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ log.info("BladePropertySourcePostProcessor process @BladePropertySource bean.");
+ Map beansWithAnnotation = beanFactory.getBeansWithAnnotation(BladePropertySource.class);
+ Set> beanEntrySet = beansWithAnnotation.entrySet();
+ // 没有 @YmlPropertySource 注解,跳出
+ if (beanEntrySet.isEmpty()) {
+ log.warn("Not found @BladePropertySource on spring bean class.");
+ return;
+ }
+ // 组装资源
+ List propertyFileList = new ArrayList<>();
+ for (Map.Entry entry : beanEntrySet) {
+ Class> beanClass = ClassUtils.getUserClass(entry.getValue());
+ BladePropertySource propertySource = AnnotationUtils.getAnnotation(beanClass, BladePropertySource.class);
+ if (propertySource == null) {
+ continue;
+ }
+ int order = propertySource.order();
+ boolean loadActiveProfile = propertySource.loadActiveProfile();
+ String location = propertySource.value();
+ propertyFileList.add(new PropertyFile(order, location, loadActiveProfile));
+ }
+
+ // 装载 PropertySourceLoader
+ Map loaderMap = new HashMap<>(16);
+ for (PropertySourceLoader loader : propertySourceLoaders) {
+ String[] loaderExtensions = loader.getFileExtensions();
+ for (String extension : loaderExtensions) {
+ loaderMap.put(extension, loader);
+ }
+ }
+ // 去重,排序
+ List sortedPropertyList = propertyFileList.stream()
+ .distinct()
+ .sorted()
+ .collect(Collectors.toList());
+ ConfigurableEnvironment environment = beanFactory.getBean(ConfigurableEnvironment.class);
+ MutablePropertySources propertySources = environment.getPropertySources();
+
+ // 只支持 activeProfiles,没有必要支持 spring.profiles.include。
+ String[] activeProfiles = environment.getActiveProfiles();
+ ArrayList propertySourceList = new ArrayList<>();
+ for (String profile : activeProfiles) {
+ for (PropertyFile propertyFile : sortedPropertyList) {
+ // 不加载 ActiveProfile 的配置文件
+ if (!propertyFile.loadActiveProfile) {
+ continue;
+ }
+ String extension = propertyFile.getExtension();
+ PropertySourceLoader loader = loaderMap.get(extension);
+ if (loader == null) {
+ throw new IllegalArgumentException("Can't find PropertySourceLoader for PropertySource extension:" + extension);
+ }
+ String location = propertyFile.getLocation();
+ String filePath = StringUtils.stripFilenameExtension(location);
+ String profiledLocation = filePath + "-" + profile + "." + extension;
+ Resource resource = resourceLoader.getResource(profiledLocation);
+ loadPropertySource(profiledLocation, resource, loader, propertySourceList);
+ }
+ }
+ // 本身的 Resource
+ for (PropertyFile propertyFile : sortedPropertyList) {
+ String extension = propertyFile.getExtension();
+ PropertySourceLoader loader = loaderMap.get(extension);
+ String location = propertyFile.getLocation();
+ Resource resource = resourceLoader.getResource(location);
+ loadPropertySource(location, resource, loader, propertySourceList);
+ }
+ // 转存
+ for (PropertySource propertySource : propertySourceList) {
+ propertySources.addLast(propertySource);
+ }
+ }
+
+ private static void loadPropertySource(String location, Resource resource,
+ PropertySourceLoader loader,
+ List sourceList) {
+ if (resource.exists()) {
+ String name = "bladePropertySource: [" + location + "]";
+ try {
+ sourceList.addAll(loader.load(name, resource));
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+
+ @Override
+ public void afterPropertiesSet() throws Exception {
+ log.info("BladePropertySourcePostProcessor init.");
+ }
+
+ @Override
+ public int getOrder() {
+ return Ordered.LOWEST_PRECEDENCE;
+ }
+
+ @Getter
+ @ToString
+ @EqualsAndHashCode
+ private static class PropertyFile implements Comparable {
+ private final int order;
+ private final String location;
+ private final String extension;
+ private final boolean loadActiveProfile;
+
+ PropertyFile(int order, String location, boolean loadActiveProfile) {
+ this.order = order;
+ this.location = location;
+ this.loadActiveProfile = loadActiveProfile;
+ this.extension = Objects.requireNonNull(StringUtils.getFilenameExtension(location));
+ }
+
+ @Override
+ public int compareTo(PropertyFile other) {
+ return Integer.compare(this.order, other.order);
+ }
+ }
+}
diff --git a/blade-core-loadbalancer/pom.xml b/blade-core-loadbalancer/pom.xml
index 1b343ca..a38abbe 100644
--- a/blade-core-loadbalancer/pom.xml
+++ b/blade-core-loadbalancer/pom.xml
@@ -55,7 +55,6 @@
com.alibaba.nacosnacos-client
- ${alibaba.nacos.version}
diff --git a/blade-core-log/pom.xml b/blade-core-log/pom.xml
index dd5e2a9..35a71cd 100644
--- a/blade-core-log/pom.xml
+++ b/blade-core-log/pom.xml
@@ -28,11 +28,15 @@
org.springbladeblade-core-cloud
+
+
+ hibernate-validator
+ org.hibernate.validator
+ com.baomidoumybatis-plus
- ${mybatis.plus.version}
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java b/blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java
index fad5f36..de3bb50 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/config/BladeErrorMvcAutoConfiguration.java
@@ -36,7 +36,7 @@ import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.DispatcherServlet;
-import javax.servlet.Servlet;
+import jakarta.servlet.Servlet;
/**
* 统一异常处理
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java
index a3de7bd..b6d2057 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorAttributes.java
@@ -42,8 +42,8 @@ public class BladeErrorAttributes extends DefaultErrorAttributes {
@Override
public Map getErrorAttributes(WebRequest webRequest, ErrorAttributeOptions options) {
- String requestUri = this.getAttr(webRequest, "javax.servlet.error.request_uri");
- Integer status = this.getAttr(webRequest, "javax.servlet.error.status_code");
+ String requestUri = this.getAttr(webRequest, "jakarta.servlet.error.request_uri");
+ Integer status = this.getAttr(webRequest, "jakarta.servlet.error.status_code");
Throwable error = getError(webRequest);
R result;
if (error == null) {
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorController.java b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorController.java
index 2daffea..f6ac6b5 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorController.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeErrorController.java
@@ -25,8 +25,8 @@ import org.springframework.http.MediaType;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.json.MappingJackson2JsonView;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
import java.util.Map;
/**
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java
index 77294bd..cb692cf 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/error/BladeRestExceptionTranslator.java
@@ -18,6 +18,7 @@ package org.springblade.core.log.error;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.validator.internal.engine.path.PathImpl;
+import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.log.props.BladeLogProperties;
import org.springblade.core.log.publisher.ErrorLogPublisher;
@@ -46,9 +47,9 @@ import org.springframework.web.method.annotation.MethodArgumentTypeMismatchExcep
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.NoHandlerFoundException;
-import javax.servlet.Servlet;
-import javax.validation.ConstraintViolation;
-import javax.validation.ConstraintViolationException;
+import jakarta.servlet.Servlet;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
import java.util.Set;
/**
@@ -64,6 +65,7 @@ import java.util.Set;
@RequiredArgsConstructor
public class BladeRestExceptionTranslator {
+ private final BladeProperties bladeProperties;
private final BladeLogProperties bladeLogProperties;
@ExceptionHandler(MissingServletRequestParameterException.class)
@@ -163,6 +165,10 @@ public class BladeRestExceptionTranslator {
if (bladeLogProperties.getError()) {
ErrorLogPublisher.publishEvent(e, UrlUtil.getPath(WebUtil.getRequest().getRequestURI()));
}
+ // 生产环境屏蔽具体异常信息返回
+ if (bladeProperties.isProd()) {
+ return R.fail(ResultCode.INTERNAL_SERVER_ERROR);
+ }
return R.fail(ResultCode.INTERNAL_SERVER_ERROR, (Func.isEmpty(e.getMessage()) ? ResultCode.INTERNAL_SERVER_ERROR.getMessage() : e.getMessage()));
}
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/event/ErrorLogListener.java b/blade-core-log/src/main/java/org/springblade/core/log/event/ErrorLogListener.java
index bbc2e01..6fabf31 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/event/ErrorLogListener.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/event/ErrorLogListener.java
@@ -22,7 +22,6 @@ import org.springblade.core.launch.props.BladeProperties;
import org.springblade.core.launch.server.ServerInfo;
import org.springblade.core.log.constant.EventConstant;
import org.springblade.core.log.feign.ILogClient;
-import org.springblade.core.log.model.LogAbstract;
import org.springblade.core.log.model.LogError;
import org.springblade.core.log.utils.LogAbstractUtil;
import org.springframework.context.event.EventListener;
@@ -48,10 +47,14 @@ public class ErrorLogListener {
@Order
@EventListener(ErrorLogEvent.class)
public void saveErrorLog(ErrorLogEvent event) {
- Map source = (Map) event.getSource();
- LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
- LogAbstractUtil.addOtherInfoToLog(logError, bladeProperties, serverInfo);
- logService.saveErrorLog(logError);
+ try {
+ Map source = (Map) event.getSource();
+ LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
+ LogAbstractUtil.addOtherInfoToLog(logError, bladeProperties, serverInfo);
+ logService.saveErrorLog(logError);
+ } catch (Exception e) {
+ log.error("保存错误日志失败", e);
+ }
}
}
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogApi.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogApi.java
index d8a3de0..a18e220 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/model/LogApi.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogApi.java
@@ -19,6 +19,7 @@ package org.springblade.core.log.model;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
+import java.io.Serial;
import java.io.Serializable;
/**
@@ -30,6 +31,7 @@ import java.io.Serializable;
@TableName("blade_log_api")
public class LogApi extends LogAbstract implements Serializable {
+ @Serial
private static final long serialVersionUID = 1L;
/**
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogApiVo.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogApiVo.java
index 72ac39a..90ea232 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/model/LogApiVo.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogApiVo.java
@@ -18,6 +18,8 @@ package org.springblade.core.log.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import java.io.Serial;
+
/**
* LogApi视图实体类
*
@@ -26,6 +28,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class LogApiVo extends LogApi {
+ @Serial
private static final long serialVersionUID = 1L;
private String strId;
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogError.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogError.java
index 448db85..74529b8 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/model/LogError.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogError.java
@@ -19,6 +19,7 @@ package org.springblade.core.log.model;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
+import java.io.Serial;
import java.io.Serializable;
/**
@@ -30,6 +31,7 @@ import java.io.Serializable;
@TableName("blade_log_error")
public class LogError extends LogAbstract implements Serializable {
+ @Serial
private static final long serialVersionUID = 1L;
/**
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogErrorVo.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogErrorVo.java
index 4700105..5c8b0a2 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/model/LogErrorVo.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogErrorVo.java
@@ -18,6 +18,8 @@ package org.springblade.core.log.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import java.io.Serial;
+
/**
* LogError视图实体类
*
@@ -26,6 +28,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class LogErrorVo extends LogError {
+ @Serial
private static final long serialVersionUID = 1L;
private String strId;
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsual.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsual.java
index 2c15c4f..88f5bbb 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsual.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsual.java
@@ -19,6 +19,7 @@ package org.springblade.core.log.model;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
+import java.io.Serial;
import java.io.Serializable;
/**
@@ -31,6 +32,7 @@ import java.io.Serializable;
@TableName("blade_log_usual")
public class LogUsual extends LogAbstract implements Serializable {
+ @Serial
private static final long serialVersionUID = 1L;
/**
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsualVo.java b/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsualVo.java
index 6a50f08..076c2fb 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsualVo.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/model/LogUsualVo.java
@@ -18,6 +18,8 @@ package org.springblade.core.log.model;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import java.io.Serial;
+
/**
* LogUsual视图实体类
*
@@ -26,6 +28,7 @@ import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
public class LogUsualVo extends LogUsual {
+ @Serial
private static final long serialVersionUID = 1L;
private String strId;
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/publisher/ApiLogPublisher.java b/blade-core-log/src/main/java/org/springblade/core/log/publisher/ApiLogPublisher.java
index ac9a3bc..3d6d87a 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/publisher/ApiLogPublisher.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/publisher/ApiLogPublisher.java
@@ -28,7 +28,7 @@ import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.WebUtil;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/publisher/ErrorLogPublisher.java b/blade-core-log/src/main/java/org/springblade/core/log/publisher/ErrorLogPublisher.java
index 3c5564b..f568cc4 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/publisher/ErrorLogPublisher.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/publisher/ErrorLogPublisher.java
@@ -26,7 +26,7 @@ import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.WebUtil;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/publisher/UsualLogPublisher.java b/blade-core-log/src/main/java/org/springblade/core/log/publisher/UsualLogPublisher.java
index 7f0e39a..a3081dc 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/publisher/UsualLogPublisher.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/publisher/UsualLogPublisher.java
@@ -24,7 +24,7 @@ import org.springblade.core.log.utils.LogAbstractUtil;
import org.springblade.core.tool.utils.SpringUtil;
import org.springblade.core.tool.utils.WebUtil;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
diff --git a/blade-core-log/src/main/java/org/springblade/core/log/utils/LogAbstractUtil.java b/blade-core-log/src/main/java/org/springblade/core/log/utils/LogAbstractUtil.java
index de6192b..ff75e4d 100644
--- a/blade-core-log/src/main/java/org/springblade/core/log/utils/LogAbstractUtil.java
+++ b/blade-core-log/src/main/java/org/springblade/core/log/utils/LogAbstractUtil.java
@@ -22,7 +22,7 @@ import org.springblade.core.log.model.LogAbstract;
import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.utils.*;
-import javax.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
/**
* Log 相关工具
diff --git a/blade-core-mybatis/pom.xml b/blade-core-mybatis/pom.xml
index d699180..1f7444a 100644
--- a/blade-core-mybatis/pom.xml
+++ b/blade-core-mybatis/pom.xml
@@ -19,17 +19,18 @@
org.mybatismybatis
- ${mybatis.version}org.mybatismybatis-spring
- ${mybatis.spring.version}com.baomidoumybatis-plus
- ${mybatis.plus.version}
+
+
+ org.mybatis
+ mybatis-typehandlers-jsr310
diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseEntity.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseEntity.java
index 25f9c48..a276aed 100644
--- a/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseEntity.java
+++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseEntity.java
@@ -22,7 +22,7 @@ import com.baomidou.mybatisplus.annotation.TableLogic;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import io.swagger.annotations.ApiModelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springblade.core.tool.utils.DateUtil;
import org.springframework.format.annotation.DateTimeFormat;
@@ -41,7 +41,7 @@ public class BaseEntity implements Serializable {
/**
* 主键
*/
- @ApiModelProperty(value = "主键")
+ @Schema(description = "主键")
@TableId(value = "id", type = IdType.ASSIGN_ID)
@JsonSerialize(using = ToStringSerializer.class)
private Long id;
@@ -50,14 +50,14 @@ public class BaseEntity implements Serializable {
* 创建人
*/
@JsonSerialize(using = ToStringSerializer.class)
- @ApiModelProperty(value = "创建人")
+ @Schema(description = "创建人")
private Long createUser;
/**
* 创建部门
*/
@JsonSerialize(using = ToStringSerializer.class)
- @ApiModelProperty(value = "创建部门")
+ @Schema(description = "创建部门")
private Long createDept;
/**
@@ -65,14 +65,14 @@ public class BaseEntity implements Serializable {
*/
@DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME)
@JsonFormat(pattern = DateUtil.PATTERN_DATETIME)
- @ApiModelProperty(value = "创建时间")
+ @Schema(description = "创建时间")
private Date createTime;
/**
* 更新人
*/
@JsonSerialize(using = ToStringSerializer.class)
- @ApiModelProperty(value = "更新人")
+ @Schema(description = "更新人")
private Long updateUser;
/**
@@ -80,19 +80,19 @@ public class BaseEntity implements Serializable {
*/
@DateTimeFormat(pattern = DateUtil.PATTERN_DATETIME)
@JsonFormat(pattern = DateUtil.PATTERN_DATETIME)
- @ApiModelProperty(value = "更新时间")
+ @Schema(description = "更新时间")
private Date updateTime;
/**
* 状态[1:正常]
*/
- @ApiModelProperty(value = "业务状态")
+ @Schema(description = "业务状态")
private Integer status;
/**
* 状态[0:未删除,1:删除]
*/
@TableLogic
- @ApiModelProperty(value = "是否已删除")
+ @Schema(description = "是否已删除")
private Integer isDeleted;
}
diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseService.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseService.java
index 8b4b5bd..8ca4a27 100644
--- a/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseService.java
+++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseService.java
@@ -18,7 +18,7 @@ package org.springblade.core.mp.base;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.service.IService;
-import javax.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotEmpty;
import java.util.List;
/**
diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseServiceImpl.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseServiceImpl.java
index 7c02db2..2f61b44 100644
--- a/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseServiceImpl.java
+++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/BaseServiceImpl.java
@@ -28,7 +28,7 @@ import org.springblade.core.tool.utils.DateUtil;
import org.springblade.core.tool.utils.Func;
import org.springframework.validation.annotation.Validated;
-import javax.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotEmpty;
import java.util.Collection;
import java.util.Date;
import java.util.List;
diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/TenantEntity.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/TenantEntity.java
index a53bf61..086ced5 100644
--- a/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/TenantEntity.java
+++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/base/TenantEntity.java
@@ -16,7 +16,7 @@
package org.springblade.core.mp.base;
-import io.swagger.annotations.ApiModelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@@ -32,7 +32,7 @@ public class TenantEntity extends BaseEntity {
/**
* 租户ID
*/
- @ApiModelProperty(value = "租户ID")
+ @Schema(description = "租户ID")
private String tenantId;
}
diff --git a/blade-core-mybatis/src/main/java/org/springblade/core/mp/support/Query.java b/blade-core-mybatis/src/main/java/org/springblade/core/mp/support/Query.java
index 10188bb..da1253f 100644
--- a/blade-core-mybatis/src/main/java/org/springblade/core/mp/support/Query.java
+++ b/blade-core-mybatis/src/main/java/org/springblade/core/mp/support/Query.java
@@ -15,11 +15,12 @@
*/
package org.springblade.core.mp.support;
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
+import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.experimental.Accessors;
+import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
+
/**
* 分页工具
*
@@ -27,31 +28,31 @@ import lombok.experimental.Accessors;
*/
@Data
@Accessors(chain = true)
-@ApiModel(description = "查询条件")
+@Schema(description = "查询条件")
public class Query {
/**
* 当前页
*/
- @ApiModelProperty(value = "当前页")
+ @Schema(description = "当前页")
private Integer current;
/**
* 每页的数量
*/
- @ApiModelProperty(value = "每页的数量")
+ @Schema(description = "每页的数量")
private Integer size;
/**
* 排序的字段名
*/
- @ApiModelProperty(hidden = true)
+ @Schema(accessMode = READ_ONLY)
private String ascs;
/**
* 排序方式
*/
- @ApiModelProperty(hidden = true)
+ @Schema(accessMode = READ_ONLY)
private String descs;
}
diff --git a/blade-core-report/pom.xml b/blade-core-report/pom.xml
index 00e77ba..a5aa445 100644
--- a/blade-core-report/pom.xml
+++ b/blade-core-report/pom.xml
@@ -21,8 +21,35 @@
com.bstek.ureportureport2-console
+
+
+ commons-fileupload
+ commons-fileupload
+
+
+ javax.servlet
+ servlet-api
+
+ 2.2.9
+
+ com.bstek.ureport
+ ureport2-core
+
+
+ javax.servlet
+ servlet-api
+
+
+ 2.2.9
+
+
+ jakarta.servlet
+ jakarta.servlet-api
+ 6.0.0
+ provided
+
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/build/Splash.java b/blade-core-report/src/main/java/com/bstek/ureport/build/Splash.java
new file mode 100644
index 0000000..54581d5
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/build/Splash.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.build;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年6月19日
+ */
+public class Splash {
+ public void doPrint() {
+ String sb = "\n" +
+ " ___ ___ ________ _______ ________ ________ ________ _________ ________ \n" +
+ "|\\ \\|\\ \\|\\ __ \\|\\ ___ \\ |\\ __ \\|\\ __ \\|\\ __ \\|\\___ ___\\ |\\_____ \\ \n" +
+ "\\ \\ \\\\\\ \\ \\ \\|\\ \\ \\ __/|\\ \\ \\|\\ \\ \\ \\|\\ \\ \\ \\|\\ \\|___ \\ \\_| \\|____|\\ /_ \n" +
+ " \\ \\ \\\\\\ \\ \\ _ _\\ \\ \\_|/_\\ \\ ____\\ \\ \\\\\\ \\ \\ _ _\\ \\ \\ \\ \\|\\ \\ \n" +
+ " \\ \\ \\\\\\ \\ \\ \\\\ \\\\ \\ \\_|\\ \\ \\ \\___|\\ \\ \\\\\\ \\ \\ \\\\ \\| \\ \\ \\ __\\_\\ \\ \n" +
+ " \\ \\_______\\ \\__\\\\ _\\\\ \\_______\\ \\__\\ \\ \\_______\\ \\__\\\\ _\\ \\ \\__\\ |\\_______\\\n" +
+ " \\|_______|\\|__|\\|__|\\|_______|\\|__| \\|_______|\\|__|\\|__| \\|__| \\|_______|\n" +
+ "........................................................................................................" +
+ "\n" +
+ ". uReport, is a Chinese style report engine" +
+ " licensed under the Apache License 2.0, ." +
+ "\n" +
+ ". which is opensource, easy to use,high-performance, with browser-based-designer, ." +
+ "\n" +
+ ". it has now been upgraded by BladeX to support jdk 17 and spring boot 3. ." +
+ "\n" +
+ "........................................................................................................" +
+ "\n";
+ System.out.println(sb);
+ }
+
+
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/build/compute/ZxingValueCompute.java b/blade-core-report/src/main/java/com/bstek/ureport/build/compute/ZxingValueCompute.java
new file mode 100644
index 0000000..528edc4
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/build/compute/ZxingValueCompute.java
@@ -0,0 +1,150 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.build.compute;
+
+import com.bstek.ureport.build.BindData;
+import com.bstek.ureport.build.Context;
+import com.bstek.ureport.definition.value.Source;
+import com.bstek.ureport.definition.value.ValueType;
+import com.bstek.ureport.definition.value.ZxingValue;
+import com.bstek.ureport.exception.ReportComputeException;
+import com.bstek.ureport.expression.model.Expression;
+import com.bstek.ureport.expression.model.data.BindDataListExpressionData;
+import com.bstek.ureport.expression.model.data.ExpressionData;
+import com.bstek.ureport.expression.model.data.ObjectExpressionData;
+import com.bstek.ureport.expression.model.data.ObjectListExpressionData;
+import com.bstek.ureport.model.Cell;
+import com.bstek.ureport.model.Image;
+import com.google.zxing.BarcodeFormat;
+import com.google.zxing.EncodeHintType;
+import com.google.zxing.MultiFormatWriter;
+import com.google.zxing.common.BitMatrix;
+import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springblade.core.tool.utils.Base64Util;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年3月27日
+ */
+public class ZxingValueCompute implements ValueCompute {
+ private static final int BLACK = 0xff000000;
+ private static final int WHITE = 0xFFFFFFFF;
+ @Override
+ public List compute(Cell cell, Context context) {
+ List list=new ArrayList();
+ ZxingValue value=(ZxingValue)cell.getValue();
+ String format=value.getFormat();
+ BarcodeFormat barcodeForamt=BarcodeFormat.QR_CODE;
+ if(StringUtils.isNotBlank(format)){
+ barcodeForamt=BarcodeFormat.valueOf(format);
+ }
+ int w=value.getWidth();
+ int h=value.getHeight();
+ Source source=value.getSource();
+ if(source.equals(Source.text)){
+ String data=value.getValue();
+ Image image=buildImage(barcodeForamt,data,w,h);
+ list.add(new BindData(image));
+ }else{
+ Expression expression=value.getExpression();
+ ExpressionData> data=expression.execute(cell,cell, context);
+ if(data instanceof BindDataListExpressionData){
+ BindDataListExpressionData listData=(BindDataListExpressionData)data;
+ List bindDataList=listData.getData();
+ for(BindData bindData:bindDataList){
+ Object obj=bindData.getValue();
+ if(obj==null)obj="";
+ Image image=buildImage(barcodeForamt,obj.toString(),w,h);
+ list.add(new BindData(image));
+ }
+ }else if(data instanceof ObjectExpressionData){
+ ObjectExpressionData exprData=(ObjectExpressionData)data;
+ Object obj=exprData.getData();
+ if(obj==null){
+ obj="";
+ }else if(obj instanceof String){
+ String text=obj.toString();
+ if(text.startsWith("\"") && text.endsWith("\"")){
+ text=text.substring(1,text.length()-1);
+ }
+ obj=text;
+ }
+ Image image=buildImage(barcodeForamt,obj.toString(),w,h);
+ list.add(new BindData(image));
+ }else if(data instanceof ObjectListExpressionData){
+ ObjectListExpressionData listExprData=(ObjectListExpressionData)data;
+ List> listData=listExprData.getData();
+ for(Object obj:listData){
+ if(obj==null){
+ obj="";
+ }else if(obj instanceof String){
+ String text=obj.toString();
+ if(text.startsWith("\"") && text.endsWith("\"")){
+ text=text.substring(1,text.length()-1);
+ }
+ obj=text;
+ }
+ Image image=buildImage(barcodeForamt,obj.toString(),w,h);
+ list.add(new BindData(image));
+ }
+ }
+ }
+ return list;
+ }
+
+ private Image buildImage(BarcodeFormat format,String data,int w,int h){
+ try{
+ Map hints = new Hashtable();
+ hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
+ hints.put(EncodeHintType.MARGIN,0);
+ if(format.equals(BarcodeFormat.QR_CODE)){
+ hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
+ }
+ BitMatrix matrix = new MultiFormatWriter().encode(data,format, w, h,hints);
+ int width = matrix.getWidth();
+ int height = matrix.getHeight();
+ BufferedImage image = new BufferedImage(width, height,BufferedImage.TYPE_INT_ARGB);
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ image.setRGB(x, y, matrix.get(x, y) ? BLACK : WHITE);
+ }
+ }
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ImageIO.write(image, "png", outputStream);
+ byte[] bytes=outputStream.toByteArray();
+ String base64Data= Base64Util.encodeToString(bytes);
+ IOUtils.closeQuietly(outputStream);
+ return new Image(base64Data,w,h);
+ }catch(Exception ex){
+ throw new ReportComputeException(ex);
+ }
+ }
+
+ @Override
+ public ValueType type() {
+ return ValueType.zxing;
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/BaseServletAction.java b/blade-core-report/src/main/java/com/bstek/ureport/console/BaseServletAction.java
new file mode 100644
index 0000000..e4a1eae
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/BaseServletAction.java
@@ -0,0 +1,125 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.StringUtils;
+
+import java.lang.reflect.Method;
+import java.net.URLDecoder;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+
+
+/**
+ * @author Jacky.gao
+ * @since 2016年6月3日
+ */
+public abstract class BaseServletAction implements ServletAction {
+ protected Throwable buildRootException(Throwable throwable) {
+ if (throwable.getCause() == null) {
+ return throwable;
+ }
+ return buildRootException(throwable.getCause());
+ }
+
+ protected String decode(String value) {
+ if (value == null) {
+ return value;
+ }
+ try {
+ value = URLDecoder.decode(value, "utf-8");
+ value = URLDecoder.decode(value, "utf-8");
+ return value;
+ } catch (Exception ex) {
+ return value;
+ }
+ }
+
+ protected String decodeContent(String content) {
+ if (content == null) {
+ return content;
+ }
+ try {
+ content = URLDecoder.decode(content, "utf-8");
+ return content;
+ } catch (Exception ex) {
+ return content;
+ }
+ }
+
+ protected Map buildParameters(HttpServletRequest req) {
+ Map parameters = new HashMap();
+ Enumeration> enumeration = req.getParameterNames();
+ while (enumeration.hasMoreElements()) {
+ Object obj = enumeration.nextElement();
+ if (obj == null) {
+ continue;
+ }
+ String name = obj.toString();
+ String value = req.getParameter(name);
+ if (name == null || value == null || name.startsWith("_")) {
+ continue;
+ }
+ parameters.put(name, decode(value));
+ }
+ return parameters;
+ }
+
+ protected void invokeMethod(String methodName, HttpServletRequest req, HttpServletResponse resp) throws ServletException {
+ try {
+ Method method = this.getClass().getMethod(methodName, new Class>[]{HttpServletRequest.class, HttpServletResponse.class});
+ method.invoke(this, new Object[]{req, resp});
+ } catch (Exception ex) {
+ throw new ServletException(ex);
+ }
+ }
+
+ protected String retriveMethod(HttpServletRequest req) throws ServletException {
+ String path = req.getContextPath() + UReportServlet.URL;
+ String uri = req.getRequestURI();
+ String targetUrl = uri.substring(path.length());
+ int slashPos = targetUrl.indexOf("/", 1);
+ if (slashPos > -1) {
+ String methodName = targetUrl.substring(slashPos + 1).trim();
+ return methodName.length() > 0 ? methodName : null;
+ }
+ return null;
+ }
+
+ protected String buildDownloadFileName(String reportFileName, String fileName, String extName) {
+ if (StringUtils.isNotBlank(fileName)) {
+ fileName = decode(fileName);
+ if (!fileName.toLowerCase().endsWith(extName)) {
+ fileName = fileName + extName;
+ }
+ return fileName;
+ } else {
+ int pos = reportFileName.indexOf(":");
+ if (pos > 0) {
+ reportFileName = reportFileName.substring(pos + 1, reportFileName.length());
+ }
+ pos = reportFileName.toLowerCase().indexOf(".ureport.xml");
+ if (pos > 0) {
+ reportFileName = reportFileName.substring(0, pos);
+ }
+ return "ureport-" + reportFileName + extName;
+ }
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/MobileUtils.java b/blade-core-report/src/main/java/com/bstek/ureport/console/MobileUtils.java
new file mode 100644
index 0000000..ac96dfb
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/MobileUtils.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年10月11日
+ */
+public class MobileUtils {
+ private static String phoneReg = "\\b(ip(hone|od)|android|opera m(ob|in)i"
+ + "|windows (phone|ce)|blackberry"
+ + "|s(ymbian|eries60|amsung)|p(laybook|alm|rofile/midp"
+ + "|laystation portable)|nokia|fennec|htc[-_]"
+ + "|mobile|up.browser|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";
+ private static String tableReg = "\\b(ipad|tablet|(Nexus 7)|up.browser"
+ + "|[1-4][0-9]{2}x[1-4][0-9]{2})\\b";
+ private static Pattern phonePat = Pattern.compile(phoneReg, Pattern.CASE_INSENSITIVE);
+ private static Pattern tablePat = Pattern.compile(tableReg, Pattern.CASE_INSENSITIVE);
+
+ public static boolean isMobile(HttpServletRequest req) {
+ String userAgent = req.getHeader("USER-AGENT");
+ if (userAgent == null) {
+ userAgent = "";
+ }
+ userAgent = userAgent.toLowerCase();
+ Matcher matcherPhone = phonePat.matcher(userAgent);
+ Matcher matcherTable = tablePat.matcher(userAgent);
+ if (matcherPhone.find() || matcherTable.find()) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/RequestHolder.java b/blade-core-report/src/main/java/com/bstek/ureport/console/RequestHolder.java
new file mode 100644
index 0000000..c45ff57
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/RequestHolder.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年3月8日
+ */
+public class RequestHolder {
+ private static final ThreadLocal requestThreadLocal = new ThreadLocal();
+
+ public static void setRequest(HttpServletRequest request) {
+ requestThreadLocal.set(request);
+ }
+
+ public static HttpServletRequest getRequest() {
+ return requestThreadLocal.get();
+ }
+
+ public static void clean() {
+ requestThreadLocal.remove();
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/ServletAction.java b/blade-core-report/src/main/java/com/bstek/ureport/console/ServletAction.java
new file mode 100644
index 0000000..3ddb64f
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/ServletAction.java
@@ -0,0 +1,34 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年1月25日
+ */
+public interface ServletAction {
+ public static final String PREVIEW_KEY = "p";
+
+ void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException;
+
+ String url();
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/UReportServlet.java b/blade-core-report/src/main/java/com/bstek/ureport/console/UReportServlet.java
new file mode 100644
index 0000000..c9670b4
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/UReportServlet.java
@@ -0,0 +1,117 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import jakarta.servlet.ServletConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServlet;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.context.support.WebApplicationContextUtils;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年1月25日
+ */
+public class UReportServlet extends HttpServlet {
+ private static final long serialVersionUID = 533049461276487971L;
+ public static final String URL = "/ureport";
+ private Map actionMap = new HashMap();
+
+ @Override
+ public void init(ServletConfig config) throws ServletException {
+ super.init(config);
+ WebApplicationContext applicationContext = getWebApplicationContext(config);
+ Collection handlers = applicationContext.getBeansOfType(ServletAction.class).values();
+ for (ServletAction handler : handlers) {
+ String url = handler.url();
+ if (actionMap.containsKey(url)) {
+ throw new RuntimeException("Handler [" + url + "] already exist.");
+ }
+ actionMap.put(url, handler);
+ }
+ }
+
+ protected WebApplicationContext getWebApplicationContext(ServletConfig config) {
+ return WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());
+ }
+
+ @Override
+ protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String path = req.getContextPath() + URL;
+ String uri = req.getRequestURI();
+ String targetUrl = uri.substring(path.length());
+ if (targetUrl.length() < 1) {
+ outContent(resp, "Welcome to use ureport,please specify target url.");
+ return;
+ }
+ int slashPos = targetUrl.indexOf("/", 1);
+ if (slashPos > -1) {
+ targetUrl = targetUrl.substring(0, slashPos);
+ }
+ ServletAction targetHandler = actionMap.get(targetUrl);
+ if (targetHandler == null) {
+ outContent(resp, "Handler [" + targetUrl + "] not exist.");
+ return;
+ }
+ RequestHolder.setRequest(req);
+ try {
+ targetHandler.execute(req, resp);
+ } catch (Exception ex) {
+ resp.setCharacterEncoding("UTF-8");
+ PrintWriter pw = resp.getWriter();
+ Throwable e = buildRootException(ex);
+ resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
+ String errorMsg = e.getMessage();
+ if (StringUtils.isBlank(errorMsg)) {
+ errorMsg = e.getClass().getName();
+ }
+ pw.write(errorMsg);
+ pw.close();
+ throw new ServletException(ex);
+ } finally {
+ RequestHolder.clean();
+ }
+ }
+
+ private Throwable buildRootException(Throwable throwable) {
+ if (throwable.getCause() == null) {
+ return throwable;
+ }
+ return buildRootException(throwable.getCause());
+ }
+
+ private void outContent(HttpServletResponse resp, String msg) throws IOException {
+ resp.setContentType("text/html");
+ PrintWriter pw = resp.getWriter();
+ pw.write("");
+ pw.write("UReport Console");
+ pw.write("");
+ pw.write(msg);
+ pw.write("");
+ pw.write("");
+ pw.flush();
+ pw.close();
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/WriteJsonServletAction.java b/blade-core-report/src/main/java/com/bstek/ureport/console/WriteJsonServletAction.java
new file mode 100644
index 0000000..f94c4d2
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/WriteJsonServletAction.java
@@ -0,0 +1,49 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console;
+
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletResponse;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.SerializationConfig;
+import org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+
+
+/**
+ * @author Jacky.gao
+ * @since 2016年5月23日
+ */
+public abstract class WriteJsonServletAction extends BaseServletAction {
+ protected void writeObjectToJson(HttpServletResponse resp, Object obj) throws ServletException, IOException {
+ resp.setContentType("text/json");
+ resp.setCharacterEncoding("UTF-8");
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.setSerializationInclusion(Inclusion.NON_NULL);
+ mapper.configure(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS, false);
+ mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
+ OutputStream out = resp.getOutputStream();
+ try {
+ mapper.writeValue(out, obj);
+ } finally {
+ out.flush();
+ out.close();
+ }
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/cache/HttpSessionReportCache.java b/blade-core-report/src/main/java/com/bstek/ureport/console/cache/HttpSessionReportCache.java
new file mode 100644
index 0000000..a905d5d
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/cache/HttpSessionReportCache.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.cache;
+
+import com.bstek.ureport.cache.ReportCache;
+import com.bstek.ureport.console.RequestHolder;
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年3月8日
+ */
+public class HttpSessionReportCache implements ReportCache {
+ private Map sessionReportMap = new HashMap();
+ private boolean disabled;
+
+ @Override
+ public Object getObject(String file) {
+ HttpServletRequest req = RequestHolder.getRequest();
+ if (req == null) {
+ return null;
+ }
+ ObjectMap objMap = getObjectMap(req);
+ return objMap.get(file);
+ }
+
+ @Override
+ public void storeObject(String file, Object object) {
+ HttpServletRequest req = RequestHolder.getRequest();
+ if (req == null) {
+ return;
+ }
+ ObjectMap map = getObjectMap(req);
+ map.put(file, object);
+ }
+
+ @Override
+ public boolean disabled() {
+ return disabled;
+ }
+
+ public void setDisabled(boolean disabled) {
+ this.disabled = disabled;
+ }
+
+ private ObjectMap getObjectMap(HttpServletRequest req) {
+ List expiredList = new ArrayList();
+ for (String key : sessionReportMap.keySet()) {
+ ObjectMap reportObj = sessionReportMap.get(key);
+ if (reportObj.isExpired()) {
+ expiredList.add(key);
+ }
+ }
+ for (String key : expiredList) {
+ sessionReportMap.remove(key);
+ }
+ String sessionId = req.getSession().getId();
+ ObjectMap obj = sessionReportMap.get(sessionId);
+ if (obj != null) {
+ return obj;
+ } else {
+ ObjectMap objMap = new ObjectMap();
+ sessionReportMap.put(sessionId, objMap);
+ return objMap;
+ }
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/cache/TempObjectCache.java b/blade-core-report/src/main/java/com/bstek/ureport/console/cache/TempObjectCache.java
new file mode 100644
index 0000000..8d3859d
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/cache/TempObjectCache.java
@@ -0,0 +1,97 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.cache;
+
+import com.bstek.ureport.console.RequestHolder;
+import jakarta.servlet.http.HttpServletRequest;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+
+/**
+ * @author Jacky.gao
+ * @since 2017年9月6日
+ */
+public class TempObjectCache {
+ private static TempObjectCache tempObjectCache = new TempObjectCache();
+ private Map sessionMap = new HashMap();
+
+ public static Object getObject(String key) {
+ return tempObjectCache.get(key);
+ }
+
+ public static void putObject(String key, Object obj) {
+ tempObjectCache.store(key, obj);
+ }
+
+ public static void removeObject(String key) {
+ tempObjectCache.remove(key);
+ }
+
+ public void remove(String key) {
+ HttpServletRequest req = RequestHolder.getRequest();
+ if (req == null) {
+ return;
+ }
+ ObjectMap mapObject = getReportMap(req);
+ if (mapObject != null) {
+ mapObject.remove(key);
+ }
+ }
+
+ public Object get(String key) {
+ HttpServletRequest req = RequestHolder.getRequest();
+ if (req == null) {
+ return null;
+ }
+ ObjectMap mapObject = getReportMap(req);
+ return mapObject.get(key);
+ }
+
+ public void store(String key, Object obj) {
+ HttpServletRequest req = RequestHolder.getRequest();
+ if (req == null) {
+ return;
+ }
+ ObjectMap mapObject = getReportMap(req);
+ mapObject.put(key, obj);
+ }
+
+ private ObjectMap getReportMap(HttpServletRequest req) {
+ List expiredList = new ArrayList();
+ for (String key : sessionMap.keySet()) {
+ ObjectMap reportObj = sessionMap.get(key);
+ if (reportObj.isExpired()) {
+ expiredList.add(key);
+ }
+ }
+ for (String key : expiredList) {
+ sessionMap.remove(key);
+ }
+ String sessionId = req.getSession().getId();
+ ObjectMap obj = sessionMap.get(sessionId);
+ if (obj != null) {
+ return obj;
+ } else {
+ ObjectMap mapObject = new ObjectMap();
+ sessionMap.put(sessionId, mapObject);
+ return mapObject;
+ }
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/chart/ChartServletAction.java b/blade-core-report/src/main/java/com/bstek/ureport/console/chart/ChartServletAction.java
new file mode 100644
index 0000000..16117fd
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/chart/ChartServletAction.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.chart;
+
+import com.bstek.ureport.cache.CacheUtils;
+import com.bstek.ureport.chart.ChartData;
+import com.bstek.ureport.console.RenderPageServletAction;
+import com.bstek.ureport.utils.UnitUtils;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.io.IOException;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年6月30日
+ */
+public class ChartServletAction extends RenderPageServletAction {
+ @Override
+ public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String method = retriveMethod(req);
+ if (method != null) {
+ invokeMethod(method, req, resp);
+ }
+ }
+
+ public void storeData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String file = req.getParameter("_u");
+ file = decode(file);
+ String chartId = req.getParameter("_chartId");
+ ChartData chartData = CacheUtils.getChartData(chartId);
+ if (chartData == null) {
+ return;
+ }
+ String base64Data = req.getParameter("_base64Data");
+ String prefix = "data:image/png;base64,";
+ if (base64Data != null) {
+ if (base64Data.startsWith(prefix)) {
+ base64Data = base64Data.substring(prefix.length(), base64Data.length());
+ }
+ }
+ chartData.setBase64Data(base64Data);
+ String width = req.getParameter("_width");
+ String height = req.getParameter("_height");
+ chartData.setHeight(UnitUtils.pixelToPoint(Integer.valueOf(height)));
+ chartData.setWidth(UnitUtils.pixelToPoint(Integer.valueOf(width)));
+ }
+
+ @Override
+ public String url() {
+ return "/chart";
+ }
+}
diff --git a/blade-core-report/src/main/java/com/bstek/ureport/console/designer/DatasourceServletAction.java b/blade-core-report/src/main/java/com/bstek/ureport/console/designer/DatasourceServletAction.java
new file mode 100644
index 0000000..779c7b2
--- /dev/null
+++ b/blade-core-report/src/main/java/com/bstek/ureport/console/designer/DatasourceServletAction.java
@@ -0,0 +1,385 @@
+/*******************************************************************************
+ * Copyright 2017 Bstek
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ ******************************************************************************/
+package com.bstek.ureport.console.designer;
+
+import com.bstek.ureport.Utils;
+import com.bstek.ureport.build.Context;
+import com.bstek.ureport.console.RenderPageServletAction;
+import com.bstek.ureport.console.exception.ReportDesignException;
+import com.bstek.ureport.definition.dataset.Field;
+import com.bstek.ureport.definition.datasource.BuildinDatasource;
+import com.bstek.ureport.definition.datasource.DataType;
+import com.bstek.ureport.expression.ExpressionUtils;
+import com.bstek.ureport.expression.model.Expression;
+import com.bstek.ureport.expression.model.data.ExpressionData;
+import com.bstek.ureport.expression.model.data.ObjectExpressionData;
+import com.bstek.ureport.utils.ProcedureUtils;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.apache.commons.beanutils.PropertyUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.PreparedStatementCallback;
+import org.springframework.jdbc.core.PreparedStatementCreator;
+import org.springframework.jdbc.core.PreparedStatementCreatorFactory;
+import org.springframework.jdbc.core.SqlParameter;
+import org.springframework.jdbc.core.namedparam.*;
+import org.springframework.jdbc.datasource.SingleConnectionDataSource;
+import org.springframework.jdbc.support.JdbcUtils;
+
+import javax.sql.DataSource;
+import java.beans.PropertyDescriptor;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.sql.*;
+import java.util.Date;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * @author Jacky.gao
+ * @since 2017年2月6日
+ */
+public class DatasourceServletAction extends RenderPageServletAction {
+
+ @Override
+ public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String method = retriveMethod(req);
+ if (method != null) {
+ invokeMethod(method, req, resp);
+ }
+ }
+
+ public void loadBuildinDatasources(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ List datasources = new ArrayList();
+ for (BuildinDatasource datasource : Utils.getBuildinDatasources()) {
+ datasources.add(datasource.name());
+ }
+ writeObjectToJson(resp, datasources);
+ }
+
+ public void loadMethods(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String beanId = req.getParameter("beanId");
+ Object obj = applicationContext.getBean(beanId);
+ Class> clazz = obj.getClass();
+ Method[] methods = clazz.getMethods();
+ List result = new ArrayList();
+ for (Method method : methods) {
+ Class>[] types = method.getParameterTypes();
+ if (types.length != 3) {
+ continue;
+ }
+ Class> typeClass1 = types[0];
+ Class> typeClass2 = types[1];
+ Class> typeClass3 = types[2];
+ if (!String.class.isAssignableFrom(typeClass1)) {
+ continue;
+ }
+ if (!String.class.isAssignableFrom(typeClass2)) {
+ continue;
+ }
+ if (!Map.class.isAssignableFrom(typeClass3)) {
+ continue;
+ }
+ result.add(method.getName());
+ }
+ writeObjectToJson(resp, result);
+ }
+
+ public void buildClass(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ String clazz = req.getParameter("clazz");
+ List result = new ArrayList();
+ try {
+ Class> targetClass = Class.forName(clazz);
+ PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(targetClass);
+ for (PropertyDescriptor pd : propertyDescriptors) {
+ String name = pd.getName();
+ if ("class".equals(name)) {
+ continue;
+ }
+ result.add(new Field(name));
+ }
+ writeObjectToJson(resp, result);
+ } catch (Exception ex) {
+ throw new ReportDesignException(ex);
+ }
+ }
+
+ public void buildDatabaseTables(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+ Connection conn = null;
+ ResultSet rs = null;
+ try {
+ conn = buildConnection(req);
+ DatabaseMetaData metaData = conn.getMetaData();
+ String url = metaData.getURL();
+ String schema = null;
+ if (url.toLowerCase().contains("oracle")) {
+ schema = metaData.getUserName();
+ }
+ List