1、在 pom.xml 里引入依賴:
成都創(chuàng)新互聯(lián)是專業(yè)的保山網(wǎng)站建設(shè)公司,保山接單;提供成都做網(wǎng)站、網(wǎng)站建設(shè)、外貿(mào)營(yíng)銷網(wǎng)站建設(shè),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行保山網(wǎng)站開發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
org.springframework.boot
spring-boot-starter-web
2、直接使用 new RestTemplate() 使用 RestTemplate:
示例代碼(注意這有坑,下面解釋):
String baiduHtml = new RestTemplate().getForObject("https://www.baidu.com", String.class);
System.out.println(baiduHtml);
注:不能直接使用 @Autowired 自動(dòng)注入 RestTemplate 使用。因?yàn)?,官網(wǎng)文檔有寫:
Since RestTemplate instances often need to be customized before being used, Spring Boot does not provide any single auto-configured RestTemplate bean.
3、使用 RestTemplateBuilder,官網(wǎng)文檔也有寫,提供了自動(dòng)配置的 RestTemplateBuilder,可以用 RestTemplateBuilder 創(chuàng)建 RestTemplate:
示例代碼:
@Autowired
private RestTemplateBuilder restTemplateBuilder;
@Autowired
private RestTemplate restTemplate;
@Bean
public RestTemplate getRestTemplate() {
return restTemplateBuilder.build();
}
//調(diào)用方式:
String baiduHtml = restTemplate.getForObject("https://www.baidu.com", String.class);
System.out.println(baiduHtml);
這樣處理之后(在 SpringBootApplication 入口中定義),在任何地方就可以直接使用自動(dòng)配置的 RestTemplate 了。
4、編寫配置類使用:
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 注入使用了。
通過(guò)以上三種方式(2、3、4)都可以使用 RestTemplate 訪問第三方接口,但是上面說(shuō)的有個(gè)坑,在這里:
使用 new RestTemplate() 和 RestTemplateBuilder 創(chuàng)建的 RestTemplate 訪問的時(shí)候,編碼有問題,我使用 new RestTemplate() 訪問百度,得到亂碼的HTML,但是使用 RestTemplateBuilder 創(chuàng)建的 RestTemplate 訪問的時(shí)候,確是正常的?。?!
來(lái)看源碼,一探究竟:
通過(guò)集成 actuator 查看所有 beans 發(fā)現(xiàn)這么一個(gè) Bean:
"restTemplateBuilder": {
aliases: [ ],
scope: "singleton",
type: "org.springframework.boot.web.client.RestTemplateBuilder",
resource: "class path resource [org/springframework/boot/autoconfigure/web/client/RestTemplateAutoConfiguration.class]",
dependencies: [ ]
}
根據(jù) resource 找到這個(gè) RestTemplateAutoConfiguration 類:
@Configuration
@AutoConfigureAfter({HttpMessageConvertersAutoConfiguration.class})
@ConditionalOnClass({RestTemplate.class})
public class RestTemplateAutoConfiguration {
private final ObjectProvider messageConverters;
private final ObjectProvider restTemplateCustomizers;
public RestTemplateAutoConfiguration(ObjectProvider messageConverters, ObjectProvider 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());
//↑ ↑ ↑ 看這里,猜測(cè)編碼轉(zhuǎn)換應(yīng)該是這里加入了轉(zhuǎn)換器
}
List customizers = (List)this.restTemplateCustomizers.orderedStream().collect(Collectors.toList());
if(!CollectionUtils.isEmpty(customizers)) {
builder = builder.customizers(customizers);
}
return builder;
}
}
看這個(gè)類上面有注解:
@AutoConfigureAfter({HttpMessageConvertersAutoConfiguration.class})
顧名思義,是在 HttpMessageConvertersAutoConfiguration 這個(gè)配置類之后配置此類。繼續(xù)進(jìn)入 HttpMessageConvertersAutoConfiguration 類:
@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> converters;
public HttpMessageConvertersAutoConfiguration(ObjectProvider> 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;
}
}
}
可以看到這個(gè)類中有一個(gè) protected 的內(nèi)部類,里面配置了名為 StringHttpMessageConverter 的 Bean,他內(nèi)部使用了 HttpProperties.class 這個(gè)配置類里面的配置,再深入 HttpProperties 看看,代碼過(guò)多,所以省略了很多:
@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 創(chuàng)建的 RestTemplate,它默認(rèn)就是用了 spring.http.encoding.charset 這個(gè)配置的編碼。在 application.properties 中配置的時(shí)候,可以看到這個(gè)編碼默認(rèn)就是 UTF-8,截圖如下:
那么我們來(lái)實(shí)驗(yàn)一下,修改 application.properties 增加配置:
spring.http.encoding.charset=ISO-8859-1
如果不出意外,使用 RestTemplateBuilder 創(chuàng)建的 RestTemplate 訪問的時(shí)候應(yīng)該是會(huì)是亂碼。
@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"));
}
此時(shí),第二種方式獲取到的百度源代碼和第一種方式獲取到的源代碼一致,都是亂碼,可見直接使用 new RestTemplate() 將使用默認(rèn)編碼 ISO-8859-1。
那么問題來(lái)了,如何在使用 new RestTemplate() 的時(shí)候同樣是 UTF-8 編碼呢?在創(chuàng)建 RestTemplate 之后做一點(diǎn)處理即可,代碼如下:
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();
}
}
此時(shí),RestTemplate 亂碼問題已經(jīng)得到解決。