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

2 years ago
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);
}
/**
* APIAction
*
* @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());
}
}