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 tags = new ArrayList<>(); // 所有接口路径 Map> paths = new LinkedHashMap<>(); // 扫描所有API类Action注解 Map, List> classMap = scanAllApiAction(); classMap.keySet().forEach(clazz -> { List 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 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 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 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 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())// 传输协议Scheme:HTTP、HTTPS .set("paths", paths) .set("securityDefinitions", SwaggerConfig.getSecurityDefinition()) .set("definitions", SwaggerConfig.getDefinition()) .set("externalDocs", SwaggerConfig.getExternalDocs()); renderJson(allApi); } /** * 扫描所有API类Action注解 * * @return */ private static Map, List> scanAllApiAction() { Map, List> apiMap = new HashMap<>(); // 获取遍历所有action JFinal.me().getAllActionKeys().forEach(actionKey -> { Action action = JFinal.me().getAction(actionKey, new String[1]); Class controller = action.getControllerClass(); if (apiMap.containsKey(controller)) { if (action.getMethod().isAnnotationPresent(ActionApi.class)) { List 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 actions = new ArrayList<>(); actions.add(action); apiMap.put(controller, actions); } } } }); List> list = new ArrayList<>(apiMap.keySet()); list.sort(comparingInt((Class clazz) -> clazz.getAnnotation(Api.class).sort())); Map, List> result = new LinkedHashMap<>(); for (Class i : list) { List 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 toSet(String value) { Set 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()); } }