Spring之在客户端访问RESTful业务



RestTemplate 是客户端访问RESTful业务的核心类。在概念上与Spring其他的模板类相似,比如JdbcTemplate和JmsTemplate。RestTemplate的行为是可以定制的,通过提供回调方法和配置HttpMessageConverter(用于将对象打包到HTTP请求体中并从返回的响应中解压为一个对象)。由于一般使用XML作为消息格式,Spring提供了MarshallingHttpMessageConverter 使用对象到XML的框架,这是org.springframework.oxm包的一部分。这个给你了将XML映射为对象,提供了宽泛的选择。


这节描述了如何使用RestTemplate和其关联的HttpMessageConverters。


21.10.1 RestTemplate

Java中调用RESTful业务,一般使用一个辅助类,比如Apache的HttpComponents  HttpClient。对于普通的REST操作,这种方式是非常低级的。

String uri = "http://example.com/hotels/1/bookings";

PostMethod post = new PostMethod(uri);
String request = // create booking request content
post.setRequestEntity(new StringRequestEntity(request));

httpClient.executeMethod(post);

if (HttpStatus.SC_CREATED == post.getStatusCode()) {
    Header location = post.getRequestHeader("Location");
    if (location != null) {
        System.out.println("Created new booking at :" + location.getValue());
    }
}



RestTemplate提供了高级方法,对应着六个主要的HTTP方法,使得在一行中调用RESTful业务并执行REST最好的实践。


注意:RestTemplate还有一个异步部分。


RestTemplate 方法回顾表

HTTP方法         RestTemplate方法

DELETE           delete

GET              getForObjectgetForEntity

HEAD             headForHeaders(String url,String。。。urlVariables)

OPTIONS          optionsForAllow(String url,String。。。urlVariables)

POST             postForLocation(String url,Object request,String。。。urlVariables)  postForObeject(String url,Object    request,Class<T> responseType,String...uriVariables)

PUT              put(String url,Object reuqest,String...urlVariables)

PATCH and others  exchange execute


RestTemplate方法的名字遵循一个命名规范,第一部分指定了调用什么HTTP方法,第二部分指明了返回值。例如,getForObject()方法执行一个GET,并将HTTP响应转为你想要的对象类型并返回这个对象。postForLocation()方法执行一个POST操作,将给定的对象转为一个HTTP请求并返回HTTP响应的location头,这里可以找到最新的对象。在处理HTTP请求的异常情形下,将抛出RestClientException异常类型;可以通过将ResponseErrorHandler实现插入到RestTemplate可以改变这种异常处理的行为。


exchange和execute方法是上述列表指定的方法的泛化版本并且支持其他的结合和方法,比如HTTP PATCH。然而,底层的HTTP也必须支持想得到的联合。JDK的HttpURLConnection 不支持PATCH方法,但是了Apache HttpComponents HttpClient的4.2版本或者后面的会支持。它们也使得RestTemplate读HTTP响应到一个一般的类型(比如List<Account>)),使用一个ParameterizedTypeReference,这是一个新类用来抓取和传递一般类型信息。


传递给这些方法的对象和从这些方法返回的对象由HttpMessageConverter实例转化和从消息转化。主要类型的转换器是默认注册的,但是了你也可以封装你自己的转换器并使用messageConverters()的bean属性注册。与这个模板注册的默认转换器实例是ByteArrayHttpMessageConverter,StringHttpMessageConverter,FormHttpMessageConverter和SourceHttpMessageConverter。你可以使用messageConverters()bean属性重写这些默认的,尤其是当使用MarshallingHttpMessageConverter或MappingJackson2HttpMessageConverter时重写就是必须的了。


每个方法传递URI模板参数,用两种方式,要不String变量长度参数,要不Map<String,String>. 例如:

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

上述使用的变量长度参数,

Map<String, String> vars = Collections.singletonMap("hotel", "42");
String result = restTemplate.getForObject(
        "http://example.com/hotels/{hotel}/rooms/{hotel}", String.class, vars);

这使用的是Map<String,String>.


为创建一个RestTemplate实例,你可以仅调用缺省的构造器。这将使用来自java.net包中的标准Java类,做实现HTTP请求的底层实现。这个可以通过指定ClientHttpRequestFactory实现来重写。Spring提供了HttpComponentsClientHttpRequestFactory 工厂类,使用Apache HttpComponents HttpClient  创建请求。HttpComponentsClientHttpRequestFactory使用org.apache.http.client.HttpClient的实例配置,反过来使用证书信息或者连接池功能配置。


注意:

    java.net实现HTTP请求时,可能产生一个异常,当访问响应状态时,这代表了一个错误。如果这是一个问题,转为使用HttpComponentsClientHttpRequestFactory  


前面的例子使用Apache HttpComponents HttpClient直接重写,并使用下面显示的RestTemplate:

uri = "http://example.com/hotels/{id}/bookings";

RestTemplate template = new RestTemplate();

Booking booking = // create booking object

URI location = template.postForLocation(uri, booking, "1");


为使用Apache HttpComponents 而不是本地的java.net功能,构造如下的RestTemplate :

RestTemplate template = new RestTemplate(new HttpComponentsClientHttpRequestFactory());


注意:Apache HttpClient支持gzip编码。为使用它,构造了HttpComponentsClientHttpRequestFactory工厂类,如下所示:

HttpClient httpClient = HttpClientBuilder.create().build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplate restTemplate = new RestTemplate(requestFactory);


一般的回调接口是RequestCallback 并当调用执行方法时调用

public <T> T execute(String url, HttpMethod method, RequestCallback requestCallback,
        ResponseExtractor<T> responseExtractor, String... urlVariables)

// also has an overload with urlVariables as a Map<String, String>.


RequestCallback接口定义如下:

public interface RequestCallback {
 void doWithRequest(ClientHttpRequest request) throws IOException;
}

允许你操作请求头并写到请求体中。当使用execute方法时,你不必担心任何资源管理,模板将总是关闭请求并处理任何错误。



使用URI working with URI


对于每个主要的HTTP方法,RestTemplate提供了String类型的URI或者java.net.URI实例的变量作为第一个参数。


String URI变量接受模板参数作为一个String变量长度参数或者作为一个Map<String,String>。它们也假设URL String类型是不编码的并且需要编码。例子如下:

restTemplate.getForObject("http://example.com/hotel list", String.class);


将在http://example.com/hotel%20list上执行一个GET请求。这意味着如果你输入String类型的已经编码的URL,其将再编码一次。即http://example.com/hotel%20list将被变为http://example.com/hotel%2520list。如果这不是我们想要的结果,使用java.net.URI方法变量,其假设已经编码的url是有用的,如果你想多次使用一个单一的URI。


UriComponentsBuilder这个类能用于构建和编码URI,包括支持URI模板。例如,你可以以一个String类型的url开始。


UriComponents uriComponents = UriComponentsBuilder.fromUriString(
        "http://example.com/hotels/{hotel}/bookings/{booking}").build()
        .expand("42", "21")
        .encode();

URI uri = uriComponents.toUri();



或者分别指定每个URI组件:

UriComponents uriComponents = UriComponentsBuilder.newInstance()
        .scheme("http").host("example.com").path("/hotels/{hotel}/bookings/{booking}").build()
        .expand("42", "21")
        .encode();

URI uri = uriComponents.toUri();

请求和响应头的处理


除了上述的方法外,RestTemplate也有exchange()方法,能用于基于HttpEntity类的任何HTTP方法的执行。


也许更加重要的是,exchange()这个方法可以用于添加请求和响应头。例如:


HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("MyRequestHeader", "MyValue");
HttpEntity<?> requestEntity = new HttpEntity(requestHeaders);

HttpEntity<String> response = template.exchange(
        "http://example.com/hotels/{hotel}",
        HttpMethod.GET, requestEntity, String.class, "42");

String responseHeader = response.getHeaders().getFirst("MyResponseHeader");
String body = response.getBody();


在上述的例子中,我们首先准备了一个请求,其包含了MyRequestHeader头信息。稍后我们检索了对应的响应,并读了MyResponseHeader和消息体。


Jackson JSON 视图支持

可能指定一个Jackson JSON View序列化对象属性子集。例如:

JacksonSerializationValue jsv = new JacksonSerializationValue(new User("eric", "7!jd#h23"),
    User.WithoutPasswordView.class);
HttpEntity<JacksonSerializationValue> entity = new HttpEntity<JacksonSerializationValue>(jsv);
String s = template.postForObject("http://example.com/user", entity, String.class);









  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值