通过 JSR 311 及其实现,我们拥有了通过 REST 公开 Java 对象的强大标准。然而,在客户端似乎缺少与 Apache Axis for SOAP 相当的东西——隐藏 Web 服务并将数据透明地编组回 Java 对象的东西。
如何创建 Java RESTful 客户端?使用 HTTPConnection 和手动解析结果?或者专门的客户,例如 Jersey 或 Apache CXR?
这是一个老问题(2008 年),所以现在有比当时更多的选择:
更新(2020 年仍然活跃的项目):
关于选择 HTTP/REST 客户端的警告。确保检查您的框架堆栈正在为 HTTP 客户端使用什么,它是如何处理线程的,并且如果提供了一个客户端,最好使用相同的客户端。也就是说,如果您使用诸如 Vert.x 或 Play 之类的东西,您可能想尝试使用其支持客户端来参与框架提供的任何总线或反应器循环......否则为可能有趣的线程问题做好准备。
正如我在这个线程中提到的,我倾向于使用实现 JAX-RS 并带有一个不错的 REST 客户端的Jersey 。好消息是,如果您使用 JAX-RS 实现 RESTful 资源,那么 Jersey 客户端可以重用实体提供程序,例如 JAXB/XML/JSON/Atom 等 - 因此您可以在服务器端重用与您相同的对象在客户端单元测试中使用。
例如,这里有一个来自Apache Camel 项目的单元测试用例,它从 RESTful 资源(使用 JAXB 对象端点)中查找 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
您可以使用标准 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);
有关更多信息,请参阅:
如果您只想调用 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]");
您还可以查看具有完整客户端功能的Restlet,比 HttpURLConnection 或 Apache HTTP 客户端(我们可以将其用作连接器)等低级库更面向 REST。
最好的问候,杰罗姆·卢维尔
你可以试试拉帕。让我们知道您对此的反馈。并随时记录问题或预期功能。
我想指出另外两个选择:
JdkRequest
从jcabi-http尝试(我是开发人员)。这是它的工作原理:
String body = new JdkRequest("http://www.google.com")
.header("User-Agent", "it's me")
.fetch()
.body()
查看此博客文章了解更多详细信息:http ://www.yegor256.com/2014/04/11/jcabi-http-intro.html
我最近从 square 尝试了Retrofit Library,它很棒,你可以很容易地调用你的 rest API。基于注释的配置允许我们摆脱大量的样板编码。
与 Retrofit 结合使用时,OkHttp 也是轻量级和强大的。这适用于一般 Java 使用以及 Android。
okhttp:http ://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);
}
我使用 Apache HTTPClient 来处理所有 HTTP 方面的事情。
我为将 XML 解析为对象模型的 XML 内容编写了 XML SAX 解析器。我相信 Axis2 还公开了 XML -> Model 方法(Axis 1 隐藏了这部分,很烦人)。XML 生成器非常简单。
在我看来,编码不需要很长时间,而且效率很高。
由于没有人提到,这里还有一个:Feign,它是Spring Cloud使用的。
尽管创建 HTTP 客户端并进行请求很简单。但是如果你想使用一些自动生成的客户端,你可以使用 WADL 来描述和生成代码。
您可以使用RestDescribe生成和编译 WSDL,您可以使用它在 php、ruby、python、java 和 C# 中生成客户端。它生成干净的代码,并且有一个很好的更改,您必须在代码生成后对其进行一些调整,您可以在此处找到该工具背后的良好文档和基本思想。
在 Wintermute 中提到的有趣且有用的WADL 工具很少。
我编写了一个将 java 接口映射到远程 JSON REST 服务的库:
https://github.com/ggeorgovassilis/spring-rest-invoker
public interface BookService {
@RequestMapping("/volumes")
QueryResult findBooksByTitle(@RequestParam("q") String q);
@RequestMapping("/volumes/{id}")
Item findBookById(@PathVariable("id") String id);
}
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));
}
在上面它返回一个 List ,我们将其作为 List 接受,然后将其转换为 Json Array ,然后将 Json Array 转换为 List 。
如果发布请求将 Json 对象作为参数传递:
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 "));
}
尝试查看 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
干杯!
我目前正在使用https://github.com/kevinsawicki/http-request我喜欢它们的简单性和显示示例的方式,但大多数时候我在阅读时被卖掉了:
有什么依赖关系?
没有任何。这个库的目标是成为一个带有一些内部静态类的单类类。测试项目确实需要 Jetty 来针对实际的 HTTP 服务器实现测试请求。
它解决了 java 1.6 项目的一些问题。至于将json解码成对象,gson简直是无敌的:)