Swagger文件轉Word 文件
作者:JmCui
http://
cnblogs。com/jmcui/p/829
8823。html
一、前言
為什麼會產生這個需求呢?
我們公司作為乙方,老是被客戶追著要一份API文件,當我們把一個 Swagger 文件地址丟給客戶的時候。客戶還是很不滿意,嫌不夠正式!!死活堅持要一份 word 文件 。然後領導給了個介面模板,就把這個活交給我了……我去,近10個微服務,幾百個介面,這不得要了我的命啊(最後整理出來將近200頁的 word 文件)。最後,還是領導有辦法:要不我們把Swagger的 json檔案轉成word文件吧!
一直堅持一句話。作為使用者,人要遷就機器;作為開發者,要機器遷就人。
二、思路
領導提供了一個介面模板,類似下面這樣,其實就是一個word的table頁。想到 html 可以轉 word ,那麼問題就變成了 :
解析JSON 檔案
把JSON檔案的內容填充進html 的Table中
由html直接轉成word
幾百個介面,一氣呵成!如下,還有一個簡單的示例,就是請求引數 和 返回值 。怎麼處理呢?在程式中寫了 HTTP 的請求,封裝了需要的引數去執行了一個請求,得到相應的返回值!
三、實現
1、封裝物件
按照面向物件的思想,一個介面Table就是一個物件,可變的請求引數和返回引數也封裝成一個物件……
Table
public
class
Table
{
Java
/**
* 大標題
*/
private
String
title
;
/**
* 小標題
*/
private
String
tag
;
/**
* url
*/
private
String
url
;
/**
* 響應引數格式
*/
private
String
responseForm
;
/**
* 請求方式
*/
private
String
requestType
;
/**
* 請求體
*/
private
List
<
Request
>
requestList
;
/**
* 返回體
*/
private
List
<
Response
>
responseList
;
/**
* 請求引數
*/
private
String
requestParam
;
/**
* 返回值
*/
private
String
responseParam
;
public
String
getTitle
()
{
return
title
;
}
public
void
setTitle
(
String
title
)
{
this
。
title
=
title
;
}
public
String
getTag
()
{
return
tag
;
}
public
void
setTag
(
String
tag
)
{
this
。
tag
=
tag
;
}
public
String
getUrl
()
{
return
url
;
}
public
void
setUrl
(
String
url
)
{
this
。
url
=
url
;
}
public
String
getResponseForm
()
{
return
responseForm
;
}
public
void
setResponseForm
(
String
responseForm
)
{
this
。
responseForm
=
responseForm
;
}
public
String
getRequestType
()
{
return
requestType
;
}
public
void
setRequestType
(
String
requestType
)
{
this
。
requestType
=
requestType
;
}
public
List
<
Request
>
getRequestList
()
{
return
requestList
;
}
public
void
setRequestList
(
List
<
Request
>
requestList
)
{
this
。
requestList
=
requestList
;
}
public
List
<
Response
>
getResponseList
()
{
return
responseList
;
}
public
void
setResponseList
(
List
<
Response
>
responseList
)
{
this
。
responseList
=
responseList
;
}
public
String
getRequestParam
()
{
return
requestParam
;
}
public
void
setRequestParam
(
String
requestParam
)
{
this
。
requestParam
=
requestParam
;
}
public
String
getResponseParam
()
{
return
responseParam
;
}
public
void
setResponseParam
(
String
responseParam
)
{
this
。
responseParam
=
responseParam
;
}
}
Request
public
class
Request
{
/**
* 請求引數
*/
private
String
description
;
/**
* 引數名
*/
private
String
name
;
/**
* 資料型別
*/
private
String
type
;
/**
* 引數型別
*/
private
String
paramType
;
/**
* 是否必填
*/
private
Boolean
require
;
/**
* 說明
*/
private
String
remark
;
public
String
getDescription
()
{
return
description
;
}
public
void
setDescription
(
String
description
)
{
this
。
description
=
description
;
}
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
。
name
=
name
;
}
public
String
getType
()
{
return
type
;
}
public
void
setType
(
String
type
)
{
this
。
type
=
type
;
}
public
Boolean
getRequire
()
{
return
require
;
}
public
void
setRequire
(
Boolean
require
)
{
this
。
require
=
require
;
}
public
String
getRemark
()
{
return
remark
;
}
public
void
setRemark
(
String
remark
)
{
this
。
remark
=
remark
;
}
public
String
getParamType
()
{
return
paramType
;
}
public
void
setParamType
(
String
paramType
)
{
this
。
paramType
=
paramType
;
}
}
Response
public
class
Response
{
/**
* 返回引數
*/
private
String
description
;
/**
* 引數名
*/
private
String
name
;
/**
* 說明
*/
private
String
remark
;
public
Response
(
String
description
,
String
name
,
String
remark
)
{
this
。
description
=
description
;
this
。
name
=
name
;
this
。
remark
=
remark
;
}
public
String
getDescription
()
{
return
description
;
}
public
void
setDescription
(
String
description
)
{
this
。
description
=
description
;
}
public
String
getName
()
{
return
name
;
}
public
void
setName
(
String
name
)
{
this
。
name
=
name
;
}
public
String
getRemark
()
{
return
remark
;
}
public
void
setRemark
(
String
remark
)
{
this
。
remark
=
remark
;
}
}
2、解析 json
先來看看Swagger
json檔案
的格式吧!需要注意的是這個 json 檔案預設的 host 是沒有加 http:// 字首的,需要我們手動加上,因為程式的HTTP請求不像瀏覽器一樣會自動補上 http:// 的字首 ……
解析JSO
N真是一件枯燥的工作,大家可以按照自己想要生成模板的樣子修改這邊的程式碼……需要提的是,這裡有一點讓我糾結了好久。怎麼偽造介面的請求引數傳送HTTP請求以避免不會拋異常呢?最後還是參考了Swagger的方式,即:如果是 String 型別的引數,就把這個引數置為“string”;如果是 Integer 型別的引數,就把這個引數置為 0 ;如果是Double 型別的引數,就置為 0。0 ;如果是其他沒辦法預見的型別,就全部置為 null;
解析 JSON 用的是Spring推薦的 jackson ,這部分感覺沒什麼好說的,直接上程式碼吧!
@Service
public
class
TableServiceImpl
implements
TableService
{
@Override
public
List
<
Table
>
tableList
()
{
List
<
Table
>
list
=
new
LinkedList
();
try
{
ClassLoader
classLoader
=
TableService
。
class
。
getClassLoader
();
URL
resource
=
classLoader
。
getResource
(
“data。json”
);
Map
map
=
new
ObjectMapper
()。
readValue
(
resource
,
Map
。
class
);
//得到host,用於模擬http請求
String
host
=
String
。
valueOf
(
map
。
get
(
“host”
));
//解析paths
LinkedHashMap
<
String
,
LinkedHashMap
>
paths
=
(
LinkedHashMap
)
map
。
get
(
“paths”
);
if
(
paths
!=
null
)
{
Iterator
<
Map
。
Entry
<
String
,
LinkedHashMap
>>
iterator
=
paths
。
entrySet
()。
iterator
();
while
(
iterator
。
hasNext
())
{
Table
table
=
new
Table
();
List
<
Request
>
requestList
=
new
LinkedList
<
Request
>();
String
requestType
=
“”
;
Map
。
Entry
<
String
,
LinkedHashMap
>
next
=
iterator
。
next
();
String
url
=
next
。
getKey
();
//得到url
LinkedHashMap
<
String
,
LinkedHashMap
>
value
=
next
。
getValue
();
//得到請求方式,輸出結果類似為 get/post/delete/put 這樣
Set
<
String
>
requestTypes
=
value
。
keySet
();
for
(
String
str
:
requestTypes
)
{
requestType
+=
str
+
“/”
;
}
Iterator
<
Map
。
Entry
<
String
,
LinkedHashMap
>>
it2
=
value
。
entrySet
()。
iterator
();
//解析請求
Map
。
Entry
<
String
,
LinkedHashMap
>
get
=
it2
。
next
();
//得到get
LinkedHashMap
getValue
=
get
。
getValue
();
String
title
=
(
String
)
((
List
)
getValue
。
get
(
“tags”
))。
get
(
0
);
//得到大標題
String
tag
=
String
。
valueOf
(
getValue
。
get
(
“summary”
));
//請求體
ArrayList
parameters
=
(
ArrayList
)
getValue
。
get
(
“parameters”
);
if
(
parameters
!=
null
&&
parameters
。
size
()
>
0
)
{
for
(
int
i
=
0
;
i
<
parameters
。
size
();
i
++)
{
Request
request
=
new
Request
();
LinkedHashMap
<
String
,
Object
>
param
=
(
LinkedHashMap
)
parameters
。
get
(
i
);
request
。
setDescription
(
String
。
valueOf
(
param
。
get
(
“description”
)));
request
。
setName
(
String
。
valueOf
(
param
。
get
(
“name”
)));
request
。
setType
(
String
。
valueOf
(
param
。
get
(
“type”
)));
request
。
setParamType
(
String
。
valueOf
(
param
。
get
(
“in”
)));
request
。
setRequire
((
Boolean
)
param
。
get
(
“required”
));
requestList
。
add
(
request
);
}
}
//返回體,比較固定
List
<
Response
>
responseList
=
listResponse
();
//模擬一次HTTP請求,封裝請求體和返回體,如果是Restful的文件可以再補充
if
(
requestType
。
contains
(
“post”
))
{
Map
<
String
,
String
>
stringStringMap
=
toPostBody
(
requestList
);
table
。
setRequestParam
(
stringStringMap
。
toString
());
String
post
=
NetUtil
。
post
(
host
+
url
,
stringStringMap
);
table
。
setResponseParam
(
post
);
}
else
if
(
requestType
。
contains
(
“get”
))
{
String
s
=
toGetHeader
(
requestList
);
table
。
setResponseParam
(
s
);
String
getStr
=
NetUtil
。
get
(
host
+
url
+
s
);
table
。
setResponseParam
(
getStr
);
}
//封裝Table
table
。
setTitle
(
title
);
table
。
setUrl
(
url
);
table
。
setTag
(
tag
);
table
。
setResponseForm
(
“application/json”
);
table
。
setRequestType
(
StringUtils
。
removeEnd
(
requestType
,
“/”
));
table
。
setRequestList
(
requestList
);
table
。
setResponseList
(
responseList
);
list
。
add
(
table
);
}
}
return
list
;
}
catch
(
IOException
e
)
{
e
。
printStackTrace
();
}
return
null
;
}
//封裝返回資訊,可能需求不一樣,可以自定義
private
List
<
Response
>
listResponse
()
{
List
<
Response
>
responseList
=
new
LinkedList
<
Response
>();
responseList
。
add
(
new
Response
(
“受影響的行數”
,
“counts”
,
null
));
responseList
。
add
(
new
Response
(
“結果說明資訊”
,
“msg”
,
null
));
responseList
。
add
(
new
Response
(
“是否成功”
,
“success”
,
null
));
responseList
。
add
(
new
Response
(
“返回物件”
,
“data”
,
null
));
responseList
。
add
(
new
Response
(
“錯誤程式碼”
,
“errCode”
,
null
));
return
responseList
;
}
//封裝post請求體
private
Map
<
String
,
String
>
toPostBody
(
List
<
Request
>
list
)
{
Map
<
String
,
String
>
map
=
new
HashMap
<>(
16
);
if
(
list
!=
null
&&
list
。
size
()
>
0
)
{
for
(
Request
request
:
list
)
{
String
name
=
request
。
getName
();
String
type
=
request
。
getType
();
switch
(
type
)
{
case
“string”
:
map
。
put
(
name
,
“string”
);
break
;
case
“integer”
:
map
。
put
(
name
,
“0”
);
break
;
case
“double”
:
map
。
put
(
name
,
“0。0”
);
break
;
default
:
map
。
put
(
name
,
“null”
);
break
;
}
}
}
return
map
;
}
//封裝get請求頭
private
String
toGetHeader
(
List
<
Request
>
list
)
{
StringBuffer
stringBuffer
=
new
StringBuffer
();
if
(
list
!=
null
&&
list
。
size
()
>
0
)
{
for
(
Request
request
:
list
)
{
String
name
=
request
。
getName
();
String
type
=
request
。
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
,
“&”
);
}
}
3、html 模板
我們需要一個和 Word Table 模板一樣的HTML 頁面,然後利用JSP的 foreach 遍歷後臺得到的
List