个人博客 Spring提供了一种简单便捷的模板类 RestTemplate
来调用 RESTful
接口。它提供了多种便捷访问HTTP服务的方法,能够大大提高客户端的编写效率。
RestTemplate方法 HTTP方法 getForEntity GET getForObject GET postForEntity POST postForObject POST put PUT patch PATCH delete DELETE exchange any execute any
1、RESTful API接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 @RestController @Slf4j public class RestfulController { @GetMapping(value = "/getUser1", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public User getUser1 () { return new User(1L , "zhaoxb" ); } @GetMapping(value = "/getUser2", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public User getUser2 (User user) { log.info("getUser2:{}" , JSONUtil.toJsonPrettyStr(user)); return user; } @PostMapping(value = "/postUser", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public User postUser (User user) { log.info("postUser:{}" , JSONUtil.toJsonPrettyStr(user)); return user; } @PostMapping(value = "/postBody", produces = MediaType.APPLICATION_JSON_UTF8_VALUE) public User postBody (@RequestBody User user) { log.info("postBody:{}" , JSONUtil.toJsonPrettyStr(user)); return user; } }
GET
请求,不带参。GET
请求,带参。POST
请求,带参。POST
请求,带有请求体。实体类,需要提供有参和无参构造
1 2 3 4 5 6 7 @Data @AllArgsConstructor @NoArgsConstructor public class User { private Long id; private String name; }
RestTemplate配置类
1 2 3 4 5 6 7 8 9 10 11 @Configuration public class RestConfig { @Bean public RestTemplate restTemplate (RestTemplateBuilder restTemplateBuilder) { RestTemplate restTemplate = restTemplateBuilder .setConnectTimeout(Duration.ofMillis(5000L )) .setReadTimeout(Duration.ofMillis(30000L )) .build(); return restTemplate; } }
2、发送GET请求 2.1、getForEntity方法,不带参 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @ActiveProfiles("test") @RunWith(SpringRunner.class) @SpringBootTest @Slf4j public class RestfulGetTests { @Autowired private RestTemplate restTemplate; @Test public void getForEntity1 () { ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://127.0.0.1:31000/getUser1" , String.class); log.info("响应码:{}" , responseEntity.getStatusCodeValue()); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(responseEntity.getBody())); } }
1 2 3 4 5 响应码:200 响应体:{ "name" : "zhaoxb" , "id" : 1 }
2.2、getForEntity方法,数字占位符方式传参 1 2 3 4 5 @Test public void getForEntity2 () { ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://127.0.0.1:31000/getUser2?id={1}&name={2}" , String.class, 2 , "zhaoxb" ); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(responseEntity.getBody())); }
用一个数字做占位符。最后是一个可变长度的参数,用来替换前面的占位符。
1 2 3 4 响应体:{ "name" : "zhaoxb" , "id" : 2 }
2.3、getForEntity方法,map占位符方式传参 1 2 3 4 5 6 7 8 @Test public void getForEntity3 () { Map<String, Object> map = new HashMap<>(); map.put("id" , 3 ); map.put("name" , "zhaoxb" ); ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://127.0.0.1:31000/getUser2?id={id}&name={name}" , String.class, map); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(responseEntity.getBody())); }
使用 name={name}
这种形式。最后一个参数是map,map的key为前边占位符的名字,value为实际参数值。
1 2 3 4 响应体:{ "name" : "zhaoxb" , "id" : 3 }
2.4、getForEntity方法,返回对象 1 2 3 4 5 @Test public void getForEntity4 () { ResponseEntity<User> responseEntity = restTemplate.getForEntity("http://127.0.0.1:31000/getUser1" , User.class); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(responseEntity.getBody())); }
1 2 3 4 响应体:{ "name" : "zhaoxb" , "id" : 1 }
2.5、getForObject方法,直接返回对象 1 2 3 4 5 @Test public void getForObject () { User User = restTemplate.getForObject("http://127.0.0.1:31000/getUser1" , User.class); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(User)); }
getForObject
是对getForEntity
函数的进一步封装,只关注返回消息的实体内容。
1 2 3 4 响应体:{ "name" : "zhaoxb" , "id" : 1 }
3、发送POST请求 用post方法发送带参的请求时,Map不能被定义为 HashMap
、LinkedHashMap
,而应被定义为 LinkedMultiValueMap
,这样参数才能成功传递到后台。
3.1、postForEntity方法 1 2 3 4 5 6 7 8 9 @Test public void postForEntity () { MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>(); multiValueMap.add("id" , 5 ); multiValueMap.add("name" , "zhaoxb" ); ResponseEntity<User> responseEntity = restTemplate.postForEntity("http://127.0.0.1:31000/postUser" , multiValueMap, User.class); log.info("响应码:{}" , responseEntity.getStatusCodeValue()); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(responseEntity.getBody())); }
1 2 3 4 响应体:{ "name" : "zhaoxb" , "id" : 5 }
3.2、postForObject方法 1 2 3 4 5 6 7 8 @Test public void postForObject () { MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>(); multiValueMap.add("id" , 6 ); multiValueMap.add("name" , "zhaoxb" ); User user = restTemplate.postForObject("http://127.0.0.1:31000/postUser" , multiValueMap, User.class); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(user)); }
和 getForObject
相对应,只关注返回的消息体。
1 2 3 4 响应体:{ "name" : "zhaoxb" , "id" : 6 }
3.3、postForObject方法,带有请求体body 1 2 3 4 5 6 @Test public void postForObject2 () { User reqUser = new User(10L , "zhaoxb" ); User user = restTemplate.postForObject("http://127.0.0.1:31000/postBody" , reqUser, User.class); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(user)); }
RestTemplate
底层实现序列化和反序列化。
1 2 3 4 响应体:{ "name" : "zhaoxb" , "id" : 10 }
3.4、exchange方法 1 2 3 4 5 6 7 8 9 10 @Test public void exchange () { MultiValueMap<String, Object> multiValueMap = new LinkedMultiValueMap<>(); multiValueMap.add("id" , 7 ); multiValueMap.add("name" , "zhaoxb" ); HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(multiValueMap); ResponseEntity<User> responseEntity = restTemplate.exchange("http://127.0.0.1:31000/postUser" , HttpMethod.POST, httpEntity, User.class); log.info("响应体:{}" , JSONUtil.toJsonPrettyStr(responseEntity.getBody())); }
HttpEntity
还支持带有HTTP请求头的构造方法。
1 2 3 4 响应体:{ "name" : "zhaoxb" , "id" : 7 }
用RestTemplate
发送PUT
、PATCH
、DELETE
方法与GET
、POST
方法非常类似,这里不做展开。
4、自定义template 4.1、自定义HTTP源 ClientHttpRequestFactory
是Spring定义的一个接口,用于生产ClientHttpRequest
对象,RestTemplate
只是模板类,抽象了很多调用方法,而底层真正使用何种框架发送HTTP请求是通过ClientHttpRequestFactory
指定的。
RestTemplate
默认使用的是SimpleClientHttpRequestFactory
,其内部使用的是JDK的java.net.HttpURLConnection
创建底层连接,默认是没有连接池的。可以通过 setRequestFactory
函数设置不同的HTTP源,比如 Apache HttpComponents
、Netty
和OkHttp
。
设置Apache HttpComponents
为HTTP客户端源
1 2 3 4 5 6 <dependencies > <dependency > <groupId > org.apache.httpcomponents</groupId > <artifactId > httpclient</artifactId > </dependency > </dependencies >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Configuration public class RestConfig { @Bean public RestTemplate restTemplate (RestTemplateBuilder restTemplateBuilder) { RestTemplate restTemplate = restTemplateBuilder .setConnectTimeout(Duration.ofMillis(5000L )) .setReadTimeout(Duration.ofMillis(30000L )) .requestFactory(() -> clientHttpRequestFactory()) .build(); return restTemplate; } @Bean public ClientHttpRequestFactory clientHttpRequestFactory () { HttpClientBuilder httpClientBuilder = HttpClientBuilder.create(); PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(); poolingHttpClientConnectionManager.setMaxTotal(100 ); poolingHttpClientConnectionManager.setDefaultMaxPerRoute(20 ); httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); HttpClient httpClient = httpClientBuilder.build(); HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); clientHttpRequestFactory.setConnectionRequestTimeout(30 * 1000 ); return clientHttpRequestFactory; } }
4.2、自定义messageConverter RestTemplate
默认使用 jackson
来实现序列化和反序列化,默认情况下会注册MIME
类型的转换器,但可以通过 setMessageConverters
函数指定其他类型的转化器。
这里其实也可以用FastJson
库的FastJsonHttpMessageConverter4
类来做转换器,只是近些年FastJson
屡爆漏洞,还是建议用默认的jackson
来实现。
参考链接 代码地址