昂首阔步:让开发人员喜欢使用您的REST API

随着JAX-RS API的发展,以及今年早些时候在JSR-339下发布的2.0版本,使用出色的Java平台创建REST服务变得更加容易。

但是,极大的简化带来了巨大的责任:记录所有这些API,以便其他开发人员可以快速了解如何使用它们。 不幸的是,在这方面开发人员只能靠自己: JSR-339并没有太大帮助。 可以肯定的是,从源代码生成冗长且易于遵循的文档,而不是要求某人在开发过程中编写它,真是太棒了。 听起来不真实,对吧? 在某种程度上确实如此,但是帮助以Swagger的形式出现。

本质上, Swagger做的是一件简单但非常强大的事情:通过添加一些附加注释,它会生成REST API描述( HTTP方法,路径/查询/表单参数,响应, HTTP错误代码等),甚至提供了一个简单的Web UI来玩对您的API的REST调用(更不用说所有这些元数据也可以通过REST获得)。

在深入研究实现细节之前,让我们快速看一下Swagger来自API消费者预期的含义。 假设您已经开发了一种出色的REST服务来管理人员。 作为良好的公民,此REST服务具有完整的功能,并提供以下功能:

  • 列出所有人( GET
  • 通过电子邮件查找人( GET
  • 添加新人( POST
  • 更新现有人员( PUT
  • 最后删除人( DELETE

Swagger的角度来看,这是相同的API:

昂首阔步

看起来很漂亮。 让我们做更多的事情,并从Swagger UI调用我们的REST服务,这真棒。 最复杂的用例是添加新人( POST ),因此将仔细研究这一情况。

昂首阔步

如您在上面的快照中所见,每一个REST服务调用都存在:

  • 服务说明
  • 相对语境路径
  • 参数(形式/路径/查询),必需或可选
  • HTTP状态码: 201 CREATED409 CONFLICT
  • 准备出发尝试一下! 立即调用REST服务(具有开箱即用的参数验证功能)

招摇反应

为了完成演示部分,让我展示另一个示例,其中涉及REST资源(在我们的例子中,这是一个简单的Person类)。 Swagger能够提供其属性和有意义的描述以及预期的响应内容类型。

大摇大摆

看起来不错! 转到下一部分,所有内容都与实现细节有关。 Swagger支持与JAX-RS服务的无缝集成,在现有注释的顶部仅需几个附加注释。 首先,在我们的示例中,应该记录的每个单个JAX-RS服务都应使用@Api注释进行注释:

@Path( "/people" ) 
@Api( value = "/people", description = "Manage people" )
public class PeopleRestService {
    // ...
}

接下来,相同的方法适用于REST服务操作:应该记录的每个方法都应使用@ApiOperation批注(可选)并使用@ ApiResponses / @ ApiResponse进行批注 。 如果它接受参数,则应使用@ApiParam批注进行批注。 这里有几个例子:

@Produces( { MediaType.APPLICATION_JSON } )
@GET
@ApiOperation( 
    value = "List all people", 
    notes = "List all people using paging", 
    response = Person.class, 
    responseContainer = "List"
)
public Collection< Person > getPeople(  
        @ApiParam( value = "Page to fetch", required = true ) 
        @QueryParam( "page") @DefaultValue( "1" ) final int page ) {
    // ...
}

还有一个:

@Produces( { MediaType.APPLICATION_JSON } )
@Path( "/{email}" )
@GET
@ApiOperation( 
    value = "Find person by e-mail", 
    notes = "Find person by e-mail", 
    response = Person.class 
)
@ApiResponses( {
    @ApiResponse( code = 404, message = "Person with such e-mail doesn't exists" )    
} )
public Person getPeople( 
        @ApiParam( value = "E-Mail address to lookup for", required = true ) 
        @PathParam( "email" ) final String email ) {
    // ...
}

REST资源类(或模型类)需要特殊的注释: @ApiModel@ApiModelProperty 。 这是我们的Person类的样子:

@ApiModel( value = "Person", description = "Person resource representation" )
public class Person {
    @ApiModelProperty( value = "Person's first name", required = true ) 
    private String email;
    @ApiModelProperty( value = "Person's e-mail address", required = true ) 
    private String firstName;
    @ApiModelProperty( value = "Person's last name", required = true ) 
    private String lastName;

    // ...
}

最后一步是将Swagger插入JAX-RS应用程序。 我开发的示例使用Spring FrameworkApache CXFSwagger UI和嵌入式Jetty (完整项目可在Github上找到 )。 集成Swagger只需添加配置bean( swaggerConfig ),一个附加的JAX-RS服务( apiListingResourceJson )和两个JAX-RS提供程序( resourceListingProviderapiDeclarationProvider )即可。

package com.example.config;

import java.util.Arrays;

import javax.ws.rs.ext.RuntimeDelegate;

import org.apache.cxf.bus.spring.SpringBus;
import org.apache.cxf.endpoint.Server;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.core.env.Environment;

import com.example.resource.Person;
import com.example.rs.JaxRsApiApplication;
import com.example.rs.PeopleRestService;
import com.example.services.PeopleService;
import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider;
import com.wordnik.swagger.jaxrs.config.BeanConfig;
import com.wordnik.swagger.jaxrs.listing.ApiDeclarationProvider;
import com.wordnik.swagger.jaxrs.listing.ApiListingResourceJSON;
import com.wordnik.swagger.jaxrs.listing.ResourceListingProvider;

@Configuration
public class AppConfig {
    public static final String SERVER_PORT = "server.port";
    public static final String SERVER_HOST = "server.host";
    public static final String CONTEXT_PATH = "context.path";  

    @Bean( destroyMethod = "shutdown" )
    public SpringBus cxf() {
        return new SpringBus();
    }

    @Bean @DependsOn( "cxf" )
    public Server jaxRsServer() {
        JAXRSServerFactoryBean factory = RuntimeDelegate.getInstance().createEndpoint( jaxRsApiApplication(), JAXRSServerFactoryBean.class );
        factory.setServiceBeans( Arrays.< Object >asList( peopleRestService(), apiListingResourceJson() ) );
        factory.setAddress( factory.getAddress() );
        factory.setProviders( Arrays.< Object >asList( jsonProvider(), resourceListingProvider(), apiDeclarationProvider() ) );
        return factory.create();
    }

    @Bean @Autowired
    public BeanConfig swaggerConfig( Environment environment ) {
        final BeanConfig config = new BeanConfig();

        config.setVersion( "1.0.0" );
        config.setScan( true );
        config.setResourcePackage( Person.class.getPackage().getName() );
        config.setBasePath( 
            String.format( "http://%s:%s/%s%s",
                environment.getProperty( SERVER_HOST ),
                environment.getProperty( SERVER_PORT ),
                environment.getProperty( CONTEXT_PATH ),
                jaxRsServer().getEndpoint().getEndpointInfo().getAddress() 
            ) 
        );

        return config;
    }

    @Bean
    public ApiDeclarationProvider apiDeclarationProvider() {
        return new ApiDeclarationProvider();
    }

    @Bean
    public ApiListingResourceJSON apiListingResourceJson() {
        return new ApiListingResourceJSON();
    }

    @Bean
    public ResourceListingProvider resourceListingProvider() {
        return new ResourceListingProvider();
    }

    @Bean 
    public JaxRsApiApplication jaxRsApiApplication() {
        return new JaxRsApiApplication();
    }

    @Bean 
    public PeopleRestService peopleRestService() {
        return new PeopleRestService();
    }

    // ... 
}

为了摆脱任何可能的硬编码配置,所有参数都通过命名属性( SERVER_PORTSERVER_HOSTCONTEXT_PATH )传递。 Swagger公开了其他REST端点来提供API文档,在我们的示例中,可以通过以下网址访问它: http:// localhost:8080 / rest / api / api-docsSwagger UI使用它,它本身已嵌入最终的JAR存档中,并由Jetty用作静态Web资源。

最后一个难题是启动嵌入式Jetty容器,该容器将所有这些部件粘合在一起并封装到Starter类中:

package com.example;

import org.apache.cxf.transport.servlet.CXFServlet;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.handler.HandlerList;
import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.util.resource.Resource;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;

import com.example.config.AppConfig;

public class Starter {
    private static final int SERVER_PORT = 8080;
    private static final String CONTEXT_PATH = "rest";

    public static void main( final String[] args ) throws Exception {
        Resource.setDefaultUseCaches( false );

        final Server server = new Server( SERVER_PORT );  
        System.setProperty( AppConfig.SERVER_PORT, Integer.toString( SERVER_PORT ) );
        System.setProperty( AppConfig.SERVER_HOST, "localhost" );
        System.setProperty( AppConfig.CONTEXT_PATH, CONTEXT_PATH );    

        // Configuring Apache CXF servlet and Spring listener  
        final ServletHolder servletHolder = new ServletHolder( new CXFServlet() );      
        final ServletContextHandler context = new ServletContextHandler();   
        context.setContextPath( "/" );
        context.addServlet( servletHolder, "/" + CONTEXT_PATH + "/*" );     
        context.addEventListener( new ContextLoaderListener() ); 

        context.setInitParameter( "contextClass", AnnotationConfigWebApplicationContext.class.getName() );
        context.setInitParameter( "contextConfigLocation", AppConfig.class.getName() );

        // Configuring Swagger as static web resource
        final ServletHolder swaggerHolder = new ServletHolder( new DefaultServlet() );
        final ServletContextHandler swagger = new ServletContextHandler();
        swagger.setContextPath( "/swagger" );
        swagger.addServlet( swaggerHolder, "/*" );
        swagger.setResourceBase( new ClassPathResource( "/webapp" ).getURI().toString() );

        final HandlerList handlers = new HandlerList();
        handlers.addHandler( context );
        handlers.addHandler( swagger );

        server.setHandler( handlers );
        server.start();
        server.join(); 
    }
}

几点评论使事情变得更加清晰:我们的JAX-RS服务将在/ rest / *上下文路径下可用,而Swagger UI/ swagger上下文路径下可用。 关于Resource.setDefaultUseCaches(false)的一个重要说明:因为我们正在从JAR文件提供静态Web内容,所以必须将此属性设置为false作为此bug的解决方法。

现在,让我们通过输入以下内容来构建并运行我们的JAX-RS应用程序:

mvn clean package
java -jar target/jax-rs-2.0-swagger-0.0.1-SNAPSHOT.jar

稍后,您的浏览器中将提供Swagger UI网址为: http:// localhost:8080 / swagger /

最后一点,关于Swagger还有很多话要说,但是我希望这个简单的示例能够显示出使我们的REST服务具有自文档化的功能,并且只需很少的工作即可轻松使用。 非常感谢Wordnik团队。


翻译自: https://www.javacodegeeks.com/2013/10/swagger-make-developers-love-working-with-your-rest-api.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MobAXTerm是一个功能强大的远程控制和终端模拟器,它可以用于连接Linux、Unix、Windows等服务器,包括通过TFTP协议传输文件。TFTP(Trivial File Transfer Protocol)是一种小型的文件传输协议,常用于网络设备(如路由器、交换机)的软件升级。 要在MobAXTerm中使用TFTP命令,首先确保你的MobAXTerm配置了正确的TFTP服务器地址。下面是基本步骤: 1. **打开MobAXTerm**:启动MobAXTerm并登录到你的目标服务器或计算机。 2. **打开命令行界面**:在MobAXTerm的菜单中,通常选择"终端"或"Session" -> "Shell",进入命令行环境。 3. **设置TFTP路径和文件名**:在命令行中,你可以使用`tftp`命令加上服务器IP地址和文件操作,例如: ``` tftp <server-ip> put <filename> /path/to/save/in/target ``` 这里 `put` 是上传文件的命令,`get` 则是下载文件。 4. **上传文件**:运行`put`命令后,从本地选择你要上传的文件,然后回车,文件会被发送到指定的目标路径。 5. **下载文件**:如果你想下载文件,用`get`代替`put`,然后指定远程文件名和本地保存路径。 6. **检查传输状态**:TFTP没有进度显示,但可以通过查看传输是否成功来判断。如果文件上传或下载完成后,会收到确认消息。 **相关问题--:** 1. TFTP主要适用于哪些场景? 2. MobAXTerm如何配置TFTP服务器地址? 3. 如何验证TFTP传输是否成功?

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值