一、在 pom.xml 裏引入依賴:web
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
二、直接使用 new RestTemplate() 使用 RestTemplate:spring
示例代碼(注意這有坑,下面解釋):json
String baiduHtml = new RestTemplate().getForObject("https://www.baidu.com", String.class); System.out.println(baiduHtml);
注:不能直接使用 @Autowired 自動注入 RestTemplate 使用。由於,官網文檔有寫:
Since RestTemplate instances often need to be customized before being used, Spring Boot does not provide any single auto-configured RestTemplate bean.
三、使用 RestTemplateBuilder,官網文檔也有寫,提供了自動配置的 RestTemplateBuilder,能夠用 RestTemplateBuilder 建立 RestTemplate:
示例代碼:app
@Autowired private RestTemplateBuilder restTemplateBuilder; @Autowired private RestTemplate restTemplate; @Bean public RestTemplate getRestTemplate() { return restTemplateBuilder.build(); } //調用方式: String baiduHtml = restTemplate.getForObject("https://www.baidu.com", String.class); System.out.println(baiduHtml);
這樣處理以後(在 SpringBootApplication 入口中定義),在任何地方就能夠直接使用自動配置的 RestTemplate 了。ide
四、編寫配置類使用:spring-boot
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.client.RestTemplateBuilder; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.client.RestTemplate; @Configuration public class RestTemplateConfig { @Autowired private RestTemplateBuilder restTemplateBuilder; @Bean public RestTemplate restTemplate(){ return restTemplateBuilder.build(); } }
而後就能夠在其餘地方直接使用 @Autowired 注入使用了。
經過以上三種方式(二、三、4)均可以使用 RestTemplate 訪問第三方接口,可是上面說的有個坑,在這裏:
使用 new RestTemplate() 和 RestTemplateBuilder 建立的 RestTemplate 訪問的時候,編碼有問題,我使用 new RestTemplate() 訪問百度,獲得亂碼的HTML,可是使用 RestTemplateBuilder 建立的 RestTemplate 訪問的時候,確是正常的!!!
來看源碼,一探究竟:
經過集成 actuator 查看全部 beans 發現這麼一個 Bean:ui
"restTemplateBuilder": { aliases: [ ], scope: "singleton", type: "org.springframework.boot.web.client.RestTemplateBuilder", resource: "class path resource [org/springframework/boot/autoconfigure/web/client/RestTemplateAutoConfiguration.class]", dependencies: [ ] }
根據 resource 找到這個 RestTemplateAutoConfiguration 類:this
@Configuration @AutoConfigureAfter({HttpMessageConvertersAutoConfiguration.class}) @ConditionalOnClass({RestTemplate.class}) public class RestTemplateAutoConfiguration { private final ObjectProvider<HttpMessageConverters> messageConverters; private final ObjectProvider<RestTemplateCustomizer> restTemplateCustomizers; public RestTemplateAutoConfiguration(ObjectProvider<HttpMessageConverters> messageConverters, ObjectProvider<RestTemplateCustomizer> restTemplateCustomizers) { this.messageConverters = messageConverters; this.restTemplateCustomizers = restTemplateCustomizers; } @Bean @ConditionalOnMissingBean public RestTemplateBuilder restTemplateBuilder() { RestTemplateBuilder builder = new RestTemplateBuilder(new RestTemplateCustomizer[0]); HttpMessageConverters converters = (HttpMessageConverters)this.messageConverters.getIfUnique(); if(converters != null) { builder = builder.messageConverters(converters.getConverters()); //↑ ↑ ↑ 看這裏,猜想編碼轉換應該是這裏加入了轉換器 } List customizers = (List)this.restTemplateCustomizers.orderedStream().collect(Collectors.toList()); if(!CollectionUtils.isEmpty(customizers)) { builder = builder.customizers(customizers); } return builder; } }
看這個類上面有註解:編碼
@AutoConfigureAfter({HttpMessageConvertersAutoConfiguration.class})
顧名思義,是在 HttpMessageConvertersAutoConfiguration 這個配置類以後配置此類。繼續進入 HttpMessageConvertersAutoConfiguration 類:url
@Configuration @ConditionalOnClass({HttpMessageConverter.class}) @AutoConfigureAfter({GsonAutoConfiguration.class, JacksonAutoConfiguration.class, JsonbAutoConfiguration.class}) @Import({JacksonHttpMessageConvertersConfiguration.class, GsonHttpMessageConvertersConfiguration.class, JsonbHttpMessageConvertersConfiguration.class}) public class HttpMessageConvertersAutoConfiguration { static final String PREFERRED_MAPPER_PROPERTY = "spring.http.converters.preferred-json-mapper"; private final List<HttpMessageConverter<?>> converters; public HttpMessageConvertersAutoConfiguration(ObjectProvider<HttpMessageConverter<?>> convertersProvider) { this.converters = (List)convertersProvider.orderedStream().collect(Collectors.toList()); } @Bean @ConditionalOnMissingBean public HttpMessageConverters messageConverters() { return new HttpMessageConverters(this.converters); } @Configuration @ConditionalOnClass({StringHttpMessageConverter.class}) @EnableConfigurationProperties({HttpProperties.class}) protected static class StringHttpMessageConverterConfiguration { private final Encoding properties; protected StringHttpMessageConverterConfiguration(HttpProperties httpProperties) { this.properties = httpProperties.getEncoding(); } @Bean @ConditionalOnMissingBean public StringHttpMessageConverter stringHttpMessageConverter() { StringHttpMessageConverter converter = new StringHttpMessageConverter(this.properties.getCharset()); converter.setWriteAcceptCharset(false); return converter; } } }
能夠看到這個類中有一個 protected 的內部類,裏面配置了名爲 StringHttpMessageConverter 的 Bean,他內部使用了 HttpProperties.class 這個配置類裏面的配置,再深刻 HttpProperties 看看,代碼過多,因此省略了不少:
@ConfigurationProperties( prefix = "spring.http" ) public class HttpProperties { private final HttpProperties.Encoding encoding = new HttpProperties.Encoding(); //...省略其餘代碼 public HttpProperties.Encoding getEncoding() { return this.encoding; } public static class Encoding { public static final Charset DEFAULT_CHARSET; private Charset charset; public Encoding() { this.charset = DEFAULT_CHARSET; } public Charset getCharset() { return this.charset; } //...省略其餘代碼 static { DEFAULT_CHARSET = StandardCharsets.UTF_8; } //...省略其餘代碼 } }
到這裏彷佛就漸漸明白了,若是使用 RestTemplateBuilder 建立的 RestTemplate,它默認就是用了 spring.http.encoding.charset 這個配置的編碼。在 application.properties 中配置的時候,能夠看到這個編碼默認就是 UTF-8,截圖以下:
那麼咱們來實驗一下,修改 application.properties 增長配置:
spring.http.encoding.charset=ISO-8859-1
若是不出意外,使用 RestTemplateBuilder 建立的 RestTemplate 訪問的時候應該是會是亂碼。
@Autowired private RestTemplate restTemplate; private String getRestResponse(String url) { try { return new RestTemplate().getForObject(url, String.class); } catch(Exception ex) { return ex.toString(); } } private String getRestResponse2(String url) { try { return restTemplate.getForObject(url, String.class); } catch(Exception ex) { return ex.toString(); } } @Override public void run(ApplicationArguments applicationArguments) throws Exception { System.out.println(getRestResponse("https://www.baidu.com")); System.out.println(getRestResponse2("https://www.baidu.com")); }
此時,第二種方式獲取到的百度源代碼和第一種方式獲取到的源代碼一致,都是亂碼,可見直接使用 new RestTemplate() 將使用默認編碼 ISO-8859-1。
那麼問題來了,如何在使用 new RestTemplate() 的時候一樣是 UTF-8 編碼呢?在建立 RestTemplate 以後作一點處理便可,代碼以下:
private String getRestResponse(String url) { try { RestTemplate rest = new RestTemplate(); for (HttpMessageConverter<?> converter : rest.getMessageConverters()) { if (converter instanceof StringHttpMessageConverter) { ((StringHttpMessageConverter)converter).setDefaultCharset(Charset.forName("UTF-8")); break; } } return rest.getForObject(url, String.class); } catch(Exception ex) { return ex.toString(); } }
此時,RestTemplate 亂碼問題已經獲得解決。