SwaggerConfiguration.java 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. /**
  2. * Copyright 2008-2009. Chongqing Communications Industry Services Co.,Ltd Information Technology Branch. All rights reserved. <a>http://www.crunii.com</a>
  3. */
  4. package com.crunii.micro.common.config;
  5. import com.crunii.micro.common.constants.CommonConstants;
  6. import com.crunii.micro.common.exception.BusinessException;
  7. import org.springframework.beans.factory.annotation.Value;
  8. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.Configuration;
  11. import org.springframework.util.AntPathMatcher;
  12. import org.springframework.util.Assert;
  13. import springfox.documentation.RequestHandler;
  14. import springfox.documentation.builders.ApiInfoBuilder;
  15. import springfox.documentation.builders.PathSelectors;
  16. import springfox.documentation.oas.annotations.EnableOpenApi;
  17. import springfox.documentation.service.*;
  18. import springfox.documentation.spi.DocumentationType;
  19. import springfox.documentation.spi.service.contexts.SecurityContext;
  20. import springfox.documentation.spring.web.plugins.Docket;
  21. import java.util.*;
  22. import java.util.function.Function;
  23. import java.util.function.Predicate;
  24. import java.util.stream.Collectors;
  25. /**
  26. * <pre>
  27. * 本地和测试环境需要api 生产环境安全原因不加载
  28. * </pre>
  29. *
  30. * @author 田平 create 2018年10月15日下午2:39:36
  31. */
  32. @Configuration
  33. @ConditionalOnProperty(name = "swagger.enabled", havingValue = "true")
  34. @EnableOpenApi
  35. public class SwaggerConfiguration {
  36. @Value("${spring.application.name}")
  37. private String appName;
  38. /**
  39. * <pre>
  40. * 可以单独指定一个特别的扫描路径,
  41. * 除非特殊情况,一般不建议使用
  42. * </pre>
  43. */
  44. @Value("${swagger.special.controller.package:NONE}")
  45. private String specialControllerPackage;
  46. private AntPathMatcher matcher = new AntPathMatcher();
  47. private static final String BASE_PKG_PREFIX = "com.crunii.micro.";
  48. private static final String BASE_PKG_SUFFIX = ".controller";
  49. public static final Map<String, String> PACKAGE_MAPPER = new HashMap<>();
  50. static {
  51. PACKAGE_MAPPER.put("service-", "service.");
  52. PACKAGE_MAPPER.put("intf-", "intf.");
  53. PACKAGE_MAPPER.put("module-", "module.");
  54. }
  55. @Bean
  56. public Docket createRestApi() {
  57. // 设置可以扫描多个包逗号分隔
  58. String packageStr = getControllerPackage(appName);
  59. if (!specialControllerPackage.equals("NONE")) {
  60. packageStr = packageStr + "," + specialControllerPackage;
  61. }
  62. return new Docket(DocumentationType.OAS_30)
  63. .apiInfo(apiInfo())
  64. .select()
  65. .apis(basePackage(packageStr))
  66. .paths(PathSelectors.any())
  67. .build()
  68. .securitySchemes(securitySchemes())
  69. .securityContexts(securityContexts());
  70. }
  71. private static String replaceLast(String text, String regex, String replacement) {
  72. return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", replacement);
  73. }
  74. public static void main(String[] args) {
  75. System.out.println(getControllerPackage("service-sysmgr"));
  76. System.out.println(getControllerPackage("intf-hlra-ws"));
  77. System.out.println(getControllerPackage("module-log-http"));
  78. }
  79. private static String getControllerPackage(String appName) {
  80. Assert.notNull(appName, "appName not allowed null!");
  81. String lower = appName.toLowerCase();
  82. String[] suffixes = lower.split("-");
  83. int length = suffixes.length;
  84. if (length == 1) {
  85. return BASE_PKG_PREFIX + lower + BASE_PKG_SUFFIX;
  86. } else {
  87. StringBuilder pkgs = new StringBuilder(BASE_PKG_PREFIX);
  88. pkgs.append(getPackage(lower));
  89. List<String> subs = new ArrayList<>();
  90. for (int i = 1; i < length; i++) {
  91. subs.add(suffixes[i]);
  92. pkgs.append(suffixes[i]);
  93. }
  94. pkgs.append(BASE_PKG_SUFFIX);
  95. String subsStr = subs.stream().collect(Collectors.joining("."));
  96. while (subsStr.indexOf(".") > -1) {
  97. StringBuilder sb = new StringBuilder(",");
  98. sb.append(BASE_PKG_PREFIX);
  99. sb.append(getPackage(lower));
  100. sb.append(subsStr);
  101. sb.append(BASE_PKG_SUFFIX);
  102. pkgs.append(sb);
  103. subsStr = replaceLast(subsStr.toString(), "\\.", "");
  104. }
  105. return pkgs.toString();
  106. }
  107. }
  108. public static String getPackage(String lower) {
  109. for (Map.Entry<String, String> entry : PACKAGE_MAPPER.entrySet()) {
  110. if (lower.startsWith(entry.getKey())) {
  111. return entry.getValue();
  112. }
  113. }
  114. throw new BusinessException("unsupported the project name prefix:{},please config in SwaggerConfig.PACKAGE_MAPPER", lower);
  115. }
  116. public static Predicate<RequestHandler> basePackage(final String basePackage) {
  117. return new Predicate<RequestHandler>() {
  118. @Override
  119. public boolean test(RequestHandler t) {
  120. return declaringClass(t).map(handlerPackage(basePackage)).orElse(true);
  121. }
  122. };
  123. }
  124. private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
  125. return input -> {
  126. for (String strPackage : basePackage.split(",")) {
  127. boolean isMatch = input.getPackage().getName().startsWith(strPackage);
  128. if (isMatch) {
  129. return true;
  130. }
  131. }
  132. return false;
  133. };
  134. }
  135. @SuppressWarnings("deprecation")
  136. private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
  137. return Optional.ofNullable(input.declaringClass());
  138. }
  139. private ApiInfo apiInfo() {
  140. return new ApiInfoBuilder().title(appName + " Rest Api").version("1.0").build();
  141. }
  142. private List<SecurityScheme> securitySchemes() {
  143. List<SecurityScheme> schemes = new ArrayList<>();
  144. schemes.add(new ApiKey("Authorization", "token", "header"));
  145. return schemes;
  146. }
  147. private List<SecurityContext> securityContexts() {
  148. return Arrays.asList(SecurityContext.builder()
  149. .securityReferences(defaultAuth())
  150. .operationSelector(ctx -> matcher.match(CommonConstants.AUTH_PATTERN, ctx.requestMappingPattern()))
  151. .build());
  152. }
  153. private List<SecurityReference> defaultAuth() {
  154. AuthorizationScope[] authorizationScopes = { new AuthorizationScope("global", "accessEverything") };
  155. return Arrays.asList(new SecurityReference("Authorization", authorizationScopes));
  156. }
  157. }