## api文档 Swagger - 前后端分离后的契约 ### 前后端分离 >按照现在的趋势,前后端分离几乎已经是业界对开发和部署方式所达成的一种共识。所谓的前后端分离,并不是传统行业中的按部门划分,一部分人只做前端(HTML/CSS/JavaScript等等),另一部分人只做后端(或者叫服务端),因为这种方式是不工作的:比如很多团队采取了后端的模板技术(JSP, FreeMarker, ERB等等),前端的开发和调试需要一个后台Web容器的支持,从而无法将前后端开发和部署做到真正的分离。 通常,前后端分别有着自己的开发流程,构建工具,测试等。做前端的谁也不会想要用Maven或者Gradle作为构建工具,同样的道理,做后端的谁也不会想要用Grunt或者Gulp作为构建工具。前后端仅仅通过接口来协作,这个接口可能是JSON格式的RESTFul的接口,也可能是XML的,重点是后台只负责数据的提供和计算,而完全不处理展现。而前端则负责拿到数据,组织数据并展现的工作。这样结构清晰,关注点分离,前后端会变得相对独立并松耦合。但是这种想法依然还是很理想化,前后端集成往往还是一个很头痛的问题。比如在最后需要集成的时候,我们才发现最开始商量好的数据结构发生了变化,而且这种变化往往是在所难免的,这样就会增加大量的集成时间。 归根结底,还是前端或者后端感知到变化的时间周期太长,不能“及时协商,尽早解决”,最终导致集中爆发。怎么解决这个问题呢?我们需要提前协商好一些契约,并将这些契约作为可以被测试的中间产品,然后前后端都通过自动化测试来检验这些契约,一旦契约发生变化,测试就会失败。这样,每个失败的测试都会驱动双方再次协商,有效的缩短了反馈周期,并且降低集成风险。具体的实践方式,请参加我同事的一篇博文,“前后端分离了,然后呢?”[http://icodeit.org/2015/06/whats-next-after-separate-frontend-and-backend/](http://icodeit.org/2015/06/whats-next-after-separate-frontend-and-backend/)。 不过,仅仅靠纪律是不够的,还需要通过工具的辅助来提高效率。下面,我们就来看一下,一个API设计工具——Swagger,将如何帮助我们更好的实现“前后端分离”。 两款更符合前后分离的swagger-ui [swagger-bootstrap-ui](https://gitee.com/xiaoym/swagger-bootstrap-ui) [swagger-mg-ui](https://gitee.com/zyplayer/swagger-mg-ui) 封装swagger依赖,方便使用 pom核心依赖 ``` <dependencies> <!-- swagger --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-bean-validators</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>${swagger.version}</version> </dependency> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>swagger-bootstrap-ui</artifactId> <version>1.9.1</version> </dependency> <dependency> <groupId>com.zyplayer</groupId> <artifactId>swagger-mg-ui</artifactId> <version>${swagger.m.version}</version> </dependency> </dependencies> ``` 使用方法 ``` <!-- swagger --> <dependency> <groupId>com.open.capacity</groupId> <artifactId>swagger-core</artifactId> <version>${core.version}</version> </dependency> ``` ## SwaggerConfig 自动形成swagger文档核心代码 ``` package com.open.capacity.server.config; import org.springframework.context.MessageSource; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.support.ResourceBundleMessageSource; import org.springframework.stereotype.Component; import org.springframework.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer; import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.ParameterBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.schema.ModelRef; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Parameter; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.List; @Component @Configuration @EnableSwagger2 public class SwaggerConfig implements WebMvcConfigurer { @Bean public Docket createRestApi() { ParameterBuilder tokenPar = new ParameterBuilder(); List<Parameter> pars = new ArrayList<>(); tokenPar.name("Authorization").description("令牌"). modelRef(new ModelRef("string")). parameterType("header").required(false).build(); ParameterBuilder clientPar = new ParameterBuilder(); clientPar.name("client_id").description("应用ID"). modelRef(new ModelRef("string")). parameterType("header").required(false).build(); ParameterBuilder secretPar = new ParameterBuilder(); secretPar.name("client_secret").description("应用密钥"). modelRef(new ModelRef("string")). parameterType("header").required(false).build(); pars.add(tokenPar.build()); pars.add(clientPar.build()); pars.add(secretPar.build()); return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).select() // .apis(RequestHandlerSelectors.basePackage("com.open.capacity")) .apis(RequestHandlerSelectors.any()) .paths( input -> PathSelectors.regex("/oauth/client.*").apply(input) || PathSelectors.regex("/oauth/user.*").apply(input) || PathSelectors.regex("/oauth/get.*").apply(input) || PathSelectors.regex("/oauth/userinfo.*").apply(input) || PathSelectors.regex("/oauth/remove.*").apply(input) || PathSelectors.regex("/oauth/refresh/token.*").apply(input)|| PathSelectors.regex("/oauth/token/list.*").apply(input)|| PathSelectors.regex("/clients.*").apply(input)|| PathSelectors.regex("/services.*").apply(input)|| PathSelectors.regex("/redis.*").apply(input) ) // .paths(PathSelectors.any()) .build().globalOperationParameters(pars); } private ApiInfo apiInfo() { return new ApiInfoBuilder().title("认证中心swagger接口文档").description("认证中心swagger接口文档").version("1.0").build(); } @Bean public ViewResolver viewResolver() { InternalResourceViewResolver resolver = new InternalResourceViewResolver(); resolver.setViewClass(JstlView.class); resolver.setPrefix("/"); resolver.setSuffix(".html"); return resolver; } @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); return messageSource; } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { // super.addResourceHandlers(registry); registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/"); registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/"); } @Override public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { configurer.enable(); } } ``` ## 访问网关swagger-ui [http://106.13.3.200:9200/swagger-ui.html](http://106.13.3.200:9200/swagger-ui.html) ![](https://img.kancloud.cn/33/2f/332f836695f69b5afdd4936b567477d9_1904x517.png) ## 访问认证中心swagger-ui [http://106.13.3.200:8000/doc.html](http://106.13.3.200:8000/doc.html) ![](https://img.kancloud.cn/38/c2/38c2ba225f0b1f4a7cfef0770cddee49_1874x981.png) ![](https://img.kancloud.cn/a3/0a/a30a807ad336f550ff416d4619a9f243_1917x607.png) ## 访问用户中心swagger-ui ![](https://img.kancloud.cn/6e/20/6e202e8f49b6de8f4af274d16925b92e_1885x428.png)