RESTful客户端的一种java实现

RESTful client implemented by java

RESTful客户端的一种java实现


Apache HttpClient
The Apache foundation has written a nice, extendible, HTTP client library called
HttpClient.* It is currently on version 4.0 as of the writing of this book. Although it is
not JAX-RS-aware, it does have facilities for preemptive authentication and APIs for
dealing with a few different media types like forms and multipart. Some of its other
features are a full interceptor model, automatic cookie handling between requests, and
pluggable authentication to name a few. Let’s look at a simple example:
[color=blue]import org.apache.http.*;
import org.apache.http.client.*;
public class MyClient {
public static void main(String[] args) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
HttpGet get = new HttpGet("http://example.com/customers/1");
get.addHeader("accept", "application/xml");
HttpResponse response = client.execute(get);
if (response.getStatusLine().getStatusCode() != 200) {
throw new RuntimeExceptioin("Operation failed: " +
response.getStatusLine().getStatusCode());
}
System.out.println("Content-Type: " +
response.getEntity().getContentType().getValue());
BufferedReader reader = new BufferedReader(new
InputStreamReader(response.getEntity()
.getInputStream()));
String line = reader.readLine();
while (line != null) {
* For more information, see http://hc.apache.org.
170 | Chapter 13: RESTful Java Clients
Download at WoweBook.Com
System.out.println(line);
line = reader.readLine();
}
client.getConnectionManager().shutdown();
}
}[/color]
In Apache HttpClient 4.x, the org.apache.http.client.DefaultHttpClient class is responsible
for managing HTTP connections. It handles the default authentication settings,
pools and manages persistent HTTP connections (keepalive), and any other
default configuration settings. It is also responsible for executing requests. The
org.apache.http.client.methods.HttpGet class is used to build an actual HTTP GET
request. You initialize it with a URL and set any request headers you want using the
HttpGet.addHeader() method. There are similar classes in this package for doing POST,
PUT, and DELETE invocations. Once you have built your request, you execute it by
calling DefaultHttpClient.execute(), passing in the request you built. This returns an
org.apache.http.HttpResponse object. To get the response code from this object, execute
HttpResponse.getStatusLine().getStatusCode(). The HttpResponse.getEntity()
method returns an org.apache.http.HttpEntity object, which represents the message
body of the response. From it you can get the Content-Type by executing
HttpEntity.getContentType() as well as a java.io.InputStream so you can read the response.
When you are done invoking requests, you clean up your connections by calling
HttpClient.getConnectionManager().shutdown().
To push data to the server via a POST or PUT operation, you need to encapsulate your
data within an instance of the org.apache.http.HttpEntity interface. The framework
has some simple prebuilt ones for sending strings, forms, byte arrays, and input streams.
Let’s look at sending some XML.
In this example, we want to create a customer in a RESTful customer database. The
API works by POSTing an XML representation of the new customer to a specific URI.
A successful response is 201, “Created.” Also, a Location response header is returned
that points to the newly created customer:
[color=blue]import org.apache.http.*;
import org.apache.http.client.*;
public class MyClient {
public static void main(String[] args) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("http://example.com/customers");
StringEntity entity = new StringEntity("<customer id='333'/>");
entity.setContentType("application/xml");
post.setEntity(entity);
HttpClientParams.setRedirection(post.getParams(), false);
HttpResponse response = client.execute(post);
if (response.getStatusLine().getStatusCode() != 201) {
throw new RuntimeExceptioin("Operation failed: " +
response.getStatusLine().getStatusCode());
Apache HttpClient | 171
Download at WoweBook.Com
}
String location = response.getLastHeader("Location")
.getValue();
System.out.println("Object created at: " + location);
System.out.println("Content-Type: " +
response.getEntity().getContentType().getValue());
BufferedReader reader = new BufferedReader(new
InputStreamReader(response.getEntity().getContent()));
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
client.getConnectionManager().shutdown();
}
}[/color]
We create an org.apache.http.entity.StringEntity to encapsulate the XML we want
to send across the wire. We set its Content-Type by calling StringEntity.setContent
Type(). We add the entity to the request by calling HttpPost.setEntity(). Since we are
expecting a redirection header with our response and we do not want to be automatically
redirected, we must configure the request to not do automatic redirects. We do
this by calling HttpClientParams.setRedirection(). We execute the request the same
way we did with our GET example. We get the Location header by calling
HttpResponse.getLastHeader().
Authentication
The Apache HttpClient 4.x supports Basic, Digest, and Client Certificate authentication.
Basic and Digest authentication are done through the DefaultHttpClient.getCre
dentialsProvider().setCredentials() method. Here’s an example:
DefaultHttpClient client = new DefaultHttpClient();
client.getCredentialsProvider().setCredentials(
new AuthScope("example.com", 443),
new UsernamePasswordCredentials("bill", "geheim");
);
The org.apache.http.auth.AuthScope class defines the server and port that you want
to associate with a username and password. The org.apache.http.auth.UsernamePass
wordCredentials class encapsulates the username and password into an object. You can
call setCredentials() for every domain you need to communicate with securely.
Apache HttpClient, by default, does not do preemptive authentication for the Basic
and Digest protocols, but does support it. Since the code to do this is a bit verbose, we
won’t cover it in this book.
172 | Chapter 13: RESTful Java Clients
Download at WoweBook.Com
Client Certificate authentication
Apache HttpClient also supports Client Certificate authentication. As with HttpsURL
Connection, you have to load in a KeyStore that contains your client certificates.
“java.net.URL” on page 165 describes how to do this. You initialize an
org.apache.http.conn.ssl.SSLSocketFactory with a loaded KeyStore and associate it
with the DefaultHttpClient. Here is an example of doing this:
[color=blue]import java.io.File;
import java.io.FileInputStream;
import java.security.KeyStore;
import org.apache.http.*;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.*;
import org.apache.http.conn.scheme.*;
import org.apache.http.conn.ssl.*;
import org.apache.http.impl.client.DefaultHttpClient;
public class MyClient {
public final static void main(String[] args) throws Exception {
DefaultHttpClient client = new DefaultHttpClient();
KeyStore trustStore = KeyStore.getInstance(
KeyStore.getDefaultType());
FileInputStream instream = new FileInputStream(
new File("my.keystore"));
try {
trustStore.load(instream, "changeit".toCharArray());
} finally {
instream.close();
}
SSLSocketFactory socketFactory =
new SSLSocketFactory(trustStore);
Scheme scheme = new Scheme("https", socketFactory, 443);
client.getConnectionManager()
.getSchemeRegistry().register(scheme);
HttpGet httpget = new HttpGet("https://localhost/");
... proceed with the invocation ...
}
}[/color]
Advantages and Disadvantages
Apache HttpClient is a more complete solution and is better designed than
java.net.HttpURLConnection. Although you have to download it separately from the
JDK, I highly recommend you take a look at it. It has none of the disadvantages of
HttpURLConnection, except that it is not JAX-RS-aware.
Apache HttpClient | 173
Download at WoweBook.Com
RESTEasy Client Framework
RESTEasy† is the JBoss (Red Hat) JAX-RS implementation. As with java.net.HttpURL
Connection and Apache HTTP Client, it provides a programmatic API to submit HTTP
requests with the additional feature of it being JAX-RS-aware. To use the API, you
create org.jboss.resteasy.client.ClientRequest objects. You build up the request using
the following constructor and methods:
[color=blue]public class ClientRequest {
public ClientRequest(String uriTemplate) {}
public ClientRequest followRedirects(boolean follow) {}
public ClientRequest accept(String accept) {}
public ClientRequest formParameter(String parameterName,
Object value) {}
public ClientRequest queryParameter(String parameterName,
Object value) {}
public ClientRequest matrixParameter(String parameterName,
Object value) {}
public ClientRequest header(String headerName, Object value) {}
public ClientRequest cookie(String cookieName, Object value) {}
public ClientRequest cookie(Cookie cookie) {}
public ClientRequest pathParameter(String parameterName,
Object value)
public ClientRequest body(String contentType, Object data) {}
...
}[/color]
The ClientRequest constructor can take any expression you put in an @Path annotation,
but it must also have scheme, host, and port information. Here’s an example of building
up a GET request:
ClientRequest request =
new ClientRequest("http://example.com/customers/{id}");
request.accept("application/xml")
.pathParameter("id", 333);
We allocate the ClientRequest instance, passing in a URL template. We set the
Accept header to state we want XML returned and the id path parameter to 333. To
invoke the request, call one of ClientRequest’s HTTP invocation methods listed here:
[color=blue]public class ClientRequest {
...
// HTTP METHODS
public <T> T getTarget(Class<T> returnType) throws Exception {}
public <T> ClientResponse<T> get(Class<T> returnType)
throws Exception {}
public ClientResponse put() throws Exception {}
public <T> ClientResponse<T> put(Class<T> returnType)
throws Exception {}
† For more information, see http://jboss.org/resteasy.
174 | Chapter 13: RESTful Java Clients
Download at WoweBook.Com
public ClientResponse post() throws Exception {}
public <T> ClientResponse<T> post(Class<T> returnType)
throws Exception {}
public <T> T postTarget(Class<T> returnType) throws Exception {}
public ClientResponse delete() throws Exception {}
public <T> ClientResponse<T> delete(Class<T> returnType)
throws Exception {}
...
}[/color]
Finishing up our GET request example, we invoke either the get() or getTarget()
methods. The getTarget() method invokes the request and automatically converts it
to the type you want returned. For example:
ClientRequest request =
new ClientRequest("http://example.com/customers/{id}");
request.accept("application/xml")
.pathParameter("id", 333);
Customer customer = request.getTarget(Customer.class);
In this example, our Customer class is a JAXB annotated class. When ClientRequest.get
Target() is invoked, the request object builds the URL to invoke on using the passed
in path parameter, sets the Accept header with the desired media type, and then calls
the server. If a successful response comes back, the client framework matches the
Customer class with an appropriate MessageBodyReader and unmarshalls the returned
XML into a Customer instance. If an unsuccessful response comes back from the server,
the framework throws an org.jboss.resteasy.client.ClientResponseFailure instead
of returning a Customer object:
public class ClientResponseFailure extends RuntimeException {
...
public ClientResponse<byte[]> getResponse() {}
}
If you need to get the response code or want to look at a response header from your
HTTP invocation, you can opt to invoke the ClientRequest.get() method instead. This
method returns an org.jboss.resteasy.client.ClientResponse object instead of the
unmarshalled requested type. Here’s what ClientResponse looks like:
[color=blue]public abstract class ClientResponse<T> extends Response {
public abstract MultivaluedMap<String, String> getHeaders();
public abstract Response.Status getResponseStatus();
public abstract T getEntity();
...
public abstract void releaseConnection();
}[/color]
The ClientResponse class extends the javax.ws.rs.core.Response class. You can obtain
the status code by calling ClientResponse.getStatus() or getResponseStatus() if you
want an enum. The getEntity() method unmarshalls the HTTP message body into the
type you want. Finally, you must also call releaseConnection() when you are finished.
Here’s an example of using this class with the ClientRequest.get() method:
RESTEasy Client Framework | 175
Download at WoweBook.Com
ClientRequest request =
new ClientRequest("http://example.com/customers/{id}");
request.accept("application/xml")
.pathParameter("id", 333);
ClientResponse<Customer> response = request.get(Customer.class);
try {
if (response.getStatus() != 200)
throw new RuntimeException("Failed!");
Customer customer = response.getEntity();
} finally {
response.releaseConnection();
}
Authentication
The RESTEasy Client Framework runs on top of Apache HttpClient. If you need to
execute authenticated requests, you do so by configuring the Apache HttpClient backbone
RESTEasy uses. You first set up a DefaultHttpClient with the appropriate configuration
parameters set. Then you initialize an org.jboss.resteasy.client.core.exec
utors.ApacheHttpClient4Executor passing in the DefaultHttpClient instance you created.
This executor is used when instantiating ClientRequest objects. For example:
[color=blue]DefaultHttpClient client = new DefaultHttpClient();
client.getCredentialsProvider().setCredentials(
new AuthScope("example.com", 443),
new UsernamePasswordCredentials("bill", "geheim");
);
ApacheHttpClient4Executor executor =
new ApacheHttpClient4Executor(client);
ClientRequest request =
new ClientRequest("https://example.com/customers/{id}",
executor);
request.accept("application/xml")
.pathParameter("id", 333);
ClientResponse<Customer> response = request.get(Customer.class);
try {
if (response.getStatus() != 200)
throw new RuntimeException("Failed!");
Customer customer = response.getEntity();
} finally {
response.releaseConnection();
}[/color]
RESTEasy also supports using Apache HttpClient 3.1 and java.net.URLConnection as
a backbone if you can’t use Apache HttpClient 4.x.
176 | Chapter 13: RESTful Java Clients
Download at WoweBook.Com
Advantages and Disadvantages
Using something like RESTEasy’s Client Framework makes writing RESTful clients a
lot easier, as you can take advantage of the variety of content handlers available in the
Java community for JAX-RS. The biggest disadvantage of RESTEasy’s Client Framework
is that, although open source, it is not a standard. I mention it in this book not
only because it is the project I am currently leading, but also because JAX-RS implementations
like Jersey‡ and Apache CXF§ have very similar frameworks. There is a lot
of interest from the JAX-RS specification lead and expert group members to get a
standardized client framework baked into JAX-RS 2.0. I hope that by the time you finish
reading this chapter, the effort is already well under way!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值