RestTemplate 详解
1936字约6分钟
2024-08-08
RestTemplate
是一个执行HTTP请求的同步阻塞式工具类,它仅仅只是在 HTTP 客户端库(例如 JDK HttpURLConnection
、Apache HttpComponents
、okHttp
等)基础上,封装了更加简单易用的模板方法 API
,方便程序员利用已提供的模板方法发起网络请求和处理,能很大程度上提升我们的开发效率。
开始前的准备
我们需要简单配置一下 RestTemplate
,更全更丰富的配置方式移步 RestTemplate 实战
package com.marui.utils.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
/**
* @ClassName RestConfig
* @Desciption RestTemplate 简略配置
* @Author MaRui
* @Date 2022/9/21 20:38
* @Version 1.0
*/
@Configuration
public class RestConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
return new RestTemplate(factory);
}
@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// 超时设置,单位 ms
factory.setReadTimeout(5000);
factory.setConnectTimeout(15000);
return factory;
}
}
准备测试时使用的接口。ResultDTO
是封装的通用结果类,详解请移步 封装通用结果类
/**
* @ClassName UserController
* @Desciption 用户控制层
* @Author MaRui
* @Date 2022/9/20 15:40
* @Version 1.0
*/
@RestController
@RequestMapping("/user")
public class UserController {
/**
* 通过 id 获取用户信息
* @return
*/
@GetMapping
public ResultDTO<User> getUserInfo(@RequestParam Long id) {
// 这里模拟查询 id 为 1L 的用户
if (Long.valueOf(1L).equals(id)) {
User user = User.builder().id(1L).name("马锐").build();
return ResultDTO.ok(user);
}
return ResultDTO.error("请求id错误");
}
/**
* 为了演示效果,写了个特别的 POST 请求方式,没有请求体,只有 url 上有参数
* @return
*/
@PostMapping("/special")
public ResultDTO<Long> special(@RequestParam Long id) {
return ResultDTO.ok(id);
}
/**
* 新增用户信息
* @return
*/
@PostMapping
public ResultDTO<User> addUserInfo(@RequestBody User user) {
return ResultDTO.ok(user);
}
}
/**
* @ClassName LoginController
* @Desciption 登录控制层
* @Author MaRui
* @Date 2022/9/21 14:43
* @Version 1.0
*/
@Controller
@RequestMapping("/login")
public class LoginController {
/**
* 登录接口,登录成功,重定向
* @return
*/
@PostMapping
public String login() {
return "redirect:/success.html";
}
}
/**
* @ClassName User
* @Desciption 用户实体类
* @Author MaRui
* @Date 2022/9/20 15:58
* @Version 1.0
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
/** ID */
private Long id;
/** 姓名 */
private String name;
}
GET 请求方式
GET
请求方式主要分为两种:getForObject
、getForEntity
,我们主要探究一下 getForObject
的使用,因为从他们的返回值可以看出,getForEntity
返回值外面包了一层 ResponseEntity
,可以通过 getStatusCode()
、getBody()
方法获取到 http
请求响应编码以及响应结果。
我们先把所有的参数认识一下
URI url
:URI 类型的数据,一般使用URI.create(String url)
,传入一个请求的url
Class<T> responseType
:请求结果响应类型String url
:请求地址Object... uriVariables
:可变长参数,url
上要携带的参数Map<String, ?> uriVariables
:Map 类型入参,url
上要携带的参数
getForObject
/**
* @ClassName UserTest
* @Desciption
* @Author MaRui
* @Date 2022/9/20 16:53
* @Version 1.0
*/
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserTest {
@Resource
private RestTemplate restTemplate;
/**
* 请求参数拼接在 url 上
*/
@Test
public void testGetForObject1() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user?id=1";
ResultDTO result = restTemplate.getForObject(reqUrl, ResultDTO.class);
log.info("==========>请求结果:{}", result);
// ==========>请求结果:ResultDTO(code=000000, msg=Success, data={id=1, name=马锐})
}
/**
* 请求参数通过 map 传参
*/
@Test
public void testGetForObject2() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user?id={id}";
// 请求参数,map 的 key 要与 url 上的占位符 {id} 相匹配
Map<String, Long> reqMap = new HashMap<>(1);
reqMap.put("id", 1L);
ResultDTO result = restTemplate.getForObject(reqUrl, ResultDTO.class, reqMap);
log.info("==========>请求结果:{}", result);
// ==========>请求结果:ResultDTO(code=000000, msg=Success, data={id=1, name=马锐})
}
/**
* 请求参数通过 可变长参数 传参。按占位符的顺序填写参数
*/
@Test
public void testGetForObject3() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user?id={id}";
ResultDTO result = restTemplate.getForObject(reqUrl, ResultDTO.class, 1L);
log.info("==========>请求结果:{}", result);
// ==========>请求结果:ResultDTO(code=000000, msg=Success, data={id=1, name=马锐})
}
}
getForEntity
getForEntity
与 getForObject
的区别前面也提到了,返回值外面包了一层 ResponseEntity
,可以通过 getStatusCode()
获取到 http
请求响应编码,通过 getBody()
方法获取到请求结果。
@Test
public void testGetForEntity() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user?id=1";
ResponseEntity<ResultDTO> responseEntity = restTemplate.getForEntity(reqUrl, ResultDTO.class);
int statusCodeValue = responseEntity.getStatusCodeValue();
HttpStatus statusCode = responseEntity.getStatusCode();
ResultDTO result = responseEntity.getBody();
// ==========>请求结果状态码int值:200,状态码:200 OK,结果:ResultDTO(code=000000, msg=Success, data={id=1, name=马锐})
}
exchange
设置 header
内容的方式
public static void main(String[] args) {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user?id=1";
HttpHeaders headers = new HttpHeaders();
headers.add("token", "token的值");
HttpEntity<String> requestEntity = new HttpEntity<>(null, headers);
ResponseEntity<ResultDTO> responseEntity = restTemplate.exchange(reqUrl, HttpMethod.GET, requestEntity, String.class);
int statusCodeValue = responseEntity.getStatusCodeValue();
HttpStatus statusCode = responseEntity.getStatusCode();
ResultDTO result = responseEntity.getBody();
// ==========>请求结果状态码int值:200,状态码:200 OK,结果:ResultDTO(code=000000, msg=Success, data={id=1, name=马锐})
}
POST 请求方式
POST
请求方式主要分为三种:postForObject
、postForEntity
、postForLocation
,我们主要探究一下 postForObject
的使用,因为从他们的返回值可以看出,postForEntity
返回值外面包了一层 ResponseEntity
,可以通过 getStatusCode()
、getBody()
方法获取到 http
请求响应编码以及响应结果。postForLocation
和前两者的唯一区别在于返回值是一个 URI
。
我们先把所有的参数认识一下
URI url
:URI 类型的数据,一般使用URI.create(String url)
,传入一个请求的url
Class<T> responseType
:请求结果响应类型String url
:请求地址Object request
:请求体,一般是HttpEntity
类型,查看源码可知,其他类型请求体内部会转换为HttpEntity
类型Object... uriVariables
:可变长参数,url
上要携带的参数Map<String, ?> uriVariables
:Map 类型入参,url
上要携带的参数
postForObject
/**
* @ClassName UserTest
* @Desciption
* @Author MaRui
* @Date 2022/9/20 16:53
* @Version 1.0
*/
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserTest {
/**
* 无请求体,参数携带在 url 上,与 GET 方式中一样,
* 可以通过 直接拼接在 url上、map 传参、可变长参数传参
*
* 如果没有请求体,request 参数可直接赋值为 null
*/
@Test
public void testPostForObject1() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user/special?id={id}";
ResultDTO result = restTemplate.postForObject(reqUrl, null, ResultDTO.class, 1L);
log.info("==========>请求结果:{}", result);
// ==========>请求结果:ResultDTO(code=000000, msg=Success, data=1)
}
/**
* 正常请求,有请求体。
*/
@Test
public void testPostForObject2() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user";
// 请求体
User reqUser = User.builder().id(1L).name("马锐").build();
HttpEntity<User> httpEntity = new HttpEntity<>(reqUser);
ResultDTO result = restTemplate.postForObject(reqUrl, httpEntity, ResultDTO.class);
log.info("==========>请求结果:{}", result);
// ==========>请求结果:ResultDTO(code=000000, msg=Success, data={id=1, name=马锐})
}
/**
* 正常请求,有请求体,设置 headers
*/
@Test
public void testPostForObject3() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user";
// 设置 headers 的 contentType 为 application/json
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
// 请求体
User reqUser = User.builder().id(1L).name("马锐").build();
HttpEntity<User> httpEntity = new HttpEntity<>(reqUser, headers);
ResultDTO result = restTemplate.postForObject(reqUrl, httpEntity, ResultDTO.class);
log.info("==========>请求结果:{}", result);
// ==========>请求结果:ResultDTO(code=000000, msg=Success, data={id=1, name=马锐})
}
}
postForEntity
从返回值可以看出,postForEntity
返回值外面包了一层 ResponseEntity
,可以通过 getStatusCode()
、getBody()
方法获取到 http
请求响应编码以及响应结果。
/**
* @ClassName UserTest
* @Desciption
* @Author MaRui
* @Date 2022/9/20 16:53
* @Version 1.0
*/
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserTest {
/**
* 正常请求,有请求体。
*/
@Test
public void testPostForEntity() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/user";
// 请求体
User reqUser = User.builder().id(1L).name("马锐").build();
HttpEntity<User> httpEntity = new HttpEntity<>(reqUser);
ResponseEntity<ResultDTO> responseEntity = restTemplate.postForEntity(reqUrl, httpEntity, ResultDTO.class);
int statusCodeValue = responseEntity.getStatusCodeValue();
HttpStatus statusCode = responseEntity.getStatusCode();
ResultDTO result = responseEntity.getBody();
log.info("==========>请求结果状态码int值:{},状态码:{},结果:{}", statusCodeValue, statusCode, result);
// ==========>请求结果状态码int值:200,状态码:200 OK,结果:ResultDTO(code=000000, msg=Success, data={id=1, name=马锐})
}
}
postForLocation
和前两者的唯一区别在于返回值是一个URI
。该URI
返回值体现的是:用于提交完成数据之后的页面跳转,或数据提交完成之后的下一步数据操作URI
。
/**
* @ClassName UserTest
* @Desciption
* @Author MaRui
* @Date 2022/9/20 16:53
* @Version 1.0
*/
@Slf4j
@SpringBootTest
@RunWith(SpringRunner.class)
public class UserTest {
/**
* 没有请求参数,直接请求
*/
@Test
public void testPostForLocation() {
// 请求的 URL 地址
String reqUrl = "http://127.0.0.1:9999/login";
URI uri = restTemplate.postForLocation(reqUrl, null);
String path = uri.getPath();
log.info("==========>请求结果path:{},请求结果:{}", path, uri);
// ==========>请求结果path:/success.html,请求结果:http://127.0.0.1:9999/success.html
}
}