RestTemplate使用

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值