Merge pull request #8039 from EightMonth/knife_arch

Knife4j升级4.4.0 架构代码改动
dev
JEECG 3 months ago committed by GitHub
commit 7e436f2efd
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -211,14 +211,9 @@
</dependency> </dependency>
<!-- knife4j --> <!-- knife4j -->
<!-- <dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>-->
<dependency> <dependency>
<groupId>com.github.xiaoymin</groupId> <groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId> <artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
<version>${knife4j-spring-boot-starter.version}</version> <version>${knife4j-spring-boot-starter.version}</version>
</dependency> </dependency>

@ -1,188 +1,182 @@
package org.jeecg.config; //package org.jeecg.config;
//
//
import io.swagger.annotations.ApiOperation; //import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
import org.jeecg.common.constant.CommonConstant; //import org.jeecg.common.constant.CommonConstant;
import org.jeecg.config.mybatis.MybatisPlusSaasConfig; //import org.springframework.beans.BeansException;
import org.springframework.beans.BeansException; //import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor; //import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Bean; //import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Configuration; //import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Import; //import org.springframework.util.ReflectionUtils;
import org.springframework.util.ReflectionUtils; //import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestController; //import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; //import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; //import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping; //import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration;
import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; //import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ApiInfoBuilder; //import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.ParameterBuilder; //import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.PathSelectors; //import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestHandlerSelectors; //import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.schema.ModelRef; //import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.*; //import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType; //import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext; //import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket; //import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider; //import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc; //import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
//import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.lang.reflect.Field; //
import java.util.ArrayList; //import java.lang.reflect.Field;
import java.util.Collections; //import java.util.ArrayList;
import java.util.List; //import java.util.Collections;
import java.util.stream.Collectors; //import java.util.List;
//import java.util.stream.Collectors;
/** //
* @Author scott ///**
*/ // * @Author scott
@Configuration // */
@EnableSwagger2WebMvc //@Configuration
@Import(BeanValidatorPluginsConfiguration.class) //@EnableSwagger2 //开启 Swagger2
public class Swagger2Config implements WebMvcConfigurer { //@EnableKnife4j //开启 knife4j可以不写
//@Import(BeanValidatorPluginsConfiguration.class)
/** //public class Swagger2Config implements WebMvcConfigurer {
* //
* swagger-ui.htmlswagger // /**
* // *
* @param registry // * 显示swagger-ui.html文档展示页还必须注入swagger资源
*/ // *
@Override // * @param registry
public void addResourceHandlers(ResourceHandlerRegistry registry) { // */
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); // @Override
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/"); // public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); // registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
} // registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
// registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
/** // }
* swagger2swagger2 //
* // /**
* @return Docket // * swagger2的配置文件这里可以配置swagger2的一些基本的内容比如扫描的包等等
*/ // *
@Bean(value = "defaultApi2") // * @return Docket
public Docket defaultApi2() { // */
return new Docket(DocumentationType.SWAGGER_2) // @Bean(value = "defaultApi2")
.apiInfo(apiInfo()) // public Docket defaultApi2() {
.select() // return new Docket(DocumentationType.SWAGGER_2)
//此包路径下的类,才生成接口文档 // .apiInfo(apiInfo())
.apis(RequestHandlerSelectors.basePackage("org.jeecg")) // .select()
//加了ApiOperation注解的类才生成接口文档 // //此包路径下的类,才生成接口文档
.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class)) // .apis(RequestHandlerSelectors.basePackage("org.jeecg"))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)) // //加了ApiOperation注解的类才生成接口文档
.paths(PathSelectors.any()) // .apis(RequestHandlerSelectors.withClassAnnotation(RestController.class))
.build() // .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.securitySchemes(Collections.singletonList(securityScheme())) // .paths(PathSelectors.any())
.securityContexts(securityContexts()) // .build()
.globalOperationParameters(setHeaderToken()); // .securitySchemes(Collections.singletonList(securityScheme()))
} // .securityContexts(securityContexts())
// .globalOperationParameters(setHeaderToken());
/*** // }
* oauth2 //
* swagger // /***
* http://localhost:8888/webjars/springfox-swagger-ui/o2c.html // * oauth2配置
* @return // * 需要增加swagger授权回调地址
*/ // * http://localhost:8888/webjars/springfox-swagger-ui/o2c.html
@Bean // * @return
SecurityScheme securityScheme() { // */
return new ApiKey(CommonConstant.X_ACCESS_TOKEN, CommonConstant.X_ACCESS_TOKEN, "header"); // @Bean
} // SecurityScheme securityScheme() {
/** // return new ApiKey(CommonConstant.X_ACCESS_TOKEN, CommonConstant.X_ACCESS_TOKEN, "header");
* JWT token // }
* @return // /**
*/ // * JWT token
private List<Parameter> setHeaderToken() { // * @return
ParameterBuilder tokenPar = new ParameterBuilder(); // */
List<Parameter> pars = new ArrayList<>(); // private List<Parameter> setHeaderToken() {
tokenPar.name(CommonConstant.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); // ParameterBuilder tokenPar = new ParameterBuilder();
pars.add(tokenPar.build()); // List<Parameter> pars = new ArrayList<>();
//update-begin-author:liusq---date:2024-08-15--for: 开启多租户时全局参数增加租户id // tokenPar.name(CommonConstant.X_ACCESS_TOKEN).description("token").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
if(MybatisPlusSaasConfig.OPEN_SYSTEM_TENANT_CONTROL){ // pars.add(tokenPar.build());
ParameterBuilder tenantPar = new ParameterBuilder(); // return pars;
tenantPar.name(CommonConstant.TENANT_ID).description("租户ID").modelRef(new ModelRef("string")).parameterType("header").required(false).build(); // }
pars.add(tenantPar.build()); //
} // /**
//update-end-author:liusq---date:2024-08-15--for: 开启多租户时全局参数增加租户id // * api文档的详细信息函数,注意这里的注解引用的是哪个
// *
return pars; // * @return
} // */
// private ApiInfo apiInfo() {
/** // return new ApiInfoBuilder()
* api, // // //大标题
* // .title("JeecgBoot 后台服务API接口文档")
* @return // // 版本号
*/ // .version("1.0")
private ApiInfo apiInfo() { //// .termsOfServiceUrl("NO terms of service")
return new ApiInfoBuilder() // // 描述
// //大标题 // .description("后台API接口")
.title("JeecgBoot 后台服务API接口文档") // // 作者
// 版本号 // .contact(new Contact("北京国炬信息技术有限公司","www.jeccg.com","jeecgos@163.com"))
.version("1.0") // .license("The Apache License, Version 2.0")
// .termsOfServiceUrl("NO terms of service") // .licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
// 描述 // .build();
.description("后台API接口") // }
// 作者 //
.contact(new Contact("北京国炬信息技术有限公司","www.jeccg.com","jeecgos@163.com")) // /**
.license("The Apache License, Version 2.0") // * 新增 securityContexts 保持登录状态
.licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html") // */
.build(); // private List<SecurityContext> securityContexts() {
} // return new ArrayList(
// Collections.singleton(SecurityContext.builder()
/** // .securityReferences(defaultAuth())
* securityContexts // .forPaths(PathSelectors.regex("^(?!auth).*$"))
*/ // .build())
private List<SecurityContext> securityContexts() { // );
return new ArrayList( // }
Collections.singleton(SecurityContext.builder() //
.securityReferences(defaultAuth()) // private List<SecurityReference> defaultAuth() {
.forPaths(PathSelectors.regex("^(?!auth).*$")) // AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
.build()) // AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
); // authorizationScopes[0] = authorizationScope;
} // return new ArrayList(
// Collections.singleton(new SecurityReference(CommonConstant.X_ACCESS_TOKEN, authorizationScopes)));
private List<SecurityReference> defaultAuth() { // }
AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); //
AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; // /**
authorizationScopes[0] = authorizationScope; // * 解决springboot2.6 和springfox不兼容问题
return new ArrayList( // * @return
Collections.singleton(new SecurityReference(CommonConstant.X_ACCESS_TOKEN, authorizationScopes))); // */
} // @Bean
// public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
/** // return new BeanPostProcessor() {
* springboot2.6 springfox //
* @return // @Override
*/ // public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
@Bean // if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() { // customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
return new BeanPostProcessor() { // }
// return bean;
@Override // }
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { //
if (bean instanceof WebMvcRequestHandlerProvider) { // private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean)); // List<T> copy = mappings.stream()
} // .filter(mapping -> mapping.getPatternParser() == null)
return bean; // .collect(Collectors.toList());
} // mappings.clear();
// mappings.addAll(copy);
private <T extends RequestMappingInfoHandlerMapping> void customizeSpringfoxHandlerMappings(List<T> mappings) { // }
List<T> copy = mappings.stream() //
.filter(mapping -> mapping.getPatternParser() == null) // @SuppressWarnings("unchecked")
.collect(Collectors.toList()); // private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) {
mappings.clear(); // try {
mappings.addAll(copy); // Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
} // field.setAccessible(true);
// return (List<RequestMappingInfoHandlerMapping>) field.get(bean);
@SuppressWarnings("unchecked") // } catch (IllegalArgumentException | IllegalAccessException e) {
private List<RequestMappingInfoHandlerMapping> getHandlerMappings(Object bean) { // throw new IllegalStateException(e);
try { // }
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings"); // }
field.setAccessible(true); // };
return (List<RequestMappingInfoHandlerMapping>) field.get(bean); // }
} catch (IllegalArgumentException | IllegalAccessException e) { //
throw new IllegalStateException(e); //
} //}
}
};
}
}

@ -0,0 +1,109 @@
package org.jeecg.config;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.constant.CommonConstant;
import org.springdoc.core.GroupedOpenApi;
import org.springdoc.core.customizers.GlobalOpenApiCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
/**
* @author eightmonth
*/
@Slf4j
@Configuration
public class Swagger3Config implements WebMvcConfigurer {
// 定义不需要注入安全要求的路径集合
Set<String> excludedPaths = new HashSet<>(Arrays.asList(
"/sys/randomImage/{key}",
"/sys/login",
"/sys/phoneLogin",
"/sys/mLogin",
"/sys/sms",
"/sys/cas/client/validateLogin",
"/test/jeecgDemo/demo3",
"/sys/thirdLogin/**",
"/sys/user/register"
));
/**
*
* swagger-ui.htmlswagger
*
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
}
@Bean
public GroupedOpenApi swaggerOpenApi() {
return GroupedOpenApi.builder()
.group("default")
.packagesToScan("org.jeecg")
// 剔除以下几个包路径的接口生成文档
.packagesToExclude("org.jeecg.modules.drag", "org.jeecg.modules.online", "org.jeecg.modules.jmreport")
// 加了Operation注解的方法才生成接口文档
.addOpenApiMethodFilter(method -> method.isAnnotationPresent(Operation.class))
.addOpenApiCustomiser(globalOpenApiCustomizer())
.build();
}
@Bean
public GlobalOpenApiCustomizer globalOpenApiCustomizer() {
return openApi -> {
// 全局添加鉴权参数
if (openApi.getPaths() != null) {
openApi.getPaths().forEach((path, pathItem) -> {
log.info("path: {}", path);
// 检查当前路径是否在排除列表中
boolean isExcluded = excludedPaths.stream().anyMatch(excludedPath ->
excludedPath.equals(path) ||
(excludedPath.endsWith("**") && path.startsWith(excludedPath.substring(0, excludedPath.length() - 2)))
);
if (!isExcluded) {
// 接口添加鉴权参数
pathItem.readOperations()
.forEach(operation ->
operation.addSecurityItem(new SecurityRequirement().addList(CommonConstant.X_ACCESS_TOKEN))
);
}
});
}
};
}
@Bean
public OpenAPI customOpenAPI() {
return new OpenAPI()
.info(new Info()
.title("JeecgBoot 后台服务API接口文档")
.version("3.7.4")
.contact(new Contact().name("北京国炬信息技术有限公司").url("www.jeccg.com").email("jeecgos@163.com"))
.description( "后台API接口")
.termsOfService("NO terms of service")
.license(new License().name("Apache 2.0").url("http://www.apache.org/licenses/LICENSE-2.0.html")))
.addSecurityItem(new SecurityRequirement().addList(CommonConstant.X_ACCESS_TOKEN))
.components(new Components().addSecuritySchemes(CommonConstant.X_ACCESS_TOKEN,
new SecurityScheme().name(CommonConstant.X_ACCESS_TOKEN).type(SecurityScheme.Type.HTTP)));
}
}

@ -134,7 +134,7 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/swagger-ui.html", "anon"); filterChainDefinitionMap.put("/swagger-ui.html", "anon");
filterChainDefinitionMap.put("/swagger**/**", "anon"); filterChainDefinitionMap.put("/swagger**/**", "anon");
filterChainDefinitionMap.put("/webjars/**", "anon"); filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/v2/**", "anon"); filterChainDefinitionMap.put("/v3/**", "anon");
// update-begin--Author:sunjianlei Date:20210510 for排除消息通告查看详情页面用于第三方APP // update-begin--Author:sunjianlei Date:20210510 for排除消息通告查看详情页面用于第三方APP
filterChainDefinitionMap.put("/sys/annountCement/show/**", "anon"); filterChainDefinitionMap.put("/sys/annountCement/show/**", "anon");

@ -9,7 +9,7 @@ import com.unfbx.chatgpt.entity.chat.Message;
import com.unfbx.chatgpt.exception.BaseException; import com.unfbx.chatgpt.exception.BaseException;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils; import org.apache.shiro.SecurityUtils;
import org.jeecg.chatgpt.prop.AiChatProperties; import org.jeecg.ai.prop.AiChatProperties;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.exception.JeecgBootException; import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.LoginUser;

@ -73,7 +73,7 @@
<!-- Swagger API文档 --> <!-- Swagger API文档 -->
<dependency> <dependency>
<groupId>com.github.xiaoymin</groupId> <groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi2-spring-boot-starter</artifactId> <artifactId>knife4j-gateway-spring-boot-starter</artifactId>
<version>${knife4j-spring-boot-starter.version}</version> <version>${knife4j-spring-boot-starter.version}</version>
</dependency> </dependency>
<dependency> <dependency>

@ -1,6 +1,15 @@
server: server:
port: 9999 port: 9999
knife4j:
gateway:
enabled: true
strategy: discover
discover:
excluded-services: ${spring.application.name}
enabled: true
version: OpenAPI3
spring: spring:
application: application:
name: jeecg-gateway name: jeecg-gateway

@ -1,6 +1,11 @@
server: server:
port: 7001 port: 7001
springdoc:
packages-to-exclude:
- org.jeecg.modules.drag
- org.jeecg.modules.online
- org.jeecg.modules.jmreport
spring: spring:
application: application:
name: jeecg-system name: jeecg-system

Loading…
Cancel
Save