1、简介
-
RestTemplate是由Spring框架提供的一个可用于应用中调用rest服务的类它简化了与http服务的通信方式,统一了RESTFul的标准,封装了http连接,我们只需要传入url及其返回值类型即可。相较于之前常用的HttpClient,RestTemplate是一种更为优雅的调用RESTFul服务的方式。
-
在Spring应用程序中访问第三方REST服务与使用Spring
RestTemplate类有关。RestTemplate类的设计原则与许多其他Spring的模板类(例如JdbcTemplate)相同,为执行复杂任务提供了一种具有默认行为的简化方法。 -
RestTemplate默认依赖JDK提供了http连接的能力(HttpURLConnection),如果有需要的话也可以通过setRequestFactory方法替换为例如Apache
HttpCompoent、Netty或OKHttp等其他Http libaray。 -
考虑到了RestTemplate类是为了调用REST服务而设计的,因此它的主要方法与REST的基础紧密相连就不足为奇了,后者时HTTP协议的方法:HEAD、GET、POST、PUT、DELETE、OPTIONS例如,RestTemplate类具有headForHeaders()、getForObject()、putForObject(),put()和delete()等方法。
2、RestTemplate的使用之get请求
2.1 不带参数的Get请求
服务端
@RequestMapping("/testGetMethod")
public String testGetMethod(){
return "hello";
}
客户端
String url = "http://localhost:9999/testGetMethod";
String str = restTemplate.getForObject(url , String.class);
2.2 带参数的Get请求 (按{}顺序绑定参数)
服务端
@RequestMapping("/testGetMethod/{talk}/{name}")
public String testGetMethod(@PathVariable("talk") String talk ,
@PathVariable("name") String name){
log.info("【{} : {}】" , talk , name);
return "hello";
}
客户端
String url = "http://localhost:9999/testGetMethod/{talk}/{name}";
//或者testGetMethod/{1}/{2} {里面的参数无所谓,只是根据下面的Object... uriVariables 逐一绑定到上面{} 中去的}
String str = restTemplate.getForObject(url , String.class,"hello" , "johnny");
说明{} http://localhost:9999/testGetMethod/{talk}/{name} 里面的参数名称无所谓,只是根据下面的Object… uriVariables 逐一绑上去的,具体绑定源码请看 DefaultUriBuilderFactory的fromUriString方法内部是根据正则表达式进行绑定的,最终将返回 URI,URI的string属性 就是绑定后要访问的路径
2.3 带参数的Get请求(按Map的key绑定{}参数)
服务端
@RequestMapping("/testGetMethod/{talk}/{name}")
public String testGetMethod(@PathVariable("talk") String talk ,
@PathVariable("name") String name){
log.info("【{} : {}】" , talk , name);
return "hello";
}
String url = "http://localhost:9999/testGetMethod/{talk}/{name}";
Map<String,String> map = new HashMap<>();
map.put("talk" , "hello");
map.put("name" , "johnny");
String str = restTemplate.getForObject(url , String.class,map);
注意:通过Map绑定参数的, map的key 一定要和 url中 {} 中的 保持一致 ,如果不一致会报错。
2.4 getForEntity()
RestTemplate 提供的Get请求的第二种方法 ,基本和getForObject一致 ,就是返回类型不同,它是在getForObject返回的基础上再包装了一层 ResponseEntity 用于包含Http请求的全部信息。
public void queryWeather() {
ResponseEntity<Object> forEntity = restTemplate.getForEntity("https://restapi.amap.com/v3/weather/weatherInfo?city=510100&key=e7a5fa943f706602033b6b329c49fbc6", Object.class);
System.out.println("状态码:"+forEntity.getStatusCode());
System.out.println("状态码内容:"+forEntity.getStatusCodeValue());
HttpHeaders headers = forEntity.getHeaders();
System.out.println("响应头:"+headers);
Object body = forEntity.getBody();
System.out.println("响应内容:"+body);
}
3、RestTemplate的使用之post请求
3.1post请求,传递student对象
服务端代码:
@RequestMapping("/testPostMethodForObject")
public String testGetMethodForEntity(@RequestBody Student student){
log.info("【studeng: {}】" , student);
return "success";
}
客户端代码:
String url = "http://localhost:9999/testPostMethodForObject";
Student student = new Student();
student.setName("johnny");
student.setAge("23");
String msg = restTemplate.postForObject(url , student , String.class);
3.2 postForEntity()
与getForEntity()和getForObject()的关系类似,都要通过getBody()方法获取方法体。
3.3 postForLocation()
postForLocation传参用法与前两者一致,只不过返回从实体变成了一个URL,因此它不需要指定返回响应内容的类型。
public void queryWeather() {
User user = new User();
user.setName("鲁大师");
URI uri = restTemplate.postForLocation("https://httpbin.org/post", user);
System.out.println(uri);
}
这个只需要服务提供者返回一个 URI 即可,该URI返回值体现的是:用于提交完成数据之后的页面跳转,或数据提交完成之后的下一步数据操作URI。
3.4 使用POST以表单方式提交
这里说明一下如何封装一个请求体,以及springboot如何接受一个Form表单数据。
3.4.1封装请求体
需要3个类:
- HttpHeaders
- MultiValueMap<K,V>
- HttpEntity<T>
HttpHeaders
就是用来封装Http请求的请求头的,这里我们要设置他的ContentType为MediaType.APPLICATION_FORM_URLENCODED以使得我们提交的参数是以Form(表单)的形式提交。
//设置请求头, x-www-form-urlencoded格式的数据
HttpHeaders httpHeaders = new HttpHeaders();
//这里指定参数以UTF-8编码格式传输
MediaType mediaType = new MediaType(MediaType.APPLICATION_FORM_URLENCODED, UTF_8);
httpHeaders.setContentType(mediaType);
//提交参数设置
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("name","鲁大师");
MultiValueMap<K,V>
该类是用来封装请求参数的,是以key-value的形式封装但是以单个key对应多个value的格式传输(也就是是以单个key:[value…]的格式传输的)。
如果像传输单个key对应单个value使用普通的Map传参即可。
HttpEntity
该类是用来封装请求的,主要作用就是将请求头和请求体封装在一起成为一个请求实体 T用来指定用来封装参数的容器的类型。
//组装请求体
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, httpHeaders);
通过上述3各类,可以自己封装一个以form形式提交参数的POST请求了。
@Test
void contextLoads() {
//请求地址
String url = "https://httpbin.org/post";
//设置请求头, x-www-form-urlencoded格式的数据
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
//提交参数设置
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("name","鲁大师");
//组装请求体
HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, httpHeaders);
//发送post请求并打印结果 以String类型接收响应结果JSON字符串
String s = restTemplate.postForObject(url, request, String.class);
System.out.println(s);
}
3.4.2 SpringBoot接收Form表单
基本的接收方式,下面样例Controller接收form-data格式的POST数据:
@PostMapping("/postHello2")
public String postHello2(@RequestParam(name = "name", defaultValue = "xxx") String name,
@RequestParam(name = "age", required = false) Integer age) {
return "name:" + name + "\nage:" + age;
}
使用@RequestParam注解。使用required = false标注参数是非必须的。
使用defaultValue给参数指定个默认值。
既可以使用数组接收参数
@PostMapping("/postHello4")
public String postHello4(@RequestParam("name") String[] names) {
String result = "";
for(String name:names){
result += name + "\n";
}
return result;
}
也可以使用对象接收参数
@PostMapping("/postHello5")
public String postHello5(User user) {
return "name:" + user.getName() + "\nage:" + user.getAge();
}
如果一个 post 请求的参数分属不同的对象,也可以使用多个对象来接收参数:
@PostMapping("/postHello5-1")
public String hello(User user, Phone phone) {
return "name:" + user.getName() + "\nage:" + user.getAge()
+ "\nnumber:" + phone.getNumber();
}
如果传递过来的是Text文本,我们可以通过HttpServletRequest获取输入流从而读取文本内容。
@PostMapping("/helloText")
public String hello(HttpServletRequest request) {
ServletInputStream is = null;
try {
is = request.getInputStream();
StringBuilder sb = new StringBuilder();
byte[] buf = new byte[1024];
int len = 0;
while ((len = is.read(buf)) != -1) {
sb.append(new String(buf, 0, len));
}
System.out.println(sb.toString());
return "获取到的文本内容为:" + sb.toString();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
4、RestTemplate相关参数问题
使用Springboot提供的RestTemplateBuilder构造类来构造一个RestTemplate,可以自定义一些连接参数,如:连接超时时间,读取超时时间,还有认证信息等。
@Configuration
public class WebConfiguration {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder){
return builder
//设置连接超时时间
.setConnectTimeout(Duration.ofSeconds(5000))
//设置读取超时时间
.setReadTimeout(Duration.ofSeconds(5000))
//设置认证信息
.basicAuthentication("username","password")
//设置根路径
.rootUri("https://api.test.com/")
//添加拦截器
.additionalInterceptors(new CustomClientHttpRequestInterceptor())
//构建
.build();
}
}
添加自定义的拦截器
自定义拦截器示例
@Slf4j
public class CustomClientHttpRequestInterceptor implements ClientHttpRequestInterceptor {
@Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
//打印请求明细
logRequestDetails(request,body);
ClientHttpResponse response = execution.execute(request, body);
//打印响应明细
logResponseDetails(response);
return response;
}
private void logRequestDetails(HttpRequest request, byte[] body){
log.debug("Headers:{}",request.getHeaders());
log.debug("body:{}",new String(body, StandardCharsets.UTF_8));
log.debug("{}:{}",request.getMethod(),request.getMethodValue());
}
private void logResponseDetails(ClientHttpResponse response) throws IOException {
log.debug("Status code : {}",response.getStatusCode());
log.debug("Status text : {}",response.getStatusText());
log.debug("Headers : {}",response.getHeaders());
log.debug("Response body: {}", StreamUtils.copyToString(response.getBody(),StandardCharsets.UTF_8));
}
}
本文内容为检索多篇相关文章总结而成,原文地址附在下面:
https://zhuanlan.zhihu.com/p/97757286
https://blog.csdn.net/D1842501760/article/details/124216538
https://www.jb51.net/article/258596.htm