🎉 5.0.0.RELEASE 重构升级 SpringBoot4 SpringCloud2025 JDK21 TypeScript
Some checks failed
Publish Snapshot / publish (push) Has been cancelled
Java CI / build on java17 (push) Has been cancelled

This commit is contained in:
smallchill 2026-07-13 13:21:28 +08:00
parent 1470c19128
commit e518473599
151 changed files with 1838 additions and 1595 deletions

View File

@ -1,9 +1,9 @@
<p align="center">
<img src="https://img.shields.io/badge/Release-V4.10.1-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/JDK-17+-green.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Release-V5.0.0-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/JDK-21+-green.svg" alt="Build Status">
<img src="https://img.shields.io/badge/license-LGPL%20v3-blue.svg" alt="Build Status">
<img src="https://img.shields.io/badge/Spring%20Cloud-2025-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-3.5-blue.svg" alt="Downloads">
<img src="https://img.shields.io/badge/Spring%20Cloud-2025.1-blue.svg" alt="Coverage Status">
<img src="https://img.shields.io/badge/Spring%20Boot-4.1-blue.svg" alt="Downloads">
<br/>
<a target="_blank" href="https://bladex.cn">
<img src="https://img.shields.io/badge/Author-Small%20Chill-ff69b4.svg" alt="Downloads">
@ -22,7 +22,7 @@
* 极简封装了多租户底层用更少的代码换来拓展性更强的SaaS多租户系统。
* 借鉴OAuth2自研多终端认证系统可控制子系统的token权限互相隔离。
* 借鉴Security自研Secure模块采用JWT做Token认证可拓展集成Redis等细颗粒度控制方案。
* 稳定生产了年,经历了从 Camden -> Hoxton -> 2025 的技术架构也经历了从fat jar -> docker -> k8s + jenkins的部署架构。
* 稳定生产了年,经历了从 Camden -> Hoxton -> 2025 的技术架构也经历了从fat jar -> docker -> k8s + jenkins的部署架构。
* 项目分包明确,规范微服务的开发模式,使包与包之间的分工清晰。
## 架构图
@ -32,14 +32,14 @@
| 技术栈 | 版本 |
|----------------------|------------|
| Java | 17+ |
| Java | 21+ |
| NodeJS | 18+ |
| Spring | 6.2.17 |
| Spring Boot | 3.5.13 |
| Spring Cloud | 2025.0.2 |
| Spring Cloud Alibaba | 2025.0.0.0 |
| Nacos Alibaba | 3.1.2 |
| Mybatis Plus | 3.5.14 |
| Spring | 7.0.8 |
| Spring Boot | 4.1.0 |
| Spring Cloud | 2025.1.2 |
| Spring Cloud Alibaba | 2025.1.0.0 |
| Nacos Alibaba | 3.2.2 |
| Mybatis Plus | 3.5.17 |
## 工程结构
@ -122,7 +122,6 @@ blade-tool
|---------------------------|--------------------------------------------------------------------------------------------------------------------------|
| SpringBlade开发手册一览 | [https://gitee.com/smallc/SpringBlade/wikis/SpringBlade开发手册](https://gitee.com/smallc/SpringBlade/wikis/SpringBlade开发手册) |
| SpringBlade常见问题集锦 | [https://sns.bladex.cn/article-14966.html](https://sns.bladex.cn/article-14966.html) |
| SpringBlade基于Kuboard部署K8S | [https://kuboard.cn/learning/k8s-practice/spring-blade/](https://kuboard.cn/learning/k8s-practice/spring-blade/) |
| SpringBlade基于Rainbond部署 | [https://www.rainbond.com/docs/micro-service/example/blade](https://www.rainbond.com/docs/micro-service/example/blade) |

View File

@ -78,7 +78,7 @@
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<artifactId>mybatis-plus-spring-boot4-starter</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
@ -92,7 +92,7 @@
<!-- Druid -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<artifactId>druid-spring-boot-4-starter</artifactId>
</dependency>
<!-- MySQL -->
<dependency>

View File

@ -1,21 +1,12 @@
#服务器配置
server:
undertow:
# 以下的配置会影响buffer,这些buffer会用于服务器连接的IO操作,有点类似netty的池化内存管理
buffer-size: 1024
# 是否分配的直接内存
direct-buffers: true
tomcat:
# 线程配置
threads:
# 设置IO线程数, 它主要执行非阻塞的任务,它们会负责多个连接, 默认设置每个CPU核心一个线程
io: 16
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker: 400
servlet:
# 编码配置
encoding:
charset: UTF-8
force: true
# 最大工作线程数(可同时处理请求的线程上限)
max: 400
# 最小空闲工作线程数(保持存活的常驻线程数)
min-spare: 16
#spring配置
spring:
@ -26,11 +17,13 @@ spring:
multipart:
max-file-size: 256MB
max-request-size: 1024MB
# 编码配置
encoding:
charset: UTF-8
force: true
web:
resources:
add-mappings: false
mvc:
throw-exception-if-no-handler-found: true
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
druid:
@ -101,7 +94,7 @@ mybatis-plus:
swagger:
title: SpringBlade 接口文档系统
description: SpringBlade 接口文档系统
version: 3.7.2
version: 5.0.0
license: Powered By SpringBlade
licenseUrl: https://bladex.vip
terms-of-service-url: https://bladex.vip

View File

@ -57,8 +57,8 @@
<logger name="org.apache.ibatis.io" level="INFO"/>
<logger name="org.apache.velocity" level="INFO"/>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="io.undertow" level="INFO"/>
<logger name="org.xnio.nio" level="INFO"/>
<logger name="org.apache.catalina" level="INFO"/>
<logger name="org.apache.coyote" level="INFO"/>
<logger name="org.thymeleaf" level="INFO"/>
<logger name="springfox.documentation" level="INFO"/>
<logger name="org.hibernate.validator" level="INFO"/>

View File

@ -23,15 +23,16 @@
<groupId>org.springblade</groupId>
<artifactId>blade-core-secure</artifactId>
</dependency>
<!--RestClient-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-restclient</artifactId>
</dependency>
<!--Feign-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
@ -71,6 +72,12 @@
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<exclusions>
<exclusion>
<groupId>com.alibaba.nacos</groupId>
<artifactId>logback-adapter</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- Sentinel -->
<dependency>

View File

@ -25,7 +25,7 @@ import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.Method;
import java.util.Objects;

View File

@ -16,7 +16,7 @@
package org.springblade.core.cloud.header;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import jakarta.servlet.http.HttpServletRequest;

View File

@ -17,7 +17,7 @@ package org.springblade.core.cloud.header;
import org.springblade.core.cloud.props.BladeFeignHeadersProperties;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.util.concurrent.Callable;

View File

@ -20,7 +20,7 @@ import org.springblade.core.tool.utils.StringUtil;
import org.springblade.core.tool.utils.WebUtil;
import org.springframework.core.NamedThreadLocal;
import org.springframework.http.HttpHeaders;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.PatternMatchUtils;
import jakarta.servlet.http.HttpServletRequest;

View File

@ -33,14 +33,14 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.boot.restclient.RestTemplateBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
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.jspecify.annotations.Nullable;
import org.springframework.web.client.RestTemplate;
import javax.net.ssl.SSLContext;
@ -154,8 +154,7 @@ public class RestTemplateConfiguration {
@Bean
@ConditionalOnMissingBean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder, OkHttpClient okHttpClient) {
restTemplateBuilder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient));
RestTemplate restTemplate = restTemplateBuilder.build();
RestTemplate restTemplate = restTemplateBuilder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient)).build();
configMessageConverters(context, restTemplate.getMessageConverters());
return restTemplate;
}
@ -178,14 +177,14 @@ public class RestTemplateConfiguration {
@LoadBalanced
@ConditionalOnMissingBean
public LbRestTemplate lbRestTemplate(RestTemplateBuilder restTemplateBuilder, OkHttpClient okHttpClient) {
restTemplateBuilder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient));
LbRestTemplate restTemplate = restTemplateBuilder.build(LbRestTemplate.class);
LbRestTemplate restTemplate = restTemplateBuilder.requestFactory(() -> new OkHttp3ClientHttpRequestFactory(okHttpClient)).build(LbRestTemplate.class);
restTemplate.getInterceptors().add(context.getBean(RestTemplateHeaderInterceptor.class));
configMessageConverters(context, restTemplate.getMessageConverters());
return restTemplate;
}
}
@SuppressWarnings("removal")
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));

View File

@ -24,7 +24,7 @@ import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.IOException;

View File

@ -20,7 +20,7 @@ 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.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FastByteArrayOutputStream;

View File

@ -25,7 +25,7 @@ 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.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
import java.io.IOException;

View File

@ -18,7 +18,7 @@ package org.springblade.core.cloud.http.client;
import okhttp3.Cache;
import okhttp3.OkHttpClient;
import org.jetbrains.annotations.NotNull;
import org.jspecify.annotations.NonNull;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.http.HttpMethod;
import org.springframework.http.client.ClientHttpRequest;
@ -133,7 +133,7 @@ public class OkHttp3ClientHttpRequestFactory implements ClientHttpRequestFactory
}
@NotNull
@NonNull
@Override
public ClientHttpRequest createRequest(URI uri, HttpMethod httpMethod) {
return new OkHttp3ClientHttpRequest(this.client, uri, httpMethod);

View File

@ -20,7 +20,7 @@ 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.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import java.io.IOException;

View File

@ -19,7 +19,7 @@ import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.util.Arrays;
import java.util.List;

View File

@ -20,7 +20,7 @@ import org.springblade.core.cloud.annotation.UrlVersion;
import org.springblade.core.tool.utils.StringPool;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.cloud.version;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.boot.webmvc.autoconfigure.WebMvcRegistrations;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

View File

@ -17,7 +17,7 @@ package org.springblade.core.cloud.version;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.web.servlet.WebMvcRegistrations;
import org.springframework.boot.webmvc.autoconfigure.WebMvcRegistrations;
import org.springframework.context.annotation.Bean;
/**

View File

@ -22,35 +22,13 @@
<!--Spring-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-undertow</artifactId>
<artifactId>spring-boot-starter-webmvc</artifactId>
</dependency>
<!-- jakarta -->
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
</dependency>
<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>jakarta.activation</groupId>
<artifactId>jakarta.activation-api</artifactId>

View File

@ -98,13 +98,14 @@ public class BladeApplication {
props.setProperty("blade.env", profile);
props.setProperty("blade.name", appName);
props.setProperty("blade.is-local", String.valueOf(isLocalDev()));
props.setProperty("blade.dev-mode", profile.equals(AppConstant.PROD_CODE) ? "false" : "true");
props.setProperty("blade.dev-mode", Boolean.toString(!profile.equals(AppConstant.PROD_CODE)));
props.setProperty("blade.service.version", AppConstant.APPLICATION_VERSION);
props.setProperty("spring.main.allow-bean-definition-overriding", "true");
props.setProperty("spring.cloud.sentinel.transport.dashboard", SentinelConstant.SENTINEL_ADDR);
props.setProperty("spring.cloud.alibaba.seata.tx-service-group", appName.concat(NacosConstant.NACOS_GROUP_SUFFIX));
props.setProperty("spring.config.import", String.join(",", NacosConstant.dataId(), NacosConstant.dataId(profile), NacosConstant.dataId(appName, profile)));
props.setProperty("nacos.logging.default.config.enabled", "false");
props.setProperty("management.info.process.enabled", "true");
// 加载自定义组件
List<LauncherService> launcherList = new ArrayList<>();
ServiceLoader.load(LauncherService.class).forEach(launcherList::add);

View File

@ -17,7 +17,7 @@ package org.springblade.core.launch;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.boot.web.server.context.WebServerInitializedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;

View File

@ -76,10 +76,6 @@ public interface AppConstant {
* 资源模块名称
*/
String APPLICATION_RESOURCE_NAME = APPLICATION_NAME_PREFIX + "resource";
/**
* 链路追踪模块名称
*/
String APPLICATION_ZIPKIN_NAME = APPLICATION_NAME_PREFIX + "zipkin";
/**
* 报表系统名称
*/

View File

@ -22,7 +22,7 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.core.env.EnvironmentCapable;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;

View File

@ -20,7 +20,7 @@ import org.springblade.core.launch.utils.INetUtil;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.web.server.autoconfigure.ServerProperties;
/**
* 服务器信息

View File

@ -37,7 +37,7 @@ import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.lang.NonNull;
import org.jspecify.annotations.NonNull;
import java.lang.reflect.Method;

View File

@ -39,6 +39,7 @@ public class SecureRegistry {
this.defaultExcludePatterns.add("/actuator/health/**");
this.defaultExcludePatterns.add("/v3/api-docs/**");
this.defaultExcludePatterns.add("/swagger-ui/**");
this.defaultExcludePatterns.add("/swagger-ui.html");
this.defaultExcludePatterns.add("/auth/**");
this.defaultExcludePatterns.add("/oauth/**");
this.defaultExcludePatterns.add("/token/**");

View File

@ -25,7 +25,7 @@ import org.springblade.core.launch.constant.SentinelConstant;
import org.springblade.core.launch.service.LauncherService;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.NonNull;
import org.jspecify.annotations.NonNull;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.*;

View File

@ -24,6 +24,15 @@
<groupId>org.springblade</groupId>
<artifactId>blade-core-launch</artifactId>
</dependency>
<!-- Jackson -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-jackson2</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>

View File

@ -23,7 +23,7 @@ import lombok.Setter;
import lombok.ToString;
import org.springblade.core.tool.constant.BladeConstant;
import org.springblade.core.tool.utils.ObjectUtil;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.Serial;
import java.io.Serializable;

View File

@ -15,37 +15,60 @@
*/
package org.springblade.core.tool.config;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.springblade.core.tool.jackson.BladeJacksonProperties;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springblade.core.tool.jackson.BladeJavaTimeModule;
import org.springblade.core.tool.jackson.BladeViewAnnotationIntrospector;
import org.springblade.core.tool.utils.DateUtil;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.jackson2.autoconfigure.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.context.annotation.Bean;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.util.Locale;
import java.util.TimeZone;
/**
* Jackson配置类
*
* @author Chill
*/
@AutoConfiguration(before = JacksonAutoConfiguration.class)
@AutoConfiguration
@ConditionalOnClass(ObjectMapper.class)
@EnableConfigurationProperties(BladeJacksonProperties.class)
@SuppressWarnings({"deprecation", "removal"})
public class JacksonConfiguration {
@Bean
@ConditionalOnMissingBean
public ObjectMapper objectMapper() {
//创建默认的ObjectMapper
ObjectMapper objectMapper = JsonUtil.getInstance();
//允许空字符串序列化为null对象
objectMapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
//自定义拓展配置
objectMapper.findAndRegisterModules();
return objectMapper;
public Jackson2ObjectMapperBuilderCustomizer bladeJacksonCustomizer() {
return builder -> {
// 默认视图包含 / 兼容宽松的读取特性 / 允许空字符串反序列化为 null 对象
builder.featuresToEnable(
MapperFeature.DEFAULT_VIEW_INCLUSION,
JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS,
JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER,
JsonParser.Feature.ALLOW_SINGLE_QUOTES,
DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
// 日期不序列化为时间戳 / 空对象不报错 / 未知属性不报错
builder.featuresToDisable(
SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,
SerializationFeature.FAIL_ON_EMPTY_BEANS,
DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
builder.locale(Locale.CHINA);
builder.timeZone(TimeZone.getTimeZone(ZoneId.systemDefault()));
builder.dateFormat(new SimpleDateFormat(DateUtil.PATTERN_DATETIME, Locale.CHINA));
builder.modulesToInstall(new BladeJavaTimeModule());
builder.findModulesViaServiceLoader(true);
// 视图注解内省器 Jackson 识别 @BladeView
builder.annotationIntrospector(introspector -> new BladeViewAnnotationIntrospector());
};
}
}

View File

@ -0,0 +1,47 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.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.tool.config;
import net.dreamlu.mica.auto.annotation.AutoService;
import org.springblade.core.launch.service.LauncherService;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.core.Ordered;
import java.util.Properties;
/**
* Jackson 启动服务
*
* @author Chill
*/
@AutoService(LauncherService.class)
public class JacksonLauncherServiceImpl implements LauncherService {
@Override
public void launcher(SpringApplicationBuilder builder, String appName, String profile) {
Properties props = System.getProperties();
// Spring Boot 4 默认 JSON 底座为 Jackson 3命令式 HTTP 消息转换器与反应式编解码器需分别指定首选实现
// 两处同时锁回 Jackson 2确保 @BladeView 视图过滤大数转字符串等既有序列化约定在 servlet webflux 两侧表现一致
props.setProperty("spring.http.converters.preferred-json-mapper", "jackson2");
props.setProperty("spring.http.codecs.preferred-json-mapper", "jackson2");
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}

View File

@ -29,6 +29,7 @@ import org.springframework.http.converter.json.AbstractJackson2HttpMessageConver
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
import java.util.ListIterator;
/**
* 消息配置类
@ -47,13 +48,23 @@ public class MessageConfiguration implements WebMvcConfigurer {
* 使用 JACKSON 作为JSON MessageConverter
*/
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.removeIf(x -> x instanceof StringHttpMessageConverter || x instanceof AbstractJackson2HttpMessageConverter);
converters.add(new StringHttpMessageConverter(Charsets.UTF_8));
converters.add(new ByteArrayHttpMessageConverter());
converters.add(new ResourceHttpMessageConverter());
converters.add(new ResourceRegionHttpMessageConverter());
converters.add(new MappingApiJackson2HttpMessageConverter(objectMapper, properties));
@SuppressWarnings("removal")
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingApiJackson2HttpMessageConverter bladeJson = new MappingApiJackson2HttpMessageConverter(objectMapper, properties);
boolean jsonReplaced = false;
ListIterator<HttpMessageConverter<?>> iterator = converters.listIterator();
while (iterator.hasNext()) {
HttpMessageConverter<?> converter = iterator.next();
if (converter instanceof AbstractJackson2HttpMessageConverter) {
iterator.set(bladeJson);
jsonReplaced = true;
} else if (converter instanceof StringHttpMessageConverter) {
iterator.set(new StringHttpMessageConverter(Charsets.UTF_8));
}
}
if (!jsonReplaced) {
converters.add(0, bladeJson);
}
}
}

View File

@ -21,7 +21,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.data.redis.autoconfigure.DataRedisAutoConfiguration;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.data.redis.connection.RedisConnectionFactory;
@ -36,7 +36,7 @@ import org.springframework.data.redis.serializer.RedisSerializer;
*/
@EnableCaching
@AutoConfiguration
@AutoConfigureBefore(RedisAutoConfiguration.class)
@AutoConfigureBefore(DataRedisAutoConfiguration.class)
public class RedisConfiguration {
/**

View File

@ -2,7 +2,7 @@ package org.springblade.core.tool.convert;
import org.springframework.boot.convert.ApplicationConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringValueResolver;
/**

View File

@ -8,7 +8,7 @@ import org.springblade.core.tool.utils.ConvertUtil;
import org.springblade.core.tool.utils.ReflectUtil;
import org.springframework.cglib.core.Converter;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.Field;
import java.util.concurrent.ConcurrentHashMap;

View File

@ -5,7 +5,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.ConvertUtil;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;

View File

@ -6,7 +6,7 @@ import org.springblade.core.tool.utils.ConvertUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.ConditionalGenericConverter;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Constructor;

View File

@ -16,7 +16,7 @@
package org.springblade.core.tool.function;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.Serializable;

View File

@ -16,7 +16,7 @@
package org.springblade.core.tool.function;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.Serializable;

View File

@ -16,7 +16,7 @@
package org.springblade.core.tool.function;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.Serializable;

View File

@ -16,7 +16,7 @@
package org.springblade.core.tool.function;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.Serializable;

View File

@ -31,7 +31,7 @@ import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.TypeUtils;
import java.io.IOException;
@ -45,6 +45,7 @@ import java.util.concurrent.atomic.AtomicReference;
*
* @author L.cm
*/
@SuppressWarnings("removal")
public abstract class AbstractReadWriteJackson2HttpMessageConverter extends AbstractJackson2HttpMessageConverter {
private static final java.nio.charset.Charset DEFAULT_CHARSET = Charsets.UTF_8;

View File

@ -23,8 +23,8 @@ import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ -40,6 +40,7 @@ import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@AutoIgnore
@ControllerAdvice
@RequiredArgsConstructor
@SuppressWarnings("removal")
public class BladeViewResponseAdvice implements ResponseBodyAdvice<Object> {
private final BladeViewResolver viewResolver;

View File

@ -28,7 +28,7 @@ import com.fasterxml.jackson.databind.type.CollectionLikeType;
import com.fasterxml.jackson.databind.type.MapType;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.utils.*;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.IOException;
import java.io.InputStream;
@ -280,7 +280,7 @@ public class JsonUtil {
* @return Bean
*/
@Nullable
public static <T> T readValue(@Nullable byte[] content, Class<T> valueType) {
public static <T> T readValue(byte @Nullable [] content, Class<T> valueType) {
if (ObjectUtil.isEmpty(content)) {
return null;
}
@ -340,7 +340,7 @@ public class JsonUtil {
* @return Bean
*/
@Nullable
public static <T> T readValue(@Nullable byte[] content, TypeReference<T> typeReference) {
public static <T> T readValue(byte @Nullable [] content, TypeReference<T> typeReference) {
if (ObjectUtil.isEmpty(content)) {
return null;
}
@ -414,7 +414,7 @@ public class JsonUtil {
* @return Bean
*/
@Nullable
public static <T> T readValue(@Nullable byte[] content, JavaType javaType) {
public static <T> T readValue(byte @Nullable [] content, JavaType javaType) {
if (content == null || content.length == 0) {
return null;
}
@ -565,7 +565,7 @@ public class JsonUtil {
* @param <T> 泛型
* @return 集合
*/
public static <T> List<T> readList(@Nullable byte[] content, Class<T> elementClass) {
public static <T> List<T> readList(byte @Nullable [] content, Class<T> elementClass) {
if (content == null || content.length == 0) {
return Collections.emptyList();
}
@ -639,7 +639,7 @@ public class JsonUtil {
* @param content bytes
* @return 集合
*/
public static Map<String, Object> readMap(@Nullable byte[] content) {
public static Map<String, Object> readMap(byte @Nullable [] content) {
return readMap(content, Object.class);
}
@ -681,7 +681,7 @@ public class JsonUtil {
* @param <V> 泛型
* @return 集合
*/
public static <V> Map<String, V> readMap(@Nullable byte[] content, Class<?> valueClass) {
public static <V> Map<String, V> readMap(byte @Nullable [] content, Class<?> valueClass) {
return readMap(content, String.class, valueClass);
}
@ -731,7 +731,7 @@ public class JsonUtil {
* @param <V> 泛型
* @return 集合
*/
public static <K, V> Map<K, V> readMap(@Nullable byte[] content, Class<?> keyClass, Class<?> valueClass) {
public static <K, V> Map<K, V> readMap(byte @Nullable [] content, Class<?> keyClass, Class<?> valueClass) {
if (content == null || content.length == 0) {
return Collections.emptyMap();
}

View File

@ -19,7 +19,7 @@ import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.IOException;
import java.util.ArrayList;
@ -35,6 +35,7 @@ import java.util.List;
*
* @author L.cm
*/
@SuppressWarnings("deprecation")
public class MappingApiJackson2HttpMessageConverter extends AbstractReadWriteJackson2HttpMessageConverter {
@Nullable

View File

@ -19,7 +19,7 @@ import org.springframework.cache.interceptor.SimpleKey;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
@ -58,8 +58,7 @@ public class RedisKeySerializer implements RedisSerializer<Object> {
}
@Override
@Nullable
public byte[] serialize(Object object) {
public byte @Nullable [] serialize(Object object) {
Objects.requireNonNull(object, "redis key is null");
String key;
if (object instanceof SimpleKey) {

View File

@ -1,7 +1,7 @@
package org.springblade.core.tool.support;
import org.springblade.core.tool.utils.StringPool;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.Writer;

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import javax.crypto.Cipher;
@ -145,8 +145,7 @@ public class AesUtil {
* @param aesTextKey 文本密钥
* @return byte[]
*/
@Nullable
public static byte[] decryptFormHex(@Nullable String content, String aesTextKey) {
public static byte @Nullable [] decryptFormHex(@Nullable String content, String aesTextKey) {
if (StringUtil.isBlank(content)) {
return null;
}
@ -187,8 +186,7 @@ public class AesUtil {
* @param aesTextKey 文本密钥
* @return byte[]
*/
@Nullable
public static byte[] decryptFormBase64(@Nullable String content, String aesTextKey) {
public static byte @Nullable [] decryptFormBase64(@Nullable String content, String aesTextKey) {
if (StringUtil.isBlank(content)) {
return null;
}

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.CollectionUtils;
import java.util.Arrays;
@ -38,7 +38,7 @@ public class CollectionUtil extends org.springframework.util.CollectionUtils {
* @param <T> The generic tag
* @return {@code true} if found, {@code false} else
*/
public static <T> boolean contains(@Nullable T[] array, final T element) {
public static <T> boolean contains(T @Nullable [] array, final T element) {
if (array == null) {
return false;
}

View File

@ -4,7 +4,7 @@ import lombok.experimental.UtilityClass;
import org.springblade.core.tool.convert.BladeConversionService;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* 基于 spring ConversionService 类型转换

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;

View File

@ -17,7 +17,7 @@
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
import java.util.Arrays;

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
@ -421,7 +421,7 @@ public class DigestUtil extends org.springframework.util.DigestUtils {
return slowEquals(a.getBytes(Charsets.UTF_8), b.getBytes(Charsets.UTF_8));
}
public static boolean slowEquals(@Nullable byte[] a, @Nullable byte[] b) {
public static boolean slowEquals(byte @Nullable [] a, byte @Nullable [] b) {
if (a == null || b == null) {
return false;
}

View File

@ -17,7 +17,7 @@
package org.springblade.core.tool.utils;
import lombok.experimental.UtilityClass;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.FileSystemUtils;
import org.springframework.util.PatternMatchUtils;

View File

@ -22,7 +22,7 @@ import org.springblade.core.tool.jackson.JsonUtil;
import org.springframework.beans.BeansException;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
@ -268,7 +268,7 @@ public class Func {
* @param array the array to check
* @return 数组是否为空
*/
public static boolean isEmpty(@Nullable Object[] array) {
public static boolean isEmpty(Object @Nullable [] array) {
return ObjectUtil.isEmpty(array);
}
@ -278,7 +278,7 @@ public class Func {
* @param array 数组
* @return 数组是否不为空
*/
public static boolean isNotEmpty(@Nullable Object[] array) {
public static boolean isNotEmpty(Object @Nullable [] array) {
return ObjectUtil.isNotEmpty(array);
}
@ -348,7 +348,7 @@ public class Func {
* @param <T> The generic tag
* @return {@code true} if found, {@code false} else
*/
public static <T> boolean contains(@Nullable T[] array, final T element) {
public static <T> boolean contains(T @Nullable [] array, final T element) {
return CollectionUtil.contains(array, element);
}

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.nio.charset.Charset;
@ -107,8 +107,7 @@ public class HexUtil {
* @param data Hex data
* @return decode hex to bytes
*/
@Nullable
public static byte[] decode(@Nullable String data) {
public static byte @Nullable [] decode(@Nullable String data) {
if (StringUtil.isBlank(data)) {
return null;
}

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.Closeable;
import java.io.IOException;

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.Serializable;
import java.util.function.Supplier;

View File

@ -16,7 +16,7 @@
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* 数字类型工具类

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* 对象工具类

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.io.File;
import java.net.URL;

View File

@ -5,7 +5,7 @@ import org.springframework.beans.BeansException;
import org.springframework.cglib.core.CodeGenerationException;
import org.springframework.core.convert.Property;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.ReflectionUtils;
import java.beans.PropertyDescriptor;

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

View File

@ -16,7 +16,7 @@
package org.springblade.core.tool.utils;
import org.springblade.core.tool.support.StrSpliter;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.util.HtmlUtils;
@ -337,7 +337,7 @@ public class StringUtil extends org.springframework.util.StringUtils {
* @param arguments 需要替换的变量
* @return 转换后的字符串
*/
public static String format(@Nullable String message, @Nullable Object... arguments) {
public static String format(@Nullable String message, Object @Nullable ... arguments) {
// message null 返回空字符串
if (message == null) {
return StringPool.EMPTY;

View File

@ -18,7 +18,7 @@ package org.springblade.core.tool.utils;
import lombok.extern.slf4j.Slf4j;
import org.springblade.core.tool.jackson.JsonUtil;
import org.springframework.http.MediaType;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.RequestAttributes;

View File

@ -15,7 +15,7 @@
*/
package org.springblade.core.tool.utils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

View File

@ -26,7 +26,7 @@ import org.springblade.core.tool.utils.Charsets;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;

View File

@ -15,7 +15,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.lang.NonNull;
import org.jspecify.annotations.NonNull;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;

View File

@ -16,8 +16,8 @@ import org.springframework.core.annotation.Order;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

View File

@ -13,7 +13,7 @@ import org.springblade.core.tool.utils.ClassUtil;
import org.springblade.core.tool.utils.DesUtil;
import org.springblade.core.tool.utils.StringUtil;
import org.springframework.core.MethodParameter;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
/**
* <p>辅助检测工具类</p>

View File

@ -19,7 +19,7 @@ import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.SpringUtil;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.lang.Nullable;
import org.jspecify.annotations.Nullable;
import java.util.concurrent.Callable;

View File

@ -37,10 +37,6 @@ public class CodeGenerator {
* 代码生成的包名
*/
public static String PACKAGE_NAME = "org.springblade.test";
/**
* 前端代码生成所属系统
*/
public static String SYSTEM_NAME = "saber";
/**
* 前端代码生成地址
*/
@ -77,7 +73,6 @@ public class CodeGenerator {
BladeCodeGenerator generator = new BladeCodeGenerator();
generator.setCodeName(CODE_NAME);
generator.setServiceName(SERVICE_NAME);
generator.setSystemName(SYSTEM_NAME);
generator.setPackageName(PACKAGE_NAME);
generator.setPackageWebDir(PACKAGE_WEB_DIR);
generator.setTablePrefix(TABLE_PREFIX);

View File

@ -1,38 +0,0 @@
/**
* Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.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.develop.constant;
/**
* 系统常量.
*
* @author zhuangqian
*/
public interface DevelopConstant {
/**
* sword 系统名
*/
String SWORD_NAME = "sword";
/**
* saber 系统名
*/
String SABER_NAME = "saber";
/**
* saber3 系统名
*/
String SABER3_NAME = "saber3";
}

View File

@ -19,7 +19,6 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.TemplateType;
import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
@ -28,9 +27,9 @@ import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Mapper;
import org.jspecify.annotations.NonNull;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.develop.constant.DevelopConstant;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PropertiesLoaderUtils;
@ -50,14 +49,14 @@ import java.util.Properties;
@Data
@Slf4j
public class BladeCodeGenerator {
/**
* 代码所在系统
*/
private String systemName = DevelopConstant.SABER3_NAME;
/**
* 代码模块名称
*/
private String codeName;
/**
* 代码所在系统
*/
private String systemName = "Saber";
/**
* 代码所在服务名
*/
@ -141,54 +140,40 @@ public class BladeCodeGenerator {
customMap.put("tenantColumn", tenantColumn);
customMap.put("hasWrapper", hasWrapper);
customMap.put("hasServiceName", hasServiceName);
Map<String, String> customFile = new HashMap<>(15);
Map<String, String> customFile = new HashMap<>(8);
customFile.put("menu.sql", "/templates/sql/menu.sql.vm");
customFile.put("entityVO.java", "/templates/entityVO.java.vm");
customFile.put("entityDTO.java", "/templates/entityDTO.java.vm");
customFile.put("entityVO.java", "/templates/api/entityVO.java.vm");
customFile.put("entityDTO.java", "/templates/api/entityDTO.java.vm");
if (hasWrapper) {
customFile.put("wrapper.java", "/templates/wrapper.java.vm");
customFile.put("wrapper.java", "/templates/api/wrapper.java.vm");
}
if (Func.isNotBlank(packageWebDir)) {
if (Func.equals(systemName, DevelopConstant.SWORD_NAME)) {
customFile.put("action.js", "/templates/sword/action.js.vm");
customFile.put("model.js", "/templates/sword/model.js.vm");
customFile.put("service.js", "/templates/sword/service.js.vm");
customFile.put("list.js", "/templates/sword/list.js.vm");
customFile.put("add.js", "/templates/sword/add.js.vm");
customFile.put("edit.js", "/templates/sword/edit.js.vm");
customFile.put("view.js", "/templates/sword/view.js.vm");
} else if (Func.equals(systemName, DevelopConstant.SABER_NAME)) {
customFile.put("api.js", "/templates/saber/api.js.vm");
customFile.put("crud.vue", "/templates/saber/crud.vue.vm");
} else if (Func.equals(systemName, DevelopConstant.SABER3_NAME)) {
customFile.put("api.js", "/templates/saber3/api.js.vm");
customFile.put("crud.vue", "/templates/saber3/crud.vue.vm");
}
customFile.put("api.js", "/templates/saber/api.js.vm");
customFile.put("crud.vue", "/templates/saber/crud.vue.vm");
}
FastAutoGenerator.create(url, username, password)
.globalConfig(builder -> builder.author(props.getProperty("author")).dateType(DateType.TIME_PACK).enableSwagger().outputDir(getOutputDir()).disableOpenDir())
.packageConfig(builder -> builder.parent(packageName).controller("controller").entity("entity").service("service").serviceImpl("service.impl").mapper("mapper").xml("mapper"))
.packageConfig(builder -> builder.parent(packageName).controller("controller").entity("pojo.entity").service("service").serviceImpl("service.impl").mapper("mapper").xml("mapper"))
.strategyConfig(builder -> builder.addTablePrefix(tablePrefix).addInclude(includeTables).addExclude(excludeTables)
.entityBuilder().naming(NamingStrategy.underline_to_camel).columnNaming(NamingStrategy.underline_to_camel).enableLombok().superClass("org.springblade.core.mp.base.BaseEntity").addSuperEntityColumns(superEntityColumns).enableFileOverride()
.javaTemplate("/templates/api/entity.java.vm")
.serviceBuilder().superServiceClass("org.springblade.core.mp.base.BaseService").superServiceImplClass("org.springblade.core.mp.base.BaseServiceImpl").formatServiceFileName("I%sService").formatServiceImplFileName("%sServiceImpl").enableFileOverride()
.serviceTemplate("/templates/api/service.java.vm")
.serviceImplTemplate("/templates/api/serviceImpl.java.vm")
.mapperBuilder().mapperAnnotation(Mapper.class).enableBaseResultMap().enableBaseColumnList().formatMapperFileName("%sMapper").formatXmlFileName("%sMapper").enableFileOverride()
.mapperTemplate("/templates/api/mapper.java.vm")
.mapperXmlTemplate("/templates/api/mapper.xml.vm")
.controllerBuilder().superClass("org.springblade.core.boot.ctrl.BladeController").formatFileName("%sController").enableRestStyle().enableHyphenStyle().enableFileOverride()
.template("/templates/api/controller.java.vm")
)
.templateConfig(builder -> builder.disable(TemplateType.ENTITY)
.entity("/templates/entity.java.vm")
.service("/templates/service.java.vm")
.serviceImpl("/templates/serviceImpl.java.vm")
.mapper("/templates/mapper.java.vm")
.xml("/templates/mapper.xml.vm")
.controller("/templates/controller.java.vm"))
.injectionConfig(builder -> builder.beforeOutputFile(
(tableInfo, objectMap) -> System.out.println("tableInfo: " + tableInfo.getEntityName() + " objectMap: " + objectMap.size())
).customMap(customMap).customFile(customFile)
)
.templateEngine(new VelocityTemplateEngine() {
@Override
protected void outputCustomFile(List<CustomFile> customFiles, TableInfo tableInfo, Map<String, Object> objectMap) {
protected void outputCustomFile(@NonNull List<CustomFile> customFiles, @NonNull TableInfo tableInfo, @NonNull Map<String, Object> objectMap) {
String entityName = tableInfo.getEntityName();
String entityNameLower = tableInfo.getEntityName().toLowerCase();
@ -206,45 +191,17 @@ public class BladeCodeGenerator {
outputPath = getOutputDir() + StringPool.SLASH + "sql" + StringPool.SLASH + entityNameLower + ".menu.sql";
}
if (StringUtil.equals(key, "entityVO.java")) {
outputPath = getOutputDir() + StringPool.SLASH + packageName.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + "vo" + StringPool.SLASH + entityName + "VO" + StringPool.DOT_JAVA;
outputPath = getOutputDir() + StringPool.SLASH + packageName.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + "pojo" + StringPool.SLASH + "vo" + StringPool.SLASH + entityName + "VO" + StringPool.DOT_JAVA;
}
if (StringUtil.equals(key, "entityDTO.java")) {
outputPath = getOutputDir() + StringPool.SLASH + packageName.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + "dto" + StringPool.SLASH + entityName + "DTO" + StringPool.DOT_JAVA;
outputPath = getOutputDir() + StringPool.SLASH + packageName.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + "pojo" + StringPool.SLASH + "dto" + StringPool.SLASH + entityName + "DTO" + StringPool.DOT_JAVA;
}
if (StringUtil.equals(key, "wrapper.java")) {
outputPath = getOutputDir() + StringPool.SLASH + packageName.replace(StringPool.DOT, StringPool.SLASH) + StringPool.SLASH + "wrapper" + StringPool.SLASH + entityName + "Wrapper" + StringPool.DOT_JAVA;
}
if (StringUtil.equals(key, "action.js")) {
outputPath = getOutputWebDir() + StringPool.SLASH + "actions" + StringPool.SLASH + entityNameLower + ".js";
}
if (StringUtil.equals(key, "model.js")) {
outputPath = getOutputWebDir() + StringPool.SLASH + "models" + StringPool.SLASH + entityNameLower + ".js";
}
if (StringUtil.equals(key, "service.js")) {
outputPath = getOutputWebDir() + StringPool.SLASH + "services" + StringPool.SLASH + entityNameLower + ".js";
}
if (StringUtil.equals(key, "list.js")) {
outputPath = getOutputWebDir() + StringPool.SLASH + "pages" + StringPool.SLASH + StringUtil.upperFirst(servicePackage) + StringPool.SLASH + entityName + StringPool.SLASH + entityName + ".js";
}
if (StringUtil.equals(key, "add.js")) {
outputPath = getOutputWebDir() + StringPool.SLASH + "pages" + StringPool.SLASH + StringUtil.upperFirst(servicePackage) + StringPool.SLASH + entityName + StringPool.SLASH + entityName + "Add.js";
}
if (StringUtil.equals(key, "edit.js")) {
outputPath = getOutputWebDir() + StringPool.SLASH + "pages" + StringPool.SLASH + StringUtil.upperFirst(servicePackage) + StringPool.SLASH + entityName + StringPool.SLASH + entityName + "Edit.js";
}
if (StringUtil.equals(key, "view.js")) {
outputPath = getOutputWebDir() + StringPool.SLASH + "pages" + StringPool.SLASH + StringUtil.upperFirst(servicePackage) + StringPool.SLASH + entityName + StringPool.SLASH + entityName + "View.js";
}
if (StringUtil.equals(key, "api.js")) {
outputPath = getOutputWebDir() + StringPool.SLASH + "api" + StringPool.SLASH + servicePackage.toLowerCase() + StringPool.SLASH + entityNameLower + ".js";
}
@ -260,7 +217,6 @@ public class BladeCodeGenerator {
}
/**
* 获取配置文件
*

View File

@ -18,12 +18,12 @@ package $!{package.Controller};
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 jakarta.validation.Valid;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.swagger.annotation.ApiOrder;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springframework.web.bind.annotation.*;
@ -34,7 +34,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import $!{package.Entity}.$!{entity};
#set($voPackage=$package.Entity.replace("entity","vo"))
import $!{voPackage}.$!{entity}VO;
#set($wrapperPackage=$package.Entity.replace("entity","wrapper"))
#set($wrapperPackage=$package.Entity.replace("pojo.entity","wrapper"))
#if($!{hasWrapper})
import $!{wrapperPackage}.$!{entity}Wrapper;
#end
@ -54,6 +54,7 @@ import $!{superControllerClassPackage};
@RestController
@AllArgsConstructor
@RequestMapping("#if($!{hasServiceName})/$!{serviceName}#end/$!{entityKey}")
@ApiOrder
@Tag(name = "$!{table.comment}", description = "$!{table.comment}接口")
#if($!{superControllerClass})
public class $!{table.controllerName} extends $!{superControllerClass} {
@ -68,7 +69,6 @@ public class $!{table.controllerName} {
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入$!{table.entityPath}")
public R<$!{entity}VO> detail($!{entity} $!{table.entityPath}) {
$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
@ -79,7 +79,6 @@ public class $!{table.controllerName} {
* 分页 $!{table.comment}
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@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}));
@ -91,7 +90,6 @@ public class $!{table.controllerName} {
* 详情
*/
@GetMapping("/detail")
@ApiOperationSupport(order = 1)
@Operation(summary = "详情", description = "传入$!{table.entityPath}")
public R<$!{entity}> detail($!{entity} $!{table.entityPath}) {
$!{entity} detail = $!{table.entityPath}Service.getOne(Condition.getQueryWrapper($!{table.entityPath}));
@ -102,7 +100,6 @@ public class $!{table.controllerName} {
* 分页 $!{table.comment}
*/
@GetMapping("/list")
@ApiOperationSupport(order = 2)
@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}));
@ -114,7 +111,6 @@ public class $!{table.controllerName} {
* 自定义分页 $!{table.comment}
*/
@GetMapping("/page")
@ApiOperationSupport(order = 3)
@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});
@ -125,7 +121,6 @@ public class $!{table.controllerName} {
* 新增 $!{table.comment}
*/
@PostMapping("/save")
@ApiOperationSupport(order = 4)
@Operation(summary = "新增", description = "传入$!{table.entityPath}")
public R save(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.save($!{table.entityPath}));
@ -135,7 +130,6 @@ public class $!{table.controllerName} {
* 修改 $!{table.comment}
*/
@PostMapping("/update")
@ApiOperationSupport(order = 5)
@Operation(summary = "修改", description = "传入$!{table.entityPath}")
public R update(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.updateById($!{table.entityPath}));
@ -145,7 +139,6 @@ public class $!{table.controllerName} {
* 新增或修改 $!{table.comment}
*/
@PostMapping("/submit")
@ApiOperationSupport(order = 6)
@Operation(summary = "新增或修改", description = "传入$!{table.entityPath}")
public R submit(@Valid @RequestBody $!{entity} $!{table.entityPath}) {
return R.status($!{table.entityPath}Service.saveOrUpdate($!{table.entityPath}));
@ -157,7 +150,6 @@ public class $!{table.controllerName} {
* 删除 $!{table.comment}
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 7)
@Operation(summary = "逻辑删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status($!{table.entityPath}Service.deleteLogic(Func.toLongList(ids)));
@ -169,7 +161,6 @@ public class $!{table.controllerName} {
* 删除 $!{table.comment}
*/
@PostMapping("/remove")
@ApiOperationSupport(order = 8)
@Operation(summary = "删除", description = "传入ids")
public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
return R.status($!{table.entityPath}Service.removeByIds(Func.toLongList(ids)));

View File

@ -54,7 +54,7 @@ public class $!{entity} extends Model<$!{entity}> {
public class $!{entity} implements Serializable {
#end
@Serial
@Serial
private static final long serialVersionUID = 1L;
## ---------- BEGIN 字段循环遍历 ----------
@ -64,42 +64,42 @@ public class $!{entity} implements Serializable {
#set($keyPropertyName=$!{field.propertyName})
#end
#if("$!field.comment" != "")
/**
* $!{field.comment}
*/
/**
* $!{field.comment}
*/
#if($!{swagger})
@Schema(description = "$!{field.comment}")
@Schema(description = "$!{field.comment}")
#end
#end
#if($!{field.keyFlag})
## 主键
#if($!{field.keyIdentityFlag})
@TableId(value = "$!{field.name}", type = IdType.AUTO)
@TableId(value = "$!{field.name}", type = IdType.AUTO)
#elseif(!$null.isNull($!{idType}) && "$!idType" != "")
@TableId(value = "$!{field.name}", type = IdType.$!{idType})
@TableId(value = "$!{field.name}", type = IdType.$!{idType})
#elseif($!{field.convert})
@TableId("$!{field.name}")
@TableId("$!{field.name}")
#end
## 普通字段
#elseif($!{field.fill})
## ----- 存在字段填充设置 -----
#if($!{field.convert})
@TableField(value = "$!{field.name}", fill = FieldFill.$!{field.fill})
@TableField(value = "$!{field.name}", fill = FieldFill.$!{field.fill})
#else
@TableField(fill = FieldFill.$!{field.fill})
@TableField(fill = FieldFill.$!{field.fill})
#end
#elseif($!{field.convert})
@TableField("$!{field.name}")
@TableField("$!{field.name}")
#end
## 乐观锁注解
#if($!{versionFieldName}==$!{field.name})
@Version
@Version
#end
## 逻辑删除注解
#if($!{logicDeleteFieldName}==$!{field.name})
@TableLogic
@TableLogic
#end
private $!{field.propertyType} $!{field.propertyName};
private $!{field.propertyType} $!{field.propertyName};
#end
#end
## ---------- END 字段循环遍历 ----------
@ -112,52 +112,52 @@ public class $!{entity} implements Serializable {
#set($getprefix="get")
#end
public $!{field.propertyType} $!{getprefix}$!{field.capitalName}() {
return $!{field.propertyName};
}
public $!{field.propertyType} $!{getprefix}$!{field.capitalName}() {
return $!{field.propertyName};
}
#if($!{entityBuilderModel})
public $!{entity} set$!{field.capitalName}($!{field.propertyType} $!{field.propertyName}) {
public $!{entity} set$!{field.capitalName}($!{field.propertyType} $!{field.propertyName}) {
#else
public void set$!{field.capitalName}($!{field.propertyType} $!{field.propertyName}) {
public void set$!{field.capitalName}($!{field.propertyType} $!{field.propertyName}) {
#end
this.$!{field.propertyName} = $!{field.propertyName};
this.$!{field.propertyName} = $!{field.propertyName};
#if($!{entityBuilderModel})
return this;
return this;
#end
}
}
#end
#end
#if($!{entityColumnConstant})
#foreach($field in $!{table.fields})
public static final String $!{field.name.toUpperCase()} = "$!{field.name}";
public static final String $!{field.name.toUpperCase()} = "$!{field.name}";
#end
#end
#if($!{activeRecord})
@Override
protected Serializable pkVal() {
@Override
protected Serializable pkVal() {
#if($!{keyPropertyName})
return this.$!{keyPropertyName};
return this.$!{keyPropertyName};
#else
return this.id;
return this.id;
#end
}
}
#end
#if(!$!{entityLombokModel})
@Override
public String toString() {
return "$!{entity}{" +
@Override
public String toString() {
return "$!{entity}{" +
#foreach($field in $!{table.fields})
#if($!{velocityCount}==1)
"$!{field.propertyName}=" + $!{field.propertyName} +
"$!{field.propertyName}=" + $!{field.propertyName} +
#else
", $!{field.propertyName}=" + $!{field.propertyName} +
", $!{field.propertyName}=" + $!{field.propertyName} +
#end
#end
"}";
}
"}";
}
#end
}

View File

@ -36,9 +36,9 @@ public interface $!{table.mapperName} extends $!{superMapperClass}<$!{entity}> {
/**
* 自定义分页
*
* @param page
* @param $!{table.entityPath}
* @return
* @param page 分页参数
* @param $!{table.entityPath} $!{table.comment}查询条件
* @return $!{table.comment}分页数据
*/
List<$!{entity}VO> select$!{entity}Page(IPage page, $!{entity}VO $!{table.entityPath});

View File

@ -35,9 +35,9 @@ public interface $!{table.serviceName} extends $!{superServiceClass}<$!{entity}>
/**
* 自定义分页
*
* @param page
* @param $!{table.entityPath}
* @return
* @param page 分页参数
* @param $!{table.entityPath} $!{table.comment}查询条件
* @return $!{table.comment}分页数据
*/
IPage<$!{entity}VO> select$!{entity}Page(IPage<$!{entity}VO> page, $!{entity}VO $!{table.entityPath});

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#set($wrapperPackage=$package.Entity.replace("entity","wrapper"))
#set($wrapperPackage=$package.Entity.replace("pojo.entity","wrapper"))
package $!{wrapperPackage};
import lombok.AllArgsConstructor;
@ -31,7 +31,7 @@ import $!{voPackage}.$!{entity}VO;
*/
public class $!{entity}Wrapper extends BaseEntityWrapper<$!{entity}, $!{entity}VO> {
public static $!{entity}Wrapper build() {
public static $!{entity}Wrapper build() {
return new $!{entity}Wrapper();
}

View File

@ -1,8 +1,8 @@
import request from '@/router/axios';
import request from '@/axios';
export const getList = (current, size, params) => {
return request({
url: '/api/$!{serviceName}/$!{entityKey}/list',
url: '/$!{serviceName}/$!{entityKey}/list',
method: 'get',
params: {
...params,
@ -14,7 +14,7 @@ export const getList = (current, size, params) => {
export const getDetail = (id) => {
return request({
url: '/api/$!{serviceName}/$!{entityKey}/detail',
url: '/$!{serviceName}/$!{entityKey}/detail',
method: 'get',
params: {
id
@ -24,7 +24,7 @@ export const getDetail = (id) => {
export const remove = (ids) => {
return request({
url: '/api/$!{serviceName}/$!{entityKey}/remove',
url: '/$!{serviceName}/$!{entityKey}/remove',
method: 'post',
params: {
ids,
@ -34,7 +34,7 @@ export const remove = (ids) => {
export const add = (row) => {
return request({
url: '/api/$!{serviceName}/$!{entityKey}/submit',
url: '/$!{serviceName}/$!{entityKey}/submit',
method: 'post',
data: row
})
@ -42,7 +42,7 @@ export const add = (row) => {
export const update = (row) => {
return request({
url: '/api/$!{serviceName}/$!{entityKey}/submit',
url: '/$!{serviceName}/$!{entityKey}/submit',
method: 'post',
data: row
})

View File

@ -3,11 +3,12 @@
<avue-crud :option="option"
:table-loading="loading"
:data="data"
:page="page"
ref="crudRef"
v-model="form"
v-model:search="search"
v-model:page="page"
:permission="permissionList"
:before-open="beforeOpen"
v-model="form"
ref="crud"
@row-update="rowUpdate"
@row-save="rowSave"
@row-del="rowDel"
@ -17,9 +18,8 @@
@current-change="currentChange"
@size-change="sizeChange"
@on-load="onLoad">
<template slot="menuLeft">
<template #menu-left>
<el-button type="danger"
size="small"
icon="el-icon-delete"
plain
v-if="permission.$!{entityKey}_delete"
@ -30,178 +30,222 @@
</basic-container>
</template>
<script>
import {getList, getDetail, add, update, remove} from "@/api/$!{servicePackage}/$!{entityKey}";
import {mapGetters} from "vuex";
<script setup lang="ts">
import { ref, reactive, computed } from 'vue';
import { useStore } from 'vuex';
import { ElMessage, ElMessageBox } from 'element-plus';
import { getList, getDetail, add, update, remove } from '@/api/$!{servicePackage}/$!{entityKey}';
import { validData } from '@/utils/util';
export default {
data() {
return {
form: {},
query: {},
loading: true,
page: {
pageSize: 10,
currentPage: 1,
total: 0
},
selectionList: [],
option: {
height: 'auto',
calcHeight: 210,
searchShow: true,
searchMenuSpan: 6,
tip: false,
border: true,
index: true,
viewBtn: true,
selection: true,
column: [
// 数据实体
interface $!{entity}Entity {
id: string;
#foreach($field in $!{table.fields})
#if($!{field.name}!=$!{tenantColumn})
{
label: "$!{field.comment}",
prop: "$!{field.propertyName}",
rules: [{
required: true,
message: "请输入$!{field.comment}",
trigger: "blur"
}]
},
#if($!{field.propertyName} != "id")
#if($!{field.propertyType} == "Integer" || $!{field.propertyType} == "Long" || $!{field.propertyType} == "Short" || $!{field.propertyType} == "Byte" || $!{field.propertyType} == "Double" || $!{field.propertyType} == "Float" || $!{field.propertyType} == "BigDecimal")
$!{field.propertyName}?: number;
#elseif($!{field.propertyType} == "Boolean")
$!{field.propertyName}?: boolean;
#else
$!{field.propertyName}?: string;
#end
#end
]
},
data: []
};
#end
#end
}
// 新增与编辑共用的表单模型,字段均可选
type $!{entity}Form = Partial<$!{entity}Entity>;
// 权限
const store = useStore();
const permission = computed(() => store.getters.permission);
// 表格实例与数据状态
const crudRef = ref();
const form = ref<$!{entity}Form>({});
const search = ref<Partial<$!{entity}Entity>>({});
const data = ref<$!{entity}Entity[]>([]);
const selectionList = ref<$!{entity}Entity[]>([]);
const query = ref<Partial<$!{entity}Entity>>({});
const loading = ref(true);
// 分页参数(整体替换,需用 ref
const page = ref({
pageSize: 10,
currentPage: 1,
total: 0,
});
// 选中行 id 集合,供批量删除使用
const ids = computed(() => selectionList.value.map(ele => ele.id).join(','));
// 表格配置
const option = reactive({
height: 'auto',
calcHeight: 210,
searchShow: true,
searchMenuSpan: 6,
tip: false,
border: true,
index: true,
viewBtn: true,
selection: true,
column: [
#foreach($field in $!{table.fields})
#if($!{field.name}!=$!{tenantColumn})
{
label: '$!{field.comment}',
prop: '$!{field.propertyName}',
rules: [{
required: true,
message: '请输入$!{field.comment}',
trigger: 'blur',
}],
},
computed: {
...mapGetters(["permission"]),
permissionList() {
return {
addBtn: this.vaildData(this.permission.$!{entityKey}_add, false),
viewBtn: this.vaildData(this.permission.$!{entityKey}_view, false),
delBtn: this.vaildData(this.permission.$!{entityKey}_delete, false),
editBtn: this.vaildData(this.permission.$!{entityKey}_edit, false)
};
},
ids() {
let ids = [];
this.selectionList.forEach(ele => {
ids.push(ele.id);
});
return ids.join(",");
}
},
methods: {
rowSave(row, done, loading) {
add(row).then(() => {
done();
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
}, error => {
window.console.log(error);
loading();
});
},
rowUpdate(row, index, done, loading) {
update(row).then(() => {
done();
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
}, error => {
window.console.log(error);
loading();
});
},
rowDel(row) {
this.$confirm("确定将选择数据删除?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
return remove(row.id);
})
.then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
});
},
handleDelete() {
if (this.selectionList.length === 0) {
this.$message.warning("请选择至少一条数据");
return;
}
this.$confirm("确定将选择数据删除?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
return remove(this.ids);
})
.then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
this.$refs.crud.toggleSelection();
});
},
beforeOpen(done, type) {
if (["edit", "view"].includes(type)) {
getDetail(this.form.id).then(res => {
this.form = res.data.data;
});
}
done();
},
searchReset() {
this.query = {};
this.onLoad(this.page);
},
searchChange(params, done) {
this.query = params;
this.page.currentPage = 1;
this.onLoad(this.page, params);
done();
},
selectionChange(list) {
this.selectionList = list;
},
selectionClear() {
this.selectionList = [];
this.$refs.crud.toggleSelection();
},
currentChange(currentPage){
this.page.currentPage = currentPage;
},
sizeChange(pageSize){
this.page.pageSize = pageSize;
},
onLoad(page, params = {}) {
this.loading = true;
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
const data = res.data.data;
this.page.total = data.total;
this.data = data.records;
this.loading = false;
this.selectionClear();
});
}
}
};
#end
#end
],
});
// 行操作按钮权限
const permissionList = computed(() => ({
addBtn: validData(permission.value.$!{entityKey}_add, false),
viewBtn: validData(permission.value.$!{entityKey}_view, false),
delBtn: validData(permission.value.$!{entityKey}_delete, false),
editBtn: validData(permission.value.$!{entityKey}_edit, false),
}));
// 加载列表数据
const onLoad = (pageData: { currentPage: number; pageSize: number }, params: Partial<$!{entity}Entity> = {}) => {
loading.value = true;
getList(pageData.currentPage, pageData.pageSize, Object.assign(params, query.value)).then(res => {
const list = res.data.data;
page.value.total = list.total;
data.value = list.records;
loading.value = false;
selectionClear();
});
};
// 条件检索
const searchChange = (params: Partial<$!{entity}Entity>, done: () => void) => {
query.value = params;
page.value.currentPage = 1;
onLoad(page.value, params);
done();
};
// 重置检索条件
const searchReset = () => {
query.value = {};
onLoad(page.value);
};
// 切换页码
const currentChange = (currentPage: number) => {
page.value.currentPage = currentPage;
};
// 调整每页条数
const sizeChange = (pageSize: number) => {
page.value.pageSize = pageSize;
};
// 记录当前选中行
const selectionChange = (list: $!{entity}Entity[]) => {
selectionList.value = list;
};
// 清空选中状态
const selectionClear = () => {
selectionList.value = [];
crudRef.value.toggleSelection();
};
// 新增保存
const rowSave = (row: $!{entity}Form, done: () => void, loading: () => void) => {
add(row).then(() => {
done();
onLoad(page.value);
ElMessage({
type: 'success',
message: '操作成功!',
});
}, error => {
window.console.log(error);
loading();
});
};
// 编辑更新
const rowUpdate = (row: $!{entity}Form, index: number, done: () => void, loading: () => void) => {
update(row).then(() => {
done();
onLoad(page.value);
ElMessage({
type: 'success',
message: '操作成功!',
});
}, error => {
window.console.log(error);
loading();
});
};
// 删除单行
const rowDel = (row: $!{entity}Entity) => {
ElMessageBox.confirm('确定将选择数据删除?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
return remove(row.id);
})
.then(() => {
onLoad(page.value);
ElMessage({
type: 'success',
message: '操作成功!',
});
});
};
// 批量删除选中行
const handleDelete = () => {
if (selectionList.value.length === 0) {
ElMessage.warning('请选择至少一条数据');
return;
}
ElMessageBox.confirm('确定将选择数据删除?', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
return remove(ids.value);
})
.then(() => {
onLoad(page.value);
ElMessage({
type: 'success',
message: '操作成功!',
});
crudRef.value.toggleSelection();
});
};
// 打开弹窗前置处理:编辑与查看回填详情
const beforeOpen = (done: () => void, type: string) => {
if (['edit', 'view'].includes(type)) {
getDetail(form.value.id).then(res => {
form.value = res.data.data;
});
}
done();
};
</script>
<style>

View File

@ -1,50 +0,0 @@
import request from '@/axios';
export const getList = (current, size, params) => {
return request({
url: '/$!{serviceName}/$!{entityKey}/list',
method: 'get',
params: {
...params,
current,
size,
}
})
}
export const getDetail = (id) => {
return request({
url: '/$!{serviceName}/$!{entityKey}/detail',
method: 'get',
params: {
id
}
})
}
export const remove = (ids) => {
return request({
url: '/$!{serviceName}/$!{entityKey}/remove',
method: 'post',
params: {
ids,
}
})
}
export const add = (row) => {
return request({
url: '/$!{serviceName}/$!{entityKey}/submit',
method: 'post',
data: row
})
}
export const update = (row) => {
return request({
url: '/$!{serviceName}/$!{entityKey}/submit',
method: 'post',
data: row
})
}

View File

@ -1,210 +0,0 @@
<template>
<basic-container>
<avue-crud :option="option"
:table-loading="loading"
:data="data"
:permission="permissionList"
:before-open="beforeOpen"
v-model="form"
v-model:search="search"
v-model:page="page"
ref="crud"
@row-update="rowUpdate"
@row-save="rowSave"
@row-del="rowDel"
@search-change="searchChange"
@search-reset="searchReset"
@selection-change="selectionChange"
@current-change="currentChange"
@size-change="sizeChange"
@on-load="onLoad">
<template #menu-left>
<el-button type="danger"
size="small"
icon="el-icon-delete"
plain
v-if="permission.$!{entityKey}_delete"
@click="handleDelete">删 除
</el-button>
</template>
</avue-crud>
</basic-container>
</template>
<script>
import {getList, getDetail, add, update, remove} from "@/api/$!{servicePackage}/$!{entityKey}";
import {mapGetters} from "vuex";
export default {
data() {
return {
form: {},
query: {},
search: {},
loading: true,
page: {
pageSize: 10,
currentPage: 1,
total: 0
},
selectionList: [],
option: {
height: 'auto',
calcHeight: 210,
searchShow: true,
searchMenuSpan: 6,
tip: false,
border: true,
index: true,
viewBtn: true,
selection: true,
column: [
#foreach($field in $!{table.fields})
#if($!{field.name}!=$!{tenantColumn})
{
label: "$!{field.comment}",
prop: "$!{field.propertyName}",
rules: [{
required: true,
message: "请输入$!{field.comment}",
trigger: "blur"
}]
},
#end
#end
]
},
data: []
};
},
computed: {
...mapGetters(["permission"]),
permissionList() {
return {
addBtn: this.validData(this.permission.$!{entityKey}_add, false),
viewBtn: this.validData(this.permission.$!{entityKey}_view, false),
delBtn: this.validData(this.permission.$!{entityKey}_delete, false),
editBtn: this.validData(this.permission.$!{entityKey}_edit, false)
};
},
ids() {
let ids = [];
this.selectionList.forEach(ele => {
ids.push(ele.id);
});
return ids.join(",");
}
},
methods: {
rowSave(row, done, loading) {
add(row).then(() => {
done();
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
}, error => {
window.console.log(error);
loading();
});
},
rowUpdate(row, index, done, loading) {
update(row).then(() => {
done();
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
}, error => {
window.console.log(error);
loading();
});
},
rowDel(row) {
this.$confirm("确定将选择数据删除?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
return remove(row.id);
})
.then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
});
},
handleDelete() {
if (this.selectionList.length === 0) {
this.$message.warning("请选择至少一条数据");
return;
}
this.$confirm("确定将选择数据删除?", {
confirmButtonText: "确定",
cancelButtonText: "取消",
type: "warning"
})
.then(() => {
return remove(this.ids);
})
.then(() => {
this.onLoad(this.page);
this.$message({
type: "success",
message: "操作成功!"
});
this.$refs.crud.toggleSelection();
});
},
beforeOpen(done, type) {
if (["edit", "view"].includes(type)) {
getDetail(this.form.id).then(res => {
this.form = res.data.data;
});
}
done();
},
searchReset() {
this.query = {};
this.onLoad(this.page);
},
searchChange(params, done) {
this.query = params;
this.page.currentPage = 1;
this.onLoad(this.page, params);
done();
},
selectionChange(list) {
this.selectionList = list;
},
selectionClear() {
this.selectionList = [];
this.$refs.crud.toggleSelection();
},
currentChange(currentPage){
this.page.currentPage = currentPage;
},
sizeChange(pageSize){
this.page.pageSize = pageSize;
},
onLoad(page, params = {}) {
this.loading = true;
getList(page.currentPage, page.pageSize, Object.assign(params, this.query)).then(res => {
const data = res.data.data;
this.page.total = data.total;
this.data = data.records;
this.loading = false;
this.selectionClear();
});
}
}
};
</script>
<style>
</style>

View File

@ -1,37 +0,0 @@
#set($upperEntityPath=$table.entityPath.toUpperCase())
export const $!{upperEntityPath}_NAMESPACE = '$!{table.entityPath}';
export function $!{upperEntityPath}_LIST(payload) {
return {
type: `${$!{upperEntityPath}_NAMESPACE}/fetchList`,
payload,
};
}
export function $!{upperEntityPath}_DETAIL(id) {
return {
type: `${$!{upperEntityPath}_NAMESPACE}/fetchDetail`,
payload: { id },
};
}
export function $!{upperEntityPath}_CLEAR_DETAIL() {
return {
type: `${$!{upperEntityPath}_NAMESPACE}/clearDetail`,
payload: {},
};
}
export function $!{upperEntityPath}_SUBMIT(payload) {
return {
type: `${$!{upperEntityPath}_NAMESPACE}/submit`,
payload,
};
}
export function $!{upperEntityPath}_REMOVE(payload) {
return {
type: `${$!{upperEntityPath}_NAMESPACE}/remove`,
payload,
};
}

View File

@ -1,75 +0,0 @@
#set($upperEntityPath=$table.entityPath.toUpperCase())
import React, { PureComponent } from 'react';
import { Form, Input, Card, Button } from 'antd';
import { connect } from 'dva';
import Panel from '../../../components/Panel';
import styles from '../../../layouts/Sword.less';
import { $!{upperEntityPath}_SUBMIT } from '../../../actions/$!{table.entityPath}';
const FormItem = Form.Item;
@connect(({ loading }) => ({
submitting: loading.effects['$!{table.entityPath}/submit'],
}))
@Form.create()
class $!{entity}Add extends PureComponent {
handleSubmit = e => {
e.preventDefault();
const { dispatch, form } = this.props;
form.validateFieldsAndScroll((err, values) => {
if (!err) {
dispatch($!{upperEntityPath}_SUBMIT(values));
}
});
};
render() {
const {
form: { getFieldDecorator },
submitting,
} = this.props;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 7 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 12 },
md: { span: 10 },
},
};
const action = (
<Button type="primary" onClick={this.handleSubmit} loading={submitting}>
提交
</Button>
);
return (
<Panel title="新增" back="/$!{servicePackage}/$!{table.entityPath}" action={action}>
<Form hideRequiredMark style={{ marginTop: 8 }}>
<Card className={styles.card} bordered={false}>
#foreach($field in $!{table.fields})
#if($!{field.name}!=$!{tenantColumn})
<FormItem {...formItemLayout} label="$!{field.comment}">
{getFieldDecorator('$!{field.propertyName}', {
rules: [
{
required: true,
message: '请输入$!{field.comment}',
},
],
})(<Input placeholder="请输入$!{field.comment}" />)}
</FormItem>
#end
#end
</Card>
</Form>
</Panel>
);
}
}
export default $!{entity}Add;

View File

@ -1,99 +0,0 @@
#set($upperEntityPath=$table.entityPath.toUpperCase())
import React, { PureComponent } from 'react';
import { Form, Input, Card, Button } from 'antd';
import { connect } from 'dva';
import Panel from '../../../components/Panel';
import styles from '../../../layouts/Sword.less';
import { $!{upperEntityPath}_DETAIL, $!{upperEntityPath}_SUBMIT } from '../../../actions/$!{table.entityPath}';
const FormItem = Form.Item;
@connect(({ $!{table.entityPath}, loading }) => ({
$!{table.entityPath},
submitting: loading.effects['$!{table.entityPath}/submit'],
}))
@Form.create()
class $!{entity}Edit extends PureComponent {
componentWillMount() {
const {
dispatch,
match: {
params: { id },
},
} = this.props;
dispatch($!{upperEntityPath}_DETAIL(id));
}
handleSubmit = e => {
e.preventDefault();
const {
dispatch,
match: {
params: { id },
},
form,
} = this.props;
form.validateFieldsAndScroll((err, values) => {
if (!err) {
const params = {
id,
...values,
};
console.log(params);
dispatch($!{upperEntityPath}_SUBMIT(params));
}
});
};
render() {
const {
form: { getFieldDecorator },
$!{table.entityPath}: { detail },
submitting,
} = this.props;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 7 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 12 },
md: { span: 10 },
},
};
const action = (
<Button type="primary" onClick={this.handleSubmit} loading={submitting}>
提交
</Button>
);
return (
<Panel title="修改" back="/$!{servicePackage}/$!{table.entityPath}" action={action}>
<Form hideRequiredMark style={{ marginTop: 8 }}>
<Card className={styles.card} bordered={false}>
#foreach($field in $!{table.fields})
#if($!{field.name}!=$!{tenantColumn})
<FormItem {...formItemLayout} label="$!{field.comment}">
{getFieldDecorator('$!{field.propertyName}', {
rules: [
{
required: true,
message: '请输入$!{field.comment}',
},
],
initialValue: detail.$!{field.propertyName},
})(<Input placeholder="请输入$!{field.comment}" />)}
</FormItem>
#end
#end
</Card>
</Form>
</Panel>
);
}
}
export default $!{entity}Edit;

View File

@ -1,84 +0,0 @@
#set($upperEntityPath=$table.entityPath.toUpperCase())
import React, { PureComponent } from 'react';
import { connect } from 'dva';
import { Button, Col, Form, Input, Row } from 'antd';
import Panel from '../../../components/Panel';
import { $!{upperEntityPath}_LIST } from '../../../actions/$!{table.entityPath}';
import Grid from '../../../components/Sword/Grid';
const FormItem = Form.Item;
@connect(({ $!{table.entityPath}, loading }) => ({
$!{table.entityPath},
loading: loading.models.$!{table.entityPath},
}))
@Form.create()
class $!{entity} extends PureComponent {
// ============ 查询 ===============
handleSearch = params => {
const { dispatch } = this.props;
dispatch($!{upperEntityPath}_LIST(params));
};
// ============ 查询表单 ===============
renderSearchForm = onReset => {
const { form } = this.props;
const { getFieldDecorator } = form;
return (
<Row gutter={{ md: 8, lg: 24, xl: 48 }}>
<Col md={6} sm={24}>
<FormItem label="查询名称">
{getFieldDecorator('name')(<Input placeholder="查询名称" />)}
</FormItem>
</Col>
<Col>
<div style={{ float: 'right' }}>
<Button type="primary" htmlType="submit">
查询
</Button>
<Button style={{ marginLeft: 8 }} onClick={onReset}>
重置
</Button>
</div>
</Col>
</Row>
);
};
render() {
const code = '$!{table.entityPath}';
const {
form,
loading,
$!{table.entityPath}: { data },
} = this.props;
const columns = [
#foreach($field in $!{table.fields})
#if($!{field.name}!=$!{tenantColumn})
{
title: '$!{field.comment}',
dataIndex: '$!{field.propertyName}',
},
#end
#end
];
return (
<Panel>
<Grid
code={code}
form={form}
onSearch={this.handleSearch}
renderSearchForm={this.renderSearchForm}
loading={loading}
data={data}
columns={columns}
/>
</Panel>
);
}
}
export default $!{entity};

View File

@ -1,88 +0,0 @@
#set($upperEntityPath=$table.entityPath.toUpperCase())
import { message } from 'antd';
import router from 'umi/router';
import { $!{upperEntityPath}_NAMESPACE } from '../actions/$!{table.entityPath}';
import { list, submit, detail, remove } from '../services/$!{table.entityPath}';
export default {
namespace: $!{upperEntityPath}_NAMESPACE,
state: {
data: {
list: [],
pagination: false,
},
detail: {},
},
effects: {
*fetchList({ payload }, { call, put }) {
const response = yield call(list, payload);
if (response.success) {
yield put({
type: 'saveList',
payload: {
list: response.data.records,
pagination: {
total: response.data.total,
current: response.data.current,
pageSize: response.data.size,
},
},
});
}
},
*fetchDetail({ payload }, { call, put }) {
const response = yield call(detail, payload);
if (response.success) {
yield put({
type: 'saveDetail',
payload: {
detail: response.data,
},
});
}
},
*clearDetail({ payload }, { put }) {
yield put({
type: 'removeDetail',
payload: { payload },
});
},
*submit({ payload }, { call }) {
const response = yield call(submit, payload);
if (response.success) {
message.success('提交成功');
router.push('/$!{servicePackage}/$!{table.entityPath}');
}
},
*remove({ payload }, { call }) {
const {
data: { keys },
success,
} = payload;
const response = yield call(remove, { ids: keys });
if (response.success) {
success();
}
},
},
reducers: {
saveList(state, action) {
return {
...state,
data: action.payload,
};
},
saveDetail(state, action) {
return {
...state,
detail: action.payload.detail,
};
},
removeDetail(state) {
return {
...state,
detail: {},
};
},
},
};

View File

@ -1,26 +0,0 @@
#set($params="$" + "{stringify" + "(params)" + "}")
import { stringify } from 'qs';
import func from '../utils/Func';
import request from '../utils/request';
export async function list(params) {
return request(`/api/$!{serviceName}/$!{entityKey}/list?$!{params}`);
}
export async function submit(params) {
return request('/api/$!{serviceName}/$!{entityKey}/submit', {
method: 'POST',
body: params,
});
}
export async function detail(params) {
return request(`/api/$!{serviceName}/$!{entityKey}/detail?$!{params}`);
}
export async function remove(params) {
return request('/api/$!{serviceName}/$!{entityKey}/remove', {
method: 'POST',
body: func.toFormData(params),
});
}

View File

@ -1,76 +0,0 @@
#set($upperEntityPath=$table.entityPath.toUpperCase())
import React, { PureComponent } from 'react';
import router from 'umi/router';
import { Form, Card, Button } from 'antd';
import { connect } from 'dva';
import Panel from '../../../components/Panel';
import styles from '../../../layouts/Sword.less';
import { $!{upperEntityPath}_DETAIL } from '../../../actions/$!{table.entityPath}';
const FormItem = Form.Item;
@connect(({ $!{table.entityPath} }) => ({
$!{table.entityPath},
}))
@Form.create()
class $!{entity}View extends PureComponent {
componentWillMount() {
const {
dispatch,
match: {
params: { id },
},
} = this.props;
dispatch($!{upperEntityPath}_DETAIL(id));
}
handleEdit = () => {
const {
match: {
params: { id },
},
} = this.props;
router.push(`/$!{servicePackage}/$!{table.entityPath}/edit/$!{id}`);
};
render() {
const {
$!{table.entityPath}: { detail },
} = this.props;
const formItemLayout = {
labelCol: {
xs: { span: 24 },
sm: { span: 7 },
},
wrapperCol: {
xs: { span: 24 },
sm: { span: 12 },
md: { span: 10 },
},
};
const action = (
<Button type="primary" onClick={this.handleEdit}>
修改
</Button>
);
return (
<Panel title="查看" back="/$!{servicePackage}/$!{table.entityPath}" action={action}>
<Form hideRequiredMark style={{ marginTop: 8 }}>
<Card className={styles.card} bordered={false}>
#foreach($field in $!{table.fields})
#if($!{field.name}!=$!{tenantColumn})
<FormItem {...formItemLayout} label="$!{field.comment}">
<span>{detail.$!{field.propertyName}}</span>
</FormItem>
#end
#end
</Card>
</Form>
</Panel>
);
}
}
export default $!{entity}View;

View File

@ -15,9 +15,9 @@
*/
package org.springblade.core.i18n.config;
import jakarta.annotation.Nonnull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jspecify.annotations.NonNull;
import org.springblade.core.i18n.interceptor.I18nInterceptor;
import org.springblade.core.i18n.props.I18nProperties;
import org.springblade.core.i18n.resolver.I18nLocaleResolver;
@ -118,7 +118,7 @@ public class I18nAutoConfiguration {
public WebMvcConfigurer i18nWebMvcConfigurer(I18nInterceptor i18nInterceptor) {
return new WebMvcConfigurer() {
@Override
public void addInterceptors(@Nonnull InterceptorRegistry registry) {
public void addInterceptors(@NonNull InterceptorRegistry registry) {
registry.addInterceptor(i18nInterceptor)
.addPathPatterns("/**")
.order(0);

View File

@ -22,7 +22,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springblade.core.i18n.props.I18nProperties;
import org.springblade.core.i18n.utils.LocaleParseUtil;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.lang.NonNull;
import org.jspecify.annotations.NonNull;
import org.springframework.web.servlet.HandlerInterceptor;
import java.util.Locale;

View File

@ -15,11 +15,11 @@
*/
package org.springblade.core.i18n.resolver;
import jakarta.annotation.Nonnull;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.jspecify.annotations.NonNull;
import org.springblade.core.i18n.props.I18nProperties;
import org.springblade.core.i18n.utils.LocaleParseUtil;
import org.springframework.web.servlet.LocaleResolver;
@ -49,9 +49,9 @@ public class I18nLocaleResolver implements LocaleResolver {
.collect(Collectors.toSet());
}
@Nonnull
@NonNull
@Override
public Locale resolveLocale(@Nonnull HttpServletRequest request) {
public Locale resolveLocale(@NonNull HttpServletRequest request) {
return LocaleParseUtil.resolveFromRequest(
request,
properties.getHeaderName(),
@ -62,7 +62,7 @@ public class I18nLocaleResolver implements LocaleResolver {
}
@Override
public void setLocale(@Nonnull HttpServletRequest request, HttpServletResponse response, Locale locale) {
public void setLocale(@NonNull HttpServletRequest request, HttpServletResponse response, Locale locale) {
if (response != null && locale != null) {
// 检查是否支持该locale
boolean isSupported = supportedLocales.isEmpty() ||

View File

@ -25,10 +25,6 @@
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<!-- Feign -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>

View File

@ -17,7 +17,7 @@ package org.springblade.core.loadbalancer.rule;
import net.dreamlu.mica.auto.annotation.AutoEnvPostProcessor;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.boot.EnvironmentPostProcessor;
import org.springframework.core.Ordered;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.util.StringUtils;

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