Java 中的 RESTful 调用

Posted

技术标签:

【中文标题】Java 中的 RESTful 调用【英文标题】:RESTful call in Java 【发布时间】:2011-04-24 05:34:28 【问题描述】:

我将使用 Java 进行 RESTful 调用。但是,我不知道如何拨打电话。我需要使用URLConnection 或其他吗?

【问题讨论】:

这取决于您如何在应用程序中进行休息调用。你使用 JaxRS 实现吗?一个特定的?你是手动做请求吗? @Colin Hebert,感谢您的回复。但我对 RESTful 调用一无所知。你能给我更多关于 RESTful 调用不同部分的信息吗? checkout http restful 客户端click here 【参考方案1】:

更新:我写下面的答案已经快 5 年了;今天我有不同的看法。

99% 的时候,人们使用术语 REST 时,实际上是指 HTTP;他们可能不太关心“资源”、“表示”、“状态转移”、“统一接口”、“超媒体”或任何其他constraints or aspects of the REST architecture style identified by Fielding。因此,各种 REST 框架提供的抽象令人困惑且无益。

所以:您想在 2015 年使用 Java 发送 HTTP 请求。您需要一个清晰、富有表现力、直观、惯用、简单的 API。用什么?我不再使用 Java,但在过去几年中,似乎最有前途和最有趣的 Java HTTP 客户端库是OkHttp。看看吧。


您绝对可以通过使用URLConnection 或HTTPClient 对HTTP 请求进行编码来与RESTful Web 服务进行交互。

但是,通常更希望使用一个库或框架,该库或框架提供了一个专门为此目的设计的更简单、更具语义的 API。这使代码更易于编写、阅读和调试,并减少了重复工作。这些框架通常会实现一些在低级库中不一定存在或易于使用的强大功能,例如内容协商、缓存和身份验证。

一些最成熟的选项是Jersey、RESTEasy 和Restlet。

我最熟悉 Restlet 和 Jersey,让我们看看我们如何使用这两个 API 发出 POST 请求。

球衣示例

Form form = new Form();
form.add("x", "foo");
form.add("y", "bar");

Client client = ClientBuilder.newClient();

WebTarget resource = client.target("http://localhost:8080/someresource");

Builder request = resource.request();
request.accept(MediaType.APPLICATION_JSON);

Response response = request.get();

if (response.getStatusInfo().getFamily() == Family.SUCCESSFUL) 
    System.out.println("Success! " + response.getStatus());
    System.out.println(response.getEntity());
 else 
    System.out.println("ERROR! " + response.getStatus());    
    System.out.println(response.getEntity());

Restlet 示例

Form form = new Form();
form.add("x", "foo");
form.add("y", "bar");

ClientResource resource = new ClientResource("http://localhost:8080/someresource");

Response response = resource.post(form.getWebRepresentation());

if (response.getStatus().isSuccess()) 
    System.out.println("Success! " + response.getStatus());
    System.out.println(response.getEntity().getText());
 else 
    System.out.println("ERROR! " + response.getStatus());
    System.out.println(response.getEntity().getText());

当然,GET 请求更简单,您还可以指定实体标签和Accept 标头之类的内容,但希望这些示例有用但不会太复杂。

如您所见,Restlet 和 Jersey 具有相似的客户端 API。我相信它们是在同一时间发展起来的,因此相互影响。

我发现 Restlet API 更加语义化,因此更加清晰,但 YMMV。

正如我所说,我对 Restlet 最为熟悉,多年来我在许多应用程序中都使用过它,我对它非常满意。这是一个非常成熟、健壮、简单、有效、活跃且得到良好支持的框架。我无法与 Jersey 或 RESTEasy 交谈,但我的印象是它们都是可靠的选择。

【讨论】:

但仍然是一个很棒的帖子。我必须同意“99% 的情况下,人们使用术语 REST 时,它们实际上是指 HTTP;......因此,各种 REST 框架提供的抽象令人困惑且无益。” 在您的 Jersey 示例中,Form 对象在哪里/如何使用?它已创建,但似乎没有向示例添加任何内容。【参考方案2】:

如果您从服务提供商(例如 Facebook、Twitter)调用 RESTful 服务,您可以选择任何风格

如果您不想使用外部库,可以使用java.net.HttpURLConnectionjavax.net.ssl.HttpsURLConnection(用于 SSL),但这是封装在 java.net.URLConnection 中的工厂类型模式中的调用。 要接收结果,您必须发送至connection.getInputStream(),它会返回一个InputStream。然后,您必须将输入流转换为字符串,并将字符串解析为其代表对象(例如 XML、JSON 等)。

或者,Apache HttpClient(版本 4 是最新的)。它比 java 的默认 URLConnection 更稳定和健壮,它支持大多数(如果不是全部)HTTP 协议(​​以及它可以设置为严格模式)。您的回复仍将在InputStream 中,您可以按照上述方式使用它。


HttpClient 文档:http://hc.apache.org/httpcomponents-client-ga/tutorial/html/index.html

【讨论】:

不要重新发明***,使用现有的 RESTful 实现之一。 这不是重新发明***,我是说你可以使用任何你想要的flavour。有些人想要默认的URLConnection,有些人想要HttpClient。无论哪种方式,它都可供您使用。 @精英绅士,谢谢您的回复。在检查了所有的库之后,我想使用 Apache HttpClient,你介意给我更多关于这个的参考吗? @Questions,指向 HttpClient 4 示例的链接似乎已损坏,所以如果您有任何问题(双关语……哈哈),请告诉我……我几乎处理了每天。 请展示如何使用这些类的示例代码,而不是仅仅指出它们的存在【参考方案3】:

这在java中非常复杂,这就是为什么我建议使用Spring的RestTemplate抽象:

String result = 
restTemplate.getForObject(
    "http://example.com/hotels/hotel/bookings/booking",
    String.class,"42", "21"
);

参考:

春季博客:Rest in Spring 3 (RestTemplate) 弹簧参考:Accessing RESTful services on the Client JavaDoc:RestTemplate

【讨论】:

据此 - ***.com/questions/42365266/… - RestTemplate 将在未来的版本中被弃用,使用更现代的替代品 WebClient @kaushalpranav 我当时的回答是正确的,但情况发生了变化。我建议您使用 WebClient 添加自己的答案 是的。我最近在我的项目中使用了RestTemplate,但不知道WebClient,所以只是想引导来这里的人使用更新的替代方案。【参考方案4】:

如果您只需要从 java 中对 REST 服务进行简单调用,您可以使用这些方法

/*
 * Stolen from http://xml.nig.ac.jp/tutorial/rest/index.html
 * and http://www.dr-chuck.com/csev-blog/2007/09/calling-rest-web-services-from-java/
*/
import java.io.*;
import java.net.*;

public class Rest 

    public static void main(String[] args) throws IOException 
        URL url = new URL(INSERT_HERE_YOUR_URL);
        String query = INSERT_HERE_YOUR_URL_PARAMETERS;

        //make connection
        URLConnection urlc = url.openConnection();

        //use post mode
        urlc.setDoOutput(true);
        urlc.setAllowUserInteraction(false);

        //send query
        PrintStream ps = new PrintStream(urlc.getOutputStream());
        ps.print(query);
        ps.close();

        //get result
        BufferedReader br = new BufferedReader(new InputStreamReader(urlc
            .getInputStream()));
        String l = null;
        while ((l=br.readLine())!=null) 
            System.out.println(l);
        
        br.close();
    

【讨论】:

周围有一些非常好的 REST API,我建议使用其中一个而不是重新发明***。 正如我所说:复杂得要命。 (不,我没有对此投反对票,这是一个完全有效的解决方案) @Qwerky 客户端 API 库通常违反 REST 约束。它们引入了太多的耦合。从长远来看,使用一个好的 HTTP 库是一个更好的选择。【参考方案5】:

周围有几个 RESTful API。我会推荐泽西岛;

https://jersey.java.net/

客户端 API 文档在这里;

https://jersey.java.net/documentation/latest/index.html

更新 下面评论中 OAuth 文档的位置是死链接,已移至 https://jersey.java.net/nonav/documentation/latest/security.html#d0e12334

【讨论】:

OP 不是在创建 RESTful 应用程序,而是在进行 RESTful 调用,即像调用 Twitter API 方法资源一样。 @Qwerky - 我认为在回答中包含您推荐泽西岛的原因会很有帮助。【参考方案6】:

我想分享我的个人经验,使用 Post JSON 调用调用 REST WS:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.URL;
import java.net.URLConnection;

public class HWS 

    public static void main(String[] args) throws IOException 
        URL url = new URL("INSERT YOUR SERVER REQUEST");
        //Insert your JSON query request
        String query = "'PARAM1': 'VALUE','PARAM2': 'VALUE','PARAM3': 'VALUE','PARAM4': 'VALUE'";
        //It change the apostrophe char to double quote char, to form a correct JSON string
        query=query.replace("'", "\"");

        try
            //make connection
            URLConnection urlc = url.openConnection();
            //It Content Type is so important to support JSON call
            urlc.setRequestProperty("Content-Type", "application/xml");
            Msj("Conectando: " + url.toString());
            //use post mode
            urlc.setDoOutput(true);
            urlc.setAllowUserInteraction(false);
    
            //send query
            PrintStream ps = new PrintStream(urlc.getOutputStream());
            ps.print(query);
            Msj("Consulta: " + query);
            ps.close();
    
            //get result
            BufferedReader br = new BufferedReader(new InputStreamReader(urlc.getInputStream()));
            String l = null;
            while ((l=br.readLine())!=null) 
                Msj(l);
            
            br.close();
         catch (Exception e)
            Msj("Error ocurrido");
            Msj(e.toString());
        
    
    
    private static void Msj(String texto)
        System.out.println(texto);
    

【讨论】:

【参考方案7】:

您可以查看CXF。您可以访问 JAX-RS 文章here

调用就这么简单(引用):

BookStore store = JAXRSClientFactory.create("http://bookstore.com", BookStore.class);
// (1) remote GET call to http://bookstore.com/bookstore
Books books = store.getAllBooks();
// (2) no remote call
BookResource subresource = store.getBookSubresource(1);
// 3 remote GET call to http://bookstore.com/bookstore/1
Book b = subresource.getDescription();

【讨论】:

【参考方案8】:

最简单的解决方案将使用 Apache http 客户端库。请参阅以下示例代码.. 此代码使用基本安全性进行身份验证。

添加以下依赖。

<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.4</version>
</dependency>
CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
Credentials credentials = new UsernamePasswordCredentials("username", "password");
credentialsProvider.setCredentials(AuthScope.ANY, credentials);
HttpClient client = HttpClientBuilder.create().setDefaultCredentialsProvider(credentialsProvider).build();
HttpPost request = new HttpPost("https://api.plivo.com/v1/Account/MAYNJ3OT/Message/");HttpResponse response = client.execute(request);
    // Get the response
    BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
    String line = "";
    while ((line = rd.readLine()) != null)     
    textView = textView + line;
    
    System.out.println(textView);

【讨论】:

您提供了 maven 依赖项,但您没有包含任何导入语句。这几乎很有用。【参考方案9】:

确实,这“在 Java 中非常复杂”:

发件人:https://jersey.java.net/documentation/latest/client.html

Client client = ClientBuilder.newClient();
WebTarget target = client.target("http://foo").path("bar");
Invocation.Builder invocationBuilder = target.request(MediaType.TEXT_PLAIN_TYPE);
Response response = invocationBuilder.get();

【讨论】:

【参考方案10】:

我看到了很多答案,这是我们在 2020 年使用的 WebClient,顺便说一句,RestTemplate 将被弃用。 (可以查看)RestTemplate going to be deprecated

【讨论】:

您可以在这里添加解释,而不是提供链接吗?【参考方案11】:

以下是一个 GET 请求示例,它将响应正文打印为 带有HttpRequest的字符串:

   HttpClient client = HttpClient.newHttpClient();
   HttpRequest request = HttpRequest.newBuilder()
         .uri(URI.create("http://example.org/"))
         .build();
   client.sendAsync(request, BodyHandlers.ofString())
         .thenApply(HttpResponse::body)
         .thenAccept(System.out::println)
         .join(); 

如果您需要设置标题,您可以在HttpRequest.Builder 中使用以下方法:

.setHeader("api-key", "value")

【讨论】:

【参考方案12】:

你可以像这样使用Async Http Client(该库还支持WebSocket协议):

    String clientChannel = UriBuilder.fromPath("http://localhost:8080/api/id").build(id).toString();

    try (AsyncHttpClient asyncHttpClient = new AsyncHttpClient())
    
        BoundRequestBuilder postRequest = asyncHttpClient.preparePost(clientChannel);
        postRequest.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON);
        postRequest.setBody(message.toString()); // returns JSON
        postRequest.execute().get();
    

【讨论】:

它不起作用(无法实例化 ASyncHttpClient)。

以上是关于Java 中的 RESTful 调用的主要内容,如果未能解决你的问题,请参考以下文章

java调用restful api接口,有没有啥好的框架推荐

java后台接口怎么方便返回restful数据

java调用restful webservice(转)

现在有一个SSO的Restful 的接口,用java代码具体怎么调用这个接口啊,需要传参啊?

从java调用带有对象作为参数的RESTful WCFservice方法

如何在Java客户端调用RESTful服务