SwaggerExtentionSupport.java 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. package com.primeton.dgs.kernel.core.configure;
  2. import com.google.common.collect.Multimap;
  3. import com.google.common.collect.Sets;
  4. import com.google.common.net.MediaType;
  5. import com.primeton.dgs.kernel.core.web.AppBaseDispatchCommand;
  6. import org.apache.commons.lang.StringUtils;
  7. import org.slf4j.Logger;
  8. import org.slf4j.LoggerFactory;
  9. import org.springframework.beans.factory.annotation.Autowired;
  10. import org.springframework.beans.factory.annotation.Value;
  11. import org.springframework.context.ApplicationContext;
  12. import org.springframework.context.ApplicationListener;
  13. import org.springframework.context.event.ContextRefreshedEvent;
  14. import org.springframework.http.HttpMethod;
  15. import org.springframework.stereotype.Repository;
  16. import springfox.documentation.builders.ResponseMessageBuilder;
  17. import springfox.documentation.schema.ModelRef;
  18. import springfox.documentation.service.ApiDescription;
  19. import springfox.documentation.service.ApiListing;
  20. import springfox.documentation.service.Documentation;
  21. import springfox.documentation.service.Operation;
  22. import springfox.documentation.service.Parameter;
  23. import springfox.documentation.service.ResponseMessage;
  24. import springfox.documentation.service.Tag;
  25. import springfox.documentation.spring.web.DocumentationCache;
  26. import springfox.documentation.spring.web.json.JsonSerializer;
  27. import springfox.documentation.spring.web.plugins.Docket;
  28. import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
  29. import java.lang.reflect.Method;
  30. import java.lang.reflect.Modifier;
  31. import java.util.ArrayList;
  32. import java.util.Collection;
  33. import java.util.Collections;
  34. import java.util.HashMap;
  35. import java.util.HashSet;
  36. import java.util.Set;
  37. /**
  38. *
  39. *
  40. * 元数据老结构,支持 Swagger 适配器
  41. *
  42. * <pre>
  43. *
  44. * Created by zhaopx.
  45. * User: zhaopx
  46. * Date: 2020/8/28
  47. * Time: 14:34
  48. *
  49. * </pre>
  50. *
  51. * @author zhaopx
  52. */
  53. @Repository
  54. public class SwaggerExtentionSupport implements ApplicationListener<ContextRefreshedEvent> {
  55. /**
  56. * 版本
  57. */
  58. public final static String API_VER = "7.1.0";
  59. @Autowired
  60. DocumentationCache documentationCache;
  61. @Autowired
  62. private ServiceModelToSwagger2Mapper mapper;
  63. @Autowired
  64. private JsonSerializer jsonSerializer;
  65. @Value("${swagger.group}")
  66. private String groupName;
  67. private static Logger log = LoggerFactory.getLogger(SwaggerExtentionSupport.class);
  68. /**
  69. * 扫描 cotext 中 .do 的 bean,扫描 方法
  70. * @param context
  71. */
  72. private void initSwagger(ApplicationContext context) {
  73. Documentation documentation = documentationCache.documentationByGroup(groupName);
  74. if(documentation == null) {
  75. // 如果 groupName 指定的下没有,则挂载 default 上
  76. documentation = documentationCache.documentationByGroup(Docket.DEFAULT_GROUP_NAME);
  77. }
  78. if (documentation != null) {
  79. // 取得所有的 API 合集
  80. Multimap<String, ApiListing> apiListings = documentation.getApiListings();
  81. //Swagger swagger = mapper.mapDocumentation(documentation);
  82. String[] beanDefinitionNames = context.getBeanDefinitionNames();
  83. //String[] beanDefinitionNames = new String[]{"test.do", "param.do", "rule.do"};
  84. for (String name : beanDefinitionNames) {
  85. if(name.endsWith(".do")) {
  86. Class<?> aClass = context.getBean(name).getClass();
  87. if(!AppBaseDispatchCommand.class.isAssignableFrom(aClass)) {
  88. // 必须是 AppBaseDispatchCommand 的子类,才继续
  89. continue;
  90. }
  91. log.info("add swagger bean {}", name);
  92. Method[] servletMethods = aClass.getDeclaredMethods();
  93. for (Method servletMethod : servletMethods) {
  94. String methodName = servletMethod.getName();
  95. if(!"init".equals(methodName) && Modifier.isPublic(servletMethod.getModifiers())) {
  96. // 返回 tags
  97. Set<Tag> tags = addApi(apiListings, documentation.getBasePath(), name, methodName);
  98. if(!tags.isEmpty()) {
  99. documentation.getTags().addAll(tags);
  100. }
  101. }
  102. }
  103. }
  104. }
  105. log.info("swagger apis size: {}", apiListings.size());
  106. }
  107. }
  108. private Set<Tag> addApi(Multimap<String, ApiListing> apiListings,
  109. String basePath,
  110. String beanName,
  111. String methodName) {
  112. // 获取去除了 .do 的 名称
  113. String optGroup = getName(beanName);
  114. String apiId = optGroup + "_" + methodName;
  115. String optId = methodName;
  116. // 生成唯一ID
  117. Collection<ApiListing> apis = apiListings.get(apiId);
  118. if(apis == null) {
  119. // 后面只是用 apis 的 size 获取长度
  120. apis = new HashSet<>();
  121. }
  122. ArrayList<ApiDescription> apis1 = new ArrayList<>();
  123. ArrayList<Operation> operations = new ArrayList<>();
  124. ResponseMessage v200 = new ResponseMessageBuilder().code(200).message("OK").build();
  125. ResponseMessage v401 = new ResponseMessageBuilder().code(401).message("Unauthorized").build();
  126. ResponseMessage v403 = new ResponseMessageBuilder().code(403).message("Forbidden").build();
  127. ResponseMessage v404 = new ResponseMessageBuilder().code(404).message("Not Found").build();
  128. // tag
  129. HashSet<Tag> tags = new HashSet<>();
  130. // description 是生成 API JS 的文件名
  131. // optGroup 是生成的函数名
  132. Tag tag = new Tag(optGroup, optGroup + "Controller");
  133. tags.add(tag);
  134. // 注意 position,必须是不重复的值
  135. ArrayList<Parameter> parameters = new ArrayList<>();
  136. /*
  137. 暂时先不要参数
  138. Parameter parameter = new Parameter(
  139. "invoke",
  140. "Invoke Method",
  141. methodName,
  142. true,
  143. false,
  144. false,
  145. new ModelRef("string"),
  146. null, null,
  147. "string","", false, null, null, 0, null,
  148. ArrayListMultimap.create(),
  149. Collections.emptyList()
  150. );
  151. parameters.add(parameter);
  152. */
  153. /*
  154. Operation operaGet = new Operation(
  155. HttpMethod.GET,
  156. "do exec " + optGroup + "." + methodName,
  157. "",
  158. new ModelRef("string"),
  159. optId+"UsingGET",
  160. 0,
  161. Sets.newHashSet(tag.getName()),
  162. Sets.newHashSet(MediaType.ANY_TYPE.toString()),
  163. Sets.newHashSet(MediaType.create("application", "json").toString()),
  164. new HashSet<>(),
  165. new ArrayList<>(),
  166. parameters,
  167. Sets.newHashSet(v200, v401, v403, v404),
  168. "",
  169. false,
  170. new ArrayList<>()
  171. );
  172. */
  173. // Operation 只需要 tag name,他决定了该 api 在 Swagger 上挂载的tag
  174. Operation operaPost = new Operation(
  175. HttpMethod.POST,
  176. "do exec " + optGroup + "." + methodName,
  177. "",
  178. new ModelRef("string"),
  179. optId+"UsingPOST",
  180. 0,
  181. Sets.newHashSet(tag.getName()),
  182. Sets.newHashSet(MediaType.ANY_TYPE.toString()),
  183. Sets.newHashSet(MediaType.create("application", "json").toString()),
  184. new HashSet<>(),
  185. new ArrayList<>(),
  186. parameters,
  187. Sets.newHashSet(v200, v401, v403, v404),
  188. "",
  189. false,
  190. new ArrayList<>()
  191. );
  192. operations.add(operaPost);
  193. String url = "/appsapi/" + optGroup + "/" + methodName;
  194. apis1.add(new ApiDescription(groupName,
  195. url,
  196. beanName+"." + methodName,
  197. operations, false));
  198. // 注意 position,必须是不重复的值
  199. ApiListing apiListing = new ApiListing(
  200. API_VER,
  201. basePath,
  202. "/" + beanName,
  203. new HashSet<>(),new HashSet<>(),"", new HashSet<>(), new ArrayList<>(),
  204. apis1,
  205. new HashMap<>(), beanName+"." + methodName, apis.size(), tags);
  206. // 放到api列表中
  207. apiListings.put(apiId, apiListing);
  208. // 返回 tag,tag 会显示到 Swagger Content
  209. return tags;
  210. }
  211. private String getName(String beanName) {
  212. if(StringUtils.isBlank(beanName)) {
  213. return beanName;
  214. }
  215. int i = beanName.indexOf(".");
  216. if(i > 0) {
  217. return beanName.substring(0, i);
  218. }
  219. return beanName;
  220. }
  221. @Override
  222. public void onApplicationEvent(ContextRefreshedEvent event) {
  223. // Spring 框架加载完全后,扫描 bean,获取 servlet
  224. initSwagger(event.getApplicationContext());
  225. }
  226. }