You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

251 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package com.dsideal.FengHuang.Swagger.controller;
import com.dsideal.FengHuang.Swagger.annotation.Api;
import com.dsideal.FengHuang.Swagger.annotation.Item;
import com.dsideal.FengHuang.Swagger.annotation.ActionApi;
import com.dsideal.FengHuang.Swagger.annotation.Param;
import com.dsideal.FengHuang.Swagger.annotation.Params;
import com.dsideal.FengHuang.Swagger.annotation.Responses;
import com.dsideal.FengHuang.Swagger.annotation.SecurityApi;
import com.dsideal.FengHuang.Swagger.config.SwaggerConfig;
import com.dsideal.FengHuang.Swagger.enums.InType;
import com.jfinal.core.Action;
import com.jfinal.core.Controller;
import com.jfinal.core.JFinal;
import com.jfinal.kit.Kv;
import com.jfinal.kit.Okv;
import java.lang.reflect.Method;
import java.util.*;
import static java.util.Comparator.*;
/**
* Swagger UI Controller
*/
public class SwaggerController extends Controller {
// 请求方法
private static final String HTTP_METHOD = "get,post,head,put,delete";
/**
* api页面
*/
//@IsLoginInterface({})
public void index() {
String theme = getPara(0);
if (theme == null) {
theme = "layui";
} else {
theme = theme.trim();
}
switch (theme) {
case "default":
render("_default/index.html");
break;
default:
render("layui/index.html");
break;
}
}
/**
* 获取所有api接口
*/
public void api() {
// 所有接口类tag描述信息
List<Kv> tags = new ArrayList<>();
// 所有接口路径
Map<String, Map<String, Kv>> paths = new LinkedHashMap<>();
// 扫描所有API类Action注解
Map<Class<? extends Controller>, List<Action>> classMap = scanAllApiAction();
classMap.keySet().forEach(clazz -> {
List<Action> actions = classMap.get(clazz);
actions.forEach(action -> {
Method method = action.getMethod();
ActionApi ApiAction = method.getAnnotation(ActionApi.class);
String httpMethod = ApiAction.httpMethod();
if (httpMethod == null || "".equals(httpMethod.trim())) {
// 请求方法HEAD请求页面的首部、GET查看, POST创建, PUT更新, DELETE删除
httpMethod = HTTP_METHOD;
}
Map<String, Kv> methodApiMap = new HashMap<>();
String[] httpMethods = httpMethod.split(",");// 支持多个请求方法
for (String methodItem : httpMethods) {
methodItem = methodItem.trim().toLowerCase();
if (!Arrays.asList(HTTP_METHOD.split(",")).contains(methodItem)) {
continue;
}
// 获取参数注解信息
List<Param> params = new ArrayList<>();
if (method.isAnnotationPresent(Params.class)) {
params.addAll(Arrays.asList(method.getAnnotation(Params.class).value()));
}
if (method.isAnnotationPresent(Param.class)) {
// Java8新特性支持多注解
Param[] paramArray = method.getAnnotationsByType(Param.class);
params.addAll(Arrays.asList(paramArray));
}
// 构建参数列表(包含全局参数)
List<Kv> paramList = new ArrayList<>(SwaggerConfig.getGlobalParamList());
params.forEach(i -> {
// 注意swaggerUI 使用Java的关键字default作为默认值,此处将defaultValue转换为default
Kv kv = Kv.by("name", i.name()).set("description", i.remark()).set("required", i.required())
.set("type", i.dataType()).set("format", i.format()).set("default", i.defaultValue());
if ("file".equals(i.dataType())) {
kv.set("in", InType.FORM_DATA.getValue());
} else {
kv.set("in", i.in().getValue());
}
kv.set("schema", i.schema());//
kv.set("items", "");//{type:"string",enum:["a","b","c"],default:""}
kv.set("collectionFormat", i.collectionFormat());
paramList.add(kv);
});
// 每个action注解信息
Kv actionKv = Kv.by("parameters", paramList)
.set("operationId", method.getName())
.set("tags", toSet(notBlank(ApiAction.tag()) ? ApiAction.tag() : actions.get(0).getActionKey()))
.set("description", ApiAction.remark())
.set("summary", ApiAction.summary())
.set("consumes", toSet("application/json" + "," + ApiAction.consumes()))
.set("produces", toSet(ApiAction.consumes() + "," + "application/json"));
// response
Kv responseKv = Kv.by("200", Kv.by("description", "Success"))
.set("400", Kv.by("description", "Invalid ID supplied"))
.set("403", Kv.by("description", "Forbiden"))
.set("404", Kv.by("description", "Not found"))
.set("405", Kv.by("description", "Validation exception"))
.set("500", Kv.by("description", "Interneral error"));
if (method.isAnnotationPresent(Responses.class)) {
Responses response = method.getAnnotation(Responses.class);
responseKv.set(response.key(), Kv.by("description", response.remark()));
Kv itemKv = Kv.create();
for (Item i : response.schemaItems()) {
itemKv.set(i.key(), i.value());
}
responseKv.set("schema", Kv.by("type", response.schemaType()).set("items", itemKv));
actionKv.set("responses", responseKv);
}
// security
if (method.isAnnotationPresent(SecurityApi.class)) {
// Java8新特性支持多注解
SecurityApi[] securityApis = method.getAnnotationsByType(SecurityApi.class);
List<Kv> securitys = new ArrayList<>();
for (SecurityApi item : securityApis) {
Kv security = Kv.by(item.key(), toSet(item.value()));
securitys.add(security);
}
actionKv.set("security", securitys);
}
methodApiMap.put(methodItem, actionKv);
}
paths.put(notBlank(ApiAction.url()) ? ApiAction.url() : action.getActionKey(), methodApiMap);
});
Api api = clazz.getAnnotation(Api.class);
Kv tag = Kv.by("name", actions.get(0).getActionKey()).set("description", api.remark() + " (" + clazz.getSimpleName() + ")");
//Kv tag = Kv.by("name", api.remark()).set("description", api.remark() + " (" + clazz.getSimpleName() + ")");
if (notBlank(api.outerUrl()) || notBlank(api.outerRemark())) {
tag.set("externalDocs", Kv.by("description", api.outerRemark()).set("url", api.outerUrl()));
}
tags.add(tag);
});
// 获取host
String host = getRequest().getServerName();
if (this.getRequest().getServerPort() != 80) {
host += ":" + getRequest().getServerPort();
}
Okv allApi = Okv.by("Swagger", "2.0")
.set("info", SwaggerConfig.getApiInfo())
.set("host", host)
.set("basePath", "")
.set("tags", tags)
.set("schemes", SwaggerConfig.getScheme())// 传输协议SchemeHTTP、HTTPS
.set("paths", paths)
.set("securityDefinitions", SwaggerConfig.getSecurityDefinition())
.set("definitions", SwaggerConfig.getDefinition())
.set("externalDocs", SwaggerConfig.getExternalDocs());
renderJson(allApi);
}
/**
* 扫描所有API类Action注解
*
* @return
*/
private static Map<Class<? extends Controller>, List<Action>> scanAllApiAction() {
Map<Class<? extends Controller>, List<Action>> apiMap = new HashMap<>();
// 获取遍历所有action
JFinal.me().getAllActionKeys().forEach(actionKey -> {
Action action = JFinal.me().getAction(actionKey, new String[1]);
Class<? extends Controller> controller = action.getControllerClass();
if (apiMap.containsKey(controller)) {
if (action.getMethod().isAnnotationPresent(ActionApi.class)) {
List<Action> actions = apiMap.get(controller);
if (!actions.contains(action)) {
actions.add(action);
apiMap.put(controller, actions);
}
}
} else {
if (controller.isAnnotationPresent(Api.class)) {
if (action.getMethod().isAnnotationPresent(ActionApi.class)) {
List<Action> actions = new ArrayList<>();
actions.add(action);
apiMap.put(controller, actions);
}
}
}
});
List<Class<? extends Controller>> list = new ArrayList<>(apiMap.keySet());
list.sort(comparingInt((Class<? extends Controller> clazz) -> clazz.getAnnotation(Api.class).sort()));
Map<Class<? extends Controller>, List<Action>> result = new LinkedHashMap<>();
for (Class<? extends Controller> i : list) {
List<Action> actions = apiMap.get(i);
actions.sort(comparingInt((Action action) -> action.getMethod().getAnnotation(ActionApi.class).sort()));
result.put(i, actions);
}
return result;
}
/**
* 字符串转set集合
*
* @param value
* @return
*/
private static Set<String> toSet(String value) {
Set<String> result = new LinkedHashSet<>();
if (value != null) {
String[] values = value.split(",");
for (String item : values) {
if (notBlank(item)) {
result.add(item.trim());
}
}
}
return result;
}
/**
* 判断字符串非空
*
* @param value
* @return
*/
private static boolean notBlank(String value) {
return value != null && !"".equals(value.trim());
}
}