前一段时间翻阅了大量的前辈写的文章,但是发现要么版本落后一些,要么集成的是自己的Swagger-UI,因此打算利用原生+jfinal写一下Jfinal与Swagger的融合:
首先需要使用的依赖(因为我没有使用maven所以下面只列了一些jar包的名称):
jackson-dataformat-yaml-2.11.4.jar
jackson-annotations-2.11.4.jar
jackson-databind-2.11.4.jar
jackson-core-2.11.4.jar
lombok.jar
jetty-util-9.4.30.v20200611.jar
gson-2.8.5.jar
swagger-models-1.5.22.jar
swagger-core-1.5.22.jar
springfox-swagger-ui-3.0.0.jar
springfox-swagger2-3.0.0.jar
路由注册:
me.add("/swagger", SwaggerAction.class); //Swagger管理路由
后台Action:
package com.swagger.action; import com.jfinal.core.Controller; import com.jfinal.core.NotAction; import com.jfinal.plugin.activerecord.Db; import com.jfinal.plugin.activerecord.Record; import com.pansoft.constants.Constant; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; import io.swagger.models.Contact; import io.swagger.models.Info; import io.swagger.models.License; import io.swagger.models.Operation; import io.swagger.models.Path; import io.swagger.models.Response; import io.swagger.models.Scheme; import io.swagger.models.Swagger; import io.swagger.models.Tag; import io.swagger.models.parameters.Parameter; import io.swagger.models.parameters.PathParameter; import io.swagger.util.Json; import java.io.File; import java.io.FileFilter; import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.net.JarURLConnection; import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.collections4.map.HashedMap; import org.eclipse.jetty.util.StringUtil; public class SwaggerAction extends Controller { // 设置需要扫描哪个包里面的类生产api public static final String BASE_PACKAGE = "com.api.action"; public void index() { String RequestURI = this.getRequest().getRequestURI(); String ContextPath = this.getRequest().getContextPath(); String functionPath = RequestURI.replaceAll(ContextPath, ""); Record renderRcd = Db.findFirst("SELECT F_PATH FROM SYS_MENU_DCT WHERE F_FUNC_PATH = ?", functionPath); Enumeration<String> enums = this.getParaNames(); Map<String, Object> paraMaps = new HashedMap<String, Object>(); while(enums.hasMoreElements()){ String key = enums.nextElement(); paraMaps.put(key, this.getPara(key, "")); } if(null == renderRcd) { this.render(Constant.PAGE404PATH); }else { this.setAttrs(paraMaps); this.render(renderRcd.getStr("F_PATH")); } } public void api() { Swagger doc = new Swagger(); Info info = new Info(); Contact contact = new Contact(); contact.setEmail("liuzhongqi@pansoft.com"); contact.setName("Sycho"); contact.setUrl("http://www.pansoft.com"); info.setDescription("普联软件股份有限公司接口平台"); License license = new License(); license.setName("Pansoft"); license.setUrl("http://www.pansoft.com"); info.setLicense(license); info.setTitle("运营平台接口"); info.setTermsOfService("http://www.pansoft.com"); info.setVersion("2.0"); info.setContact(contact); List<Scheme> schemes = new ArrayList<>(); schemes.add(Scheme.HTTP); schemes.add(Scheme.HTTPS); Map<String, Path> paths = new HashMap<>(); Set<Class<?>> classSet = getClassSet(BASE_PACKAGE); List<Tag> tags = new ArrayList<>(); for (Class<?> cls : classSet) { if (cls.isAnnotationPresent(Api.class)) { Api api = cls.getAnnotation(Api.class); String[] apitags = api.tags(); String apiValue = api.value(); if (apitags.length > 0) { for (String tag : apitags) { Tag tagobj = new Tag(); tagobj.setName(tag); tags.add(tagobj); } } else { Tag tagobj = new Tag(); tagobj.setName(apiValue); tags.add(tagobj); } Method[] methods = cls.getMethods(); for (Method method : methods) { Annotation[] annotations = method.getAnnotations(); Path path = new Path(); for (@SuppressWarnings("unused") Annotation annotation : annotations) { // Class<?> aclass = annotation.annotationType(); Operation option = new Operation(); String opvalue = ""; if (method.isAnnotationPresent(ApiOperation.class)) { ApiOperation opertion = method.getAnnotation(ApiOperation.class); ArrayList<String> produces = new ArrayList<>(); String producesStr = opertion.produces(); produces.add(producesStr); opvalue = opertion.value(); String notes = opertion.notes(); /* * String consumesStr = opertion.consumes(); String[] ptagsarray = * opertion.tags(); */ List<String> ptags = new ArrayList<>(); ptags.add(apitags[0]); /* * if(ptagsarray.length>0){ for(String tag:ptagsarray){ ptags.add(tag); } } */ option.setConsumes(new ArrayList<String>()); option.setDescription(notes); option.setSummary(notes); option.setTags(ptags); } List<Parameter> parameters = new ArrayList<>(); if (method.isAnnotationPresent(ApiImplicitParams.class)) { ApiImplicitParams apiImplicitParams = method.getAnnotation(ApiImplicitParams.class); ApiImplicitParam[] apiImplicitParamArray = apiImplicitParams.value(); for (ApiImplicitParam param : apiImplicitParamArray) { PathParameter parameter = new PathParameter(); String in = param.paramType(); String name = param.name(); String value = param.value(); boolean required = param.required(); String dataType = param.dataType(); parameter.setType(dataType); parameter.setDefaultValue(""); parameter.setDescription(value); parameter.setRequired(required); parameter.setIn(in); parameter.setName(name); parameters.add(parameter); } } option.setParameters(parameters); Map<String, Response> responseMap = new HashMap<>(); if (method.isAnnotationPresent(ApiResponses.class)) { ApiResponses responses = method.getAnnotation(ApiResponses.class); ApiResponse[] responseArray = responses.value(); for (ApiResponse response : responseArray) { String code = response.code() + ""; String msg = response.message(); Response res = new Response(); res.setDescription(msg); responseMap.put(code, res); } } option.setResponses(responseMap); String httpMethod = method.getAnnotation(ApiOperation.class).httpMethod().toLowerCase();//小写 path.set(httpMethod, option); paths.put(opvalue, path); } } doc.setSchemes(schemes); doc.setSwagger("2.0"); // doc.setBasePath("/user"); doc.setInfo(info); String serverName = this.getRequest().getServerName(); int port = this.getRequest().getServerPort(); String contextPath = this.getRequest().getContextPath(); String rootPath = ""; if(port == 80 || port == 443){ rootPath = serverName+contextPath; }else{ rootPath = serverName+":"+port+contextPath; } doc.setHost(rootPath); doc.setTags(tags); doc.setPaths(paths); } } String jsonOutput = Json.pretty(doc); renderText(jsonOutput); } /** * 获取指定包名下所有类 * * @param packageName * @return */ @NotAction public static Set<Class<?>> getClassSet(String packageName) { Set<Class<?>> classSet = new HashSet<Class<?>>(); try { Enumeration<URL> urls = getClassLoader().getResources(packageName.replace(".", "/")); while (urls.hasMoreElements()) { URL url = urls.nextElement(); if (url != null) { String protocol = url.getProtocol(); if (protocol.equals("file")) { String packagePath = url.getPath().replace("%20", " "); addClass(classSet, packagePath, packageName); } else if (protocol.equals("jar")) { JarURLConnection jarURLConnection = (JarURLConnection) url.openConnection(); if (jarURLConnection != null) { JarFile jarFile = jarURLConnection.getJarFile(); if (jarFile != null) { Enumeration<JarEntry> jarEntries = jarFile.entries(); while (jarEntries.hasMoreElements()) { JarEntry jarEntry = jarEntries.nextElement(); String jarEntryName = jarEntry.getName(); if (jarEntryName.endsWith(".class")) { String className = jarEntryName.substring(0, jarEntryName.lastIndexOf(".")) .replaceAll("/", "."); doAddClass(classSet, className); } } } } } } } } catch (Exception e) { throw new RuntimeException(e); } return classSet; } /** * 获取类加载器 * * @return */ @NotAction public static ClassLoader getClassLoader() { return Thread.currentThread().getContextClassLoader(); } @NotAction private static void addClass(Set<Class<?>> classSet, String packagePath, String packageName) { File[] files = new File(packagePath).listFiles(new FileFilter() { public boolean accept(File file) { return (file.isFile() && file.getName().endsWith(".class")) || file.isDirectory(); } }); for (File file : files) { String fileName = file.getName(); if (file.isFile()) { String className = fileName.substring(0, fileName.lastIndexOf(".")); if (StringUtil.isNotBlank(packageName)) { className = packageName + "." + className; } doAddClass(classSet, className); } else { String subPackagePath = fileName; if (StringUtil.isNotBlank(packagePath)) { subPackagePath = packagePath + "/" + subPackagePath; } String subPackageName = fileName; if (StringUtil.isNotBlank(packageName)) { subPackageName = packageName + "." + subPackageName; } addClass(classSet, subPackagePath, subPackageName); } } } @NotAction private static void doAddClass(Set<Class<?>> classSet, String className) { Class<?> cls = loadClass(className, false); classSet.add(cls); } /** * 加载类 * * @param className * @param isInitialized false 代表装载类的时候 不进行初始化工作[不会执行静态代码块] * @return */ @NotAction public static Class<?> loadClass(String className, boolean isInitialized) { Class<?> cls; try { cls = Class.forName(className, isInitialized, getClassLoader()); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } return cls; } }
前台页面:去网站下载:https://github.com/swagger-api/swagger-ui,dist目录里面是已经打好的前台工程,直接拿出来用,目录如下:
示例Action类:
package com.api.action; import java.util.HashMap; import java.util.Map; import com.jfinal.core.Controller; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; import io.swagger.annotations.ApiOperation; @Api(value="MDMController",tags={"获取项目信息tag"}) public class TestController extends Controller { public void index() { this.renderJson(); } //测试示例 @ApiOperation(value = "/api/TestAPI", httpMethod = "POST", notes = "获取项目信息,返回项目ID和项目名称") @ApiImplicitParams({ @ApiImplicitParam(paramType="query", required = true, name = "id", value = "项目ID",dataType="string"), @ApiImplicitParam(paramType="query", required = true, name = "name", value = "项目名称",dataType="string") }) public void TestAPI() { String id = this.getPara("id"); String name = this.getPara("name"); Map<String, String> returnMap = new HashMap<String, String>(); returnMap.put("获取到的ID是:", id); returnMap.put("获取到的NAME是:", name); renderJson(returnMap); } }
启动访问:
接口测试: