如何为Java创建REST客户端?[关闭]


247

有了JSR 311及其实现,我们有了一个强大的标准,可以通过REST公开Java对象。但是,在客户端,似乎缺少与SOAP的Apache Axis类似的东西-隐藏了Web服务并将数据透明地封送回Java对象的东西。

您如何创建Java RESTful客户端?使用HTTPConnection和手动解析结果?还是专业客户(例如Jersey或Apache CXR)?


刚刚在Apache Incubator中找到了Apache Wink。创建REST服务器和客户端可能是一个有趣的项目。
Yaba


查看[Resting](code.google.com/p/resting)。它承诺一步就可以调用REST服务并根据XML / JSON / YAML响应创建对象列表。
neel 2011年

休息与POST请求有关。
RyanBrady 2012年

2
您可以使用resteasy(由Jboss)以非常简单的方式进行操作。如果您想要入门指南,我写了一篇博客文章,介绍如何开发Java REST客户端。无论如何,Java中有数百种替代方法。
Guido 2012年

Answers:


204

这是一个古老的问题(2008年),所以现在有比以前更多的选择:

更新(项目在2020年仍处于活动状态):

  • Apache HTTP组件(4.2)Fluent适配器-JDK的基本替代品,此列表中的其他几个候选者使用。比旧的Commons HTTP Client 3更好,并且更容易用于构建自己的REST客户端。您必须使用类似于 Jackson的支持JSON解析,并且可以使用 HTTP组件URIBuilder来构造类似于Jersey / JAX-RS Rest客户端的资源URI。HTTP组件也支持NIO,但我想您会因为REST的短暂要求而获得比BIO更好的性能。Apache HttpComponents 5具有HTTP / 2支持。
  • OkHttp -JDK的基本替代品,类似于http组件,此列表中的其他几个候选者使用。支持更新的HTTP协议(SPDY和HTTP2)。适用于Android。不幸的是,它没有提供真正的基于反应堆循环的异步选项(请参见上面的Ning和HTTP组件)。但是,如果您使用较新的HTTP2协议,则问题不大(假设连接计数有问题)。
  • Ning Async-http- client-提供NIO支持。以前被 Sonatype称为 Async-http-client
  • 低级http客户端(okhttp,apache httpcomponents)的包装。基于类似于某些Jersey和CXF扩展名的接口存根自动创建客户端。强大的弹簧集成。
  • 改造 -用于较低级别http客户端(okhttp)的包装。基于类似于某些Jersey和CXF扩展名的接口存根自动创建客户端。
  • Google的JDK HTTP客户端的 Volley包装器
  • 由Google为jdk http客户端或apache httpcomponents提供的 google-http包装器
  • JDK HTTP客户端的 Unirest包装器,由kong
  • 用于jdk http客户端的 Resteasy JakartaEE包装器,由jboss框架,jboss框架的一部分
  • jcabi-http包装器,用于Apache httpcomponents,是jcabi集合的一部分
  • 用于Apache httpcomponents的 restlet包装器,是restlet框架的一部分
  • 带有断言的易于保证的包装器,易于测试

关于选择HTTP / REST客户端的警告。确保检查您的框架堆栈用于HTTP客户端的方式,如何进行线程化,并且如果提供了该客户端,最好使用相同的客户端。那就是说,如果您使用Vert.x或Play之类的东西,则可能希望尝试使用其支持客户端来参与框架提供的任何总线或反应堆循环...否则,为可能发生的有趣线程问题做好准备。


1
不幸的是,如果将JDK <8
botchniaque

3
Unirest非常易于使用,但其静态设计使其无法在共享和服务器环境中使用。
bekce 2015年

9
关于单项评论,我想补充一下,当前(2016年底)看起来好像不再维护该项目。甚至还有一个问题需要新的维护者。
wegenmic '16

4
对于喜欢Unirest的来说,我拥有一个正在积极维护/更新的分支
乔什

3
将答案转变为社区Wiki非常好
tkruse

71

正如我在该线程中提到的那样,我倾向于使用实现JAX-RS并带有一个不错的REST客户端的Jersey。不错的事情是,如果您使用JAX-RS实现RESTful资源,那么Jersey客户端可以重用诸如JAXB / XML / JSON / Atom之类的实体提供程序-这样您就可以在服务器端重用与您相同的对象在客户端进行单元测试。

例如,这是来自Apache Camel项目的单元测试用例,它从RESTful资源(使用JAXB对象Endpoints)中查找XML有效负载。在此基类中定义了resource(uri)方法,方法仅使用Jersey客户端API。

例如

    clientConfig = new DefaultClientConfig();
    client = Client.create(clientConfig);

    resource = client.resource("http://localhost:8080");
    // lets get the XML as a String
    String text = resource("foo").accept("application/xml").get(String.class);        

顺便说一句,我希望将来的JAX-RS版本能像Jersey那样添加一个不错的客户端API。


有没有一种方法可以在ClientResource中提及REST服务服务器列表,以防服务器宕机尝试下一个服务器?
Njax3SmmM2x2a0Zf7Hpd

1
只是一个更新,但地址詹姆斯的‘BTW’评论,JAX-RS的新版本2.0将有一个客户端API:infoq.com/presentations/Java-REST
尼克Klauer

64

您可以使用标准的Java SE API:

private void updateCustomer(Customer customer) { 
    try { 
        URL url = new URL("http://www.example.com/customers"); 
        HttpURLConnection connection = (HttpURLConnection) url.openConnection(); 
        connection.setDoOutput(true); 
        connection.setInstanceFollowRedirects(false); 
        connection.setRequestMethod("PUT"); 
        connection.setRequestProperty("Content-Type", "application/xml"); 

        OutputStream os = connection.getOutputStream(); 
        jaxbContext.createMarshaller().marshal(customer, os); 
        os.flush(); 

        connection.getResponseCode(); 
        connection.disconnect(); 
    } catch(Exception e) { 
        throw new RuntimeException(e); 
    } 
} 

或者,您可以使用JAX-RS实现(例如Jersey)提供的REST客户端API。这些API易于使用,但在类路径上需要其他jar。

WebResource resource = client.resource("http://www.example.com/customers"); 
ClientResponse response = resource.type("application/xml");).put(ClientResponse.class, "<customer>...</customer."); 
System.out.println(response); 

有关更多信息,请参见:


15
13行简单的电话会议,在2018年,听起来太多了……
克林特·伊斯特伍德

1
一旦添加了错误处理和选项,就没有太大的不同。如果SE方法看起来很长,您总是可以将其包装在一个类中...:>经过两天的调试JAX-RS库冲突,我真的可以再加上5行代码来避免整个SPI噩梦。
tekHedd

2
@ClintEastwood这篇文章写于2010年
0ddlyoko '19

12

如果您只想调用REST服务并解析响应,则可以尝试Rest Assured

// Make a GET request to "/lotto"
String json = get("/lotto").asString()
// Parse the JSON response
List<String> winnderIds = with(json).get("lotto.winners.winnerId");

// Make a POST request to "/shopping"
String xml = post("/shopping").andReturn().body().asString()
// Parse the XML
Node category = with(xml).get("shopping.category[0]");

9

您还可以检查Restlet,它具有完整的客户端功能,相对于诸如HttpURLConnection或Apache HTTP Client(我们可以利用它们作为连接器)之类的较低级库更面向REST。

最好的问候,Jerome Louvel


2
从2019年10月24日起,提供的链接返回:“ Restlet平台已到使用寿命。”
汉斯·德拉贡

6

您可以尝试拉帕。让我们知道您对此的反馈。并随时记录问题或预期功能。


1
Rapa的界面非常好,几乎没有依赖关系。在.NET世界中,RestSharp是一个很好的选择。
日下午

项目看起来已经死了
tkruse



5

我最近尝试了Square的Retrofit库,它很棒,您可以非常轻松地调用rest API。基于注释的配置使我们摆脱了很多样板代码。


4

我使用Apache HTTPClient处理所有HTTP方面的事情。

我为XML内容编写了XML SAX解析器,该解析器将XML解析为您的对象模型。我相信Axis2还公开了XML-> Model方法(Axis 1烦人地隐藏了这部分)。XML生成器非常简单。

我认为编写代码不会花很长时间,而且效率很高。


4
我认为这是进行REST的最糟糕方法。当您有很多选择(例如JAXB和Jackson)时,用Java手动处理序列化是浪费时间。甚至加载整个文档并使用XPath都比SAX稍慢,并且与获取XML(网络速度)相比,没有任何好处。
亚当·根特

1
我也同意,我写了原始评论。那时,我渴望控制反序列化,但是如今,我将使用Jackson和具有体面注释的模型类。
JeeBee

4

与Retrofit结合使用时,OkHttp既轻巧又强大。这对于一般的Java使用以及Android都适用。

OkHttphttp : //square.github.io/okhttp/

public static final MediaType JSON
    = MediaType.parse("application/json; charset=utf-8");

OkHttpClient client = new OkHttpClient();

String post(String url, String json) throws IOException {
  RequestBody body = RequestBody.create(JSON, json);
  Request request = new Request.Builder()
      .url(url)
      .post(body)
      .build();
  Response response = client.newCall(request).execute();
  return response.body().string();
}

改造http : //square.github.io/retrofit/

public interface GitHubService {
  @GET("/users/{user}/repos")
  Call<List<Repo>> listRepos(@Path("user") String user);
}


2

虽然创建HTTP客户端并进行请求很简单。但是,如果要使用一些自动生成的客户端,则可以使用WADL来描述和生成代码。

您可以使用RestDescribe生成和编译WSDL,也可以使用php,ruby,python,java和C#生成客户端。它会生成干净的代码,并且有一个很好的变化,您需要在代码生成后进行一些调整,您可以在此处找到良好的文档和该工具的基本思想。

在Wintermute上,几乎没有提到有趣且有用的WADL工具



0

尝试查看http-rest-client

https://github.com/g00dnatur3/http-rest-client

这是一个简单的示例:

RestClient client = RestClient.builder().build();
String geocoderUrl = "http://maps.googleapis.com/maps/api/geocode/json"
Map<String, String> params = Maps.newHashMap();
params.put("address", "beverly hills 90210");
params.put("sensor", "false");
JsonNode node = client.get(geocoderUrl, params, JsonNode.class);

该库为您处理json序列化和绑定。

这是另一个例子

RestClient client = RestClient.builder().build();
String url = ...
Person person = ...
Header header = client.create(url, person);
if (header != null) System.out.println("Location header is:" + header.value());

最后一个例子

RestClient client = RestClient.builder().build();
String url = ...
Person person = client.get(url, null, Person.class); //no queryParams

干杯!


0

jersey rest客户示例:
添加依赖项:

         <!-- jersey -->
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.8</version>
    </dependency>
   <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-server</artifactId>
        <version>1.8</version>
    </dependency>

<dependency>
    <groupId>com.sun.jersey</groupId>
    <artifactId>jersey-client</artifactId>
    <version>1.8</version>
</dependency>

    <dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20090211</version>
</dependency>

ForGetMethod并传递两个参数:

          Client client = Client.create();
           WebResource webResource1 = client
                        .resource("http://localhost:10102/NewsTickerServices/AddGroup/"
                                + userN + "/" + groupName);

                ClientResponse response1 = webResource1.get(ClientResponse.class);
                System.out.println("responser is" + response1);

GetMethod传递一个参数并获得List的响应:

       Client client = Client.create();

        WebResource webResource1 = client
                    .resource("http://localhost:10102/NewsTickerServices/GetAssignedUser/"+grpName);    
    //value changed
    String response1 = webResource1.type(MediaType.APPLICATION_JSON).get(String.class);

    List <String > Assignedlist =new ArrayList<String>();
     JSONArray jsonArr2 =new JSONArray(response1);
    for (int i =0;i<jsonArr2.length();i++){

        Assignedlist.add(jsonArr2.getString(i));    
    }

在上面的代码中,返回一个我们接受为列表的列表,然后将其转换为Json Array,然后将其转换为List。

如果Post Request将Json Object作为参数传递:

   Client client = Client.create();
    WebResource webResource = client
            .resource("http://localhost:10102/NewsTickerServices/CreateJUser");
    // value added

    ClientResponse response = webResource.type(MediaType.APPLICATION_JSON).post(ClientResponse.class,mapper.writeValueAsString(user));

    if (response.getStatus() == 500) {

        context.addMessage(null, new FacesMessage("User already exist "));
    }


0

我目前正在使用https://github.com/kevinsawicki/http-request,我喜欢它们的简单性和示例的显示方式,但是当我阅读以下内容时,我大多被卖掉了:

有哪些依赖性?

没有。该库的目标是成为带有某些内部静态类的单个类。测试项目确实需要Jetty才能针对实际的HTTP服务器实现测试请求。

它解决了Java 1.6项目中的一些问题。至于将json解码为对象,gson就是无敌的:)


1
该项目看起来已经死了,自2015
。– tkruse
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.