新增Swagger接口文档导出功能

This commit is contained in:
WenG 2021-08-14 14:59:43 +08:00
parent 124672f4db
commit 3060bf4435
5 changed files with 4022 additions and 0 deletions

View File

@ -264,6 +264,12 @@
<artifactId>pdfbox</artifactId>
</dependency>
<!-- pdf end -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
<version>${spring-boot.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,47 @@
package com.cm.common.controller;
import com.cm.common.base.AbstractController;
import com.cm.common.constants.ISystemConstant;
import com.cm.common.service.IApiDocService;
import freemarker.template.TemplateException;
import io.swagger.annotations.Api;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ApiDocController
* @Description: api文档
* @Author: WangGeng
* @Date: 2021/8/14 10:58
* @Version: 1.0
**/
@Api(tags = ISystemConstant.API_TAGS_SYSTEM_PREFIX + "api文档")
@RestController
@RequestMapping(ISystemConstant.API_PREFIX + "/api-doc")
public class ApiDocController extends AbstractController {
@Autowired
private IApiDocService apiDocService;
@GetMapping("get-api")
public Map<String, Object> getApi() {
return apiDocService.getApi();
}
@GetMapping("get")
public void get(HttpServletRequest request, HttpServletResponse response) throws IOException, TemplateException {
apiDocService.get(request, response);
}
}

View File

@ -0,0 +1,37 @@
package com.cm.common.service;
import freemarker.template.TemplateException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: IApiDocService
* @Description: api文档
* @Author: WangGeng
* @Date: 2021/8/14 10:57
* @Version: 1.0
**/
public interface IApiDocService {
/**
* 获取接口
*
* @return
*/
Map<String, Object> getApi();
/**
* 获取文档
*
* @param request
* @param response
*/
void get(HttpServletRequest request, HttpServletResponse response) throws IOException, TemplateException;
}

View File

@ -0,0 +1,187 @@
package com.cm.common.service.impl;
import com.cm.common.base.AbstractService;
import com.cm.common.constants.ISystemConstant;
import com.cm.common.service.IApiDocService;
import com.cm.common.utils.DateUtil;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import io.swagger.models.*;
import io.swagger.models.parameters.Parameter;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import springfox.documentation.service.Documentation;
import springfox.documentation.spring.web.DocumentationCache;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
import javax.annotation.PostConstruct;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* When you feel like quitting. Think about why you started
* 当你想要放弃的时候想想当初你为何开始
*
* @ClassName: ApiDocServiceImpl
* @Description: api文档
* @Author: WangGeng
* @Date: 2021/8/14 10:57
* @Version: 1.0
**/
@Service
public class ApiDocServiceImpl extends AbstractService implements IApiDocService {
private static String API_TYPE_GET = "get";
private static String API_TYPE_POST = "post";
private static String API_TYPE_PUT = "put";
private static String API_TYPE_DELETE = "delete";
@Autowired
private DocumentationCache documentationCache;
@Autowired
private ServiceModelToSwagger2Mapper serviceModelToSwagger2Mapper;
@Autowired
private FreeMarkerConfigurer freeMarkerConfigurer;
@PostConstruct
public void init() {
freeMarkerConfigurer.getConfiguration().setClassForTemplateLoading(ApiDocServiceImpl.class, "/templates");
}
@Override
public Map<String, Object> getApi() {
Map<String, Object> apiDocMap = new HashMap<>();
List<Map<String, Object>> apiGroups = new ArrayList<>();
Map<String, Object> systemDocMap = new HashMap<>();
systemDocMap.put("name", "系统接口");
systemDocMap.put("api", getApi("SYSTEM"));
apiGroups.add(systemDocMap);
Map<String, Object> appDocMap = new HashMap<>();
appDocMap.put("name", "APP接口");
appDocMap.put("api", getApi("APP"));
apiGroups.add(appDocMap);
Map<String, Object> resourceDocMap = new HashMap<>();
resourceDocMap.put("name", "资源接口");
resourceDocMap.put("api", getApi("RESOURCE"));
apiGroups.add(resourceDocMap);
Map<String, Object> wechatDocMap = new HashMap<>();
wechatDocMap.put("name", "微信接口");
wechatDocMap.put("api", getApi("WECHAT"));
apiGroups.add(wechatDocMap);
apiDocMap.put("apiGroups", apiGroups);
apiDocMap.put("author", "System");
apiDocMap.put("date", DateUtil.getDay());
apiDocMap.put("version", "v1.0");
return apiDocMap;
}
@Override
public void get(HttpServletRequest request, HttpServletResponse response) throws IOException, TemplateException {
Template template = freeMarkerConfigurer.getConfiguration().getTemplate("ftl/api-template.ftl");
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode("接口文档.doc", "UTF-8"));
Map<String, Object> apiDocMap = getApi();
Writer writer = new BufferedWriter(new OutputStreamWriter(response.getOutputStream(), ISystemConstant.CHARSET_UTF8));
template.process(apiDocMap, writer);
}
private Map<String, Object> getApi(String groupName) {
Documentation documentation = documentationCache.documentationByGroup(groupName);
if (documentation == null) {
return null;
}
Swagger swagger = serviceModelToSwagger2Mapper.mapDocumentation(documentation);
Info info = swagger.getInfo();
String host = swagger.getHost();
String basePath = swagger.getBasePath();
List<Tag> tags = swagger.getTags();
Map<String, Path> paths = swagger.getPaths();
Map<String, Model> definitions = swagger.getDefinitions();
List<Map<String, Object>> apiControllers = new ArrayList<>();
Map<String, Object> apiMap = new HashMap<>();
apiMap.put("info", info);
apiMap.put("host", host);
apiMap.put("basePath", basePath);
apiMap.put("apiControllers", apiControllers);
for (Tag tag : tags) {
Map<String, Object> apiController = new HashMap<>();
apiController.put("name", tag.getName());
apiController.put("description", tag.getDescription());
apiController.put("apis", listApiMap(tag.getName(), paths));
apiControllers.add(apiController);
}
return apiMap;
}
private List<Map<String, Object>> listApiMap(String apiController, Map<String, Path> paths) {
List<Map<String, Object>> pathMaps = new ArrayList<>();
for (Map.Entry<String, Path> kv : paths.entrySet()) {
String apiUrl = kv.getKey();
Path path = kv.getValue();
Map<HttpMethod, Operation> operationMap = path.getOperationMap();
for (Map.Entry<HttpMethod, Operation> operationEntry : operationMap.entrySet()) {
HttpMethod httpMethod = operationEntry.getKey();
Operation operation = operationEntry.getValue();
if (StringUtils.equalsIgnoreCase(apiController, operation.getTags().get(0))) {
Map<String, Object> methodOperationMap = new HashMap<>();
methodOperationMap.put("apiUrl", apiUrl);
methodOperationMap.put("method", httpMethod.name());
methodOperationMap.put("summary", operation.getSummary());
methodOperationMap.put("description", operation.getDescription() == null ? "" : operation.getDescription());
methodOperationMap.put("consumes", operation.getConsumes());
methodOperationMap.put("produces", operation.getProduces());
methodOperationMap.put("parameters", listRequestParameter(operation));
methodOperationMap.put("responses", listResponseMap(operation));
pathMaps.add(methodOperationMap);
}
}
}
return pathMaps;
}
private List<Map<String, Object>> listRequestParameter(Operation operation) {
List<Map<String, Object>> requestParameterList = new ArrayList<>();
List<Parameter> parameters = operation.getParameters();
for (Parameter parameter : parameters) {
Map<String, Object> requestParameter = new HashMap<>();
requestParameter.put("name", parameter.getName());
requestParameter.put("description", parameter.getDescription());
requestParameter.put("in", parameter.getIn());
requestParameter.put("type", parameter.getPattern() == null ? "string" : parameter.getPattern());
requestParameter.put("source", parameter);
requestParameterList.add(requestParameter);
}
return requestParameterList;
}
private List<Map<String, Object>> listResponseMap(Operation operation) {
Map<String, Response> responses = operation.getResponses();
List<Map<String, Object>> responseMaps = new ArrayList<>();
for (Map.Entry<String, Response> responseEntry : responses.entrySet()) {
String code = responseEntry.getKey();
Response response = responseEntry.getValue();
Map<String, Object> responseMap = new HashMap<>();
responseMap.put("code", code);
responseMap.put("description", response.getDescription());
responseMap.put("schema", response.getSchema());
responseMaps.add(responseMap);
}
return responseMaps;
}
}

File diff suppressed because it is too large Load Diff