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