Spring 的 RestTemplate 是一个健壮的、流行的基于 Java 的 REST 客户端。Spring for Android RestTemplate Module 提供了一个在 Android 环境中工作的 RestTemplate 版本。
该类是 Spring for Android RestTemplate 库的核心。它在概念上类似于其他 Spring 项目组合项目中的其他模板类。RestTemplate 的行为是通过提供回调方法和配置用于将对象封送到 HTTP 请求正文中以及将任何响应取消封送回对象来自定义的。创建新实例时,构造函数将设置多个构成 RestTemplate 功能的支持对象。RestTemplateHttpMessageConverterRestTemplate
(资料图)
下面概述了 中支持的功能。RestTemplate
RestTemplate提供了一个用于发出 RESTful HTTP 请求的抽象,并在内部为这些请求使用本机 Android HTTP 客户端库。Android 上有两个本机 HTTP 客户端,标准 J2SE 设施和HttpComponents HttpClient。标准的 JS2SE 工具可通过 获得,而 HttpClient 可通过 使用。对原生 HttpClient 4.0 的支持已被弃用,取而代之的是 HttpClient 4.3 的 Android 端口。创建新实例时使用的默认值因运行应用程序的 Android 版本而异。RestTemplateSimpleClientHttpRequestFactoryHttpComponentsAndroidClientHttpRequestFactoryClientHttpRequestFactoryRestTemplate
Google 建议在Android 2.3(Gingerbread)及更高版本上使用 J2SE 工具,而以前的版本应使用 HttpComponents HttpClient。根据此建议,检查运行应用的 Android 版本,并使用相应的 .若要使用特定实例,必须将新实例传递到构造函数中,或调用现有实例。RestTemplateClientHttpRequestFactoryClientHttpRequestFactoryRestTemplatesetRequestFactory(ClientHttpRequestFactory requestFactory)RestTemplate
Spring for Android 还包括对第三方 HTTP 客户端库的支持。适用于Android的HttpClient 4.3与所有版本的Android兼容,并且可以通过简单地将依赖项包含在项目中来用作本机客户端的替代方案。如果 Spring for Android 检测到 HttpClient 4.3,那么它会自动将其配置为默认 .HttpClient 4.3 对 Android 中包含的原生 HttpClient 4.0 进行了大量错误修复和改进。ClientHttpRequestFactory
dependencies { compile("org.apache.httpcomponents:httpclient-android:$httpClientVersion")}基于OkHttp的附加功能可作为两个本机客户端的替代方法。 可以配置为通过构造函数或通过设置属性来使用。它在Android 2.3(Gingerbread)及更高版本上受支持,但是为了使用它,您必须在项目中包含OkHttp依赖项。ClientHttpRequestFactoryRestTemplateOkHttpRequestFactoryRestTemplaterequestFactory
dependencies { compile("com.squareup.okhttp:okhttp-urlconnection:$okHttpVersion")}RestTemplate支持发送和接收使用 gzip 压缩编码的数据。HTTP 规范允许在标头字段中使用其他值,但目前仅支持 gzip 压缩。Accept-EncodingRestTemplate
Spring for Android RestTemplate 中的 JSON 封送处理对象需要使用第三方 JSON 映射库。Spring for Android 支持两个库,Jackson 2.x和Google Gson。虽然 Jackson 是一个众所周知的 JSON 解析库,但 Gson 库更小,这将导致打包时 Android 应用程序更小。
在 Spring for Android RestTemplate 中反对 XML 封送处理需要使用第三方 XML 映射库。简单 XML 序列化程序用于提供此封送处理功能。
有几种方法可以在您的 Android 应用中包含外部 jar。您可以使用 Gradle 或 Maven 进行依赖关系管理,也可以手动下载它们并将其包含在应用的文件夹中。libs/
Android Studio 和New Build Systemfor Android 提供了一个用于构建Android应用程序的 Gradle 插件。Gradle 提供了内置的依赖项管理,可用于将 Spring for Android 依赖项包含在项目中。
将 spring-android-rest-template 依赖项添加到您的文件中:build.gradle
dependencies { compile("org.springframework.android:spring-android-rest-template:${version}")}Maven可用于管理依赖项和构建Android应用程序。有关更多信息,请参阅Spring for Android 和 Maven部分。可能需要其他依赖项,具体取决于您在 RestTemplate 中使用的 HTTP 消息转换器。有关详细信息,请参阅消息转换器部分。
将 spring-android-rest-template 依赖项添加到您的文件中:pom.xml
org.springframework.android spring-android-rest-template ${spring-android-version}
为了在Android应用程序中使用RestTemplate,您必须在文件夹中包含以下Spring for Android jars。libs/
spring-android-rest-template-{version}.jarspring-android-core-{version}.jar如果使用 Ant 构建项目,Ant 将自动包含位于项目根目录中的任何 jar。但是,在 Eclipse 中,您必须手动将 jar 添加到构建路径中。按照以下步骤将 jar 添加到 Eclipse 中的现有 Android 项目中。libs/
libs/右键单击(按住命令单击)第一个 jar。选择子菜单。BuildPath从上下文菜单中选择。Add to Build Path对每个罐子重复这些步骤。下面列出了构造函数。默认构造函数包括一组标准的消息正文转换器。有关默认转换器的列表,请参阅HTTP 消息转换部分。RestTemplate
RestTemplate();RestTemplate(ClientHttpRequestFactory requestFactory);RestTemplate(List> messageConverters);
如果要指定替代项,例如 ,则可以将其传递给参数。ClientHttpRequestFactoryOkHttpClientHttpRequestFactoryrequestFactory
OkHttpClientHttpRequestFactory requestFactory = new OkHttpClientHttpRequestFactory();RestTemplate template = new RestTemplate(ClientHttpRequestFactory requestFactory);
RestTemplate提供与六个主要 HTTP 方法中的每一个相对应的高级方法。这些方法可以轻松调用许多 RESTful 服务并强制实施 REST 最佳实践。
方法的名称遵循命名约定,第一部分指示正在调用的 HTTP 方法,第二部分指示返回的内容。例如,该方法将执行 GET,将 HTTP 响应转换为您选择的对象类型并返回该对象。该方法将执行 POST,将给定对象转换为 HTTP 请求,并返回响应 HTTP 位置标头,可在其中找到新创建的对象。如果处理 HTTP 请求发生异常,将引发该类型的异常。可以通过将另一个实现插入到RestTemplategetForObject()postForLocation()RestClientExceptionResponseErrorHandlerRestTemplate.
有关及其相关方法的更多信息,请参阅API JavadocRestTemplate
public void delete(String url, Object... urlVariables) throws RestClientException;public void delete(String url, MapurlVariables) throws RestClientException;public void delete(URI url) throws RestClientException;
publicT getForObject(String url, Class responseType, Object... urlVariables) throws RestClientException;public T getForObject(String url, Class responseType, Map urlVariables) throws RestClientException;public T getForObject(URI url, Class responseType) throws RestClientException;public ResponseEntity getForEntity(String url, Class responseType, Object... urlVariables);public ResponseEntity getForEntity(String url, Class responseType, Map urlVariables);public ResponseEntity getForEntity(URI url, Class responseType) throws RestClientException;
public HttpHeaders headForHeaders(String url, Object... urlVariables) throws RestClientException;public HttpHeaders headForHeaders(String url, MapurlVariables) throws RestClientException;public HttpHeaders headForHeaders(URI url) throws RestClientException;
public SetoptionsForAllow(String url, Object... urlVariables) throws RestClientException;public Set optionsForAllow(String url, Map urlVariables) throws RestClientException;public Set optionsForAllow(URI url) throws RestClientException;
public URI postForLocation(String url, Object request, Object... urlVariables) throws RestClientException;public URI postForLocation(String url, Object request, MapurlVariables);public URI postForLocation(URI url, Object request) throws RestClientException;public T postForObject(String url, Object request, Class responseType, Object... uriVariables);public T postForObject(String url, Object request, Class responseType, Map uriVariables);public T postForObject(URI url, Object request, Class responseType) throws RestClientException;public ResponseEntity postForEntity(String url, Object request, Class responseType, Object... uriVariables);public ResponseEntity postForEntity(String url, Object request, Class responseType, Map uriVariables) throws RestClientException;public ResponseEntity postForEntity(URI url, Object request, Class responseType) throws RestClientException;
public void put(String url, Object request, Object... urlVariables) throws RestClientException;public void put(String url, Object request, MapurlVariables) throws RestClientException;public void put(String url, Object request, Map urlVariables) throws RestClientException;
传递给方法 、 和 从方法返回的对象被实例转换为 HTTP 请求和 HTTP 响应。界面如下所示,让您更好地了解其功能。getForObject()getForEntity()postForLocation()postForObject()put()HttpMessageConverterHttpMessageConverter
public interface HttpMessageConverter{ // Indicates whether the given class can be read by this converter. boolean canRead(Class> clazz, MediaType mediaType); // Indicates whether the given class can be written by this converter. boolean canWrite(Class> clazz, MediaType mediaType); // Return the list of {@link MediaType} objects supported by this converter. List getSupportedMediaTypes(); // Read an object of the given type form the given input message, and returns it. T read(Class extends T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException; // Write an given object to the given output message. void write(T t, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException;}
框架中提供了主要媒体 (MIME) 类型的具体实现。
默认构造函数为主要 MIME 类型注册一组标准的消息转换器。您还可以编写自己的转换器并通过属性注册。RestTemplatemessageConverters
向模板注册的默认转换器实例为 、、 和 。有关详细信息,请参阅下表。ByteArrayHttpMessageConverterStringHttpMessageConverterResourceHttpMessageConverterSourceHttpMessageConverterAllEncompassingFormHttpMessageConverter
表 2.1.默认消息转换器
消息正文转换器 | 收录规则 |
ByteArrayHttpMessageConverter | 始终包括在内 |
StringHttpMessageConverter | |
ResourceHttpMessageConverter | |
SourceHttpMessageConverter | |
AllEncompassingFormHttpMessageConverter | |
SimpleXmlHttpMessageConverter | 如果存在简单 XML 序列化程序,则包括在内。 |
MappingJackson2HttpMessageConverter | 如果存在杰克逊 2.x JSON 处理器,则包括在内。 |
GsonHttpMessageConverter | 如果 Gson 存在,则包括在内。如果 Jackson 2.x 在类路径上都可用,则 Gson 优先于 Gson。 |
以下实现在 Spring for Android 中可用。对于所有转换器,将使用默认媒体类型,但可以通过属性重写。HttpMessageConvertersupportedMediaTypes
可以从 HTTP 请求和响应读取和写入字节数组的实现。默认情况下,此转换器支持所有媒体类型 (),并且写入时为 .这可以通过设置支持的媒体类型属性和重写来覆盖。HttpMessageConverter*/*Content-Typeapplication/octet-streamgetContentType(byte[])
可以从 HTTP 请求和响应读取和写入表单数据的实现。默认情况下,此转换器读取和写入媒体类型。从 .HttpMessageConverterapplication/x-www-form-urlencodedMultiValueMap
的扩展,添加了对基于 XML 和 JSON 的部分的支持。FormHttpMessageConverter
可以读取和写入资源的实现。默认情况下,此转换器可以读取所有媒体类型。写入资源用于 。HttpMessageConverterResourceapplication/octet-streamContent-Type
可以从 HTTP 请求和响应读取和写入的实现。仅支持 、 和。默认情况下,此转换器支持 和 。HttpMessageConverterjavax.xml.transform.SourceDOMSourceSAXSourceStreamSourcetext/xmlapplication/xml
可以从 HTTP 请求和响应读取和写入字符串的实现。默认情况下,此转换器支持所有文本媒体类型 (),并使用 .HttpMessageConvertertext/*Content-Typetext/plain
可以使用简单框架的 HTTP 请求和响应读取和写入 XML 的实现。XML映射可以通过使用Simple提供的注释根据需要进行自定义。当需要其他控件时,可以通过属性注入自定义。默认情况下,此转换器读取和写入媒体类型 、 和 。HttpMessageConverterSerializerSerializerSerializerapplication/xmltext/xmlapplication/*+xml
重要的是要注意,这不是与Spring OXM兼容的消息转换器。它是一个独立的实现,通过 Spring for Android 实现 XML 序列化。
将以下依赖项添加到类路径中以启用 .SimpleXmlHttpMessageConverter
格拉德尔:
dependencies { compile("org.simpleframework:simple-xml:${version}")}专家:
org.simpleframework simple-xml ${simple-version}
可以使用杰克逊 (2.x)的 .JSON 映射可以根据需要通过使用 Jackson 提供的注释进行自定义。当需要进一步控制时,对于需要为特定类型提供自定义 JSON 序列化程序/反序列化程序的情况,可以通过属性注入自定义。默认情况下,此转换器支持 .HttpMessageConverterObjectMapperObjectMapperObjectMapperapplication/json
请注意,默认情况下,此消息转换器和两者都支持。因此,您应该只向实例添加一个 JSON 消息转换器。 将使用它找到的第一个与指定 MIME 类型匹配的转换器,因此包括两者可能会产生意外结果。GsonHttpMessageConverterapplication/jsonRestTemplateRestTemplate
在类路径中包含以下依赖项以启用 .请注意,如果您手动将 jar 复制到项目中,则还需要包含 和 jar。MappingJackson2HttpMessageConverterjackson-annotationsjackson-core
格拉德尔:
dependencies { compile("com.fasterxml.jackson.core:jackson-databind:${version}")}专家:
com.fasterxml.jackson.core jackson-databind ${jackson-version}
可以使用 Google Gson 的类读取和写入 JSON 的实现。 JSON 映射可以根据需要通过使用Gson提供的注释进行自定义。当需要进一步控制时,对于需要为特定类型提供自定义 JSON 序列化程序/反序列化程序的情况,可以通过属性注入自定义。默认情况下,此转换器支持 .HttpMessageConverterGsonGsonGsonapplication/json
请注意,默认情况下,此消息转换器和两者都支持。因此,您应该只向实例添加一个 JSON 消息转换器。 将使用它找到的第一个与指定 MIME 类型匹配的转换器,因此包括两者可能会产生意外结果。MappingJackson2HttpMessageConverterapplication/jsonRestTemplateRestTemplate
在类路径中包含以下依赖项以启用 .GsonHttpMessageConverter
格拉德尔:
dependencies { compile("com.google.code.gson:gson:${version}")}专家:
com.google.code.gson gson ${gson-version}
使用 ,很容易调用 RESTful API。下面是几个使用示例,说明了发出 RESTful 请求的不同方法。RestTemplate
以下所有示例均基于示例 Android 应用程序。可以使用以下命令检索示例应用的源代码:
$ git clone git://github.com/spring-projects/spring-android-samples.git
以下示例显示了对搜索词“Spring Framework”的搜索向 google 的查询。
String url = "https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q={query}"; // Create a new RestTemplate instanceRestTemplate restTemplate = new RestTemplate();// Make the HTTP GET request, marshaling the response to a StringString result = restTemplate.getForObject(url, String.class, "Spring Framework");Gzip 压缩可以显著减小 REST 请求中返回的响应数据的大小。Gzip 必须由向其发出请求的 Web 服务器支持。通过将标头的内容编码类型设置为 ,您将请求服务器使用 gzip 压缩进行响应。如果 gzip 可用或在服务器上启用,则它应返回压缩响应。RestTemplate 检查响应中的标头,以确定响应实际上是否经过 gzip 压缩。目前,RestTemplate 仅支持标头中的 gzip 内容编码类型。如果响应数据被确定为 gzip 压缩,则使用GZIPInputStream对其进行解压缩。Accept-EncodinggzipContent-EncodingContent-Encoding
以下示例演示如何从服务器请求 gzip 压缩响应。
// Add the gzip Accept-Encoding headerHttpHeaders requestHeaders = new HttpHeaders();requestHeaders.setAcceptEncoding(ContentCodingType.GZIP);HttpEntity> requestEntity = new HttpEntity
需要注意的一点是,当将 J2SE 工具与 、Gingerbread 和更新版本一起使用时,会自动设置接受编码标头以请求 gzip 响应。这是较新版本的Android内置功能。如果要禁用 gzip,则必须在标头中设置值。SimpleClientHttpRequestFactoryidentity
// Add the identity Accept-Encoding headerHttpHeaders requestHeaders = new HttpHeaders();requestHeaders.setAcceptEncoding(ContentCodingType.IDENTITY);HttpEntity> requestEntity = new HttpEntity
假设您已经定义了一个 Java 对象,您希望从返回 JSON 内容的 RESTful Web 请求中填充。封送处理 JSON 内容需要 Jackson 或 Gson 在类路径上可用。
根据从 RESTful 请求返回的 JSON 数据定义对象:
public class Event { private Long id; private String title; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public String setTitle(String title) { this.title = title; }}发出 REST 请求:
// Create a new RestTemplate instanceRestTemplate restTemplate = new RestTemplate();// Make the HTTP GET request, marshaling the response from JSON to an array of EventsEvent[] events = restTemplate.getForObject(url, Event[].class);
您还可以设置请求的标头:Accept
// Set the Accept headerHttpHeaders requestHeaders = new HttpHeaders();requestHeaders.setAccept(Collections.singletonList(new MediaType("application","json")));HttpEntity> requestEntity = new HttpEntity使用我们之前定义的相同 Java 对象,我们可以修改检索 XML 的请求。
根据从 RESTful 请求返回的 XML 数据定义对象。请注意 Simple 用于封送对象的注释:
@Rootpublic class Event { @Element private Long id; @Element private String title; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getTitle() { return title; } public String setTitle(String title) { this.title = title; }}若要从 xml 封送事件数组,需要为列表定义一个包装类:
@Root(name="events")public class EventList { @ElementList(inline=true) private List events; public List getEvents() { return events; } public void setEvents(List events) { this.events = events; }} 发出 REST 请求:
// Create a new RestTemplate instanceRestTemplate restTemplate = new RestTemplate();// Make the HTTP GET request, marshaling the response from XML to an EventList objectEventList eventList = restTemplate.getForObject(url, EventList.class);
您还可以指定请求的标头:Accept
// Set the Accept headerHttpHeaders requestHeaders = new HttpHeaders();requestHeaders.setAccept(Collections.singletonList(new MediaType("application","xml")));HttpEntity> requestEntity = new HttpEntity将您定义的 Java 对象发布到接受 JSON 数据的 RESTful 服务。
根据 RESTful 请求所需的 JSON 数据定义对象:
public class Message { private long id; private String subject; private String text; public void setId(long id) { this.id = id; } public long getId() { return id; } public void setSubject(String subject) { this.subject = subject; } public String getSubject() { return subject; } public void setText(String text) { this.text = text; } public String getText() { return text; }}发出 REST 请求。在此示例中,请求以字符串值响应:
// Create and populate a simple object to be used in the requestMessage message = new Message();message.setId(555);message.setSubject("test subject");message.setText("test text");// Create a new RestTemplate instanceRestTemplate restTemplate = new RestTemplate();// Make the HTTP POST request, marshaling the request to JSON, and the response to a StringString response = restTemplate.postForObject(url, message, String.class);您还可以在请求中指定标头:Content-Type
// Create and populate a simple object to be used in the requestMessage message = new Message();message.setId(555);message.setSubject("test subject");message.setText("test text");// Set the Content-Type headerHttpHeaders requestHeaders = new HttpHeaders();requestHeaders.setContentType(new MediaType("application","json"));HttpEntity requestEntity = new HttpEntity(message, requestHeaders);// Create a new RestTemplate instanceRestTemplate restTemplate = new RestTemplate();// Make the HTTP POST request, marshaling the request to JSON, and the response to a StringResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.POST, requestEntity, String.class);String result = responseEntity.getBody(); 此示例说明如何使用用户名和密码填充HTTP 基本身份验证标头。如果用户名和密码被接受,您将收到请求的响应。如果它们不被接受,则服务器应该返回HTTP 401未授权响应。在内部,RestTemplate 处理响应,然后抛出 .通过调用此异常,可以确定确切原因并适当处理它。HttpClientErrorExceptiongetStatusCode()
// Set the username and password for creating a Basic Auth requestHttpAuthentication authHeader = new HttpBasicAuthentication(username, password);HttpHeaders requestHeaders = new HttpHeaders();requestHeaders.setAuthorization(authHeader);HttpEntity> requestEntity = new HttpEntity