swagger-ui生成的接口文档想来大家用者不少,但是有时候需要打印或者各种需求,那么怎么转换成html或者word格式呢,下面带大家一起看一下(代码可直接复制使用,部分已标注地方需根据各自项目进行修改)。
新建3个实体类和1个html文件,html文件可放在resources下的static包中。实体类参数用于接收接口数据,不建议修改。
package good.doctor.test.config;
import lombok.Data;
@Data
public class SwaggerRequest {
/**
* 请求参数
*/
private String description;
/**
* 参数名
*/
private String name;
/**
* 数据类型
*/
private String type;
/**
* 参数类型
*/
private String paramType;
/**
* 是否必填
*/
private Boolean require;
/**
* 说明
*/
private String remark;
}
package good.doctor.test.config;
import lombok.Data;
@Data
public class SwaggerResponse {
/**
* 返回参数
*/
private String description;
/**
* 参数名
*/
private String name;
/**
* 说明
*/
private String remark;
public SwaggerResponse(String description, String name, String remark) {
this.description = description;
this.name = name;
this.remark = remark;
}
}
package good.doctor.test.config;
import lombok.Data;
import java.util.List;
@Data
public class SwaggerTable {
/**
* 大标题
*/
private String title;
/**
* 小标题
*/
private String tag;
/**
* url
*/
private String url;
/**
* 响应参数格式
*/
private String responseForm;
/**
* 请求方式
*/
private String requestType;
/**
* 请求体
*/
private List<SwaggerRequest> swaggerRequestList;
/**
* 返回体
*/
private List<SwaggerResponse> swaggerResponseList;
/**
* 请求参数
*/
private String requestParam;
/**
* 返回值
*/
private String responseParam;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>接口文档</title>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="http://libs.baidu.com/jquery/1.9.1/jquery.js"></script>
</head>
<body>
<div id="app">
<div class="item" v-for="(item,i) in data" :key="i">
<h4>{
{
i + 1 }}、{
{
item.title }}:{
{
item.url }}</h4>
<table cellspacing="0" cellpadding="0" border="1" id="out-table">
<thead class="bg">
<tr>
<th colspan="6">{
{
item.tag }}</th>
</tr>
</thead>
<tbody>
<tr>
<td>URL</td>
<td colspan="5">{
{
item.url }}</td>
</tr>
<tr>
<td>请求方式</td>
<td colspan="5">{
{
item.responseForm }}</td>
</tr>
<tr>
<td>返回值类型</td>
<td colspan="5">{
{
item.requestType }}</td>
</tr>
<tr class="bg">
<td>请求参数</td>
<td>参数名</td>
<td>数据类型</td>
<td>参数类型</td>
<td>是否必填</td>
<td>说明</td>
</tr>
<tr v-for="(r,inIndex) in item.swaggerRequestList">
<td>{
{
r.description }}</td>
<td>{
{
r.name }}</td>
<td>{
{
r.type }}</td>
<td>{
{
r.paramType }}</td>
<td>{
{
r.require }}</td>
<td>{
{
r.remark }}</td>
</tr>
<tr class="bg">
<td>返回参数</td>
<td>参数名</td>
<td colspan="4">说明</td>
</tr>
<tr v-for="(r,inIndex) in item.swaggerResponseList">
<td>{
{
r.description }}</td>
<td>{
{
r.name }}</td>
<td colspan="4">{
{
r.remark }}</td>
</tr>
<tr class="bg">
<td colspan="6">示例</td>
</tr>
<tr>
<td>请求参数</td>
<td colspan="5">{
{
item.requestParam }}</td>
</tr>
<tr>
<td>返回值</td>
<td colspan="5">{
{
item.responseParam }}</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
<script>
var app = new Vue({
el: "#app",
data() {
return {
data: []
};
},
created() {
let self = this;
$.ajax({
type: "POST",
url: "/get/swagger/to/word",
//注意:controller会有一个接口用于将文档转换成html或word格式。
//该处url即接口的完整路径,需要根据项目进行修改。
data: "",
dataType: "json",
mimeType: "multipart/form-data",
cache: false,
processData: false,
contentType: false,
success: function(data) {
self.data = data;
}
});
}
});
</script>
<style>
.item {
width: 800px;
margin: 0 auto;
}
table {
width: 100%;
}
table td {
padding: 10px;
}
table tr td:first-child {
min-width: 80px;
}
.item + .item {
margin-top: 20px;
}
.bg {
color: #fff;
background: #5079a9;
}
</style>
回到我们的swagger页面:
点击链接即可获取接口文档的JSON形式数据,复制保存,如下所示:
创建SwaggerUtil类,具体代码如下:
package good.doctor.test.config;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
public class SwaggerUtil {
public static List<SwaggerTable> getTableList() throws Exception{
List<SwaggerTable> list = new LinkedList();
try {
//注意:此处json即我们上一步复制的json数据,
//有的作者是把这些字段复制在文档中,然后读取该文档。小编这里偷个懒,直接复制在代码里。
String json="{\"swagger\":\"2.0\",\"info\":{\"description\":\"测试接口描述\",\"version\":\"1.0\",\"title\":\"测试项目\",\"contact\":{\"name\":\"name\",\"url\":\"url\",\"email\":\"email\"}},\"host\":\"localhost:7096\",\"basePath\":\"/\",\"tags\":[{\"name\":\"basic-error-controller\",\"description\":\"Basic Error Controller\"},{\"name\":\"地区相关接口\",\"description\":\"controller\"}],\"paths\":{\"/error\":{\"get\":{\"tags\":[\"basic-error-controller\"],\"summary\":\"error\",\"operationId\":\"errorUsingGET\",\"produces\":[\"*/*\"],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"},\"404\":{\"description\":\"Not Found\"}},\"deprecated\":false},\"head\":{\"tags\":[\"basic-error-controller\"],\"summary\":\"error\",\"operationId\":\"errorUsingHEAD\",\"consumes\":[\"application/json\"],\"produces\":[\"*/*\"],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"204\":{\"description\":\"No Content\"},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"}},\"deprecated\":false},\"post\":{\"tags\":[\"basic-error-controller\"],\"summary\":\"error\",\"operationId\":\"errorUsingPOST\",\"consumes\":[\"application/json\"],\"produces\":[\"*/*\"],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"201\":{\"description\":\"Created\"},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"},\"404\":{\"description\":\"Not Found\"}},\"deprecated\":false},\"put\":{\"tags\":[\"basic-error-controller\"],\"summary\":\"error\",\"operationId\":\"errorUsingPUT\",\"consumes\":[\"application/json\"],\"produces\":[\"*/*\"],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"201\":{\"description\":\"Created\"},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"},\"404\":{\"description\":\"Not Found\"}},\"deprecated\":false},\"delete\":{\"tags\":[\"basic-error-controller\"],\"summary\":\"error\",\"operationId\":\"errorUsingDELETE\",\"produces\":[\"*/*\"],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"204\":{\"description\":\"No Content\"},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"}},\"deprecated\":false},\"options\":{\"tags\":[\"basic-error-controller\"],\"summary\":\"error\",\"operationId\":\"errorUsingOPTIONS\",\"consumes\":[\"application/json\"],\"produces\":[\"*/*\"],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"204\":{\"description\":\"No Content\"},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"}},\"deprecated\":false},\"patch\":{\"tags\":[\"basic-error-controller\"],\"summary\":\"error\",\"operationId\":\"errorUsingPATCH\",\"consumes\":[\"application/json\"],\"produces\":[\"*/*\"],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"204\":{\"description\":\"No Content\"},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"}},\"deprecated\":false}},\"/get/amap/swagger/toword\":{\"post\":{\"tags\":[\"地区相关接口\"],\"summary\":\"把swagger-ui里的API转换为word文档\",\"operationId\":\"towordUsingPOST\",\"consumes\":[\"application/json\"],\"produces\":[\"*/*\"],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"object\"}},\"201\":{\"description\":\"Created\"},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"},\"404\":{\"description\":\"Not Found\"}},\"deprecated\":false}},\"/get/area\":{\"post\":{\"tags\":[\"地区相关接口\"],\"summary\":\"获取地区信息列表\",\"description\":\"获取地区信息列表\",\"operationId\":\"helloUsingPOST\",\"consumes\":[\"application/json\"],\"produces\":[\"*/*\"],\"parameters\":[{\"name\":\"试验参数\",\"in\":\"query\",\"description\":\"参数\",\"required\":true,\"type\":\"string\",\"allowEmptyValue\":false}],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"string\"}},\"201\":{\"description\":\"Created\"},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"},\"404\":{\"description\":\"Not Found\"}},\"deprecated\":false}},\"/get/town\":{\"get\":{\"tags\":[\"地区相关接口\"],\"summary\":\"获取县镇列表\",\"description\":\"获取县镇列表\",\"operationId\":\"getTownUsingGET\",\"produces\":[\"*/*\"],\"parameters\":[{\"name\":\"str\",\"in\":\"query\",\"description\":\"参数\",\"required\":false,\"type\":\"string\",\"allowEmptyValue\":false}],\"responses\":{\"200\":{\"description\":\"OK\",\"schema\":{\"type\":\"string\"}},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"},\"404\":{\"description\":\"Not Found\"}},\"deprecated\":false}}},\"definitions\":{\"ModelAndView\":{\"type\":\"object\",\"properties\":{\"empty\":{\"type\":\"boolean\"},\"model\":{\"type\":\"object\"},\"modelMap\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}},\"reference\":{\"type\":\"boolean\"},\"status\":{\"type\":\"string\",\"enum\":[\"100 CONTINUE\",\"101 SWITCHING_PROTOCOLS\",\"102 PROCESSING\",\"103 CHECKPOINT\",\"200 OK\",\"201 CREATED\",\"202 ACCEPTED\",\"203 NON_AUTHORITATIVE_INFORMATION\",\"204 NO_CONTENT\",\"205 RESET_CONTENT\",\"206 PARTIAL_CONTENT\",\"207 MULTI_STATUS\",\"208 ALREADY_REPORTED\",\"226 IM_USED\",\"300 MULTIPLE_CHOICES\",\"301 MOVED_PERMANENTLY\",\"302 FOUND\",\"302 MOVED_TEMPORARILY\",\"303 SEE_OTHER\",\"304 NOT_MODIFIED\",\"305 USE_PROXY\",\"307 TEMPORARY_REDIRECT\",\"308 PERMANENT_REDIRECT\",\"400 BAD_REQUEST\",\"401 UNAUTHORIZED\",\"402 PAYMENT_REQUIRED\",\"403 FORBIDDEN\",\"404 NOT_FOUND\",\"405 METHOD_NOT_ALLOWED\",\"406 NOT_ACCEPTABLE\",\"407 PROXY_AUTHENTICATION_REQUIRED\",\"408 REQUEST_TIMEOUT\",\"409 CONFLICT\",\"410 GONE\",\"411 LENGTH_REQUIRED\",\"412 PRECONDITION_FAILED\",\"413 PAYLOAD_TOO_LARGE\",\"413 REQUEST_ENTITY_TOO_LARGE\",\"414 URI_TOO_LONG\",\"414 REQUEST_URI_TOO_LONG\",\"415 UNSUPPORTED_MEDIA_TYPE\",\"416 REQUESTED_RANGE_NOT_SATISFIABLE\",\"417 EXPECTATION_FAILED\",\"418 I_AM_A_TEAPOT\",\"419 INSUFFICIENT_SPACE_ON_RESOURCE\",\"420 METHOD_FAILURE\",\"421 DESTINATION_LOCKED\",\"422 UNPROCESSABLE_ENTITY\",\"423 LOCKED\",\"424 FAILED_DEPENDENCY\",\"425 TOO_EARLY\",\"426 UPGRADE_REQUIRED\",\"428 PRECONDITION_REQUIRED\",\"429 TOO_MANY_REQUESTS\",\"431 REQUEST_HEADER_FIELDS_TOO_LARGE\",\"451 UNAVAILABLE_FOR_LEGAL_REASONS\",\"500 INTERNAL_SERVER_ERROR\",\"501 NOT_IMPLEMENTED\",\"502 BAD_GATEWAY\",\"503 SERVICE_UNAVAILABLE\",\"504 GATEWAY_TIMEOUT\",\"505 HTTP_VERSION_NOT_SUPPORTED\",\"506 VARIANT_ALSO_NEGOTIATES\",\"507 INSUFFICIENT_STORAGE\",\"508 LOOP_DETECTED\",\"509 BANDWIDTH_LIMIT_EXCEEDED\",\"510 NOT_EXTENDED\",\"511 NETWORK_AUTHENTICATION_REQUIRED\"]},\"view\":{\"$ref\":\"#/definitions/View\"},\"viewName\":{\"type\":\"string\"}},\"title\":\"ModelAndView\"},\"View\":{\"type\":\"object\",\"properties\":{\"contentType\":{\"type\":\"string\"}},\"title\":\"View\"}}}";
ObjectMapper mapper = new ObjectMapper();
Map map = JSONObject.toJavaObject(JSON.parseObject(json), Map.class);;
//得到host,用于模拟http请求
String host = String.valueOf(map.get("host"));
String basePath = String.valueOf(map.get("basePath"));
//解析paths
Map<String, Map> paths = (Map) map.get("paths");
System.out.println(paths);
if (paths != null) {
Iterator<Map.Entry<String, Map>> iterator = paths.entrySet().iterator();
while (iterator.hasNext()) {
SwaggerTable swaggerTable = new SwaggerTable();
List<SwaggerRequest> swaggerRequestList = new LinkedList<SwaggerRequest>();
String requestType = "";
Map.Entry<String, Map> next = iterator.next();
String url = next.getKey();//得到url
if(url.startsWith("/error")){
continue;
}
Map<String, Map> value = next.getValue();
//得到请求方式,输出结果类似为 get/post/delete/put 这样
Set<String> requestTypes = value.keySet();
for (String str : requestTypes) {
requestType += str + "/";
}
Iterator<Map.Entry<String, Map>> it2 = value.entrySet().iterator();
//解析请求
Map.Entry<String, Map> get = it2.next();//得到get
Map getValue = get.getValue();
String title = (String) ((List) getValue.get("tags")).get(0);//得到大标题
String tag = String.valueOf(getValue.get("summary"));
//请求体
List parameters = (List) getValue.get("parameters");
System.out.println(parameters);
if (parameters != null && parameters.size() > 0) {
for (int i = 0; i < parameters.size(); i++) {
SwaggerRequest swaggerRequest = new SwaggerRequest();
Map<String, Object> param = (Map) parameters.get(i);
swaggerRequest.setDescription(String.valueOf(param.get("description")));
swaggerRequest.setName(String.valueOf(param.get("name")));
swaggerRequest.setType(String.valueOf(param.get("type")));
swaggerRequest.setParamType(String.valueOf(param.get("in")));
swaggerRequest.setRequire((Boolean) param.get("required"));
swaggerRequestList.add(swaggerRequest);
}
}
//返回体,比较固定
List<SwaggerResponse> swaggerResponseList = listResponse();
//模拟一次HTTP请求,封装请求体和返回体,如果是Restful的文档可以再补充
if (requestType.contains("post")) {
String stringStringMap = toPostBody(swaggerRequestList);
swaggerTable.setRequestParam(stringStringMap.toString());
swaggerTable.setResponseParam("code:\"200\",{\"description\":\"OK\",code:\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"},\"404\":{\"description\":\"Not Found\"}");
} else if (requestType.contains("get")) {
String s = toGetHeader(swaggerRequestList);
swaggerTable.setRequestParam(s);
swaggerTable.setResponseParam("code:\"200\",{\"description\":\"OK\",\"schema\":{\"type\":\"object\",\"additionalProperties\":{\"type\":\"object\"}}},\"401\":{\"description\":\"Unauthorized\"},\"403\":{\"description\":\"Forbidden\"},\"404\":{\"description\":\"Not Found\"}");
}
//封装Table
swaggerTable.setTitle(title);
swaggerTable.setUrl(url);
swaggerTable.setTag(tag);
swaggerTable.setResponseForm("application/json");
swaggerTable.setRequestType(StringUtils.removeEnd(requestType, "/"));
swaggerTable.setSwaggerRequestList(swaggerRequestList);
swaggerTable.setSwaggerResponseList(swaggerResponseList);
list.add(swaggerTable);
}
}
return list;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
//封装返回信息,可能需求不一样,可以自定义
private static List<SwaggerResponse> listResponse() {
List<SwaggerResponse> swaggerResponseList = new LinkedList<SwaggerResponse>();
swaggerResponseList.add(new SwaggerResponse("结果说明信息", "msg", null));
swaggerResponseList.add(new SwaggerResponse("是否成功", "success", null));
swaggerResponseList.add(new SwaggerResponse("返回对象", "data", null));
swaggerResponseList.add(new SwaggerResponse("错误代码", "errCode", null));
return swaggerResponseList;
}
//封装post请求体
private static String toPostBody(List<SwaggerRequest> list) {
StringBuffer stringBuffer = new StringBuffer();
if (list != null && list.size() > 0) {
for (SwaggerRequest swaggerRequest : list) {
String name = swaggerRequest.getName();
String type = swaggerRequest.getType();
switch (type) {
case "string":
stringBuffer.append(name).append("=string");
break;
case "integer":
stringBuffer.append(name).append("=0");
break;
case "double":
stringBuffer.append(name).append("=0.0");
break;
default:
stringBuffer.append(name).append("=null");
break;
}
}
}
return stringBuffer.toString();
}
//封装get请求头
private static String toGetHeader(List<SwaggerRequest> list) {
StringBuffer stringBuffer = new StringBuffer();
if (list != null && list.size() > 0) {
for (SwaggerRequest swaggerRequest : list) {
System.out.println(swaggerRequest.getType());
String name = swaggerRequest.getName();
String type = swaggerRequest.getType();
switch (type) {
case "string":
stringBuffer.append(name+"=string");
break;
case "integer":
stringBuffer.append(name+"=0");
break;
case "double":
stringBuffer.append(name+"=0.0");
break;
default:
stringBuffer.append(name+"&=null");
break;
}
}
}
String s = stringBuffer.toString();
if ("".equalsIgnoreCase(s)){
return "";
}
return StringUtils.removeStart(s, "&");
}
}
此时工作已经完成了九成,在controller类中添加接口即可,代码如下:
ApiOperation(value="将swagger-ui文档转换为word")
@PostMapping(value = "/get/swagger/to/word")
@ResponseBody
public Object toword() throws Exception{
List<SwaggerTable> list = SwaggerUtil.getTableList();
return list;
}
访问路径:http://localhost:7096/swagger.html
localhost即ip;
7096为端口号(根据项目进行修改,未设置时默认8080);
swagger.html为我们第一步创建的html文件,我将它命名为swagger;
得到结果如下:
这就得到了接口文档的html页面。如果要得到word格式,将表格复制进word文档即可。