最近在公司发现了一个非常繁琐的事情(后台采用微服务架构开发):后台提供Rest接口的模块实在太多,每天多要有专门的人员去统计今天对应Rest接口有哪些变更,每次都要花费大量的时间,而且有时候发现统计的还跟实际不统一(统计人员还是非常发心思在做这个事情)!另外,前端开发人员一直等待后端开发人员给接口,每次后端人员都说接口快OK了,但是前端开发人员一点信息也查看不到,导致前端人员心里对进度把握很虚。
为了解决这一困局,今天学习了一下互联网主流的解决方案:采用Swagger进行线上沟通。这的确是一种非常不错的方式!它把我们碰到的问题全全解决了,为做这套开源项目的人员点个赞!另外只要接口发生变更直接通过线上就可以看到,降低了人员之间的沟通成本代发。
一、改造swagger源码(基于1.5.8版本)
本身swagger还不支持Dubbox,因此需要我们对它进行扩展。稍微看一下swagger的源码发现,这种改造非常简单,只要把Swagger返回的Response对象通过dubbox的Rest接口暴露出来即可。大家只要关注抽象类BaseApiListingResource,它里面有getListingJsonResponse()和getListingYamlResponse()方法,核心返回给前端的数据就是这两个访问透露出来的。前面有说到这个方法是抽象方法,想必就是提供我们去继承了。于是乎定义Rest接口吧:
DubboxSwaggerService.java
@Path("dubboxswagger")
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
@Produces({MediaType.APPLICATION_JSON + "; " + "charset=UTF-8", MediaType.TEXT_XML + "; " + "charset=UTF-8"})
public interface DubboxSwaggerService {
@GET
@Path("swagger")
public Response getListingJson(@Context Application app,
@Context ServletConfig sc,@Context HttpHeaders headers,
@Context UriInfo uriInfo);
}
定义好了接口,我们再写它的实现吧:
DubboxAcceptHeaderApiListingResource.java
@Service
public class DubboxAcceptHeaderApiListingResource extends BaseApiListingResource implements DubboxSwaggerService {
@Context
ServletContext context;
@Override
public Response getListingJson(Application app, ServletConfig sc,
HttpHeaders headers, UriInfo uriInfo) {
// TODO Auto-generated method stub
Response rsp = getListingJsonResponse(app, context, sc, headers, uriInfo);
return rsp;
}
}
到这里还不是完美的方案,我们要的是一个集中Rest查询中心!每个模块的访问地址都不同,前端JS请求就会涉及跨域问题。一般会报如下错误:Can't read from server. It may not have the appropriate access-control-origin settings。 怎么处理?只要加一段小代码即可解决。把getListingJsonResponse()代码修改一下即可(yaml一样):
rsp.header("Access-Control-Allow-Origin", "*");
rsp.header("Access-Control-Allow-Headers","x-requested-with, ssi-token");
rsp.header("Access-Control-Max-Age", "3600");
rsp.header("Access-Control-Allow-Methods","GET,POST,PUT,DELETE,OPTIONS");
OK!这样Swagger的修改完成了,打包上传你的私库吧。
二、在dubbox后台开发中使用
后台使用就只要把需要显示的Rest接口加入注解@api,@ApiOperation,然后配置对应bean即可使用,具体如下:
1)引入jar包:
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-core</artifactId>
<version>你的版本号</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jaxrs</artifactId>
<version>你的版本号</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jersey-jaxrs</artifactId>
<version>你的版本号</version>
</dependency>
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-jersey2-jaxrs</artifactId>
<version>你的版本号</version>
</dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.10</version>
</dependency>
2)在spring的配置文件里加入:
<bean id="swaggerService" class="io.swagger.jaxrs.listing.DubboxAcceptHeaderApiListingResource" />
<bean id="beanConfig" class="io.swagger.jaxrs.config.BeanConfig">
<property name="schemes" value="http" />
<!-- com.abc.aa这个值不能写成com.abc.aa.*-->
<property name="resourcePackage" value="com.abc.aa"/>
<property name="version" value="1.0"/>
<property name="host" value="10.10.10.23:8888"/>
<property name="basePath" value="/test"/>
<property name="title" value="这个是标题啊"/>
<property name="description" value="这里是描述呢"/>
<property name="contact" value="abc"/>
<property name="license" value="Apache 2.0"/>
<property name="licenseUrl" value="http://www.apache.org/licenses/LICENSE-2.0.html"/>
<property name="scan" value="true"/>
</bean>
<dubbo:service interface="io.swagger.jaxrs.listing.DubboxSwaggerService" ref="swaggerService"/>
3)对应的接口加入注解。如:
@Path("abc")
@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
@Produces({MediaType.APPLICATION_JSON + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8", MediaType.TEXT_XML + "; " + MediaType.CHARSET_PARAMETER + "=UTF-8"})
@Api("Demo-api")
public interface DemoRestService {
@GET
@Path("{id : \\d+}")
@ApiOperation(value="通过主键获取用户信息")
Demo getDemo(@PathParam("id") @Min(1) Integer id);
}
恭喜你!要进行的操作完成了。在浏览器输入:http://10.10.10.23:8888/test/dubboxswagger/swagger.json即可看到结果.
注意:这里配置的端口号要跟dubbox配置的Rest端口一致。