From 59ecaf44773a8ce2f3cd9450bbc2fcd9943c374e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9A=AE=E5=85=89=EF=BC=9A=E5=9F=8E=E4=B8=AD=E5=9F=8E?= <806783409@qq.com> Date: Thu, 28 Oct 2021 23:25:12 +0800 Subject: [PATCH] =?UTF-8?q?swagger=E5=B7=B2=E5=AE=9E=E7=8E=B0=E6=96=87?= =?UTF-8?q?=E6=A1=A3=E7=9A=84=E5=8F=82=E6=95=B0=E5=92=8C=E8=BF=94=E5=9B=9E?= =?UTF-8?q?=E5=80=BC=E6=9F=A5=E7=9C=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/SwaggerDocumentController.java | 15 -- .../SwaggerGlobalParamController.java | 23 +- .../service/SwaggerHttpRequestService.java | 18 +- .../swagger-ui/src/api/zyplayer.js | 2 + .../src/assets/utils/SwaggerAnalysis.js | 228 ++++++++++++++++++ .../src/assets/utils/SwaggerAnalysisV2.js | 146 +++++++++++ .../swagger-ui/src/assets/utils/formatjson.js | 125 ++++++++++ .../src/components/layouts/MenuLayout.vue | 13 +- zyplayer-doc-ui/swagger-ui/src/routes.js | 10 +- .../swagger-ui/src/store/SwaggerDocUtil.js | 199 ++++++--------- zyplayer-doc-ui/swagger-ui/src/store/index.js | 6 +- .../swagger-ui/src/views/doc/DocManage.vue | 43 +--- .../swagger-ui/src/views/doc/DocView.vue | 128 +++++++++- .../swagger-ui/src/views/doc/GlobalParam.vue | 119 +++++++++ 14 files changed, 869 insertions(+), 206 deletions(-) create mode 100644 zyplayer-doc-ui/swagger-ui/src/assets/utils/SwaggerAnalysis.js create mode 100644 zyplayer-doc-ui/swagger-ui/src/assets/utils/SwaggerAnalysisV2.js create mode 100644 zyplayer-doc-ui/swagger-ui/src/assets/utils/formatjson.js create mode 100644 zyplayer-doc-ui/swagger-ui/src/views/doc/GlobalParam.vue diff --git a/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/controller/SwaggerDocumentController.java b/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/controller/SwaggerDocumentController.java index 769026f8..165a293f 100644 --- a/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/controller/SwaggerDocumentController.java +++ b/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/controller/SwaggerDocumentController.java @@ -128,19 +128,4 @@ public class SwaggerDocumentController { swaggerDocService.updateById(swaggerDocUp); return DocResponseJson.ok(); } - - /** - * 获取文档内容 - * - * @return 文档内容 - * @author 暮光:城中城 - * @since 2021年10月16日 - */ - @ResponseBody - @PostMapping(value = "/content") - public ResponseJson> content(HttpServletRequest request, String docUrl) { - String contentStr = swaggerHttpRequestService.requestUrl(request, docUrl); - return DocResponseJson.ok(contentStr); - } - } diff --git a/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/controller/SwaggerGlobalParamController.java b/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/controller/SwaggerGlobalParamController.java index 43d43e4f..b68dd6f5 100644 --- a/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/controller/SwaggerGlobalParamController.java +++ b/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/controller/SwaggerGlobalParamController.java @@ -5,6 +5,8 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.zyplayer.doc.core.annotation.AuthMan; import com.zyplayer.doc.core.json.DocResponseJson; import com.zyplayer.doc.core.json.ResponseJson; +import com.zyplayer.doc.data.config.security.DocUserDetails; +import com.zyplayer.doc.data.config.security.DocUserUtil; import com.zyplayer.doc.data.repository.manage.entity.SwaggerDoc; import com.zyplayer.doc.data.repository.manage.entity.SwaggerGlobalParam; import com.zyplayer.doc.data.service.manage.SwaggerGlobalParamService; @@ -16,6 +18,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; +import java.util.Date; import java.util.List; import java.util.Objects; import java.util.stream.Collectors; @@ -60,17 +63,15 @@ public class SwaggerGlobalParamController { */ @ResponseBody @PostMapping(value = "/update") - public ResponseJson> update(String globalParam) { - List newParamList = JSON.parseArray(globalParam, SwaggerGlobalParam.class); - QueryWrapper queryWrapper = new QueryWrapper<>(); - queryWrapper.eq("yn", 1); - List queryParamList = swaggerGlobalParamService.list(queryWrapper); - List newIdList = newParamList.stream().map(SwaggerGlobalParam::getId).filter(Objects::nonNull).collect(Collectors.toList()); - List deletedList = queryParamList.stream().map(SwaggerGlobalParam::getId).filter(id -> !newIdList.contains(id)).collect(Collectors.toList()); - // 删除不存在的 - swaggerGlobalParamService.removeByIds(deletedList); - // 保存或更新的 - swaggerGlobalParamService.saveOrUpdateBatch(newParamList); + public ResponseJson> update(SwaggerGlobalParam globalParam) { + if (globalParam.getId() == null) { + DocUserDetails currentUser = DocUserUtil.getCurrentUser(); + globalParam.setYn(1); + globalParam.setCreateTime(new Date()); + globalParam.setCreateUserId(currentUser.getUserId()); + globalParam.setCreateUserName(currentUser.getUsername()); + } + swaggerGlobalParamService.saveOrUpdate(globalParam); return DocResponseJson.ok(); } } diff --git a/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/service/SwaggerHttpRequestService.java b/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/service/SwaggerHttpRequestService.java index e581b4c2..24bfd428 100644 --- a/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/service/SwaggerHttpRequestService.java +++ b/zyplayer-doc-swagger-plus/src/main/java/com/zyplayer/doc/swaggerplus/service/SwaggerHttpRequestService.java @@ -3,6 +3,7 @@ package com.zyplayer.doc.swaggerplus.service; import cn.hutool.http.HttpRequest; import com.zyplayer.doc.data.repository.manage.entity.SwaggerGlobalParam; import com.zyplayer.doc.data.service.manage.SwaggerGlobalParamService; +import org.apache.commons.collections.MapUtils; import org.springframework.stereotype.Service; import javax.annotation.Resource; @@ -27,25 +28,26 @@ public class SwaggerHttpRequestService { .collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue)); Map globalHeaderParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 2)) .collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue)); - + Map globalCookieParamMap = globalParamList.stream().filter(item -> Objects.equals(item.getParamType(), 3)) + .collect(Collectors.toMap(SwaggerGlobalParam::getParamKey, SwaggerGlobalParam::getParamValue)); + // 执行请求 String resultStr = HttpRequest.get(docUrl) .form(globalFormParamMap) .header("Accept", "application/json, text/javascript, */*; q=0.01") .header("User-Agent", request.getHeader("User-Agent")) .addHeaders(globalHeaderParamMap) - .cookie(this.getHttpCookie(request)) + .cookie(this.getHttpCookie(request, globalCookieParamMap)) .timeout(5000).execute().body(); return resultStr; } - private List getHttpCookie(HttpServletRequest request) { + private List getHttpCookie(HttpServletRequest request, Map globalCookieParamMap) { List httpCookies = new LinkedList<>(); for (Cookie cookie : request.getCookies()) { - HttpCookie httpCookie = new HttpCookie(cookie.getName(), cookie.getValue()); - httpCookie.setDomain(cookie.getDomain()); - httpCookie.setPath(cookie.getPath()); - httpCookie.setMaxAge(cookie.getMaxAge()); - httpCookies.add(httpCookie); + httpCookies.add(new HttpCookie(cookie.getName(), cookie.getValue())); + } + if (MapUtils.isNotEmpty(globalCookieParamMap)) { + globalCookieParamMap.forEach((key, value) -> httpCookies.add(new HttpCookie(key, value))); } return httpCookies; } diff --git a/zyplayer-doc-ui/swagger-ui/src/api/zyplayer.js b/zyplayer-doc-ui/swagger-ui/src/api/zyplayer.js index f5c64a61..a42a464c 100644 --- a/zyplayer-doc-ui/swagger-ui/src/api/zyplayer.js +++ b/zyplayer-doc-ui/swagger-ui/src/api/zyplayer.js @@ -7,5 +7,7 @@ export const zyplayerApi = { swaggerDocList: data => apiClient({url: '/doc-swagger/doc/list', method: 'post', data: data}), swaggerDocAdd: data => apiClient({url: '/doc-swagger/doc/add', method: 'post', data: data}), swaggerDocUpdate: data => apiClient({url: '/doc-swagger/doc/update', method: 'post', data: data}), + docSwaggerGlobalParamList: data => apiClient({url: '/doc-swagger/global-param/list', method: 'post', data: data}), + docSwaggerGlobalParamUpdate: data => apiClient({url: '/doc-swagger/global-param/update', method: 'post', data: data}), }; diff --git a/zyplayer-doc-ui/swagger-ui/src/assets/utils/SwaggerAnalysis.js b/zyplayer-doc-ui/swagger-ui/src/assets/utils/SwaggerAnalysis.js new file mode 100644 index 00000000..8170ec70 --- /dev/null +++ b/zyplayer-doc-ui/swagger-ui/src/assets/utils/SwaggerAnalysis.js @@ -0,0 +1,228 @@ +import formatjson from '../../assets/utils/formatjson' + +/** + * 参数解析 + * @author 暮光:城中城 + * @since 2017年5月7日 + */ +export default { + getRequestParamList(parameters, definitionsDataMap) { + if (!parameters) { + return []; + } + formatjson.annotationObject = {}; + let requestParamList = [], requestParamExample = []; + Object.keys(parameters).forEach(key => { + let tempParameters = parameters[key]; + let htmlStr = "", htmlStrExample = ""; + let responsesJson = []; + let responsesExample = []; + let required = tempParameters.required; + let paramName = tempParameters.name || ''; + let paramType = tempParameters.type || ''; + let paramDesc = tempParameters.description || ''; + let paramIn = tempParameters.in || ''; + let example = tempParameters.example || tempParameters.default || ''; + if (tempParameters.items) { + htmlStr = paramName + "[0]"; + htmlStrExample = paramName + "[0]"; + } else if (tempParameters.schema) { + if ("array" === tempParameters.schema.type) { + let responsesObj = definitionsDataMap[tempParameters.schema.items.$ref]; + if (responsesObj != null) { + responsesJson[0] = this.getResponsesJson(responsesObj, "", false, 1, definitionsDataMap); + responsesExample[0] = this.getResponsesJson(responsesObj, "", true, 1, definitionsDataMap); + } else { + responsesJson = [""]; + responsesExample = [""]; + if (tempParameters.schema.items.type === "boolean") { + responsesJson = [true]; + responsesExample = [true]; + } else if (tempParameters.schema.items.type === "integer") { + responsesJson = [0]; + responsesExample = [0]; + } + } + if (tempParameters.schema.$ref) { + let arrTmp = tempParameters.schema.$ref.split("/"); + paramType = arrTmp[arrTmp.length - 1]; + } + htmlStr = formatjson.processObjectToHtmlPre(responsesJson, 0, false, false, false, true); + htmlStrExample = formatjson.processObjectToHtmlPre(responsesExample, 0, false, false, false, false); + } else if (tempParameters.schema.$ref) { + let responsesObj = definitionsDataMap[tempParameters.schema.$ref]; + if (tempParameters.schema.$ref) { + let arrTmp = tempParameters.schema.$ref.split("/"); + paramType = arrTmp[arrTmp.length - 1]; + } + if (responsesObj) { + responsesJson = this.getResponsesJson(responsesObj, "", false, 1, definitionsDataMap); + responsesExample = this.getResponsesJson(responsesObj, "", true, 1, definitionsDataMap); + htmlStr = formatjson.processObjectToHtmlPre(responsesJson, 0, false, false, false, true); + htmlStrExample = formatjson.processObjectToHtmlPre(responsesExample, 0, false, false, false, false); + } else { + htmlStr = paramName; + htmlStrExample = paramName; + } + } else if ("string" === tempParameters.schema.type) { + htmlStr = paramName; + htmlStrExample = paramName; + } else { + htmlStr = paramName; + htmlStrExample = paramName; + } + } else { + htmlStr = paramName; + htmlStrExample = paramName; + } + requestParamList.push({htmlStr, paramDesc, paramType, paramIn, required}); + requestParamExample.push({htmlStrExample, paramDesc, paramType, paramIn, required}); + }); + console.log(requestParamList); + console.log(requestParamExample); + return requestParamList; + }, + getResponsesJson(responsesObj, prevRef, isExample, recursiveCount, definitionsDataMap) { + let responsesJson = {}; + recursiveCount++;// 多层递归,最多递归10层,防止无限递归 + if (!responsesObj || !responsesObj.properties || recursiveCount > 10) { + return responsesJson; + } + let requiredArr = responsesObj.required; + Object.keys(responsesObj.properties).forEach(prop => { + let tmpData = responsesObj.properties[prop]; + if ("array" === tmpData.type) {// 数组 + formatjson.annotationObject[prop] = tmpData.description || ''; + if (prevRef !== tmpData.items.$ref) { + let tempObj = definitionsDataMap[tmpData.items.$ref]; + if (tempObj != null) { + let tempArr = responsesJson[prop] = []; + tempArr[0] = this.getResponsesJson(tempObj, tmpData.items.$ref, isExample, recursiveCount, definitionsDataMap); + } else { + let responsesJsonSub = []; + let bodyFor = responsesJsonSub; + let items = tmpData.items; + for (let i = 0; i < 10; i++) { + if ("array" === items.type) { + bodyFor = bodyFor[0] = []; + items = items.items; + } else { + tempObj = definitionsDataMap[items.$ref]; + if (tempObj != null) { + bodyFor[0] = this.getResponsesJson(tempObj, items.$ref, isExample, recursiveCount, definitionsDataMap); + } else { + if (items.type === "boolean") { + bodyFor[0] = true; + } else if (items.type === "integer") { + bodyFor[0] = 0; + } else { + bodyFor[0] = ""; + } + } + break; + } + } + responsesJson[prop] = responsesJsonSub; + } + } else { + responsesJson[prop] = "{}" + (tmpData.description || ''); + } + } else if (tmpData.$ref) {// 对象 + formatjson.annotationObject[prop] = tmpData.description || ''; + if (prevRef !== tmpData.$ref) { + let tempObj = definitionsDataMap[tmpData.$ref]; + responsesJson[prop] = this.getResponsesJson(tempObj, tmpData.$ref, isExample, recursiveCount, definitionsDataMap); + } else { + responsesJson[prop] = "{}" + (tmpData.description || ''); + } + } else {// 字段 + let enumExample = ""; + let enumObj = tmpData["enum"]; + if (enumObj && enumObj.length > 0) { + enumExample = "枚举值:"; + for (let i = 0; i < enumObj.length; i++) { + if (i > 0) { + enumExample += "、"; + } + enumExample += enumObj[i]; + } + } + let typeStr = tmpData.format || tmpData.type || ''; + if (isExample) { + let tempVal = tmpData.example || ''; + if (tempVal && enumExample) { + tempVal = tempVal + "," + enumExample; + } + responsesJson[prop] = tempVal; + } else { + if (requiredArr && requiredArr.indexOf(prop) >= 0) { + typeStr = (typeStr ? typeStr + "," : "") + "required"; + } + if (typeStr) { + typeStr = "(" + typeStr + ")"; + } + let descriptionStr = typeStr + tmpData.description || ''; + if (descriptionStr && enumExample) { + descriptionStr = descriptionStr + "," + enumExample; + } + responsesJson[prop] = descriptionStr; + } + } + }); + return responsesJson; + }, + getResponseParamList(responses, definitionsDataMap) { + if (!responses) { + return []; + } + let responsesList = []; + formatjson.annotationObject = {}; + Object.keys(responses).forEach(key => { + let tempRespones = responses[key]; + if (tempRespones.schema) { + let responsesJson, responsesExample; + if ("array" === tempRespones.schema.type) { + responsesJson = []; + responsesExample = []; + let responsesObj = definitionsDataMap[tempRespones.schema.items.$ref]; + if (responsesObj != null) { + responsesJson[0] = this.getResponsesJson(responsesObj, "", false, 1, definitionsDataMap); + responsesExample[0] = this.getResponsesJson(responsesObj, "", true, 1, definitionsDataMap); + } else { + responsesJson = [""]; + responsesExample = [""]; + if (tempRespones.schema.items.type === "boolean") { + responsesJson = [true]; + responsesExample = [true]; + } else if (tempRespones.schema.items.type === "integer") { + responsesJson = [0]; + responsesExample = [0]; + } + } + } else if (tempRespones.schema.$ref) { + let responsesObj = definitionsDataMap[tempRespones.schema.$ref]; + if (!responsesObj) { + let arrTmp = tempRespones.schema.$ref.split("/"); + let lastObjName = arrTmp[arrTmp.length - 1]; + responsesJson = lastObjName; + responsesExample = lastObjName; + } else { + responsesJson = this.getResponsesJson(responsesObj, "", false, 1, definitionsDataMap); + responsesExample = this.getResponsesJson(responsesObj, "", true, 1, definitionsDataMap); + } + } else { + responsesJson = ""; + responsesExample = ""; + } + if (!responsesJson) { + return; + } + let htmlStr = formatjson.processObjectToHtmlPre(responsesJson, 0, false, false, false, true); + responsesList.push({code: key, desc: htmlStr}); + htmlStr = formatjson.processObjectToHtmlPre(responsesExample, 0, false, false, false, false); + } + }); + return responsesList; + } +} + diff --git a/zyplayer-doc-ui/swagger-ui/src/assets/utils/SwaggerAnalysisV2.js b/zyplayer-doc-ui/swagger-ui/src/assets/utils/SwaggerAnalysisV2.js new file mode 100644 index 00000000..10a4fc88 --- /dev/null +++ b/zyplayer-doc-ui/swagger-ui/src/assets/utils/SwaggerAnalysisV2.js @@ -0,0 +1,146 @@ +import {message} from 'ant-design-vue'; +// 无需特殊处理的参数类型 +let notNeedHandleTypeArr = ['file', 'string', 'integer', 'long', 'double', 'object', 'number', 'boolean']; +/** + * 参数解析 + * @author 暮光:城中城 + * @since 2017年5月7日 + */ +export default { + getRequestParamList(parameters, definitionsDataMap) { + if (!parameters) { + return []; + } + let indexKey = 1; + let requestParamList = []; + for (let i = 0; i < parameters.length; i++) { + let parameter = parameters[i]; + let type = parameter.type; + let subType = undefined; + let children = undefined; + if (!type) { + if (parameter.schema && parameter.schema.type) { + type = parameter.schema.type; + } + } + if (type === 'array') { + // 解析parameter.items.$ref 或 parameter.items.originalRef {$ref: "#/definitions/Model", originalRef: "Model"} + // 解析parameter.items.type {type: 'file'} + if (parameter.items && parameter.items.originalRef) { + children = this.getParamDefinitions(parameter.items.originalRef, definitionsDataMap, indexKey, {}, 0); + } else if (parameter.schema && parameter.schema.items && parameter.schema.items.originalRef) { + children = this.getParamDefinitions(parameter.schema.items.originalRef, definitionsDataMap, indexKey, {}, 0); + } else if (parameter.items && parameter.items.type) { + subType = parameter.items.type; + } else { + console.log('001-遇到未处理的类型,请联系开发人员修改:' + type, parameter); + message.error('001-遇到未处理的类型,请联系开发人员修改:' + type); + } + } else if (!type) { + if (parameter.schema && parameter.schema.originalRef) { + // 解析parameter.schema {originalRef: "Model", $ref: "#/definitions/Model"} + type = parameter.schema.originalRef; + children = this.getParamDefinitions(type, definitionsDataMap, indexKey, {}, 0); + } else { + console.log('002-遇到未处理的类型,请联系开发人员修改:' + type, parameter); + message.error('002-遇到未处理的类型,请联系开发人员修改:' + type); + } + } else { + if (notNeedHandleTypeArr.indexOf(type) >= 0) { + // 无需特殊处理的类型 + } else { + console.log('003-遇到未处理的类型,请联系开发人员修改:' + type, parameter); + message.error('003-遇到未处理的类型,请联系开发人员修改:' + type); + } + } + requestParamList.push({ + type: type, + key: indexKey, + in: parameter.in, + name: parameter.name, + required: parameter.required ? '是' : '否', + description: parameter.description, + children: children, + }); + indexKey++; + } + return requestParamList; + }, + getResponseParamList(responses, definitionsDataMap) { + let responsesList = []; + let indexKey = 1; + Object.keys(responses).forEach(code => { + let codeResponses = responses[code]; + let type = undefined; + let children = undefined; + if (codeResponses.schema && codeResponses.schema.originalRef) { + type = codeResponses.schema.originalRef; + children = this.getParamDefinitions(codeResponses.schema.originalRef, definitionsDataMap, indexKey, {}, 0); + } + responsesList.push({ + code: code, + type: type, + key: indexKey, + desc: codeResponses.description, + schemas: children, + }); + indexKey++; + }); + return responsesList; + }, + getParamDefinitions(ref, definitionsDataMap, indexKey, parentRef, deep) { + let definition = definitionsDataMap[ref]; + // 层级大于5层 或 父节点已经解析过此类型了 或者 没有类型定义 + if (deep >= 5 || parentRef[ref] || !definition) { + return undefined; + } + parentRef[ref] = 1; + let paramList = []; + let type = definition.type; + let properties = definition.properties; + let indexSub = 1; + if (type === 'object') { + Object.keys(properties).forEach(key => { + let parameter = properties[key]; + let type = parameter.type; + let keySub = indexKey + '_' + indexSub; + let children = undefined; + if (type === 'array') { + // 解析parameter.items {originalRef: "Model", $ref: "#/definitions/Model"} + if (parameter.items && parameter.items.originalRef) { + children = this.getParamDefinitions(parameter.items.originalRef, definitionsDataMap, keySub, parentRef, deep + 1); + } else { + console.log('004-遇到未处理的类型,请联系开发人员修改:' + type, parameter); + message.error('004-遇到未处理的类型,请联系开发人员修改:' + type); + } + } else if (!type) { + if (parameter.originalRef) { + type = parameter.originalRef; + children = this.getParamDefinitions(parameter.originalRef, definitionsDataMap, keySub, parentRef, deep + 1); + } else { + console.log('005-遇到未处理的类型,请联系开发人员修改:' + type, parameter); + message.error('005-遇到未处理的类型,请联系开发人员修改:' + type); + } + } else { + if (notNeedHandleTypeArr.indexOf(type) >= 0) { + // 无需特殊处理的类型 + } else { + console.log('006-遇到未处理的类型,请联系开发人员修改:' + type, parameter); + message.error('006-遇到未处理的类型,请联系开发人员修改:' + type); + } + } + paramList.push({ + type: type, + name: key, + key: keySub, + description: parameter.description, + children: children, + }); + indexSub++; + }); + } + return paramList.length > 0 ? paramList : undefined; + }, + +} + diff --git a/zyplayer-doc-ui/swagger-ui/src/assets/utils/formatjson.js b/zyplayer-doc-ui/swagger-ui/src/assets/utils/formatjson.js new file mode 100644 index 00000000..db24f3d3 --- /dev/null +++ b/zyplayer-doc-ui/swagger-ui/src/assets/utils/formatjson.js @@ -0,0 +1,125 @@ + +/** + * 将对象处理成json格式化和着色的html + * @author 暮光:城中城 + * @since 2017年5月7日 + */ +export default { + // 需要在对象或列表后面添加注释的对象,例:{userList: "用户列表"} + // 那么在名字为userList的对象或列表后面都会加上:“用户列表” 这个注释 + annotationObject: {}, + tabStr: " ", + isArray: function(obj) { + return obj && typeof obj === 'object' && typeof obj.length === 'number' + && !(obj.propertyIsEnumerable('length')); + }, + processObjectToHtmlPre: function(obj, indent, addComma, isArray, isPropertyContent, showAnnotation) { + let htmlStr = this.processObject(obj, "", indent, addComma, isArray, isPropertyContent, showAnnotation); + htmlStr = '
' + htmlStr + '
'; + return htmlStr; + }, + processObject: function(obj, keyName, indent, addComma, isArray, isPropertyContent, showAnnotation) { + let html = ""; + let comma = (addComma) ? ", " : ""; + let type = typeof obj; + if (this.isArray(obj)) { + if (obj.length === 0) { + html += this.getRow(indent, "[ ]" + comma, isPropertyContent); + } else { + let clpsHtml = ''; + let annotation = ''; + if(showAnnotation && keyName && this.annotationObject[keyName]) { + annotation = '// '+this.annotationObject[keyName]+''; + } + html += this.getRow(indent, "["+clpsHtml+annotation, isPropertyContent); + for (let i = 0; i < obj.length; i++) { + html += this.processObject(obj[i], "", indent + 1, i < (obj.length - 1), true, false, showAnnotation); + } + clpsHtml = ""; + html += this.getRow(indent, clpsHtml + "]" + comma); + } + } else if (type === 'object' && obj == null) { + html += this.formatLiteral("null", "", comma, indent, isArray, "null"); + } else if (type === 'object') { + let numProps = 0; + for ( let prop in obj) { + numProps++; + } + if (numProps === 0) { + html += this.getRow(indent, "{ }" + comma, isPropertyContent); + } else { + let clpsHtml = ''; + let annotation = ''; + if(showAnnotation && keyName && this.annotationObject[keyName]) { + annotation = '// '+this.annotationObject[keyName]+''; + } + html += this.getRow(indent, "{"+clpsHtml+annotation, isPropertyContent); + let j = 0; + for ( let prop in obj) { + let processStr = '"' + prop + '": ' + this.processObject(obj[prop], prop, indent + 1, ++j < numProps, false, true, showAnnotation); + html += this.getRow(indent + 1, processStr); + } + clpsHtml = ""; + html += this.getRow(indent, clpsHtml + "}" + comma); + } + } else if (type === 'number') { + html += this.formatLiteral(obj, "", comma, indent, isArray, "number"); + } else if (type === 'boolean') { + html += this.formatLiteral(obj, "", comma, indent, isArray, "boolean"); + } else if (type === 'function') { + obj = this.formatFunction(indent, obj); + html += this.formatLiteral(obj, "", comma, indent, isArray, "function"); + } else if (type === 'undefined') { + html += this.formatLiteral("undefined", "", comma, indent, isArray, "null"); + } else { + html += this.formatLiteral(obj, "\"", comma, indent, isArray, "string"); + } + return html; + }, + expImgClicked: function(img){ + let container = img.parentNode.nextSibling; + if(!container) return; + let disp = "none"; + let src = "webjars/mg-ui/img/collapsed.png"; + if(container.style.display === "none"){ + disp = "inline"; + src = "webjars/mg-ui/img/expanded.png"; + } + container.style.display = disp; + img.src = src; + }, + formatLiteral: function(literal, quote, comma, indent, isArray, style) { + if (typeof literal == 'string') { + literal = literal.split("<").join("<").split(">").join(">"); + } + let str = "" + quote + literal + quote + comma + ""; + if (isArray) { + str = this.getRow(indent, str); + } + return str; + }, + formatFunction: function(indent, obj) { + let tabs = ""; + for (let i = 0; i < indent; i++) { + tabs += this.tabStr; + } + let funcStrArray = obj.toString().split("\n"); + let str = ""; + for (let i = 0; i < funcStrArray.length; i++) { + str += ((i === 0) ? "" : tabs) + funcStrArray[i] + "\n"; + } + return str; + }, + getRow: function(indent, data, isPropertyContent) { + let tabs = ""; + for (let i = 0; i < indent && !isPropertyContent; i++) { + tabs += this.tabStr; + } + if (data != null && data.length > 0 && data.charAt(data.length - 1) !== "\n") { + data = data + "\n"; + } + return tabs + data; + } + +} + diff --git a/zyplayer-doc-ui/swagger-ui/src/components/layouts/MenuLayout.vue b/zyplayer-doc-ui/swagger-ui/src/components/layouts/MenuLayout.vue index edaa1501..c2cc68bc 100644 --- a/zyplayer-doc-ui/swagger-ui/src/components/layouts/MenuLayout.vue +++ b/zyplayer-doc-ui/swagger-ui/src/components/layouts/MenuLayout.vue @@ -75,6 +75,11 @@ if (matched.length >= 1) { this.openKeys = [matched[1].path]; } + // 加载初始化的地址 + if (this.$route.path === '/doc/view' && this.$route.query.url) { + this.swaggerDocChoice = this.$route.query.url; + this.swaggerDocChoiceChange(); + } this.getSwaggerResourceList(); }, methods: { @@ -111,10 +116,10 @@ } this.$store.commit('setSwaggerDoc', v2Doc); let metaInfo = {url}; - let treeData = createTreeViewByTag(v2Doc); - this.treeData = getTreeDataForTag(v2Doc, treeData.pathIndex, metaInfo); - this.$store.commit('setSwaggerTreePathMap', treeData.treePathDataMap); - setTimeout(() => this.treeDataLoading = false, 300); + let treeData = createTreeViewByTag(v2Doc, ''); + this.treeData = getTreeDataForTag(v2Doc, treeData.pathData, metaInfo); + this.$store.commit('setSwaggerTreePathMap', treeData.pathDataMap); + setTimeout(() => this.treeDataLoading = false, 100); }); }, toJsonObj(value) { diff --git a/zyplayer-doc-ui/swagger-ui/src/routes.js b/zyplayer-doc-ui/swagger-ui/src/routes.js index 221d28de..959732e3 100644 --- a/zyplayer-doc-ui/swagger-ui/src/routes.js +++ b/zyplayer-doc-ui/swagger-ui/src/routes.js @@ -23,7 +23,7 @@ let routers = [ }, { path: '/doc/manage', - name: '文档管理', + name: '文档地址管理', meta: { icon: 'FileTextOutlined' }, @@ -37,9 +37,17 @@ let routers = [ }, component: EmptyLayout, children: [ + { + path: '/doc/setting/globalParam', + name: '全局参数', + component: () => import('./views/doc/GlobalParam.vue') + }, { path: '/doc/setting/view', name: '展示配置', + meta: { + hidden: true, + }, component: () => import('./views/common/SettingView.vue') }, ] diff --git a/zyplayer-doc-ui/swagger-ui/src/store/SwaggerDocUtil.js b/zyplayer-doc-ui/swagger-ui/src/store/SwaggerDocUtil.js index a50600ac..c6b5e325 100644 --- a/zyplayer-doc-ui/swagger-ui/src/store/SwaggerDocUtil.js +++ b/zyplayer-doc-ui/swagger-ui/src/store/SwaggerDocUtil.js @@ -1,146 +1,95 @@ -export function getDefinitions(definitions) { - if (!definitions) { - return {}; - } - let swaggerDefinitions = {}; - Object.keys(definitions).forEach((key) => { - swaggerDefinitions["#/definitions/" + key] = definitions[key]; - }); - return swaggerDefinitions; -} - -export function createTreeViewByTag(swagger, keywords) { - let pathIndex = {}, treePathDataMap = {}; - let paths = swagger.paths; - let domain = swagger.domainUrl;// 服务器代理会返回此属性 - let rewriteDomainUrl = swagger.rewriteDomainUrl;// 服务器代理会返回此属性 - if (!paths) { - return; - } - if (!domain) { - domain = "http://" + swagger.host + swagger.basePath; - } - if (domain.substring(domain.length - 1) === "/") { - domain = domain.substring(0, domain.length - 1); - } - //console.log(paths); - Object.keys(paths).forEach(key => { - //console.log(key, paths[key]); - setRequestMethodForTag(rewriteDomainUrl, domain, paths[key], pathIndex, key, "get", treePathDataMap); - setRequestMethodForTag(rewriteDomainUrl, domain, paths[key], pathIndex, key, "head", treePathDataMap); - setRequestMethodForTag(rewriteDomainUrl, domain, paths[key], pathIndex, key, "post", treePathDataMap); - setRequestMethodForTag(rewriteDomainUrl, domain, paths[key], pathIndex, key, "put", treePathDataMap); - setRequestMethodForTag(rewriteDomainUrl, domain, paths[key], pathIndex, key, "patch", treePathDataMap); - setRequestMethodForTag(rewriteDomainUrl, domain, paths[key], pathIndex, key, "delete", treePathDataMap); - setRequestMethodForTag(rewriteDomainUrl, domain, paths[key], pathIndex, key, "options", treePathDataMap); - setRequestMethodForTag(rewriteDomainUrl, domain, paths[key], pathIndex, key, "trace", treePathDataMap); - }); - // console.log(pathIndex); - // console.log(treePathDataMap); - // console.log(treeData); - return {pathIndex: pathIndex, treePathDataMap: treePathDataMap}; -} +const methodArray = ["get", "head", "post", "put", "patch", "delete", "options", "trace"]; /** - * 设置对象的各种请求方式,存在则复制 - * @param source 资源,原始json的paths的指定对象 - * @param pathObj 当前的待赋值对象 - * @param url url绝对路径 - * @param method 请求方式,post、get... - * @returns + * 通过tag创建文档树 + * @param swagger 文档内容 + * @param keywords 搜索内容 + * @returns {{pathDataMap: {}, pathData: {}}} */ -function setRequestMethodForTag(rewriteDomainUrl, domain, source, pathObj, url, method, treePathDataMap) { - if (!source[method] || !source[method].tags) { - return; +export function createTreeViewByTag(swagger, keywords) { + let pathData = {}, pathDataMap = {}; + let swaggerPaths = swagger.paths; + if (!swaggerPaths) { + return {pathDataMap, pathData}; } - source[method].tags.forEach(function(val, index) { - let tempObj = pathObj[val]; - if(!tempObj) { - tempObj = pathObj[val] = {}; + //console.log(swaggerPaths); + Object.keys(swaggerPaths).forEach(url => { + //console.log(key, swaggerPaths[key]); + let pathMethods = swaggerPaths[url]; + for (let method of methodArray) { + if (!pathMethods[method] || !pathMethods[method].tags) { + continue; + } + pathMethods[method].tags.forEach(tag => { + let pathTag = pathData[tag]; + if (!pathTag) { + pathTag = pathData[tag] = {}; + } + let pathTagUrl = pathTag[url]; + if (!pathTagUrl) { + pathTagUrl = pathTag[url] = {}; + } + let tempPath = url + "." + method; + pathTagUrl[method] = pathMethods[method]; + pathTagUrl[method].path = tempPath; + pathTagUrl[method].url = url; + pathTagUrl[method].method = method; + // url对应文档的映射 + pathDataMap[tempPath] = pathMethods[method]; + }); } - let tempUrlObj = tempObj[url]; - if(!tempUrlObj) { - tempUrlObj = tempObj[url] = {}; - } - let tempPath = url + "." + method; - tempUrlObj[method] = source[method]; - tempUrlObj[method].path = tempPath; - tempUrlObj[method].url = url; - tempUrlObj[method].method = method; - tempUrlObj[method].domain = domain; - tempUrlObj[method].rewriteDomainUrl = rewriteDomainUrl; - treePathDataMap[tempPath] = source[method]; }); + return {pathData, pathDataMap}; } export function getTreeDataForTag(swagger, pathData, metaInfo) { return [ { + key: 'main', title: swagger.title || 'Swagger接口文档', - key: '0-0', - children: getTreeHtmlForTag(pathData, 0, metaInfo) + children: getTreeHtmlForTag(swagger.tags, pathData, metaInfo) } ]; } -function getTreeHtmlForTag(pathData, treeId, metaInfo) { +function getTreeHtmlForTag(swaggerTags, pathData, metaInfo) { let treeData = []; - let indexNow = 1; - // get, head, post, put, patch, delete, options, trace - let actionArrays = ["get", "head", "post", "put", "patch", "delete", "options", "trace"]; - Object.keys(pathData).forEach(key => { - let tempNode = pathData[key]; - let tempTreeId = treeId + "_" + indexNow; - // 只有一个子元素,而且有method元素,说明是只有一个节点 - let nodeSub = getObjectFirstAttributeIfOnly(tempNode); - if (nodeSub && nodeSub.method) { - nodeSub.treeId = tempTreeId; - let title = nodeSub.summary || nodeSub.path; - treeData.push({ - title: title, - key: tempTreeId, - isLeaf: true, - method: nodeSub.method, - query: { - ...metaInfo, - path: nodeSub.url, - method: nodeSub.method, - } - }); - } else if (actionArrays.indexOf(key) >= 0) { - tempNode.treeId = tempTreeId; - let title = tempNode.summary || tempNode.path; - treeData.push({ - title: title, - key: tempTreeId, - isLeaf: true, - method: tempNode.method, - query: { - ...metaInfo, - path: tempNode.url, - method: tempNode.method, - } - }); - } else { - treeData.push({title: key, key: key, children: getTreeHtmlForTag(tempNode, tempTreeId, metaInfo)}); + let indexTag = 1; + // 遍历分组 + swaggerTags.forEach(tag => { + let indexUrl = 1; + let urlTree = []; + let pathTagNode = pathData[tag.name]; + if (!pathTagNode) { + return; } - indexNow++; + // 遍历路劲 + Object.keys(pathTagNode).forEach(url => { + let indexMethod = 1; + let pathUrlNode = pathTagNode[url]; + // 遍历方法 + Object.keys(pathUrlNode).forEach(method => { + let tempTreeId = indexTag + "_" + indexUrl + "_" + indexMethod; + let methodNode = pathUrlNode[method]; + methodNode.treeId = tempTreeId; + let title = methodNode.summary || methodNode.path; + urlTree.push({ + title: title, + key: tempTreeId, + isLeaf: true, + method: methodNode.method, + query: { + ...metaInfo, + path: methodNode.url, + method: methodNode.method, + } + }); + indexMethod++; + }); + indexUrl++; + }); + treeData.push({title: tag.name, key: indexTag, children: urlTree}); + indexTag++; }); return treeData; } - -/** - * 如果对象只有一个属性则返回第一个属性,否则返回null - * @param data - * @returns - */ -function getObjectFirstAttributeIfOnly(data) { - let len = 0, value = ""; - for (let key in data) { - if (++len > 1) { - return undefined; - } - value = data[key]; - } - return value; -} diff --git a/zyplayer-doc-ui/swagger-ui/src/store/index.js b/zyplayer-doc-ui/swagger-ui/src/store/index.js index 653554b4..27653b7c 100644 --- a/zyplayer-doc-ui/swagger-ui/src/store/index.js +++ b/zyplayer-doc-ui/swagger-ui/src/store/index.js @@ -1,5 +1,5 @@ import {createStore} from 'vuex' -import {getDefinitions, createTreeViewByTag} from './SwaggerDocUtil' +import {createTreeViewByTag} from './SwaggerDocUtil' export default createStore({ state() { @@ -9,7 +9,7 @@ export default createStore({ pageTabNameMap: {}, swaggerDoc: {}, swaggerDefinitions: {}, - swaggerTreePathMap: [], + swaggerTreePathMap: {}, } }, mutations: { @@ -21,7 +21,7 @@ export default createStore({ }, setSwaggerDoc(state, swaggerDoc) { state.swaggerDoc = swaggerDoc; - state.swaggerDefinitions = getDefinitions(swaggerDoc.definitions); + state.swaggerDefinitions = swaggerDoc.definitions || {}; }, setSwaggerTreePathMap(state, swaggerTreePathMap) { state.swaggerTreePathMap = swaggerTreePathMap; diff --git a/zyplayer-doc-ui/swagger-ui/src/views/doc/DocManage.vue b/zyplayer-doc-ui/swagger-ui/src/views/doc/DocManage.vue index 93d73728..bef772ec 100644 --- a/zyplayer-doc-ui/swagger-ui/src/views/doc/DocManage.vue +++ b/zyplayer-doc-ui/swagger-ui/src/views/doc/DocManage.vue @@ -28,7 +28,7 @@