SwaggerProvider.java 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package org.ssssssss.magicapi.swagger;
  2. import com.fasterxml.jackson.databind.ObjectMapper;
  3. import org.apache.commons.lang3.StringUtils;
  4. import org.springframework.util.CollectionUtils;
  5. import org.springframework.web.bind.annotation.ResponseBody;
  6. import org.ssssssss.magicapi.config.MappingHandlerMapping;
  7. import org.ssssssss.magicapi.model.ApiInfo;
  8. import org.ssssssss.magicapi.model.BaseDefinition;
  9. import org.ssssssss.magicapi.model.DataType;
  10. import org.ssssssss.magicapi.model.Path;
  11. import org.ssssssss.magicapi.provider.GroupServiceProvider;
  12. import org.ssssssss.script.parsing.ast.literal.BooleanLiteral;
  13. import java.util.*;
  14. import java.util.concurrent.ConcurrentHashMap;
  15. import static org.ssssssss.magicapi.model.Constants.*;
  16. /**
  17. * 生成swagger用的json
  18. */
  19. public class SwaggerProvider {
  20. private MappingHandlerMapping mappingHandlerMapping;
  21. /**
  22. * 基础路径
  23. */
  24. private String basePath;
  25. private GroupServiceProvider groupServiceProvider;
  26. private SwaggerEntity.Info info;
  27. /**
  28. * swagger Model定义路径前缀
  29. */
  30. private static final String DEFINITION = "#/definitions/";
  31. /**
  32. * body空对象
  33. */
  34. private static final String BODY_EMPTY = "{}";
  35. private final Map<String, Object> DEFINITION_MAP = new ConcurrentHashMap<>();
  36. public void setMappingHandlerMapping(MappingHandlerMapping mappingHandlerMapping) {
  37. this.mappingHandlerMapping = mappingHandlerMapping;
  38. }
  39. public void setGroupServiceProvider(GroupServiceProvider groupServiceProvider) {
  40. this.groupServiceProvider = groupServiceProvider;
  41. }
  42. public void setInfo(SwaggerEntity.Info info) {
  43. this.info = info;
  44. }
  45. public void setBasePath(String basePath) {
  46. this.basePath = basePath;
  47. }
  48. @ResponseBody
  49. public SwaggerEntity swaggerJson() {
  50. this.DEFINITION_MAP.clear();
  51. List<ApiInfo> infos = mappingHandlerMapping.getApiInfos();
  52. SwaggerEntity swaggerEntity = new SwaggerEntity();
  53. swaggerEntity.setInfo(info);
  54. swaggerEntity.setBasePath(this.basePath);
  55. ObjectMapper mapper = new ObjectMapper();
  56. for (ApiInfo info : infos) {
  57. String groupName = groupServiceProvider.getFullName(info.getGroupId()).replace("/", "-");
  58. String requestPath = "/" + mappingHandlerMapping.getRequestPath(info.getGroupId(), info.getPath());
  59. SwaggerEntity.Path path = new SwaggerEntity.Path();
  60. path.addTag(groupName);
  61. boolean hasBody = false;
  62. try {
  63. List<Map<String, Object>> parameters = parseParameters(mapper, info);
  64. hasBody = parameters.stream().anyMatch(it -> VAR_NAME_REQUEST_BODY.equals(it.get("in")));
  65. BaseDefinition baseDefinition = info.getRequestBodyDefinition();
  66. if (hasBody && baseDefinition != null) {
  67. doProcessDefinition(baseDefinition, info, "root_", "request", 0);
  68. }
  69. baseDefinition = info.getResponseBodyDefinition();
  70. parameters.forEach(path::addParameter);
  71. if (baseDefinition != null) {
  72. Map responseMap = parseResponse(info);
  73. if (!responseMap.isEmpty()) {
  74. path.setResponses(responseMap);
  75. doProcessDefinition(baseDefinition, info, "root_" + baseDefinition.getName(), "response", 0);
  76. }
  77. } else {
  78. path.addResponse("200", mapper.readValue(Objects.toString(info.getResponseBody(), BODY_EMPTY), Object.class));
  79. }
  80. } catch (Exception ignored) {
  81. }
  82. if (hasBody) {
  83. path.addConsume("application/json");
  84. } else {
  85. path.addConsume("*/*");
  86. }
  87. path.addProduce("application/json");
  88. path.setSummary(info.getName());
  89. path.setDescription(StringUtils.defaultIfBlank(info.getDescription(), info.getName()));
  90. swaggerEntity.addPath(requestPath, info.getMethod(), path);
  91. }
  92. if (this.DEFINITION_MAP.size() > 0) {
  93. Set<Map.Entry> entries = ((Map) this.DEFINITION_MAP).entrySet();
  94. for (Map.Entry entry : entries) {
  95. swaggerEntity.addDefinitions(Objects.toString(entry.getKey()), entry.getValue());
  96. }
  97. }
  98. return swaggerEntity;
  99. }
  100. private List<Map<String, Object>> parseParameters(ObjectMapper mapper, ApiInfo info) {
  101. List<Map<String, Object>> parameters = new ArrayList<>();
  102. info.getParameters().forEach(it -> parameters.add(SwaggerEntity.createParameter(it.isRequired(), it.getName(), VAR_NAME_QUERY, it.getDataType().getJavascriptType(), it.getDescription(), it.getValue())));
  103. info.getHeaders().forEach(it -> parameters.add(SwaggerEntity.createParameter(it.isRequired(), it.getName(), VAR_NAME_HEADER, it.getDataType().getJavascriptType(), it.getDescription(), it.getValue())));
  104. List<Path> paths = new ArrayList<>(info.getPaths());
  105. MappingHandlerMapping.findGroups(info.getGroupId())
  106. .stream()
  107. .flatMap(it -> it.getPaths().stream())
  108. .forEach(it -> {
  109. if (!paths.contains(it)) {
  110. paths.add(it);
  111. }
  112. });
  113. paths.forEach(it -> parameters.add(SwaggerEntity.createParameter(it.isRequired(), it.getName(), VAR_NAME_PATH_VARIABLE, it.getDataType().getJavascriptType(), it.getDescription(), it.getValue())));
  114. try {
  115. BaseDefinition baseDefinition = info.getRequestBodyDefinition();
  116. if (baseDefinition != null && !CollectionUtils.isEmpty(baseDefinition.getChildren())) {
  117. Map<String, Object> parameter = SwaggerEntity.createParameter(baseDefinition.isRequired(), StringUtils.isNotBlank(baseDefinition.getName()) ? baseDefinition.getName() : VAR_NAME_REQUEST_BODY, VAR_NAME_REQUEST_BODY, baseDefinition.getDataType().getJavascriptType(), baseDefinition.getDescription(), baseDefinition);
  118. Map<String, Object> schema = new HashMap<>(2);
  119. String groupName = groupServiceProvider.getFullName(info.getGroupId()).replace("/", "-");
  120. String voName = groupName + "«" + info.getPath().replaceFirst("/", "").replaceAll("/", "_") + "«request«";
  121. if (DataType.Array == baseDefinition.getDataType()) {
  122. voName += "root_" + (StringUtils.isNotBlank(baseDefinition.getName()) ? baseDefinition.getName() + "_" : "_") + "»»»";
  123. Map<String, Object> items = new HashMap<>(2);
  124. items.put("originalRef", voName);
  125. items.put("$ref", DEFINITION + voName);
  126. schema.put("items", items);
  127. schema.put("type", VAR_NAME_REQUEST_BODY_VALUE_TYPE_ARRAY);
  128. } else {
  129. voName += "root_" + baseDefinition.getName() + "»»»";
  130. schema.put("originalRef", voName);
  131. schema.put("$ref", DEFINITION + voName);
  132. }
  133. parameter.put("schema", schema);
  134. parameters.add(parameter);
  135. } else {
  136. Object object = mapper.readValue(info.getRequestBody(), Object.class);
  137. if ((object instanceof List || object instanceof Map) && BooleanLiteral.isTrue(object)) {
  138. parameters.add(SwaggerEntity.createParameter(false, VAR_NAME_REQUEST_BODY, VAR_NAME_REQUEST_BODY, object instanceof List ? VAR_NAME_REQUEST_BODY_VALUE_TYPE_ARRAY : VAR_NAME_REQUEST_BODY_VALUE_TYPE_OBJECT, null, object));
  139. }
  140. }
  141. } catch (Exception ignored) {
  142. }
  143. return parameters;
  144. }
  145. private Map<String, Object> parseResponse(ApiInfo info) {
  146. Map<String, Object> result = new HashMap<>();
  147. BaseDefinition baseDefinition = info.getResponseBodyDefinition();
  148. if (!CollectionUtils.isEmpty(baseDefinition.getChildren())) {
  149. String groupName = groupServiceProvider.getFullName(info.getGroupId()).replace("/", "-");
  150. String voName = groupName + "«" + info.getPath().replaceFirst("/", "").replaceAll("/", "_") + "«response«";
  151. voName += "root_" + baseDefinition.getName() + "»»»";
  152. Map<String, Object> schema = new HashMap<>(2);
  153. schema.put("originalRef", voName);
  154. schema.put("$ref", DEFINITION + voName);
  155. Map<String, Object> response = new HashMap<>(2);
  156. response.put("description", "OK");
  157. response.put("schema", schema);
  158. result.put("200", response);
  159. }
  160. return result;
  161. }
  162. private Map<String, Object> doProcessDefinition(BaseDefinition target, ApiInfo info, String parentName, String definitionType, int level) {
  163. Map<String, Object> result = new HashMap<>(4);
  164. result.put("description", target.getDescription());
  165. if (DataType.Array == target.getDataType()) {
  166. if (!CollectionUtils.isEmpty(target.getChildren())) {
  167. result.put("items", doProcessDefinition(target.getChildren().get(0), info, parentName + target.getName() + "_", definitionType, level + 1));
  168. } else {
  169. result.put("items", Collections.emptyList());
  170. }
  171. result.put("type", target.getDataType().getJavascriptType());
  172. } else if (DataType.Object == target.getDataType()) {
  173. String groupName = groupServiceProvider.getFullName(info.getGroupId()).replace("/", "-");
  174. String voName = groupName + "«" + info.getPath().replaceFirst("/", "").replaceAll("/", "_") + (StringUtils.equals("response", definitionType) ? "«response«" : "«request«") + parentName + target.getName() + "»»»";
  175. Map<String, Object> definition = new HashMap<>(4);
  176. Map<String, Map<String, Object>> properties = new HashMap<>(target.getChildren().size());
  177. Set<String> requiredSet = new HashSet <>(target.getChildren().size());
  178. for (BaseDefinition obj : target.getChildren()) {
  179. properties.put(obj.getName(), doProcessDefinition(obj, info, parentName + target.getName() + "_", definitionType, level + 1));
  180. if (obj.isRequired()) {
  181. requiredSet.add(obj.getName());
  182. }
  183. }
  184. definition.put("properties", properties);
  185. definition.put("description", target.getDescription());
  186. definition.put("type", target.getDataType().getJavascriptType());
  187. definition.put("required", requiredSet);
  188. if (this.DEFINITION_MAP.containsKey(voName)) {
  189. // TODO 应该不会出现名字都一样的
  190. voName = voName.replace("»»»", "_" + level + "»»»");
  191. }
  192. this.DEFINITION_MAP.put(voName, definition);
  193. result.put("originalRef", voName);
  194. result.put("$ref", DEFINITION + voName);
  195. } else {
  196. result.put("example", target.getValue());
  197. result.put("type", target.getDataType().getJavascriptType());
  198. }
  199. return result;
  200. }
  201. }