Swagger简单介绍
Swagger是一个Restful风格接口的文档在线自动生成和测试的框架
官网:http://swagger.io
官方描述:The World’s Most Popular Framework for APIs.
Swagger ui 的原生UI界面如下:
现在市面上的UI不足之处
1、原生UI显示的有些不够漂亮和清晰,特别是request 的model部分
2、每个服务都需要引入一套资源文件,不能作为一个中间件为其他API使用
3、默认通用配置繁琐,每个项目都需要复制重新配置一份swagger信息
后来在网上看到了别人封装的swagger-layer-ui,界面看起来不错,但是还是有些问题在。
新设计,新封装,即插即用
于是乎,结合上面的问题,采用了spring boot 的思想:约定大于配置,通用的配置全部帮大家封装好了,如有特殊业务,可单独配置
考虑到微服务和单服务版本的封装,做了一些特殊的打包配置:
微服务版本:中心UI服务需要访问API服务的接口,需要考虑一些跨域问题,简单的跨域问题,可以通过spring mvc配置来实现
单服务版本:即插即用,但是每个API服务需要加载一些资源包
我已经将代码上传到github上,有兴趣的小伙伴可以下载来看看。https://github.com/huanshare/huan-swagger
代码实现
huan-swagger-core(主要实现了一些swagger的默认配置,跨域通用配置,自定义注解的实现)
/** * 实现了swagger的默认配置,和跨域问题 */ @Configuration public class HuanSwagger { @Value("${swagger.enable:true}") boolean enable; @Value("${swagger.title:API查看器}") String title; @Value("${swagger.description:API服务的说明,请在配置文件中说明服务的作用}") String description; @Value("${swagger.contact.name:huanshare}") String contactName; @Value("${swagger.contact.url:www.huanshare.com}") String contactUrl; @Value("${swagger.contact.mail:[email protected]}") String contactMail; @Value("${swagger.version:0.0.0}") String version; public HuanSwagger() { } @Bean public Docket allApi() { if (!this.enable) { return (new Docket(DocumentationType.SWAGGER_2)).select().apis(RequestHandlerSelectors.none()).paths(PathSelectors.none()).build(); } else { ApiInfo apiInfo = (new ApiInfoBuilder()).title(this.title).description(this.description).contact(new Contact(this.contactName, this.contactUrl, this.contactMail)).version(this.version).build(); ApiSelectorBuilder builder = (new Docket(DocumentationType.SWAGGER_2)).useDefaultResponseMessages(false).apiInfo(apiInfo).select(); builder.apis(RequestHandlerSelectors.withClassAnnotation(RestController.class)); return builder.build(); } } @Bean public CorsFilter apiCrosFilter() { if (!this.enable) { return new CorsFilter(new UrlBasedCorsConfigurationSource()); } else { UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); CorsConfiguration corsConfiguration = new CorsConfiguration(); corsConfiguration.setAllowCredentials(true); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.addAllowedOrigin("*"); urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); return new CorsFilter(urlBasedCorsConfigurationSource); } } }
/** * 自定义注解,方便简单的注入 */ @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE}) @Documented @EnableSwagger2 @Import({HuanSwagger.class}) public @interface EnableHuanSwagger { }
上面代码已经打成jar包,发布到maven库上了,具体版本使用
<dependency> <groupId>com.github.huansharegroupId> <artifactId>huan-swagger-coreartifactId> <version>1.0.1version> dependency>
huan-swagger-ui(微服务UI项目)
layui.config({ base: 'assets/layext/' }).extend({ nlaytpl: 'nlaytpl', ncmntool: 'ncmntool', nswagger: 'nswagger', nupload: 'nupload' }); // layui.use(['layer', 'element', 'form', 'nlaytpl', 'nswagger', 'ncmntool', 'upload'], function () { var $ = layui.jquery, layer = layui.layer, element = layui.element, form = layui.form, ncmntool = layui.ncmntool, nlaytpl = layui.nlaytpl, nswagger = layui.nswagger; $(".logo").click(function () { $(".nav-home").click(); $(".layui-side-scroll").scrollTop(0); }); $("#iptApiUrl, .btn-clearurl").on('mouseover', function () { $(".btn-clearurl").show(); }).on('mouseout', function () { $(".btn-clearurl").hide(); }); $(".btn-clearurl").click(function () { $("#iptApiUrl").val(''); }); $(".btn-gourl").click(function () { // 清理数据 $(".api-main").empty(); // 弹出加载框 var loader = layer.load(); // 拉取数据 var iptApiUrl = $("#iptApiUrl").val() || location.hash; if (iptApiUrl.charAt(0) == "#") { iptApiUrl = iptApiUrl.substr(1); } if (iptApiUrl == "") { iptApiUrl = location.protocol + "//" + location.host + "/v2/api-docs"; if (location.search && location.search.indexOf("_ijt=") != -1) { iptApiUrl = "example.json"; } } if (iptApiUrl != "example.json") { if (!/\/v2\/api-docs$/.test(iptApiUrl)) { iptApiUrl = iptApiUrl + "/v2/api-docs"; } if (!/^http/.test(iptApiUrl)) { iptApiUrl = "http://" + iptApiUrl; } } $("#iptApiUrl").val(iptApiUrl); // 获取配置文档 $.ajax({ url: iptApiUrl, dataType: "json", type: "get", success: function (apidoc) { // 解析数据 try { nswagger.resolve(apidoc); } catch (e) { layer.msg('解析失败,请确认文档配置是否正确', {icon: 5}); console.error(e); return; } // 设置页面标题 document.title = apidoc.info.title; // 设置页面LOGO ncmntool.checkimg(apidoc.schemes[0] + "://" + apidoc.host + "/logo.png", function (imgurl) { $(".logo img").attr("src", imgurl); }); location.hash = apidoc.host; // 渲染左侧菜单导航 nlaytpl.render(".api-main")("comp/tplApiMain.html", {tags: apidoc["tags"]}, function () { // 重新渲染菜单效果 element.init(); // 监听导航点击事件 element.on("nav(left-nav)", function (ele) { if ($(ele).hasClass("nav-home")) { nlaytpl.render(".main-body")("comp/tplHomeBody.html", apidoc, function () { // 重新渲染组件效果 element.init(); }); } else { $((".layui-nav-itemed")).removeClass(("layui-nav-itemed")); $(ele).parents(".layui-nav-item").addClass("layui-nav-itemed"); var _a = $(ele).children(':first-child'); $(".layui-side-scroll").scrollTop($(_a).offset().top - $(".layui-side").offset().top + $(".layui-side").scrollTop()); var _dpath = $(_a).attr("dpath"), _dhttpmethod = $(_a).attr("dhttpmethod"); nlaytpl.render(".main-body")("comp/tplApiBody.html", { apidoc: apidoc, tagname: $(_a).attr("dtag"), dpath: _dpath, dhttpmethod: _dhttpmethod, mmeta: apidoc["paths"][_dpath][_dhttpmethod] }, function () { // 重新渲染组件效果 element.init(); form.render(); }); } }); // 监听处理导航的悬浮提示 $('.layui-nav-item a[dtitle]').on('mouseover', function () { var that = this; layer.tips($(that).attr("dtitle"), that, { time: 0 }); }).on('mouseout', function () { layer.closeAll('tips'); }); // 渲染主页 $(".nav-home a").click(); }); // 渲染顶部导航搜索 nlaytpl.render(".api-quick")("comp/tplApiQuick.html", {tags: apidoc["tags"]}, function () { form.on('select(api-quick)', function (data) { var pm = data.value.split("::"); $(".left-nav a[dpath='" + pm[1] + "'][dhttpmethod='" + pm[0] + "']").click(); }); // 重新渲染表单组件效果 form.render("select"); }); }, error: function () { layer.msg('加载失败,请确认API文档的地址是否正确', {icon: 5}); }, complete: function () { layer.close(loader); } }); }).on('mouseover', function () { var that = this; layer.tips("点击加载目标地址的API文档", that, { time: 0, tips: 3 }); }).on('mouseout', function () { layer.closeAll('tips'); }); // $(".btn-gourl").click(); });
swagger-ui-layer(单服务版本,即插即用),JS代码同huan-swagger-ui类似,只是引入jar包不同
<dependency> <groupId>com.github.huansharegroupId> <artifactId>swagger-ui-layerartifactId> <version>1.0.0version> dependency>
使用说明
项目描述
由于考虑到大家的使用情况,结合网上 swagger-ui-layer的封装情况 现把 swagger-layui 分为 微服务版,单服务版。目前只支持 RestController
1)微服务版本:微服务与 layui 分离,layui 部署到新服务器上,供各个服务使用
demo例子:http://106.12.9.238:8080/webjars/swagger-ui/index.html#106.12.9.238:8081
2)单服务版本:layui 部署在服务上,即插即用,非常方便
项目结构
huan-swagger-core swagger核心组件封装
swagger-ui-layer 单服务版本:供单服务即插即用
huan-swagger-ui 微服务版本:swagger UI页面,作为一个第三方服务来渲染接口,用来渲染远程服务器的接口说明 (aa.com)
spring-boot-demo swagger 微服务测试页面 (bb.com)
spring-mvc-demo swagger spring mvc单服务测试页面 (bb.com)
微服务访问形式:http://aa.com/webjars/swagger-ui/index.html#http://bb.com
微服务demo实例:http://106.12.9.238:8080/webjars/swagger-ui/index.html#106.12.9.238:8081
使用说明(spring boot)
一、微服务版本:
1、部署到服务器上:huan-swagger-ui项目
2、微服务项目修改
1) pom依赖
<dependency> <groupId>com.github.huansharegroupId> <artifactId>huan-swagger-coreartifactId> <version>1.0.1version> dependency>
2) spring boot项目启动项添加:
@EnableHuanSwagger
3) application.yml配置 (可选项配置)
# Swagger设置 enable 默认为true,为false时,关闭接口展示
swagger:
enable: true,
version: 版本号
title: 项目标题
description: 项目描述
contact:
name: 用户名
url: url地址
mail: 邮箱
3、页面访问:UI服务器地址/webjars/swagger-ui/index.html#API-服务器地址
4、具体使用方式,请参考 huan-swagger-test
二、单服务版本:
1、服务项目修改
1) pom依赖
<dependency> <groupId>com.github.huansharegroupId> <artifactId>swagger-ui-layerartifactId> <version>1.0.0version> dependency>
2) spring boot项目启动项添加:
@EnableHuanSwagger
3) application.yml配置 (可选项配置)
# Swagger设置 enable 默认为true,为false时,关闭接口展示
swagger:
enable: true,
version: 版本号
title: 项目标题
description: 项目描述
contact:
name: 用户名
url: url地址
mail: 邮箱
3、页面访问:UI服务器地址/api-doc.html
三、修改首页图标:根目录/logo.png(将图片地址映射到根目录下进行访问)
使用说明(spring mvc)
1、微服务版本:API需要在 添加pom依赖,需要手动解决跨域问题,具体可参考 spring-mvc-demo中的CORSFilter与web.xml中的跨域配置, 可参考 spring-mvc-demo---》CORSFilter
1) pom依赖
<dependency> <groupId>com.github.huansharegroupId> <artifactId>huan-swagger-coreartifactId> <version>1.0.1version> dependency>
2) Bean注入,Filter配置
@Configuration @EnableHuanSwagger @EnableWebMvc public class CORSFilter implements Filter { public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); chain.doFilter(req, res); } }
3) web.xml中配置过滤器
<filter> <filter-name>corsfilter-name> <filter-class>com.huanshare.springMvcDemo.config.CORSFilterfilter-class> filter> <filter-mapping> <filter-name>corsfilter-name> <url-pattern>/*url-pattern> filter-mapping>
2、单服务版本:添加pom依赖,注入各种Bean,可参考 spring-mvc-demo --》MySwaggerConfig
1) pom依赖
<dependency> <groupId>com.github.huansharegroupId> <artifactId>swagger-ui-layerartifactId> <version>1.0.0version> dependency>
2) Bean注入
@Configuration @EnableHuanSwagger @EnableWebMvc public class MySwaggerConfig { }
3、修改首页图标:根目录/logo.png(将图片地址映射到根目录下进行访问)
特点
原来看过其他小伙伴的源码,页面交互不算太理想
无论单机版还是微服务版,整体UI在小伙伴基础上做了一些修改,整体内容进行了封装,不需要配置一些额外的选项,即插即用,非常方便
微服务版:实现了API与UI的分离,但是需要为UI单独部署一套服务器,增加了其他成本;如果微服务多的话,这也算是个不错的方案
单服务版:简单配置,即插即用,非常方便
小伙伴的地址(https://github.com/ohcomeyes/swagger-ui-layer )