Java 中的 RESTful 调用

我将用 Java 做一个 RESTful 调用。但是,我不知道怎么打电话。我需要使用 URLConnection或其他?

583773 次浏览

有几个 RESTful API,我推荐 Jersey;

Https://jersey.java.net/

客户端 API 文档在这里;

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

更新
下面评论中 OAuth 文档的位置是一个死链接,已经移动到了 < a href = “ https://jersey.java.net/nonav/document/update/security.html # d0e12334”rel = “ nofollow norefrer”> https://jersey.java.net/nonav/documentation/latest/security.html#d0e12334

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

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

参考文献:

  • Spring Blog: < a href = “ http://Blog.springsource.com/2009/03/27/Rest-in-Spring-3-resttemplate/”rel = “ noReferrer”> Rest in Spring 3 (RestTemplate)
  • Spring Reference: < a href = “ http://static.springsource.org/Spring/docs/3.0.4.RELEASE/Spring-Framework-Reference/html/Remoting.html # rest-client-access”rel = “ noReferrer”> AccessingRESTful 客户端上的服务
  • JavaDoc: RestTemplate

如果您只是需要从 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();
}
}

如果你从服务提供商(比如 Facebook,Twitter)调用 RESTful 服务,你可以选择任何 味道:

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

或者,Apache HttpClient(版本4是最新的)。它比 Java 的默认 URLConnection更稳定、更健壮,并且它支持大多数(如果不是全部的话) HTTP 协议(以及可以设置为 Strictmode)。您的响应仍然在 InputStream中,并且您可以像上面提到的那样使用它。


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

您可以查看 CXF,也可以访问 JAX-RS 文章 给你

打电话就像这样简单(引用) :

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();

更新: 从我写下这个答案到现在已经差不多5年了,今天我有了一个不同的视角。

99% 的时候,当人们使用 REST 这个术语时,他们真正的意思是 HTTP; 他们可能不太关心“资源”、“表示”、“状态传输”、“统一接口”、“超媒体”或任何其他 由 Fielding 标识的 REST 体系结构样式的约束或方面。因此,各种 REST 框架提供的抽象是混乱和无益的。

因此: 您希望在2015年使用 Java 发送 HTTP 请求。你需要一个清晰的,表达的,直观的,惯用的,简单的 API。用什么?我不再使用 Java 了,但是在过去的几年中,看起来最有前途和最有趣的 Java HTTP 客户端库是 好吧。看看这个。


通过使用 URLConnectionHTTPClient编写 HTTP 请求代码,您完全可以与 RESTful Web 服务进行交互。

但是,通常更希望使用一个库或框架,它提供了专门为此目的设计的更简单、更语义化的 API。这使得代码更容易编写、读取和调试,并减少了工作的重复。这些框架通常实现了一些在底层库中不一定存在或不容易使用的重要特性,例如内容协商、缓存和身份验证。

一些最成熟的选项是 新泽西放松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。我相信它们是在同一时期发展起来的,因此相互影响。

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

正如我所说,我最熟悉 Restlet,我已经在许多应用程序中使用它多年了,我对它非常满意。它是一个非常成熟、健壮、简单、有效、活跃和受到良好支持的框架。我不能和 Jersey 或 RESTEasy 说话,但我的印象是,他们都是可靠的选择。

我想分享我的个人经验,通过 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);
}
}

实际上,这“在 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();

您可以这样使用 异步 HTTP 客户端(该库也支持 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();
}

最简单的解决方案将使用 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);

我看到了许多答案,这里是我们在2020年使用的 网络客户端,顺便说一句,RestTemplate将被弃用。(可以检查这个) 将不推荐使用 RestTemplate

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

   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")

下面是我用来调用一些内部 API 的实用程序类(2022年9月)。除了用于 Json 反序列化的 Gson 之外的所有核心 java。 发送和获取。

package com.somepackagename.utils;


import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.HashMap;
import java.util.Map;




public class HTTPCaller {


private final String BEARER_TOKEN;
private static Gson gson = new GsonBuilder().setPrettyPrinting().serializeSpecialFloatingPointValues().create();


public HTTPCaller(String bearerToken) {
this.BEARER_TOKEN = bearerToken;
}


public Map<String, Object> post(String endpoint, String jsonPayload, Map<String, String> headers)
throws IOException, URISyntaxException, InterruptedException {


HttpRequest.Builder reqBuilder = HttpRequest.newBuilder();
if (headers != null) {
for (Map.Entry<String, String> header : headers.entrySet()) {
reqBuilder.header(header.getKey(), header.getValue());
}
}
//always add these anyway, or not
reqBuilder.header("content-type", "application/json")
.header("Authorization", "Bearer " + BEARER_TOKEN);


HttpRequest request = reqBuilder
.uri(new URI(endpoint))
.POST(HttpRequest.BodyPublishers.ofByteArray(jsonPayload.getBytes()))
.build();


HttpResponse<String> response = HttpClient.newBuilder()
.build()
.send(request, java.net.http.HttpResponse.BodyHandlers.ofString());
String responseBody = response.body();
Map<String, Object> output = (Map<String, Object>) gson.fromJson(responseBody, HashMap.class);


return output;


}


public Map<String, Object> get(String endpoint) throws Exception {


HttpRequest.Builder reqBuilder = HttpRequest.newBuilder();


//always add these anyway
reqBuilder.header("content-type", "application/json")
.header("Authorization", "Bearer " + BEARER_TOKEN);


HttpRequest request = reqBuilder
.uri(new URI(endpoint))
.GET()
.build();


HttpResponse<String> response = HttpClient.newBuilder()
.build()
.send(request, java.net.http.HttpResponse.BodyHandlers.ofString());
String responseBody = response.body();
Map<String, Object> output = (Map<String, Object>) gson.fromJson(responseBody, HashMap.class);


return output;


}
}