博客
关于我
SpringBoot基础教程2-1-11 RestTemplate整合HttpClient
阅读量:795 次
发布时间:2023-03-01

本文共 10435 字,大约阅读时间需要 34 分钟。

使用RestTemplate进行HTTP请求的服务端开发

概述

Http请求在服务端开发中是必不可少的,本文将使用Spring Boot中的RestTemplate作为门面,HttpClient作为实现,演示基础的Http请求例子。

源码分析

1. 添加pom.xml依赖

RestTemplate在Spring-Web模块中内置,Spring Boot会自动引入。以下是需要添加的依赖:

org.apache.httpcomponents
httpclient
4.5.5
io.netty
netty-all
4.1.5.Final
org.springframework.boot
spring-boot-configuration-processor
true

2. 配置文件application.yml(可选)

# yml配置的优先级高于java配置;如果yml配置和java配置同时存在,则yml配置会覆盖java配置
spring:
restTemplate:
maxTotalConnect: 1000 #连接池的最大连接数,0代表不限;如果取0,需要考虑连接泄露导致系统崩溃的后果
maxConnectPerRoute: 200
connectTimeout: 3000
readTimeout: 5000
charset: UTF-8

3. 编写RestTemplate配置(必备)

@Configuration
@ConfigurationProperties(prefix = "spring.restTemplate")
@ConditionalOnClass(value = {RestTemplate.class, CloseableHttpClient.class})
public class RestTemplateConfig {
// java配置的优先级低于yml配置;如果yml配置不存在,会采用java配置
private int maxTotalConnection = 500;
private int maxConnectionPerRoute = 100;
private int connectionTimeout = 2000;
private int readTimeout = 30000;
private String charset = "UTF-8";
public void setMaxTotalConnection(int maxTotalConnection) {
this.maxTotalConnection = maxTotalConnection;
}
public void setMaxConnectionPerRoute(int maxConnectionPerRoute) {
this.maxConnectionPerRoute = maxConnectionPerRoute;
}
public void setConnectionTimeout(int connectionTimeout) {
this.connectionTimeout = connectionTimeout;
}
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
public void setCharset(String charset) {
this.charset = charset;
}
@Bean(name = "clientHttpRequestFactory")
public ClientHttpRequestFactory clientHttpRequestFactory() {
return createClientHttpRequestFactory(this.connectionTimeout, this.readTimeout);
}
@Bean(name = "restTemplate")
@ConditionalOnMissingBean(RestTemplate.class)
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return createRestTemplate(factory);
}
@Bean(name = "asyncRestTemplate")
@ConditionalOnMissingBean(AsyncRestTemplate.class)
public AsyncRestTemplate asyncRestTemplate(RestTemplate restTemplate) {
final Netty4ClientHttpRequestFactory factory = new Netty4ClientHttpRequestFactory();
factory.setConnectTimeout(this.connectionTimeout);
factory.setReadTimeout(this.readTimeout);
return new AsyncRestTemplate(factory, restTemplate);
}
private ClientHttpRequestFactory createClientHttpRequestFactory(int connectionTimeout, int readTimeout) {
if (this.maxTotalConnection <= 0) {
throw new IllegalArgumentException("invalid maxTotalConnection: " + maxTotalConnection);
}
if (this.maxConnectionPerRoute <= 0) {
throw new IllegalArgumentException("invalid maxConnectionPerRoute: " + maxTotalConnection);
}
List
headers = new LinkedList<>();
headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6"));
HttpRequestRetryHandler retryHandler = new DefaultHttpRequestRetryHandler(0, false);
CloseableHttpClient httpClient = HttpClients.custom()
.setDefaultHeaders(headers)
.setRetryHandler(retryHandler)
.build();
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
factory.setConnectTimeout(connectionTimeout);
factory.setReadTimeout(readTimeout);
return factory;
}
private RestTemplate createRestTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
modifyDefaultCharset(restTemplate);
restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
return restTemplate;
}
private void modifyDefaultCharset(RestTemplate restTemplate) {
List
converterList = restTemplate.getMessageConverters();
HttpMessageConverter converterTarget = null;
for (HttpMessageConverter item : converterList) {
if (StringHttpMessageConverter.class == item.getClass()) {
converterTarget = item;
break;
}
}
if (null != converterTarget) {
converterList.remove(converterTarget);
}
Charset defaultCharset = Charset.forName(charset);
converterList.add(1, new StringHttpMessageConverter(defaultCharset));
}
}

4. Get请求演示

@RestController
public class GetTestController {
@Resource
private RestTemplate restTemplate;
@GetMapping("/baidu1/{key}")
public String get1(@PathVariable String key) throws UnsupportedEncodingException {
String encodeKey = URLEncoder.encode(key, "UTF-8");
String url = "http://www.baidu.com/s?bdorz_come=1&ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=" + encodeKey;
return restTemplate.getForObject(url, String.class);
}
@GetMapping("/baidu2/{key}")
public String get2(@PathVariable String key) throws UnsupportedEncodingException {
HttpHeaders headers = new HttpHeaders();
headers.set("MyHeaderKey", "MyHeaderValue");
HttpEntity entity = new HttpEntity(headers);
String encodeKey = URLEncoder.encode(key, "UTF-8");
String url = "http://www.baidu.com/s?bdorz_come=1&ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&tn=baidu&wd=" + encodeKey;
ResponseEntity
response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class);
return response.getBody();
}
}

5. Post请求演示

@RestController
public class PostTestController {
@Resource
private RestTemplate restTemplate;
@GetMapping("/postForm")
public String testPostForm() {
String url = "";
MultiValueMap
form = new LinkedMultiValueMap<>();
form.add("name", "**");
form.add("age", "**");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity entity = new HttpEntity(form, headers);
String json = restTemplate.postForObject(url, entity, String.class);
return json;
}
@RequestMapping("/postBody")
public String testPostBody() {
String url = "";
String jsonBody = "{\n" +
" \"name\": \"XX\",\n" +
" \"age\": \"12\",\n" +
" \"sex\": \"man\"\n" +
"}\n";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity entity = new HttpEntity(jsonBody, headers);
String json = restTemplate.postForObject(url, entity, String.class);
return json;
// 如果需要将json转换为Java对象,可以使用restTemplate.postForObject(url, entity, ResultVo.class)
}
}

6. 文件上传与下载请求演示

@RestController
public class FileTestController {
@Resource
private RestTemplate restTemplate;
@RequestMapping("/postFile")
public String testPostFileBody() {
String filePath = "D:/config.png";
String url = "";
String appId = "";
String secureKey = "";
String time = String.valueOf(System.currentTimeMillis());
String pubStr = "1";
String tempStr = String.format("app_id=%s&is_public=%s&time=%s&vframe=0%s", appId, pubStr, time, secureKey);
MultiValueMap
form = new LinkedMultiValueMap<>();
form.add("is_public", pubStr);
form.add("vframe", "0");
form.add("file", new FileSystemResource(new File(filePath)));
form.add("app_id", appId);
form.add("time", time);
form.add("sign", DigestUtils.md5(tempStr));
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity entity = new HttpEntity(form, headers);
String json = restTemplate.postForObject(url, entity, String.class);
return json;
}
@RequestMapping("/downloadFile")
public ResponseEntity testDownloadFile() throws Exception {
String url = "http://editor.baidu.com/editor/download/BaiduEditor(Online)_5-9-16.exe";
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_OCTET_STREAM));
HttpEntity entity = new HttpEntity(headers);
ResponseEntity
response = restTemplate.exchange(url, HttpMethod.GET, entity, byte[].class);
byte[] bytes = response.getBody();
long contentLength = bytes != null ? bytes.length : 0;
headers.setContentLength((int) contentLength);
headers.setContentDispositionFormData("baidu.exe", URLEncoder.encode("百度安装包.exe", "UTF-8"));
return new ResponseEntity<>(response.getBody(), headers, HttpStatus.OK);
}
}

采坑记录

  • 只配@ConfigurationProperties时,不会自动创建bean

    正确姿势:

    @Configuration
    @ConfigurationProperties(prefix = "spring.restTemplate")
    @ConditionalOnClass(value = {RestTemplate.class, CloseableHttpClient.class})
    public class RestTemplateConfig {}

    错误姿势:

    @ConfigurationProperties(prefix = "spring.restTemplate")
    @ConditionalOnClass(value = {RestTemplate.class, CloseableHttpClient.class})
    public class RestTemplateConfig {}
  • @ConfigurationProperties无法注入没有setter的属性

  • RestTemplate默认配置会乱码

    正确姿势:

    private void modifyDefaultCharset(RestTemplate restTemplate) {
    List
    converterList = restTemplate.getMessageConverters();
    HttpMessageConverter converterTarget = null;
    for (HttpMessageConverter item : converterList) {
    if (StringHttpMessageConverter.class == item.getClass()) {
    converterTarget = item;
    break;
    }
    }
    if (null != converterTarget) {
    converterList.remove(converterTarget);
    }
    Charset defaultCharset = Charset.forName(charset);
    converterList.add(1, new StringHttpMessageConverter(defaultCharset));
    }

    错误姿势:

    @Bean
    public RestTemplate getRestTemplate() {
    RestTemplate rest = new RestTemplate(this.createFactory);
    return rest;
    }
  • 如何调试RestTemplate

  • 可以在logback里单独配一个debug级别的logger,把org.apache.http下面的日志定向到控制台:
  • 工程目录

    [图片描述]

    结束语

    有任何建议,欢迎留言探讨。

    转载地址:http://jctfk.baihongyu.com/

    你可能感兴趣的文章
    ROS中机器人的强化学习路径规划器
    查看>>
    perl---2012学习笔记
    查看>>
    Perl6 必应抓取(1):测试版代码
    查看>>
    Perl的基本語法
    查看>>
    perl输出中文有乱码
    查看>>
    Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password). 大数据ssh权限问题 hadoop起不来 hadoopssh错
    查看>>
    PermissionError:Python 中的 [Errno 13]
    查看>>
    PermissionError:[Errno 13] 权限被拒绝:‘/manage.py‘
    查看>>
    Permutation
    查看>>
    perspective意思_2020年12月英语四级词汇讲解丨考点归纳:perspective
    查看>>
    PE文件,节头有感IMAGE_SECTION_HEADER
    查看>>
    PE查找文件偏移地址
    查看>>
    PE知识复习之PE的导入表
    查看>>
    PFX(Parallel Framework) and Traditional Multithreading
    查看>>
    PGOS:今天动手给电脑装青苹果Win7 X64位系统
    查看>>
    pgpool-II3.1 的内存泄漏(一)
    查看>>
    PgSQL · 特性分析 · PG主备流复制机制
    查看>>
    PGSQL主键序列
    查看>>
    PGSQL安装PostGIS扩展模块
    查看>>
    Phalcon环境搭建与项目开发
    查看>>