题
通过 JSR 311 及其实现,我们拥有了通过 REST 公开 Java 对象的强大标准。然而,在客户端,似乎缺少一些与 Apache Axis for SOAP 类似的东西 - 隐藏 Web 服务并将数据透明地封送回 Java 对象的东西。
如何创建 Java RESTful 客户端?使用 HTTPConnection 并手动解析结果?或者专门的客户,例如Jersey 还是 Apache CXR?
解决方案
这是一个老问题(2008),所以现在有比当时更多的选择:
- 阿帕奇CXF 有三个不同的 REST 客户端选项
- 球衣 (上文提到的)。
- 春天 也有自己的叫 休息模板
- 公共 HTTP 客户端 为较旧的 Java 项目构建您自己的项目。
更新 大约 2014 年:
异步 http 客户端 通过索纳类型. Ning 异步-http-客户端.
提供 NIO 支持的新人(尽管说实话,我认为这并没有像服务器那样真正提高客户端的性能)。
- Apache HTTP 组件 (4.2) Fluent 适配器 - 比旧的 Commons HTTP Client 3 更好,并且更易于用于构建您自己的 REST 客户端。你必须使用类似的东西 Jackson 用于 JSON 解析 支持,你可以使用 用于构造资源 URI 的 HTTP 组件 URIBuilder 类似于 Jersey/JAX-RS Rest 客户端。HTTP 组件也支持 NIO,但考虑到 REST 的短请求性质,我怀疑您是否会获得比 BIO 更好的性能。
2016年更新:
- 好的http - 支持较新的 HTTP 协议(SPDY 和 HTTP2)。适用于 Android。不幸的是,它没有提供真正的基于反应器循环的异步选项(请参阅上面的 Ning 和 HTTP 组件)。但是,如果您使用较新的 HTTP2 协议,这就不是什么问题了(假设连接计数有问题)。
- 改造 - 将基于类似于某些 Jersey 和 CXF 扩展的接口存根自动创建客户端。使用 OkHttp。
- Apache HttpComponents 5 据称将支持 HTTP2
关于选择 HTTP/REST 客户端的警告。确保检查您的框架堆栈正在为 HTTP 客户端使用什么、它如何进行线程处理,并且最好使用相同的客户端(如果提供)。也就是说,如果您使用 Vert.x 或 Play 之类的东西,您可能想尝试使用其支持客户端来参与框架提供的任何总线或反应器循环......否则要为可能有趣的线程问题做好准备。
其他提示
正如我在此主题中提到的,我倾向于使用 Jersey ,它实现了JAX-RS,并带有一个不错的REST客户端。好的是,如果使用JAX-RS实现RESTful资源,那么Jersey客户端可以重用实体提供程序,例如JAXB / XML / JSON / Atom等等 - 这样您就可以在服务器端重用相同的对象了用于客户端单元测试。
例如这是一个单元测试用例 nofollow noreferrer“> Apache Camel项目,它从RESTful资源中查找XML有效负载(使用JAXB对象端点)。资源(uri)方法在这个基类只使用Jersey客户端API。
e.g。
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 ,它具有完整的客户端功能,更多面向REST的低级库,如作为HttpURLConnection或Apache HTTP Client(我们可以利用它作为连接器)。
祝你好运, 杰罗姆·洛维尔
您可以尝试 Rapa 。请告诉我们您的反馈意见。 并随时记录问题或预期功能。
我最近在广场上尝试过改造图书馆,很棒,你可以打电话给你的其他API非常简单地。 基于注释的配置允许我们摆脱大量的锅炉板编码。
我想指出另外两个选择:
- 休息, ,基于 VRaptor Web 框架,具有服务器端和客户端实现,具有非常好的超媒体支持。
- 高枕无忧 有一个 基于 JAX-RS 代理的客户端 执行。
我使用Apache HTTPClient来处理所有HTTP方面。
我为XML内容编写XML SAX解析器,将XML解析为对象模型。我相信Axis2也暴露了XML - &gt;模型方法(Axis 1隐藏了这一部分)。 XML生成器非常简单。
在我看来,编码并不需要很长时间,效率很高。
OkHttp与Retrofit结合使用时重量轻且功能强大。这适用于一般的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);
}
从 jcabi-http (我是开发人员)尝试 JdkRequest
。这是它的工作原理:
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
由于没有人提及,这里是另一个: 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);
}
尝试查看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
干杯!
泽西休息客户的例子:
添加依赖:
<!-- 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));
}
In Above It返回一个List,我们接受它作为List,然后将其转换为Json Array,然后将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 "));
}