🎉 4.0.0.RELEASE 升级 SpringBoot3 SpringCloud2023 JDK17

This commit is contained in:
smallchill 2024-04-21 23:03:58 +08:00
parent 45d7b20b75
commit 4bbcf53e63
129 changed files with 5456 additions and 714 deletions

View File

@ -1,7 +1,8 @@
<p align="center">
<img src="https://img.shields.io/badge/license-LGPL%20v3-blue.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Cloud-2021-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-2.7.10-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/license-LGPL%20v3-blue.svg" alt="Build Status">
<img src="https://img.shields.io/badge/JDK-17+-green.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Cloud-2023-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg" alt="Downloads">
</p>
## SpringBlade微服务开发平台

View File

@ -19,7 +19,7 @@
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>${maven-flatten.version}</version>
<version>${maven.flatten.version}</version>
<configuration>
<updatePomFile>true</updatePomFile>
<flattenMode>oss</flattenMode>

View File

@ -62,38 +62,27 @@
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
<version>1.0.2</version>
</dependency>
<!-- Ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.5</version>
</dependency>
<!-- Druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.19</version>
<artifactId>druid-spring-boot-3-starter</artifactId>
</dependency>
<!-- MySQL -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.32</version>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
</dependency>
<!-- PostgreSql -->
<!--<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>-->
</dependencies>
</project>

View File

@ -23,7 +23,7 @@ import org.springblade.core.tool.api.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.util.List;
/**

View File

@ -21,8 +21,8 @@ import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.*;

View File

@ -69,7 +69,6 @@
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${alibaba.nacos.version}</version>
</dependency>
<!-- Sentinel -->
<dependency>
@ -81,7 +80,6 @@
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.83_noneautotype</version>
</dependency>
</dependencies>

View File

@ -25,7 +25,7 @@ import org.springblade.core.cloud.sentinel.BladeSentinelInvocationHandler;
import org.springframework.beans.BeansException;
import org.springframework.cloud.openfeign.FallbackFactory;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.FeignContext;
import org.springframework.cloud.openfeign.FeignClientFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.annotation.AnnotationUtils;
@ -50,11 +50,10 @@ public class BladeFeignSentinel {
public static final class Builder extends Feign.Builder implements ApplicationContextAware {
private Contract contract = new Contract.Default();
private ApplicationContext applicationContext;
private FeignContext feignContext;
private FeignClientFactory feignContext;
@Override
public Feign.Builder invocationHandlerFactory(
InvocationHandlerFactory invocationHandlerFactory) {
public Feign.Builder invocationHandlerFactory(InvocationHandlerFactory invocationHandlerFactory) {
throw new UnsupportedOperationException();
}
@ -65,7 +64,7 @@ public class BladeFeignSentinel {
}
@Override
public Feign build() {
public Feign internalBuild() {
super.invocationHandlerFactory(new InvocationHandlerFactory() {
@SneakyThrows
@Override
@ -115,13 +114,13 @@ public class BladeFeignSentinel {
}
});
super.contract(new SentinelContractHolder(contract));
return super.build();
return super.internalBuild();
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
feignContext = this.applicationContext.getBean(FeignContext.class);
feignContext = this.applicationContext.getBean(FeignClientFactory.class);
}
}

View File

@ -20,7 +20,7 @@ import org.springblade.core.secure.utils.SecureUtil;
import org.springblade.core.tool.utils.Charsets;
import org.springblade.core.tool.utils.UrlUtil;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
/**
* 用户信息获取器

View File

@ -18,7 +18,7 @@ package org.springblade.core.cloud.header;
import org.springframework.lang.Nullable;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
/**
* Blade 用户信息获取器用于请求头传递

View File

@ -23,7 +23,7 @@ import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.springframework.util.PatternMatchUtils;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;

View File

@ -0,0 +1,30 @@
/**
* Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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 {
}

View File

@ -0,0 +1,64 @@
/**
* Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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;
}

View File

@ -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.
*
* <p>Example:
* <pre>{@code
* --> POST /greeting http/1.1 (3-byte body)
*
* <-- 200 OK (22ms, 6-byte body)
* }</pre>
*/
BASIC,
/**
* Logs request and response lines and their respective headers.
*
* <p>Example:
* <pre>{@code
* --> POST /greeting http/1.1
* Host: example.com
* Content-Type: plain/text
* Content-Length: 3
* --> END POST
*
* <-- 200 OK (22ms)
* Content-Type: plain/text
* Content-Length: 6
* <-- END HTTP
* }</pre>
*/
HEADERS,
/**
* Logs request and response lines and their respective headers and bodies (if present).
*
* <p>Example:
* <pre>{@code
* --> POST /greeting http/1.1
* Host: example.com
* Content-Type: plain/text
* Content-Length: 3
*
* Hi?
* --> END POST
*
* <-- 200 OK (22ms)
* Content-Type: plain/text
* Content-Length: 6
*
* Hello!
* <-- END HTTP
* }</pre>
*/
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;
}

View File

@ -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<HttpMessageConverter<?>> converters) {
private static void configMessageConverters(ApplicationContext context, List<HttpMessageConverter<?>> 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)));
}
}

View File

@ -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;
}

View File

@ -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.
*
* <p>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();
}
}
}

View File

@ -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
* <a href="https://square.github.io/okhttp/">OkHttp</a> 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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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统一限流策略

View File

@ -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;
/**

View File

@ -23,12 +23,10 @@
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis.plus.generator.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-extension</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!--Velocity-->
<dependency>

View File

@ -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<IPage<$!{entity}VO>> 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<IPage<$!{entity}>> 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<IPage<$!{entity}VO>> 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)));
}

View File

@ -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})

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -30,6 +30,28 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
</dependency>
<!-- jakarta -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<!-- javax -->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,42 @@
/**
* Copyright (c) 2019-2029, DreamLu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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();
}
}

View File

@ -25,7 +25,7 @@ public interface AppConstant {
/**
* 应用版本
*/
String APPLICATION_VERSION = "3.7.2";
String APPLICATION_VERSION = "4.0.0";
/**
* 基础包

View File

@ -0,0 +1,113 @@
/**
* Copyright (c) 2018-2028, DreamLu 卢春梦 (qq596392912@gmail.com).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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.
*
* <p>Example:
* <pre>{@code
* --> POST /greeting http/1.1 (3-byte body)
*
* <-- 200 OK (22ms, 6-byte body)
* }</pre>
*/
BASIC(1),
/**
* Logs request and response lines and their respective headers.
*
* <p>Example:
* <pre>{@code
* --> POST /greeting http/1.1
* Host: example.com
* Content-Type: plain/text
* Content-Length: 3
* --> END POST
*
* <-- 200 OK (22ms)
* Content-Type: plain/text
* Content-Length: 6
* <-- END HTTP
* }</pre>
*/
HEADERS(2),
/**
* Logs request and response lines and their respective headers and bodies (if present).
*
* <p>Example:
* <pre>{@code
* --> POST /greeting http/1.1
* Host: example.com
* Content-Type: plain/text
* Content-Length: 3
*
* Hi?
* --> END POST
*
* <-- 200 OK (22ms)
* Content-Type: plain/text
* Content-Length: 6
*
* Hello!
* <-- END HTTP
* }</pre>
*/
BODY(3);
/**
* 请求日志配置前缀
*/
public static final String REQ_LOG_PROPS_PREFIX = "blade.log.request";
/**
* 控制台日志是否启用
*/
public static final String CONSOLE_LOG_ENABLED_PROP = "blade.log.console.enabled";
/**
* 级别
*/
private final int level;
/**
* 当前版本 小于和等于 比较的版本
*
* @param level LogLevel
* @return 是否小于和等于
*/
public boolean lte(BladeLogLevel level) {
return this.level <= level.level;
}
}

View File

@ -17,6 +17,7 @@ package org.springblade.core.launch.props;
import lombok.Getter;
import lombok.Setter;
import org.springblade.core.launch.constant.AppConstant;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
@ -200,6 +201,33 @@ public class BladeProperties implements EnvironmentAware, EnvironmentCapable {
return defaultValue;
}
/**
* 是否是开发环境
*
* @return boolean
*/
public boolean isDev() {
return AppConstant.DEV_CODE.equals(getEnv());
}
/**
* 是否是生产环境
*
* @return boolean
*/
public boolean isProd() {
return AppConstant.PROD_CODE.equals(getEnv());
}
/**
* 是否是测试环境
*
* @return boolean
*/
public boolean isTest() {
return AppConstant.TEST_CODE.equals(getEnv());
}
/**
* 判断是否存在key
*

View File

@ -0,0 +1,55 @@
/**
* Copyright (c) 2019-2029, DreamLu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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;
}

View File

@ -0,0 +1,178 @@
/**
* Copyright (c) 2019-2029, DreamLu 卢春梦 (596392912@qq.com & www.dreamlu.net).
* <p>
* 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
* <p>
* http://www.gnu.org/licenses/lgpl.html
* <p>
* 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<PropertySourceLoader> 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<String, Object> beansWithAnnotation = beanFactory.getBeansWithAnnotation(BladePropertySource.class);
Set<Map.Entry<String, Object>> beanEntrySet = beansWithAnnotation.entrySet();
// 没有 @YmlPropertySource 注解跳出
if (beanEntrySet.isEmpty()) {
log.warn("Not found @BladePropertySource on spring bean class.");
return;
}
// 组装资源
List<PropertyFile> propertyFileList = new ArrayList<>();
for (Map.Entry<String, Object> 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<String, PropertySourceLoader> loaderMap = new HashMap<>(16);
for (PropertySourceLoader loader : propertySourceLoaders) {
String[] loaderExtensions = loader.getFileExtensions();
for (String extension : loaderExtensions) {
loaderMap.put(extension, loader);
}
}
// 去重排序
List<PropertyFile> 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<PropertySource> 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<PropertySource> 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<PropertyFile> {
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);
}
}
}

View File

@ -55,7 +55,6 @@
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>${alibaba.nacos.version}</version>
</dependency>
<!-- Web -->
<dependency>

View File

@ -28,11 +28,15 @@
<groupId>org.springblade</groupId>
<artifactId>blade-core-cloud</artifactId>
</dependency>
<!-- validator -->
<dependency>
<artifactId>hibernate-validator</artifactId>
<groupId>org.hibernate.validator</groupId>
</dependency>
<!--Mybatis-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -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;
/**
* 统一异常处理

View File

@ -42,8 +42,8 @@ public class BladeErrorAttributes extends DefaultErrorAttributes {
@Override
public Map<String, Object> 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) {

View File

@ -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;
/**

View File

@ -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()));
}

View File

@ -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<String, Object> source = (Map<String, Object>) event.getSource();
LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
LogAbstractUtil.addOtherInfoToLog(logError, bladeProperties, serverInfo);
logService.saveErrorLog(logError);
try {
Map<String, Object> source = (Map<String, Object>) event.getSource();
LogError logError = (LogError) source.get(EventConstant.EVENT_LOG);
LogAbstractUtil.addOtherInfoToLog(logError, bladeProperties, serverInfo);
logService.saveErrorLog(logError);
} catch (Exception e) {
log.error("保存错误日志失败", e);
}
}
}

View File

@ -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;
/**

View File

@ -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;

View File

@ -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;
/**

View File

@ -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;

View File

@ -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;
/**

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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 相关工具

View File

@ -19,17 +19,18 @@
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${mybatis.spring.version}</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-typehandlers-jsr310</artifactId>
</dependency>
<!--Blade-->
<dependency>

View File

@ -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;
}

View File

@ -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;
/**

View File

@ -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;

View File

@ -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;
}

View File

@ -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;
}

View File

@ -21,8 +21,35 @@
<dependency>
<groupId>com.bstek.ureport</groupId>
<artifactId>ureport2-console</artifactId>
<exclusions>
<exclusion>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</exclusion>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
<version>2.2.9</version>
</dependency>
<dependency>
<groupId>com.bstek.ureport</groupId>
<artifactId>ureport2-core</artifactId>
<exclusions>
<exclusion>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</exclusion>
</exclusions>
<version>2.2.9</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@ -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);
}
}

View File

@ -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<BindData> compute(Cell cell, Context context) {
List<BindData> list=new ArrayList<BindData>();
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<BindData> 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<EncodeHintType, Object> hints = new Hashtable<EncodeHintType, Object>();
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;
}
}

View File

@ -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<String, Object> buildParameters(HttpServletRequest req) {
Map<String, Object> parameters = new HashMap<String, Object>();
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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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<HttpServletRequest> requestThreadLocal = new ThreadLocal<HttpServletRequest>();
public static void setRequest(HttpServletRequest request) {
requestThreadLocal.set(request);
}
public static HttpServletRequest getRequest() {
return requestThreadLocal.get();
}
public static void clean() {
requestThreadLocal.remove();
}
}

View File

@ -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();
}

View File

@ -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<String, ServletAction> actionMap = new HashMap<String, ServletAction>();
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
WebApplicationContext applicationContext = getWebApplicationContext(config);
Collection<ServletAction> 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("<html>");
pw.write("<header><title>UReport Console</title></header>");
pw.write("<body>");
pw.write(msg);
pw.write("</body>");
pw.write("</html>");
pw.flush();
pw.close();
}
}

View File

@ -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();
}
}
}

View File

@ -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<String, ObjectMap> sessionReportMap = new HashMap<String, ObjectMap>();
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<String> expiredList = new ArrayList<String>();
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;
}
}
}

View File

@ -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<String, ObjectMap> sessionMap = new HashMap<String, ObjectMap>();
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<String> expiredList = new ArrayList<String>();
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;
}
}
}

View File

@ -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";
}
}

View File

@ -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<String> datasources = new ArrayList<String>();
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<String> result = new ArrayList<String>();
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<Field> result = new ArrayList<Field>();
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<Map<String, String>> tables = new ArrayList<Map<String, String>>();
rs = metaData.getTables(null, schema, "%", new String[]{"TABLE", "VIEW"});
while (rs.next()) {
Map<String, String> table = new HashMap<String, String>();
table.put("name", rs.getString("TABLE_NAME"));
table.put("type", rs.getString("TABLE_TYPE"));
tables.add(table);
}
writeObjectToJson(resp, tables);
} catch (Exception ex) {
throw new ServletException(ex);
} finally {
JdbcUtils.closeResultSet(rs);
JdbcUtils.closeConnection(conn);
}
}
public void buildFields(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String sql = req.getParameter("sql");
String parameters = req.getParameter("parameters");
Connection conn = null;
final List<Field> fields = new ArrayList<Field>();
try {
conn = buildConnection(req);
Map<String, Object> map = buildParameters(parameters);
sql = parseSql(sql, map);
if (ProcedureUtils.isProcedure(sql)) {
List<Field> fieldsList = ProcedureUtils.procedureColumnsQuery(sql, map, conn);
fields.addAll(fieldsList);
} else {
DataSource dataSource = new SingleConnectionDataSource(conn, false);
NamedParameterJdbcTemplate jdbc = new NamedParameterJdbcTemplate(dataSource);
PreparedStatementCreator statementCreator = getPreparedStatementCreator(sql, new MapSqlParameterSource(map));
jdbc.getJdbcOperations().execute(statementCreator, new PreparedStatementCallback<Object>() {
@Override
public Object doInPreparedStatement(PreparedStatement ps) throws SQLException, DataAccessException {
ResultSet rs = null;
try {
rs = ps.executeQuery();
ResultSetMetaData metadata = rs.getMetaData();
int columnCount = metadata.getColumnCount();
for (int i = 0; i < columnCount; i++) {
String columnName = metadata.getColumnLabel(i + 1);
fields.add(new Field(columnName));
}
return null;
} finally {
JdbcUtils.closeResultSet(rs);
}
}
});
}
writeObjectToJson(resp, fields);
} catch (Exception ex) {
throw new ReportDesignException(ex);
} finally {
JdbcUtils.closeConnection(conn);
}
}
protected PreparedStatementCreator getPreparedStatementCreator(String sql, SqlParameterSource paramSource) {
ParsedSql parsedSql = NamedParameterUtils.parseSqlStatement(sql);
String sqlToUse = NamedParameterUtils.substituteNamedParameters(parsedSql, paramSource);
Object[] params = NamedParameterUtils.buildValueArray(parsedSql, paramSource, null);
List<SqlParameter> declaredParameters = NamedParameterUtils.buildSqlParameterList(parsedSql, paramSource);
PreparedStatementCreatorFactory pscf = new PreparedStatementCreatorFactory(sqlToUse, declaredParameters);
return pscf.newPreparedStatementCreator(params);
}
public void previewData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String sql = req.getParameter("sql");
String parameters = req.getParameter("parameters");
Map<String, Object> map = buildParameters(parameters);
sql = parseSql(sql, map);
Connection conn = null;
try {
conn = buildConnection(req);
List<Map<String, Object>> list = null;
if (ProcedureUtils.isProcedure(sql)) {
list = ProcedureUtils.procedureQuery(sql, map, conn);
} else {
DataSource dataSource = new SingleConnectionDataSource(conn, false);
NamedParameterJdbcTemplate jdbc = new NamedParameterJdbcTemplate(dataSource);
list = jdbc.queryForList(sql, map);
}
int size = list.size();
int currentTotal = size;
if (currentTotal > 500) {
currentTotal = 500;
}
List<Map<String, Object>> ls = new ArrayList<Map<String, Object>>();
for (int i = 0; i < currentTotal; i++) {
ls.add(list.get(i));
}
DataResult result = new DataResult();
List<String> fields = new ArrayList<String>();
if (size > 0) {
Map<String, Object> item = list.get(0);
for (String name : item.keySet()) {
fields.add(name);
}
}
result.setFields(fields);
result.setCurrentTotal(currentTotal);
result.setData(ls);
result.setTotal(size);
writeObjectToJson(resp, result);
} catch (Exception ex) {
throw new ServletException(ex);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
private String parseSql(String sql, Map<String, Object> parameters) {
sql = sql.trim();
Context context = new Context(applicationContext, parameters);
if (sql.startsWith(ExpressionUtils.EXPR_PREFIX) && sql.endsWith(ExpressionUtils.EXPR_SUFFIX)) {
sql = sql.substring(2, sql.length() - 1);
Expression expr = ExpressionUtils.parseExpression(sql);
sql = executeSqlExpr(expr, context);
return sql;
} else {
String sqlForUse = sql;
Pattern pattern = Pattern.compile("\\$\\{.*?\\}");
Matcher matcher = pattern.matcher(sqlForUse);
while (matcher.find()) {
String substr = matcher.group();
String sqlExpr = substr.substring(2, substr.length() - 1);
Expression expr = ExpressionUtils.parseExpression(sqlExpr);
String result = executeSqlExpr(expr, context);
sqlForUse = sqlForUse.replace(substr, result);
}
Utils.logToConsole("DESIGN SQL:" + sqlForUse);
return sqlForUse;
}
}
private String executeSqlExpr(Expression sqlExpr, Context context) {
String sqlForUse = null;
ExpressionData<?> exprData = sqlExpr.execute(null, null, context);
if (exprData instanceof ObjectExpressionData) {
ObjectExpressionData data = (ObjectExpressionData) exprData;
Object obj = data.getData();
if (obj != null) {
String s = obj.toString();
s = s.replaceAll("\\\\", "");
sqlForUse = s;
}
}
return sqlForUse;
}
public void testConnection(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String driver = req.getParameter("driver");
String url = req.getParameter("url");
Connection conn = null;
Map<String, Object> map = new HashMap<String, Object>();
try {
Class.forName(driver);
conn = DriverManager.getConnection(url, username, password);
map.put("result", true);
} catch (Exception ex) {
map.put("error", ex.toString());
map.put("result", false);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
writeObjectToJson(resp, map);
}
@SuppressWarnings("unchecked")
private Map<String, Object> buildParameters(String parameters) throws IOException, JsonParseException, JsonMappingException {
Map<String, Object> map = new HashMap<String, Object>();
if (StringUtils.isBlank(parameters)) {
return map;
}
ObjectMapper mapper = new ObjectMapper();
List<Map<String, Object>> list = mapper.readValue(parameters, ArrayList.class);
for (Map<String, Object> param : list) {
String name = param.get("name").toString();
DataType type = DataType.valueOf(param.get("type").toString());
String defaultValue = (String) param.get("defaultValue");
if (defaultValue == null || defaultValue.isEmpty()) {
switch (type) {
case Boolean:
map.put(name, false);
case Date:
map.put(name, new Date());
case Float:
map.put(name, (float) 0);
case Integer:
map.put(name, 0);
case String:
if (defaultValue != null) {
map.put(name, "");
} else {
map.put(name, "null");
}
break;
case List:
map.put(name, new ArrayList<>());
}
} else {
map.put(name, type.parse(defaultValue));
}
}
return map;
}
private Connection buildConnection(HttpServletRequest req) throws Exception {
String type = req.getParameter("type");
if (type.equals("jdbc")) {
String username = req.getParameter("username");
String password = req.getParameter("password");
String driver = req.getParameter("driver");
String url = req.getParameter("url");
Class.forName(driver);
return DriverManager.getConnection(url, username, password);
} else {
String name = req.getParameter("name");
Connection conn = Utils.getBuildinConnection(name);
if (conn == null) {
throw new ReportDesignException("Buildin datasource [" + name + "] not exist.");
}
return conn;
}
}
@Override
public String url() {
return "/datasource";
}
}

View File

@ -0,0 +1,213 @@
/*******************************************************************************
* 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.cache.CacheUtils;
import com.bstek.ureport.console.RenderPageServletAction;
import com.bstek.ureport.console.cache.TempObjectCache;
import com.bstek.ureport.console.exception.ReportDesignException;
import com.bstek.ureport.definition.ReportDefinition;
import com.bstek.ureport.dsl.ReportParserLexer;
import com.bstek.ureport.dsl.ReportParserParser;
import com.bstek.ureport.dsl.ReportParserParser.DatasetContext;
import com.bstek.ureport.export.ReportRender;
import com.bstek.ureport.expression.ErrorInfo;
import com.bstek.ureport.expression.ScriptErrorListener;
import com.bstek.ureport.parser.ReportParser;
import com.bstek.ureport.provider.report.ReportProvider;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.*;
/**
* @author Jacky.gao
* @since 2017年1月25日
*/
public class DesignerServletAction extends RenderPageServletAction {
private ReportRender reportRender;
private ReportParser reportParser;
private List<ReportProvider> reportProviders = new ArrayList<ReportProvider>();
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = retriveMethod(req);
if (method != null) {
invokeMethod(method, req, resp);
} else {
VelocityContext context = new VelocityContext();
context.put("contextPath", req.getContextPath());
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
Template template = ve.getTemplate("ureport-html/designer.html", "utf-8");
PrintWriter writer = resp.getWriter();
template.merge(context, writer);
writer.close();
}
}
public void scriptValidation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String content = req.getParameter("content");
ANTLRInputStream antlrInputStream = new ANTLRInputStream(content);
ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
ReportParserParser parser = new ReportParserParser(tokenStream);
ScriptErrorListener errorListener = new ScriptErrorListener();
parser.removeErrorListeners();
parser.addErrorListener(errorListener);
parser.expression();
List<ErrorInfo> infos = errorListener.getInfos();
writeObjectToJson(resp, infos);
}
public void conditionScriptValidation(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String content = req.getParameter("content");
ANTLRInputStream antlrInputStream = new ANTLRInputStream(content);
ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
ReportParserParser parser = new ReportParserParser(tokenStream);
ScriptErrorListener errorListener = new ScriptErrorListener();
parser.removeErrorListeners();
parser.addErrorListener(errorListener);
parser.expr();
List<ErrorInfo> infos = errorListener.getInfos();
writeObjectToJson(resp, infos);
}
public void parseDatasetName(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String expr = req.getParameter("expr");
ANTLRInputStream antlrInputStream = new ANTLRInputStream(expr);
ReportParserLexer lexer = new ReportParserLexer(antlrInputStream);
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
ReportParserParser parser = new ReportParserParser(tokenStream);
parser.removeErrorListeners();
DatasetContext ctx = parser.dataset();
String datasetName = ctx.Identifier().getText();
Map<String, String> result = new HashMap<String, String>();
result.put("datasetName", datasetName);
writeObjectToJson(resp, result);
}
public void savePreviewData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String content = req.getParameter("content");
content = decodeContent(content);
InputStream inputStream = IOUtils.toInputStream(content, "utf-8");
ReportDefinition reportDef = reportParser.parse(inputStream, "p");
reportRender.rebuildReportDefinition(reportDef);
IOUtils.closeQuietly(inputStream);
TempObjectCache.putObject(PREVIEW_KEY, reportDef);
}
public void loadReport(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String file = req.getParameter("file");
if (file == null) {
throw new ReportDesignException("Report file can not be null.");
}
file = ReportUtils.decodeFileName(file);
Object obj = TempObjectCache.getObject(file);
if (obj != null && obj instanceof ReportDefinition) {
ReportDefinition reportDef = (ReportDefinition) obj;
TempObjectCache.removeObject(file);
writeObjectToJson(resp, new ReportDefinitionWrapper(reportDef));
} else {
ReportDefinition reportDef = reportRender.parseReport(file);
writeObjectToJson(resp, new ReportDefinitionWrapper(reportDef));
}
}
public void deleteReportFile(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String file = req.getParameter("file");
if (file == null) {
throw new ReportDesignException("Report file can not be null.");
}
ReportProvider targetReportProvider = null;
for (ReportProvider provider : reportProviders) {
if (file.startsWith(provider.getPrefix())) {
targetReportProvider = provider;
break;
}
}
if (targetReportProvider == null) {
throw new ReportDesignException("File [" + file + "] not found available report provider.");
}
targetReportProvider.deleteReport(file);
}
public void saveReportFile(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String file = req.getParameter("file");
file = ReportUtils.decodeFileName(file);
String content = req.getParameter("content");
content = decodeContent(content);
ReportProvider targetReportProvider = null;
for (ReportProvider provider : reportProviders) {
if (file.startsWith(provider.getPrefix())) {
targetReportProvider = provider;
break;
}
}
if (targetReportProvider == null) {
throw new ReportDesignException("File [" + file + "] not found available report provider.");
}
targetReportProvider.saveReport(file, content);
InputStream inputStream = IOUtils.toInputStream(content, "utf-8");
ReportDefinition reportDef = reportParser.parse(inputStream, file);
reportRender.rebuildReportDefinition(reportDef);
CacheUtils.cacheReportDefinition(file, reportDef);
IOUtils.closeQuietly(inputStream);
}
public void loadReportProviders(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
writeObjectToJson(resp, reportProviders);
}
public void setReportRender(ReportRender reportRender) {
this.reportRender = reportRender;
}
public void setReportParser(ReportParser reportParser) {
this.reportParser = reportParser;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
super.setApplicationContext(applicationContext);
Collection<ReportProvider> providers = applicationContext.getBeansOfType(ReportProvider.class).values();
for (ReportProvider provider : providers) {
if (provider.disabled() || provider.getName() == null) {
continue;
}
reportProviders.add(provider);
}
}
@Override
public String url() {
return "/designer";
}
}

View File

@ -0,0 +1,50 @@
/*******************************************************************************
* 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.console.RenderPageServletAction;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author Jacky.gao
* @since 2017年10月24日
*/
public class SearchFormDesignerAction extends RenderPageServletAction {
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
VelocityContext context = new VelocityContext();
context.put("contextPath", req.getContextPath());
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
Template template = ve.getTemplate("ureport-html/searchform.html", "utf-8");
PrintWriter writer = resp.getWriter();
template.merge(context, writer);
writer.close();
}
@Override
public String url() {
return "/searchFormDesigner";
}
}

View File

@ -0,0 +1,119 @@
/*******************************************************************************
* 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.excel;
import com.bstek.ureport.build.ReportBuilder;
import com.bstek.ureport.console.BaseServletAction;
import com.bstek.ureport.console.cache.TempObjectCache;
import com.bstek.ureport.console.exception.ReportDesignException;
import com.bstek.ureport.definition.ReportDefinition;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.export.ExportConfigure;
import com.bstek.ureport.export.ExportConfigureImpl;
import com.bstek.ureport.export.ExportManager;
import com.bstek.ureport.export.excel.low.Excel97Producer;
import com.bstek.ureport.model.Report;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
/**
* @author Jacky.gao
* @since 2017年7月3日
*/
public class ExportExcel97ServletAction extends BaseServletAction {
private ReportBuilder reportBuilder;
private ExportManager exportManager;
private Excel97Producer excelProducer = new Excel97Producer();
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = retriveMethod(req);
if (method != null) {
invokeMethod(method, req, resp);
} else {
buildExcel(req, resp, false, false);
}
}
public void paging(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
buildExcel(req, resp, true, false);
}
public void sheet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
buildExcel(req, resp, false, true);
}
public void buildExcel(HttpServletRequest req, HttpServletResponse resp, boolean withPage, boolean withSheet) throws IOException {
String file = req.getParameter("_u");
if (StringUtils.isBlank(file)) {
throw new ReportComputeException("Report file can not be null.");
}
String fileName = req.getParameter("_n");
if (StringUtils.isNotBlank(fileName)) {
fileName = decode(fileName);
} else {
fileName = "ureport.xls";
}
resp.setContentType("application/octet-stream;charset=ISO8859-1");
resp.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
Map<String, Object> parameters = buildParameters(req);
OutputStream outputStream = resp.getOutputStream();
if (file.equals(PREVIEW_KEY)) {
ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
if (reportDefinition == null) {
throw new ReportDesignException("Report data has expired,can not do export excel.");
}
Report report = reportBuilder.buildReport(reportDefinition, parameters);
if (withPage) {
excelProducer.produceWithPaging(report, outputStream);
} else if (withSheet) {
excelProducer.produceWithSheet(report, outputStream);
} else {
excelProducer.produce(report, outputStream);
}
} else {
ExportConfigure configure = new ExportConfigureImpl(file, parameters, outputStream);
if (withPage) {
exportManager.exportExcelWithPaging(configure);
} else if (withSheet) {
exportManager.exportExcelWithPagingSheet(configure);
} else {
exportManager.exportExcel(configure);
}
}
outputStream.flush();
outputStream.close();
}
public void setReportBuilder(ReportBuilder reportBuilder) {
this.reportBuilder = reportBuilder;
}
public void setExportManager(ExportManager exportManager) {
this.exportManager = exportManager;
}
@Override
public String url() {
return "/excel97";
}
}

View File

@ -0,0 +1,123 @@
/*******************************************************************************
* 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.excel;
import com.bstek.ureport.build.ReportBuilder;
import com.bstek.ureport.console.BaseServletAction;
import com.bstek.ureport.console.cache.TempObjectCache;
import com.bstek.ureport.console.exception.ReportDesignException;
import com.bstek.ureport.definition.ReportDefinition;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.export.ExportConfigure;
import com.bstek.ureport.export.ExportConfigureImpl;
import com.bstek.ureport.export.ExportManager;
import com.bstek.ureport.export.excel.high.ExcelProducer;
import com.bstek.ureport.model.Report;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
/**
* @author Jacky.gao
* @since 2017年4月17日
*/
public class ExportExcelServletAction extends BaseServletAction {
private ReportBuilder reportBuilder;
private ExportManager exportManager;
private ExcelProducer excelProducer = new ExcelProducer();
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = retriveMethod(req);
if (method != null) {
invokeMethod(method, req, resp);
} else {
buildExcel(req, resp, false, false);
}
}
public void paging(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
buildExcel(req, resp, true, false);
}
public void sheet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
buildExcel(req, resp, false, true);
}
public void buildExcel(HttpServletRequest req, HttpServletResponse resp, boolean withPage, boolean withSheet) throws IOException {
String file = req.getParameter("_u");
file = decode(file);
if (StringUtils.isBlank(file)) {
throw new ReportComputeException("Report file can not be null.");
}
OutputStream outputStream = resp.getOutputStream();
try {
String fileName = req.getParameter("_n");
fileName = buildDownloadFileName(file, fileName, ".xlsx");
resp.setContentType("application/octet-stream;charset=ISO8859-1");
fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
resp.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
Map<String, Object> parameters = buildParameters(req);
if (file.equals(PREVIEW_KEY)) {
ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
if (reportDefinition == null) {
throw new ReportDesignException("Report data has expired,can not do export excel.");
}
Report report = reportBuilder.buildReport(reportDefinition, parameters);
if (withPage) {
excelProducer.produceWithPaging(report, outputStream);
} else if (withSheet) {
excelProducer.produceWithSheet(report, outputStream);
} else {
excelProducer.produce(report, outputStream);
}
} else {
ExportConfigure configure = new ExportConfigureImpl(file, parameters, outputStream);
if (withPage) {
exportManager.exportExcelWithPaging(configure);
} else if (withSheet) {
exportManager.exportExcelWithPagingSheet(configure);
} else {
exportManager.exportExcel(configure);
}
}
} catch (Exception ex) {
throw new ReportException(ex);
} finally {
outputStream.flush();
outputStream.close();
}
}
public void setReportBuilder(ReportBuilder reportBuilder) {
this.reportBuilder = reportBuilder;
}
public void setExportManager(ExportManager exportManager) {
this.exportManager = exportManager;
}
@Override
public String url() {
return "/excel";
}
}

View File

@ -0,0 +1,365 @@
/*******************************************************************************
* 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.html;
import com.bstek.ureport.build.Context;
import com.bstek.ureport.build.ReportBuilder;
import com.bstek.ureport.build.paging.Page;
import com.bstek.ureport.cache.CacheUtils;
import com.bstek.ureport.chart.ChartData;
import com.bstek.ureport.console.MobileUtils;
import com.bstek.ureport.console.RenderPageServletAction;
import com.bstek.ureport.console.cache.TempObjectCache;
import com.bstek.ureport.console.exception.ReportDesignException;
import com.bstek.ureport.definition.Paper;
import com.bstek.ureport.definition.ReportDefinition;
import com.bstek.ureport.definition.searchform.FormPosition;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.export.*;
import com.bstek.ureport.export.html.HtmlProducer;
import com.bstek.ureport.export.html.HtmlReport;
import com.bstek.ureport.export.html.SearchFormData;
import com.bstek.ureport.model.Report;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.*;
/**
* @author Jacky.gao
* @since 2017年2月15日
*/
public class HtmlPreviewServletAction extends RenderPageServletAction {
private ExportManager exportManager;
private ReportBuilder reportBuilder;
private ReportRender reportRender;
private HtmlProducer htmlProducer = new HtmlProducer();
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = retriveMethod(req);
if (method != null) {
invokeMethod(method, req, resp);
} else {
VelocityContext context = new VelocityContext();
HtmlReport htmlReport = null;
String errorMsg = null;
try {
htmlReport = loadReport(req);
} catch (Exception ex) {
if (!(ex instanceof ReportDesignException)) {
ex.printStackTrace();
}
errorMsg = buildExceptionMessage(ex);
}
String title = buildTitle(req);
context.put("title", title);
if (htmlReport == null) {
context.put("content", "<div style='color:red'><strong>报表计算出错,错误信息如下:</strong><br><div style=\"margin:10px\">" + errorMsg + "</div></div>");
context.put("error", true);
context.put("searchFormJs", "");
context.put("downSearchFormHtml", "");
context.put("upSearchFormHtml", "");
} else {
SearchFormData formData = htmlReport.getSearchFormData();
if (formData != null) {
context.put("searchFormJs", formData.getJs());
if (formData.getFormPosition().equals(FormPosition.up)) {
context.put("upSearchFormHtml", formData.getHtml());
context.put("downSearchFormHtml", "");
} else {
context.put("downSearchFormHtml", formData.getHtml());
context.put("upSearchFormHtml", "");
}
} else {
context.put("searchFormJs", "");
context.put("downSearchFormHtml", "");
context.put("upSearchFormHtml", "");
}
context.put("content", htmlReport.getContent());
context.put("style", htmlReport.getStyle());
context.put("reportAlign", htmlReport.getReportAlign());
context.put("totalPage", htmlReport.getTotalPage());
context.put("totalPageWithCol", htmlReport.getTotalPageWithCol());
context.put("pageIndex", htmlReport.getPageIndex());
context.put("chartDatas", convertJson(htmlReport.getChartDatas()));
context.put("error", false);
context.put("file", req.getParameter("_u"));
context.put("intervalRefreshValue", htmlReport.getHtmlIntervalRefreshValue());
String customParameters = buildCustomParameters(req);
context.put("customParameters", customParameters);
context.put("_t", "");
Tools tools = null;
if (MobileUtils.isMobile(req)) {
tools = new Tools(false);
tools.setShow(false);
} else {
String toolsInfo = req.getParameter("_t");
if (StringUtils.isNotBlank(toolsInfo)) {
tools = new Tools(false);
if (toolsInfo.equals("0")) {
tools.setShow(false);
} else {
String[] infos = toolsInfo.split(",");
for (String name : infos) {
tools.doInit(name);
}
}
context.put("_t", toolsInfo);
context.put("hasTools", true);
} else {
tools = new Tools(true);
}
}
context.put("tools", tools);
}
context.put("contextPath", req.getContextPath());
resp.setContentType("text/html");
resp.setCharacterEncoding("utf-8");
Template template = ve.getTemplate("ureport-html/html-preview.html", "utf-8");
PrintWriter writer = resp.getWriter();
template.merge(context, writer);
writer.close();
}
}
private String buildTitle(HttpServletRequest req) {
String title = req.getParameter("_title");
if (StringUtils.isBlank(title)) {
title = req.getParameter("_u");
title = decode(title);
int point = title.lastIndexOf(".ureport.xml");
if (point > -1) {
title = title.substring(0, point);
}
if (title.equals("p")) {
title = "设计中报表";
}
} else {
title = decode(title);
}
return title + "-ureport";
}
private String convertJson(Collection<ChartData> data) {
if (data == null || data.size() == 0) {
return "";
}
ObjectMapper mapper = new ObjectMapper();
try {
String json = mapper.writeValueAsString(data);
return json;
} catch (Exception e) {
throw new ReportComputeException(e);
}
}
public void loadData(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
HtmlReport htmlReport = loadReport(req);
writeObjectToJson(resp, htmlReport);
}
public void loadPrintPages(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String file = req.getParameter("_u");
file = decode(file);
if (StringUtils.isBlank(file)) {
throw new ReportComputeException("Report file can not be null.");
}
Map<String, Object> parameters = buildParameters(req);
ReportDefinition reportDefinition = null;
if (file.equals(PREVIEW_KEY)) {
reportDefinition = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
if (reportDefinition == null) {
throw new ReportDesignException("Report data has expired,can not do export excel.");
}
} else {
reportDefinition = reportRender.getReportDefinition(file);
}
Report report = reportBuilder.buildReport(reportDefinition, parameters);
Map<String, ChartData> chartMap = report.getContext().getChartDataMap();
if (chartMap.size() > 0) {
CacheUtils.storeChartDataMap(chartMap);
}
FullPageData pageData = PageBuilder.buildFullPageData(report);
StringBuilder sb = new StringBuilder();
List<List<Page>> list = pageData.getPageList();
Context context = report.getContext();
if (list.size() > 0) {
for (int i = 0; i < list.size(); i++) {
List<Page> columnPages = list.get(i);
if (i == 0) {
String html = htmlProducer.produce(context, columnPages, pageData.getColumnMargin(), false);
sb.append(html);
} else {
String html = htmlProducer.produce(context, columnPages, pageData.getColumnMargin(), false);
sb.append(html);
}
}
} else {
List<Page> pages = report.getPages();
for (int i = 0; i < pages.size(); i++) {
Page page = pages.get(i);
if (i == 0) {
String html = htmlProducer.produce(context, page, false);
sb.append(html);
} else {
String html = htmlProducer.produce(context, page, true);
sb.append(html);
}
}
}
Map<String, String> map = new HashMap<String, String>();
map.put("html", sb.toString());
writeObjectToJson(resp, map);
}
public void loadPagePaper(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String file = req.getParameter("_u");
file = decode(file);
if (StringUtils.isBlank(file)) {
throw new ReportComputeException("Report file can not be null.");
}
ReportDefinition report = null;
if (file.equals(PREVIEW_KEY)) {
report = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
if (report == null) {
throw new ReportDesignException("Report data has expired.");
}
} else {
report = reportRender.getReportDefinition(file);
}
Paper paper = report.getPaper();
writeObjectToJson(resp, paper);
}
private HtmlReport loadReport(HttpServletRequest req) {
Map<String, Object> parameters = buildParameters(req);
HtmlReport htmlReport = null;
String file = req.getParameter("_u");
file = decode(file);
String pageIndex = req.getParameter("_i");
if (StringUtils.isBlank(file)) {
throw new ReportComputeException("Report file can not be null.");
}
if (file.equals(PREVIEW_KEY)) {
ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
if (reportDefinition == null) {
throw new ReportDesignException("Report data has expired,can not do preview.");
}
Report report = reportBuilder.buildReport(reportDefinition, parameters);
Map<String, ChartData> chartMap = report.getContext().getChartDataMap();
if (chartMap.size() > 0) {
CacheUtils.storeChartDataMap(chartMap);
}
htmlReport = new HtmlReport();
String html = null;
if (StringUtils.isNotBlank(pageIndex) && !pageIndex.equals("0")) {
Context context = report.getContext();
int index = Integer.valueOf(pageIndex);
SinglePageData pageData = PageBuilder.buildSinglePageData(index, report);
List<Page> pages = pageData.getPages();
if (pages.size() == 1) {
Page page = pages.get(0);
html = htmlProducer.produce(context, page, false);
} else {
html = htmlProducer.produce(context, pages, pageData.getColumnMargin(), false);
}
htmlReport.setTotalPage(pageData.getTotalPages());
htmlReport.setPageIndex(index);
} else {
html = htmlProducer.produce(report);
}
if (report.getPaper().isColumnEnabled()) {
htmlReport.setColumn(report.getPaper().getColumnCount());
}
htmlReport.setChartDatas(report.getContext().getChartDataMap().values());
htmlReport.setContent(html);
htmlReport.setTotalPage(report.getPages().size());
htmlReport.setStyle(reportDefinition.getStyle());
htmlReport.setSearchFormData(reportDefinition.buildSearchFormData(report.getContext().getDatasetMap(), parameters));
htmlReport.setReportAlign(report.getPaper().getHtmlReportAlign().name());
htmlReport.setHtmlIntervalRefreshValue(report.getPaper().getHtmlIntervalRefreshValue());
} else {
if (StringUtils.isNotBlank(pageIndex) && !pageIndex.equals("0")) {
int index = Integer.valueOf(pageIndex);
htmlReport = exportManager.exportHtml(file, req.getContextPath(), parameters, index);
} else {
htmlReport = exportManager.exportHtml(file, req.getContextPath(), parameters);
}
}
return htmlReport;
}
private String buildCustomParameters(HttpServletRequest req) {
StringBuilder sb = new StringBuilder();
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("_") && !name.equals("_n"))) {
continue;
}
if (sb.length() > 0) {
sb.append("&");
}
sb.append(name);
sb.append("=");
sb.append(value);
}
return sb.toString();
}
private String buildExceptionMessage(Throwable throwable) {
Throwable root = buildRootException(throwable);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
root.printStackTrace(pw);
String trace = sw.getBuffer().toString();
trace = trace.replaceAll("\n", "<br>");
pw.close();
return trace;
}
public void setExportManager(ExportManager exportManager) {
this.exportManager = exportManager;
}
public void setReportBuilder(ReportBuilder reportBuilder) {
this.reportBuilder = reportBuilder;
}
public void setReportRender(ReportRender reportRender) {
this.reportRender = reportRender;
}
@Override
public String url() {
return "/preview";
}
}

View File

@ -0,0 +1,61 @@
/*******************************************************************************
* 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.image;
import com.bstek.ureport.cache.ResourceCache;
import com.bstek.ureport.console.ServletAction;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author Jacky.gao
* @since 2016年6月6日
*/
public class ImageServletAction implements ServletAction {
public static final String URL = "/image";
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String key = req.getParameter("_key");
if (StringUtils.isNotBlank(key)) {
byte[] bytes = (byte[]) ResourceCache.getObject(key);
InputStream input = new ByteArrayInputStream(bytes);
OutputStream output = resp.getOutputStream();
resp.setContentType("image/png");
try {
IOUtils.copy(input, output);
} finally {
IOUtils.closeQuietly(input);
IOUtils.closeQuietly(output);
}
} else {
//processImage(req, resp);
}
}
@Override
public String url() {
return URL;
}
}

View File

@ -0,0 +1,87 @@
/*******************************************************************************
* 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.importexcel;
import com.bstek.ureport.console.RenderPageServletAction;
import com.bstek.ureport.console.cache.TempObjectCache;
import com.bstek.ureport.definition.ReportDefinition;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springblade.core.tool.utils.MultipartUtil;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
/**
* @author Jacky.gao
* @since 2017年5月25日
*/
public class ImportExcelServletAction extends RenderPageServletAction {
private List<ExcelParser> excelParsers = new ArrayList<ExcelParser>();
public ImportExcelServletAction() {
excelParsers.add(new HSSFExcelParser());
excelParsers.add(new XSSFExcelParser());
}
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String errorInfo;
ReportDefinition report = null;
try {
List<MultipartFile> items = MultipartUtil.extractMultipartFiles(req);
for (MultipartFile item : items) {
String fieldName = item.getName();
String name = Objects.requireNonNull(item.getOriginalFilename()).toLowerCase();
if (fieldName.equals("_excel_file") && (name.endsWith(".xls") || name.endsWith(".xlsx"))) {
InputStream inputStream = item.getInputStream();
for (ExcelParser parser : excelParsers) {
if (parser.support(name)) {
report = parser.parse(inputStream);
break;
}
}
inputStream.close();
break;
}
}
errorInfo = "请选择一个合法的Excel导入";
} catch (Exception e) {
e.printStackTrace();
errorInfo = e.getMessage();
}
Map<String, Object> result = new HashMap<String, Object>();
if (report != null) {
result.put("result", true);
TempObjectCache.putObject("classpath:template/template.ureport.xml", report);
} else {
result.put("result", false);
if (errorInfo != null) {
result.put("errorInfo", errorInfo);
}
}
writeObjectToJson(resp, result);
}
@Override
public String url() {
return "/import";
}
}

View File

@ -0,0 +1,144 @@
/*******************************************************************************
* 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.pdf;
import com.bstek.ureport.build.ReportBuilder;
import com.bstek.ureport.console.BaseServletAction;
import com.bstek.ureport.console.cache.TempObjectCache;
import com.bstek.ureport.console.exception.ReportDesignException;
import com.bstek.ureport.definition.Paper;
import com.bstek.ureport.definition.ReportDefinition;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.export.ExportConfigure;
import com.bstek.ureport.export.ExportConfigureImpl;
import com.bstek.ureport.export.ExportManager;
import com.bstek.ureport.export.ReportRender;
import com.bstek.ureport.export.pdf.PdfProducer;
import com.bstek.ureport.model.Report;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.map.ObjectMapper;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
/**
* @author Jacky.gao
* @since 2017年3月20日
*/
public class ExportPdfServletAction extends BaseServletAction {
private ReportBuilder reportBuilder;
private ExportManager exportManager;
private ReportRender reportRender;
private PdfProducer pdfProducer = new PdfProducer();
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = retriveMethod(req);
if (method != null) {
invokeMethod(method, req, resp);
} else {
buildPdf(req, resp, false);
}
}
public void show(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
buildPdf(req, resp, true);
}
public void buildPdf(HttpServletRequest req, HttpServletResponse resp, boolean forPrint) throws IOException {
String file = req.getParameter("_u");
file = decode(file);
if (StringUtils.isBlank(file)) {
throw new ReportComputeException("Report file can not be null.");
}
OutputStream outputStream = null;
try {
String fileName = req.getParameter("_n");
fileName = buildDownloadFileName(file, fileName, ".pdf");
fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
if (forPrint) {
resp.setContentType("application/pdf");
resp.setHeader("Content-Disposition", "inline;filename=\"" + fileName + "\"");
} else {
resp.setContentType("application/octet-stream;charset=ISO8859-1");
resp.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
}
outputStream = resp.getOutputStream();
Map<String, Object> parameters = buildParameters(req);
if (file.equals(PREVIEW_KEY)) {
ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
if (reportDefinition == null) {
throw new ReportDesignException("Report data has expired,can not do export pdf.");
}
Report report = reportBuilder.buildReport(reportDefinition, parameters);
pdfProducer.produce(report, outputStream);
} else {
ExportConfigure configure = new ExportConfigureImpl(file, parameters, outputStream);
exportManager.exportPdf(configure);
}
} catch (Exception ex) {
throw new ReportException(ex);
} finally {
outputStream.flush();
outputStream.close();
}
}
public void newPaging(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String file = req.getParameter("_u");
if (StringUtils.isBlank(file)) {
throw new ReportComputeException("Report file can not be null.");
}
Report report = null;
Map<String, Object> parameters = buildParameters(req);
if (file.equals(PREVIEW_KEY)) {
ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
if (reportDefinition == null) {
throw new ReportDesignException("Report data has expired,can not do export pdf.");
}
report = reportBuilder.buildReport(reportDefinition, parameters);
} else {
ReportDefinition reportDefinition = reportRender.getReportDefinition(file);
report = reportRender.render(reportDefinition, parameters);
}
String paper = req.getParameter("_paper");
ObjectMapper mapper = new ObjectMapper();
Paper newPaper = mapper.readValue(paper, Paper.class);
report.rePaging(newPaper);
}
public void setReportRender(ReportRender reportRender) {
this.reportRender = reportRender;
}
public void setExportManager(ExportManager exportManager) {
this.exportManager = exportManager;
}
public void setReportBuilder(ReportBuilder reportBuilder) {
this.reportBuilder = reportBuilder;
}
@Override
public String url() {
return "/pdf";
}
}

View File

@ -0,0 +1,78 @@
/*******************************************************************************
* 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.res;
import com.bstek.ureport.console.ServletAction;
import com.bstek.ureport.console.UReportServlet;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
/**
* @author Jacky.gao
* @since 2016年6月6日
*/
public class ResourceLoaderServletAction implements ServletAction, ApplicationContextAware {
public static final String URL = "/res";
private ApplicationContext applicationContext;
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String path = req.getContextPath() + UReportServlet.URL + URL;
String uri = req.getRequestURI();
String resPath = uri.substring(path.length() + 1);
String p = "classpath:" + resPath;
if (p.endsWith(".js")) {
resp.setContentType("text/javascript");
} else if (p.endsWith(".css")) {
resp.setContentType("text/css");
} else if (p.endsWith(".png")) {
resp.setContentType("image/png");
} else if (p.endsWith(".jpg")) {
resp.setContentType("image/jpeg");
} else if (p.endsWith(".svg")) {
resp.setContentType("image/svg+xml");
} else {
resp.setContentType("application/octet-stream");
}
InputStream input = applicationContext.getResource(p).getInputStream();
OutputStream output = resp.getOutputStream();
try {
IOUtils.copy(input, output);
} finally {
IOUtils.closeQuietly(input);
IOUtils.closeQuietly(output);
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public String url() {
return URL;
}
}

View File

@ -0,0 +1,103 @@
/*******************************************************************************
* 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.word;
import com.bstek.ureport.build.ReportBuilder;
import com.bstek.ureport.console.BaseServletAction;
import com.bstek.ureport.console.cache.TempObjectCache;
import com.bstek.ureport.console.exception.ReportDesignException;
import com.bstek.ureport.definition.ReportDefinition;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.export.ExportConfigure;
import com.bstek.ureport.export.ExportConfigureImpl;
import com.bstek.ureport.export.ExportManager;
import com.bstek.ureport.export.word.high.WordProducer;
import com.bstek.ureport.model.Report;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Map;
/**
* @author Jacky.gao
* @since 2017年4月17日
*/
public class ExportWordServletAction extends BaseServletAction {
private ReportBuilder reportBuilder;
private ExportManager exportManager;
private WordProducer wordProducer = new WordProducer();
@Override
public void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String method = retriveMethod(req);
if (method != null) {
invokeMethod(method, req, resp);
} else {
buildWord(req, resp);
}
}
public void buildWord(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String file = req.getParameter("_u");
file = decode(file);
if (StringUtils.isBlank(file)) {
throw new ReportComputeException("Report file can not be null.");
}
OutputStream outputStream = resp.getOutputStream();
try {
String fileName = req.getParameter("_n");
fileName = buildDownloadFileName(file, fileName, ".docx");
fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
resp.setContentType("application/octet-stream;charset=ISO8859-1");
resp.setHeader("Content-Disposition", "attachment;filename=\"" + fileName + "\"");
Map<String, Object> parameters = buildParameters(req);
if (file.equals(PREVIEW_KEY)) {
ReportDefinition reportDefinition = (ReportDefinition) TempObjectCache.getObject(PREVIEW_KEY);
if (reportDefinition == null) {
throw new ReportDesignException("Report data has expired,can not do export word.");
}
Report report = reportBuilder.buildReport(reportDefinition, parameters);
wordProducer.produce(report, outputStream);
} else {
ExportConfigure configure = new ExportConfigureImpl(file, parameters, outputStream);
exportManager.exportWord(configure);
}
} catch (Exception ex) {
throw new ReportException(ex);
} finally {
outputStream.flush();
outputStream.close();
}
}
public void setReportBuilder(ReportBuilder reportBuilder) {
this.reportBuilder = reportBuilder;
}
public void setExportManager(ExportManager exportManager) {
this.exportManager = exportManager;
}
@Override
public String url() {
return "/word";
}
}

View File

@ -0,0 +1,202 @@
/*******************************************************************************
* 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.definition;
import com.bstek.ureport.export.pdf.font.FontBuilder;
import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.annotate.JsonIgnore;
import java.awt.*;
import java.io.Serializable;
/**
* @author Jacky.gao
* @since 2017年1月18日
*/
public class CellStyle implements Serializable {
private static final long serialVersionUID = 8327688051735343849L;
private String bgcolor;
private String forecolor;
private int fontSize;
private String fontFamily;
private String format;
private float lineHeight;
private Alignment align;
private Alignment valign;
private Boolean bold;
private Boolean italic;
private Boolean underline;
private Boolean wrapCompute;
private Border leftBorder;
private Border rightBorder;
private Border topBorder;
private Border bottomBorder;
private Font font;
public Border getLeftBorder() {
return leftBorder;
}
public void setLeftBorder(Border leftBorder) {
this.leftBorder = leftBorder;
}
public Border getRightBorder() {
return rightBorder;
}
public void setRightBorder(Border rightBorder) {
this.rightBorder = rightBorder;
}
public Border getTopBorder() {
return topBorder;
}
public void setTopBorder(Border topBorder) {
this.topBorder = topBorder;
}
public Border getBottomBorder() {
return bottomBorder;
}
public void setBottomBorder(Border bottomBorder) {
this.bottomBorder = bottomBorder;
}
public String getBgcolor() {
return bgcolor;
}
public void setBgcolor(String bgcolor) {
this.bgcolor = bgcolor;
}
public String getForecolor() {
return forecolor;
}
public void setForecolor(String forecolor) {
this.forecolor = forecolor;
}
public int getFontSize() {
return fontSize;
}
public void setFontSize(int fontSize) {
this.fontSize = fontSize;
}
public String getFontFamily() {
return fontFamily;
}
public void setFontFamily(String fontFamily) {
this.fontFamily = fontFamily;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
public Alignment getAlign() {
return align;
}
public void setAlign(Alignment align) {
this.align = align;
}
public Alignment getValign() {
return valign;
}
public void setValign(Alignment valign) {
this.valign = valign;
}
public Boolean getBold() {
return bold;
}
public void setBold(Boolean bold) {
this.bold = bold;
}
public Boolean getItalic() {
return italic;
}
public void setItalic(Boolean italic) {
this.italic = italic;
}
public Boolean getUnderline() {
return underline;
}
public void setUnderline(Boolean underline) {
this.underline = underline;
}
public Boolean getWrapCompute() {
return wrapCompute;
}
public void setWrapCompute(Boolean wrapCompute) {
this.wrapCompute = wrapCompute;
}
public void setFont(Font font) {
this.font = font;
}
public float getLineHeight() {
return lineHeight;
}
public void setLineHeight(float lineHeight) {
this.lineHeight = lineHeight;
}
@JsonIgnore
public Font getFont() {
if (this.font == null) {
int fontStyle = Font.PLAIN;
if ((bold != null && bold) && (italic != null && italic)) {
fontStyle = Font.BOLD | Font.ITALIC;
} else if (bold != null && bold) {
fontStyle = Font.BOLD;
} else if (italic != null && italic) {
fontStyle = Font.ITALIC;
}
String fontName = fontFamily;
if (StringUtils.isBlank(fontName)) {
fontName = "宋体";
}
this.font = FontBuilder.getAwtFont(fontName, fontStyle, (float) fontSize);
}
return this.font;
}
}

View File

@ -0,0 +1,157 @@
/*******************************************************************************
* 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.font;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.export.pdf.font.FontRegister;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Font;
import com.itextpdf.text.FontFactory;
import com.itextpdf.text.pdf.BaseFont;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import java.awt.*;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.*;
/**
* @author Jacky.gao
* @since 2014年4月22日
*/
public class FontBuilder implements ApplicationContextAware {
private static ApplicationContext applicationContext;
private static final Map<String, BaseFont> fontMap = new HashMap<String, BaseFont>();
public static final Map<String, String> fontPathMap = new HashMap<String, String>();
private static List<String> systemFontNameList = new ArrayList<String>();
public static Font getFont(String fontName, int fontSize, boolean fontBold, boolean fontItalic, boolean underLine) {
BaseFont baseFont = fontMap.get(fontName);
Font font = null;
if (baseFont != null) {
font = new Font(baseFont);
} else {
font = FontFactory.getFont(fontName);
}
font.setSize(fontSize);
int fontStyle = Font.NORMAL;
if (fontBold && fontItalic && underLine) {
fontStyle = Font.BOLD | Font.ITALIC | Font.UNDERLINE;
} else if (fontBold) {
if (fontItalic) {
fontStyle = Font.BOLD | Font.ITALIC;
} else if (underLine) {
fontStyle = Font.BOLD | Font.UNDERLINE;
} else {
fontStyle = Font.BOLD;
}
} else if (fontItalic) {
if (underLine) {
fontStyle = Font.ITALIC | Font.UNDERLINE;
} else if (fontBold) {
fontStyle = Font.ITALIC | Font.BOLD;
} else {
fontStyle = Font.ITALIC;
}
} else if (underLine) {
fontStyle = Font.UNDERLINE;
}
font.setStyle(fontStyle);
return font;
}
public static java.awt.Font getAwtFont(String fontName, int fontStyle, float size) {
if (systemFontNameList.contains(fontName)) {
return new java.awt.Font(fontName, fontStyle, Integer.parseInt(String.valueOf(size)));
}
String fontPath = fontPathMap.get(fontName);
if (fontPath == null) {
fontName = "宋体";
fontPath = fontPathMap.get(fontName);
if (fontPath == null) {
return null;
}
}
InputStream inputStream = null;
try {
inputStream = applicationContext.getResource(fontPath).getInputStream();
java.awt.Font font = java.awt.Font.createFont(java.awt.Font.TRUETYPE_FONT, inputStream);
return font.deriveFont(fontStyle, size);
} catch (Exception e) {
throw new ReportException(e);
} finally {
IOUtils.closeQuietly(inputStream);
}
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
FontBuilder.applicationContext = applicationContext;
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
String[] fontNames = environment.getAvailableFontFamilyNames();
for (String name : fontNames) {
systemFontNameList.add(name);
}
Collection<FontRegister> fontRegisters = applicationContext.getBeansOfType(FontRegister.class).values();
for (FontRegister fontReg : fontRegisters) {
String fontName = fontReg.getFontName();
String fontPath = fontReg.getFontPath();
if (StringUtils.isEmpty(fontPath) || StringUtils.isEmpty(fontName)) {
continue;
}
try {
BaseFont baseFont = getIdentityFont(fontName, fontPath, applicationContext);
if (baseFont == null) {
throw new ReportComputeException("Font " + fontPath + " does not exist");
}
fontMap.put(fontName, baseFont);
} catch (Exception e) {
e.printStackTrace();
throw new ReportComputeException(e);
}
}
}
private BaseFont getIdentityFont(String fontFamily, String fontPath, ApplicationContext applicationContext) throws DocumentException, IOException {
if (!fontPath.startsWith(ApplicationContext.CLASSPATH_URL_PREFIX)) {
fontPath = ApplicationContext.CLASSPATH_URL_PREFIX + fontPath;
}
String fontName = fontPath;
int lastSlashPos = fontPath.lastIndexOf("/");
if (lastSlashPos != -1) {
fontName = fontPath.substring(lastSlashPos + 1, fontPath.length());
}
if (fontName.toLowerCase().endsWith(".ttc")) {
fontName = fontName + ",0";
}
InputStream inputStream = null;
try {
fontPathMap.put(fontFamily, fontPath);
inputStream = applicationContext.getResource(fontPath).getInputStream();
byte[] bytes = IOUtils.toByteArray(inputStream);
BaseFont baseFont = BaseFont.createFont(fontName, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, true, bytes, null);
baseFont.setSubset(true);
return baseFont;
} finally {
if (inputStream != null) inputStream.close();
}
}
}

View File

@ -0,0 +1,223 @@
/*******************************************************************************
* 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.parser;
import com.bstek.ureport.cache.ResourceCache;
import com.bstek.ureport.definition.*;
import com.bstek.ureport.definition.value.Slash;
import com.bstek.ureport.definition.value.SlashValue;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.utils.UnitUtils;
import org.springblade.core.tool.utils.Base64Util;
import javax.imageio.ImageIO;
import javax.imageio.stream.MemoryCacheImageOutputStream;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
/**
* @author Jacky.gao
* @since 2017年3月17日
*/
public class SlashBuilder {
public void buildSlashImage(CellDefinition cell, ReportDefinition report) {
int rowNumber = cell.getRowNumber();
int colNumber = cell.getColumnNumber();
int rowSpan = cell.getRowSpan();
int colSpan = cell.getColSpan();
int verticalBorderWidth = 0, horizontalBorderWidth = 0;
CellStyle cellStyle = cell.getCellStyle();
if (cellStyle.getLeftBorder() != null) {
verticalBorderWidth += cellStyle.getLeftBorder().getWidth();
}
if (cellStyle.getRightBorder() != null) {
verticalBorderWidth += cellStyle.getRightBorder().getWidth();
}
if (cellStyle.getTopBorder() != null) {
horizontalBorderWidth = cellStyle.getTopBorder().getWidth();
}
if (cellStyle.getBottomBorder() != null) {
horizontalBorderWidth = cellStyle.getBottomBorder().getWidth();
}
int width = 0;
int height = 0;
if (rowSpan == 0) {
rowSpan = 1;
}
if (colSpan == 0) {
colSpan = 1;
}
List<ColumnDefinition> columns = report.getColumns();
List<RowDefinition> rows = report.getRows();
for (int i = colNumber; i < (colNumber + colSpan); i++) {
ColumnDefinition col = columns.get(i - 1);
width += UnitUtils.pointToPixel(col.getWidth());
}
for (int i = rowNumber; i < (rowNumber + rowSpan); i++) {
RowDefinition row = rows.get(i - 1);
height += UnitUtils.pointToPixel(row.getHeight());
}
width -= horizontalBorderWidth;
height -= verticalBorderWidth;
SlashValue content = (SlashValue) cell.getValue();
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
Graphics2D g = (Graphics2D) image.getGraphics();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
Font font = cellStyle.getFont();
g.setFont(font);
g.setStroke(new BasicStroke(1f));
String bgColor = cellStyle.getBgcolor();
if (bgColor == null) {
bgColor = "255,255,255";
}
g.setColor(getColor(bgColor));
g.fillRect(0, 0, width, height);
AffineTransform transform = g.getTransform();
int allRowHeight = 0;
int index = 0;
String lc = cellStyle.getForecolor();
if (lc == null) {
lc = "0,0,0";
}
Color lineColor = getColor(lc);
String fc = cellStyle.getForecolor();
if (fc == null) {
fc = "0,0,0";
}
Color fontColor = getColor(fc);
for (int i = rowNumber; i < (rowNumber + rowSpan); i++) {
Slash slash = getSlash(content, index);
if (slash == null) {
break;
}
String text = slash.getText();
if (text == null) {
break;
}
RowDefinition row = rows.get(i - 1);
int rowHeight = UnitUtils.pointToPixel(row.getHeight());
g.setColor(fontColor);
int x = slash.getX();
int y = slash.getY();
g.rotate(Math.toRadians(slash.getDegree()), x, y);
g.drawString(text, x, y);
g.setTransform(transform);
g.setColor(lineColor);
int h = allRowHeight + rowHeight;
if (i == (rowNumber + rowSpan - 1)) {
h = allRowHeight + (rowHeight / 3) * 2;
}
g.drawLine(0, 0, width, h);
allRowHeight += rowHeight;
index++;
}
Slash slash = getSlash(content, index);
if (slash != null) {
String text = slash.getText();
if (text != null) {
int x = slash.getX();
int y = slash.getY();
g.rotate(Math.toRadians(slash.getDegree()), x, y);
g.setColor(fontColor);
g.drawString(text, x, y);
g.setTransform(transform);
index++;
}
}
if (colSpan > 0) {
colSpan--;
}
int colNumberStart = colNumber + colSpan;
for (int i = colNumberStart; i > (colNumber - 1); i--) {
slash = getSlash(content, index);
if (slash == null) {
break;
}
String text = slash.getText();
if (text == null) {
break;
}
int x = slash.getX();
int y = slash.getY();
g.rotate(Math.toRadians(slash.getDegree()), x, y);
g.setColor(fontColor);
g.drawString(text, x, y);
g.setTransform(transform);
ColumnDefinition col = columns.get(i - 1);
int colWidth = UnitUtils.pointToPixel(col.getWidth());
int w = width;
if (i == colNumberStart) {
w = width - colWidth / 3;
}
g.setColor(lineColor);
g.drawLine(0, 0, w, height);
width -= colWidth;
index++;
}
byte[] imageBytes = null;
ByteArrayOutputStream byteOutput = new ByteArrayOutputStream();
MemoryCacheImageOutputStream memoryImage = new MemoryCacheImageOutputStream(byteOutput);
try {
ImageIO.write(image, "png", memoryImage);
imageBytes = byteOutput.toByteArray();
String base64Data = Base64Util.encodeToString(imageBytes);
content.setBase64Data(base64Data);
} catch (Exception ex) {
throw new ReportComputeException(ex);
} finally {
try {
if (memoryImage != null) {
memoryImage.close();
}
if (byteOutput != null) {
byteOutput.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
g.dispose();
String imageByteKey = buildKey(report.getReportFullName(), cell.getName());
ResourceCache.putObject(imageByteKey, imageBytes);
}
private Slash getSlash(SlashValue content, int index) {
List<Slash> slashes = content.getSlashes();
if (index < slashes.size()) {
return slashes.get(index);
}
return null;
}
private Color getColor(String text) {
if (text == null) {
return null;
}
String[] str = text.split(",");
return new Color(Integer.valueOf(str[0]), Integer.valueOf(str[1]), Integer.valueOf(str[2]));
}
public static String buildKey(String reportFullName, String cellName) {
return "slash-" + reportFullName + "-" + cellName;
}
}

View File

@ -0,0 +1,71 @@
/*******************************************************************************
* 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.provider.image;
import com.bstek.ureport.exception.ReportComputeException;
import jakarta.servlet.ServletContext;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ResourceUtils;
import org.springframework.web.context.ServletContextAware;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
/**
* @author Jacky.gao
* @since 2017年3月6日
*/
public class DefaultImageProvider implements ImageProvider, ApplicationContextAware, ServletContextAware {
private ApplicationContext applicationContext;
private String baseWebPath;
@Override
public InputStream getImage(String path) {
try {
if (path.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX) || path.startsWith("/WEB-INF")) {
return applicationContext.getResource(path).getInputStream();
} else {
path = baseWebPath + path;
return new FileInputStream(path);
}
} catch (IOException e) {
throw new ReportComputeException(e);
}
}
@Override
public boolean support(String path) {
if (path.startsWith(ResourceUtils.CLASSPATH_URL_PREFIX)) {
return true;
} else if (baseWebPath != null && (path.startsWith("/") || path.startsWith("/WEB-INF"))) {
return true;
}
return false;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void setServletContext(ServletContext servletContext) {
this.baseWebPath = servletContext.getRealPath("/");
}
}

View File

@ -0,0 +1,147 @@
/*******************************************************************************
* 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.provider.report.file;
import com.bstek.ureport.exception.ReportException;
import com.bstek.ureport.provider.report.ReportFile;
import com.bstek.ureport.provider.report.ReportProvider;
import jakarta.servlet.ServletContext;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.context.WebApplicationContext;
import java.io.*;
import java.util.*;
/**
* @author Jacky.gao
* @since 2017年2月11日
*/
public class FileReportProvider implements ReportProvider, ApplicationContextAware {
private String prefix = "file:";
private String fileStoreDir;
private boolean disabled;
@Override
public InputStream loadReport(String file) {
if (file.startsWith(prefix)) {
file = file.substring(prefix.length(), file.length());
}
String fullPath = fileStoreDir + "/" + file;
try {
return new FileInputStream(fullPath);
} catch (FileNotFoundException e) {
throw new ReportException(e);
}
}
@Override
public void deleteReport(String file) {
if (file.startsWith(prefix)) {
file = file.substring(prefix.length(), file.length());
}
String fullPath = fileStoreDir + "/" + file;
File f = new File(fullPath);
if (f.exists()) {
f.delete();
}
}
@Override
public List<ReportFile> getReportFiles() {
File file = new File(fileStoreDir);
List<ReportFile> list = new ArrayList<ReportFile>();
for (File f : file.listFiles()) {
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(f.lastModified());
list.add(new ReportFile(f.getName(), calendar.getTime()));
}
Collections.sort(list, new Comparator<ReportFile>() {
@Override
public int compare(ReportFile f1, ReportFile f2) {
return f2.getUpdateDate().compareTo(f1.getUpdateDate());
}
});
return list;
}
@Override
public String getName() {
return "服务器文件系统";
}
@Override
public void saveReport(String file, String content) {
if (file.startsWith(prefix)) {
file = file.substring(prefix.length(), file.length());
}
String fullPath = fileStoreDir + "/" + file;
FileOutputStream outStream = null;
try {
outStream = new FileOutputStream(new File(fullPath));
IOUtils.write(content, outStream, "utf-8");
} catch (Exception ex) {
throw new ReportException(ex);
} finally {
if (outStream != null) {
try {
outStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
@Override
public boolean disabled() {
return disabled;
}
public void setDisabled(boolean disabled) {
this.disabled = disabled;
}
public void setFileStoreDir(String fileStoreDir) {
this.fileStoreDir = fileStoreDir;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
File file = new File(fileStoreDir);
if (file.exists()) {
return;
}
if (applicationContext instanceof WebApplicationContext) {
WebApplicationContext context = (WebApplicationContext) applicationContext;
ServletContext servletContext = context.getServletContext();
String basePath = servletContext.getRealPath("/");
fileStoreDir = basePath + fileStoreDir;
file = new File(fileStoreDir);
if (!file.exists()) {
file.mkdirs();
}
}
}
@Override
public String getPrefix() {
return prefix;
}
}

View File

@ -0,0 +1,81 @@
/*******************************************************************************
* 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.utils;
import com.bstek.ureport.exception.ReportComputeException;
import com.bstek.ureport.image.ChartImageProcessor;
import com.bstek.ureport.image.ImageProcessor;
import com.bstek.ureport.image.ImageType;
import com.bstek.ureport.image.StaticImageProcessor;
import org.apache.commons.io.IOUtils;
import org.springblade.core.tool.utils.Base64Util;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
/**
* @author Jacky.gao
* @since 2017年3月20日
*/
public class ImageUtils {
private static Map<ImageType, ImageProcessor<?>> imageProcessorMap = new HashMap<ImageType, ImageProcessor<?>>();
static {
StaticImageProcessor staticImageProcessor = new StaticImageProcessor();
imageProcessorMap.put(ImageType.image, staticImageProcessor);
ChartImageProcessor chartImageProcessor = new ChartImageProcessor();
imageProcessorMap.put(ImageType.chart, chartImageProcessor);
}
public static InputStream base64DataToInputStream(String base64Data) {
byte[] bytes = Base64Util.decodeFromString(base64Data);
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
return inputStream;
}
@SuppressWarnings("unchecked")
public static String getImageBase64Data(ImageType type, Object data, int width, int height) {
ImageProcessor<Object> targetProcessor = (ImageProcessor<Object>) imageProcessorMap.get(type);
if (targetProcessor == null) {
throw new ReportComputeException("Unknow image type :" + type);
}
InputStream inputStream = targetProcessor.getImage(data);
try {
if (width > 0 && height > 0) {
BufferedImage inputImage = ImageIO.read(inputStream);
BufferedImage outputImage = new BufferedImage(width, height, BufferedImage.TYPE_USHORT_565_RGB);
Graphics2D g = outputImage.createGraphics();
g.drawImage(inputImage, 0, 0, width, height, null);
g.dispose();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
ImageIO.write(outputImage, "png", outputStream);
inputStream = new ByteArrayInputStream(outputStream.toByteArray());
}
byte[] bytes = IOUtils.toByteArray(inputStream);
return Base64Util.encodeToString(bytes);
} catch (Exception ex) {
throw new ReportComputeException(ex);
} finally {
IOUtils.closeQuietly(inputStream);
}
}
}

View File

@ -32,7 +32,7 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.annotation.Order;
import javax.servlet.Servlet;
import jakarta.servlet.Servlet;
/**
* UReport配置类

View File

@ -19,14 +19,14 @@ import org.springblade.core.launch.constant.AppConstant;
import org.springblade.core.report.service.IReportFileService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import springfox.documentation.annotations.ApiIgnore;
import io.swagger.v3.oas.annotations.Hidden;
/**
* UReport Boot版 API端点
*
* @author Chill
*/
@ApiIgnore
@Hidden
@RestController
@RequestMapping(AppConstant.APPLICATION_REPORT_NAME + "/report/rest")
public class ReportBootEndpoint extends ReportEndpoint {

View File

@ -24,7 +24,7 @@ import org.springblade.core.report.service.IReportFileService;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;
import io.swagger.v3.oas.annotations.Hidden;
import java.util.Map;
@ -33,7 +33,7 @@ import java.util.Map;
*
* @author Chill
*/
@ApiIgnore
@Hidden
@RestController
@AllArgsConstructor
@RequestMapping("/report/rest")

View File

@ -21,6 +21,7 @@ import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.Date;
@ -33,6 +34,7 @@ import java.util.Date;
@TableName("blade_report_file")
public class ReportFileEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**

View File

@ -19,12 +19,10 @@
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
</dependency>
<!--Blade-->
<dependency>

View File

@ -17,8 +17,7 @@ package org.springblade.core.secure;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
@ -27,31 +26,31 @@ import lombok.Data;
* @author Chill
*/
@Data
@ApiModel(description = "认证信息")
@Schema(description = "认证信息")
public class AuthInfo {
@ApiModelProperty(value = "令牌")
@Schema(description = "令牌")
private String accessToken;
@ApiModelProperty(value = "令牌类型")
@Schema(description = "令牌类型")
private String tokenType;
@ApiModelProperty(value = "刷新令牌")
@Schema(description = "刷新令牌")
private String refreshToken;
@ApiModelProperty(value = "用户ID")
@Schema(description = "用户ID")
@JsonSerialize(using = ToStringSerializer.class)
private Long userId;
@ApiModelProperty(value = "租户ID")
@Schema(description = "租户ID")
private String tenantId;
@ApiModelProperty(value = "第三方系统ID")
@Schema(description = "第三方系统ID")
private String oauthId;
@ApiModelProperty(value = "头像")
@Schema(description = "头像")
private String avatar = "https://gw.alipayobjects.com/zos/rmsportal/BiazfanxmamNRoxxVxka.png";
@ApiModelProperty(value = "角色名")
@Schema(description = "角色名")
private String authority;
@ApiModelProperty(value = "用户名")
@Schema(description = "用户名")
private String userName;
@ApiModelProperty(value = "账号名")
@Schema(description = "账号名")
private String account;
@ApiModelProperty(value = "过期时间")
@Schema(description = "过期时间")
private long expiresIn;
@ApiModelProperty(value = "许可证")
@Schema(description = "许可证")
private String license = "powered by blade";
}

View File

@ -15,11 +15,14 @@
*/
package org.springblade.core.secure;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import static io.swagger.v3.oas.annotations.media.Schema.AccessMode.READ_ONLY;
/**
* 用户实体
*
@ -28,47 +31,48 @@ import java.io.Serializable;
@Data
public class BladeUser implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 客户端id
*/
@ApiModelProperty(hidden = true)
@Schema(accessMode = READ_ONLY)
private String clientId;
/**
* 用户id
*/
@ApiModelProperty(hidden = true)
@Schema(accessMode = READ_ONLY)
private Long userId;
/**
* 租户ID
*/
@ApiModelProperty(hidden = true)
@Schema(accessMode = READ_ONLY)
private String tenantId;
/**
* 部门id
*/
@ApiModelProperty(hidden = true)
@Schema(accessMode = READ_ONLY)
private String deptId;
/**
* 昵称
*/
@ApiModelProperty(hidden = true)
@Schema(accessMode = READ_ONLY)
private String userName;
/**
* 账号
*/
@ApiModelProperty(hidden = true)
@Schema(accessMode = READ_ONLY)
private String account;
/**
* 角色id
*/
@ApiModelProperty(hidden = true)
@Schema(accessMode = READ_ONLY)
private String roleId;
/**
* 角色名
*/
@ApiModelProperty(hidden = true)
@Schema(accessMode = READ_ONLY)
private String roleName;
}

View File

@ -23,7 +23,7 @@ import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.util.Objects;
/**

View File

@ -28,8 +28,8 @@ import org.springblade.core.tool.utils.WebUtil;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

View File

@ -26,8 +26,8 @@ import org.springblade.core.tool.utils.WebUtil;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.secure.provider;
import io.swagger.annotations.ApiModelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/**
@ -29,23 +29,23 @@ public class ClientDetails implements IClientDetails {
/**
* 客户端id
*/
@ApiModelProperty(value = "客户端id")
@Schema(description = "客户端id")
private String clientId;
/**
* 客户端密钥
*/
@ApiModelProperty(value = "客户端密钥")
@Schema(description = "客户端密钥")
private String clientSecret;
/**
* 令牌过期秒数
*/
@ApiModelProperty(value = "令牌过期秒数")
@Schema(description = "令牌过期秒数")
private Integer accessTokenValidity;
/**
* 刷新令牌过期秒数
*/
@ApiModelProperty(value = "刷新令牌过期秒数")
@Schema(description = "刷新令牌过期秒数")
private Integer refreshTokenValidity;
}

View File

@ -37,10 +37,10 @@ public class SecureRegistry {
public SecureRegistry() {
this.defaultExcludePatterns.add("/actuator/health/**");
this.defaultExcludePatterns.add("/v2/api-docs/**");
this.defaultExcludePatterns.add("/v3/api-docs/**");
this.defaultExcludePatterns.add("/swagger-ui/**");
this.defaultExcludePatterns.add("/auth/**");
this.defaultExcludePatterns.add("/token/**");
this.defaultExcludePatterns.add("/log/**");
this.defaultExcludePatterns.add("/user/user-info");
this.defaultExcludePatterns.add("/user/user-info-by-id");
this.defaultExcludePatterns.add("/menu/auth-routes");

View File

@ -32,7 +32,7 @@ import org.springblade.core.tool.constant.RoleConstant;
import org.springblade.core.tool.utils.*;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import java.security.Key;
import java.util.*;

View File

@ -23,7 +23,6 @@
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>1.15.8</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>

View File

@ -60,7 +60,10 @@ public class SocialUtil {
authRequest = new AuthWeChatOpenRequest(authConfig);
break;
case WECHAT_ENTERPRISE:
authRequest = new AuthWeChatEnterpriseRequest(authConfig);
authRequest = new AuthWeChatEnterpriseQrcodeRequest(authConfig);
break;
case WECHAT_ENTERPRISE_WEB:
authRequest = new AuthWeChatEnterpriseWebRequest(authConfig);
break;
case WECHAT_MP:
authRequest = new AuthWeChatMpRequest(authConfig);

Some files were not shown because too many files have changed in this diff Show More