gpt4 book ai didi

Spring学习笔记之RestTemplate使用小结

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 27 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Spring学习笔记之RestTemplate使用小结由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

前言 。

作为一个java后端,需要通过http请求其他的网络资源可以说是一个比较常见的case了;一般怎么做呢?

可能大部分的小伙伴直接捞起apache的httpclient开始做,或者用其他的一些知名的开源库如okhttp, 当然原生的httpurlconnection也是没问题的 。

本篇博文则主要关注点放在sprig的生态下,利用resttemplate来发起http请求的使用姿势 。

i. resttempalate 基本使用 。

0. 目标 。

在介绍如何使用resttemplate之前,我们先抛出一些小目标,至少需要知道通过resttemplate可以做些什么,以及我们要用它来干些什么 。

简单的给出了一下常见的问题如下 。

  • 普通的get请求获取返回数据,怎么玩?
  • post提交表达的请求,如何处理
  • post请求中requestbody的请求方式与普通的请求方式区别
  • https/http两种访问如何分别处理
  • 如何在请求中带上指定的header
  • 有跨域的问题么?如果有怎么解决
  • 有登录验证的请求,该怎么办,怎样携带身份信息
  • 上传文件可以支持么
  • 对于需要代理才能访问的http资源,加代理的姿势是怎样的

上面的问题比较多,目测不是一篇博文可以弄完的,因此对这个拆解一下,本篇主要关注在resttemplate的简单get/post请求的使用方式上 。

1. 基本接口 。

捞出源码,看一下其给出的一些常用接口,基本上可以分为下面几种 。

?
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
// get 请求
public <t> t getforobject();
public <t> responseentity<t> getforentity();
 
// head 请求
public httpheaders headforheaders();
 
// post 请求
public uri postforlocation();
public <t> t postforobject();
public <t> responseentity<t> postforentity();
 
// put 请求
public void put();
 
// pathch
public <t> t patchforobject
 
// delete
public void delete()
 
// options
public set<httpmethod> optionsforallow
 
// exchange
public <t> responseentity<t> exchange()

上面提供的几个接口,基本上就是http提供的几种访问方式的对应,其中exchange却又不一样,后面细说 。

2. get请求 。

从上面的接口命名上,可以看出可以使用的有两种方式 getforobject 和 getforentity,那么这两种有什么区别?

  • 从接口的签名上,可以看出一个是直接返回预期的对象,一个则是将对象包装到 responseentity 封装类中
  • 如果只关心返回结果,那么直接用 getforobject 即可
  • 如果除了返回的实体内容之外,还需要获取返回的header等信息,则可以使用 getforentit

a. 创建get接口 。

为了验证resttemplate的使用姿势,当然得先提供一个后端的rest服务,这了直接用了我个人的一个古诗词的后端接口,来作为简单的get测试使用 。

请求连接: https://story.hhui.top/detail?id=666106231640 。

返回结果

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
  "status" : {
  "code" : 200 ,
  "msg" : "success"
  },
  "result" : {
  "id" : 666106231640 ,
  "title" : "西塞山二首(今谓之道士矶,即兴国军大冶县" ,
  "author" : "王周" ,
  "content" : "西塞名山立翠屏,浓岚横入半江青。\n千寻铁锁无由问,石壁空存道者形。\n匹妇顽然莫问因,匹夫何去望千春。\n翻思岵屺传诗什,举世曾无化石人。" ,
  "explain" : "" ,
  "theme" : "无" ,
  "dynasty" : "唐诗"
  }
}

b. getforobject方式 。

首先看下完整的接口签名 。

?
1
2
3
4
5
6
7
8
@nullable
public <t> t getforobject(string url, class <t> responsetype, object... urivariables) throws restclientexception ;
 
@nullable
public <t> t getforobject(string url, class <t> responsetype, map<string, ?> urivariables) throws restclientexception ;
 
@nullable
public <t> t getforobject(uri url, class <t> responsetype) throws restclientexception;

有三个重载的方法,从接口上也比较容易看出如何使用,其中有点疑惑的则是第一钟,参数应该怎么传了,下面给出上面几种的使用姿势 。

?
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
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class resttestmplatetest {
  private resttemplate resttemplate;
 
  @before
  public void init() {
  resttemplate = new resttemplate();
  }
 
  @lombok .data
  static class innerres {
  private status status;
  private data result;
  }
 
  @lombok .data
  static class status {
  int code;
  string msg;
  }
 
  @lombok .data
  static class data {
  long id;
  string theme;
  string title;
  string dynasty;
  string explain;
  string content;
  string author;
  }
 
  @test
  public void testget() {
  // 使用方法一,不带参数
  string url = "https://story.hhui.top/detail?id=666106231640" ;
  innerres res = resttemplate.getforobject(url, innerres. class );
  system.out.println(res);
 
 
  // 使用方法一,传参替换
  url = "https://story.hhui.top/detail?id={?}" ;
  res = resttemplate.getforobject(url, innerres. class , "666106231640" );
  system.out.println(res);
 
  // 使用方法二,map传参
  url = "https://story.hhui.top/detail?id={id}" ;
  map<string, object> params = new hashmap<>();
  params.put( "id" , 666106231640l);
  res = resttemplate.getforobject(url, innerres. class , params);
  system.out.println(res);
 
  // 使用方法三,uri访问
  uri uri = uri.create( "https://story.hhui.top/detail?id=666106231640" );
  res = resttemplate.getforobject(uri, innerres. class );
  system.out.println(res);
  }
}

看上面的testcase,后面两个方法的使用没什么好说的,主要看一下org.springframework.web.client.resttemplate#getforobject(java.lang.string, java.lang.class<t>, java.lang.object...) 的使用姿势 。

  • 根据实际传参替换url模板中的内容
  • 使用方法一时,模板中使用 {?} 来代表坑位,根据实际的传参顺序来填充
  • 使用方法二时,模板中使用 {xx}, 而这个xx,对应的就是map中的key

上面执行后的截图如下 。

Spring学习笔记之RestTemplate使用小结

c. getforentity方式 。

既然getforobject有三种使用方法,那么getforentity理论上也应该有对应的三种方式 。

?
1
2
3
public <t> responseentity<t> getforentity(string url, class <t> responsetype, object... urivariables) throws restclientexception ;
public <t> responseentity<t> getforentity(string url, class <t> responsetype, map<string, ?> urivariables) throws restclientexception;
public <t> responseentity<t> getforentity(uri url, class <t> responsetype) throws restclientexception;

因为使用姿势和上面一致,因此只拿一个进行测试 。

?
1
2
3
4
5
6
@test
public void testgetforentity() {
  string url = "https://story.hhui.top/detail?id=666106231640" ;
  responseentity<innerres> res = resttemplate.getforentity(url, innerres. class );
  system.out.println(res);
}

对这个,我们主要关注的就是responseentity封装中,多了哪些东西,截图如下 。

从上面可以看出,多了两个东西 。

  • 一个返回的http状态码,如200表示请求成功,500服务器错误,404not found等
  • 一个 responseheader

3. post请求 。

从上面的接口说明上看,post请求除了有forobject 和 forentity之外,还多了个forlocation;其次post与get一个明显的区别就是传参的姿势问题,get的参数一般会待在url上;post的则更常见的是通过表单的方式提交 。

因此接下来关注的重点在于forlocation是什么,以及如何传参 。

a. post接口mock 。

首先创建一个简单的提供post请求的rest服务,基于spring-boot简单搭建一个,如下 。

?
1
2
3
4
5
6
7
8
9
10
@responsebody
@requestmapping (path = "post" , method = {requestmethod.get, requestmethod.options, requestmethod.post})
public string post(httpservletrequest request,
  @requestparam (value = "email" , required = false ) string email,
  @requestparam (value = "nick" , required = false ) string nick) {
  map<string, object> map = new hashmap<>();
  map.put( "code" , "200" );
  map.put( "result" , "add " + email + " # " + nick + " success!" );
  return json.tojsonstring(map);
}

b. postforobject方法 。

首先看一下接口签名 。

?
1
2
3
4
5
public <t> t postforobject(string url, @nullable object request, class <t> responsetype, object... urivariables) throws restclientexception ;
 
public <t> t postforobject(string url, @nullable object request, class <t> responsetype, map<string, ?> urivariables) throws restclientexception;
 
public <t> t postforobject(uri url, @nullable object request, class <t> responsetype) throws restclientexception ;

上面的三个方法,看起来和前面并没有太大的区别,只是多了一个request参数,那么具体的使用如何呢?

下面分别给出使用用例 。

?
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
@test
public void testpost() {
  string url = "http://localhost:8080/post" ;
  string email = "test@hhui.top" ;
  string nick = "一灰灰blog" ;
 
  multivaluemap<string, string> request = new linkedmultivaluemap<>();
  request.add( "email" , email);
  request.add( "nick" , nick);
 
  // 使用方法三
  uri uri = uri.create(url);
  string ans = resttemplate.postforobject(uri, request, string. class );
  system.out.println(ans);
 
  // 使用方法一
  ans = resttemplate.postforobject(url, request, string. class );
  system.out.println(ans);
 
  // 使用方法一,但是结合表单参数和uri参数的方式,其中uri参数的填充和get请求一致
  request.clear();
  request.add( "email" , email);
  ans = resttemplate.postforobject(url + "?nick={?}" , request, string. class , nick);
  system.out.println(ans);
 
 
  // 使用方法二
  map<string, string> params = new hashmap<>();
  params.put( "nick" , nick);
  ans = resttemplate.postforobject(url + "?nick={nick}" , request, string. class , params);
  system.out.println(ans);
}

复制代码上面分别给出了三种方法的调用方式,其中post传参区分为两种,一个是uri参数即拼接在url中的,还有一个就是表单参数 。

  • uri参数,使用姿势和get请求中一样,填充uri中模板坑位
  • 表单参数,由multivaluemap封装,同样是kv结构

c. postforentity 。

和前面的使用姿势一样,无非是多了一层包装而已,略过不讲 。

d. postforlocation 。

这个与前面有点区别,从接口定义上来说,主要是 。

post 数据到一个url,返回新创建资源的url 。

同样提供了三个接口,分别如下,需要注意的是返回结果,为uri对象,即网络资源 。

?
1
2
3
4
5
6
7
public uri postforlocation(string url, @nullable object request, object... urivariables)
  throws restclientexception ;
 
public uri postforlocation(string url, @nullable object request, map<string, ?> urivariables)
  throws restclientexception ;
 
public uri postforlocation(uri url, @nullable object request) throws restclientexception ;

那么什么样的接口适合用这种访问姿势呢?

想一下我们一般登录or注册都是post请求,而这些操作完成之后呢?大部分都是跳转到别的页面去了,这种场景下,就可以使用 postforlocation 了,提交数据,并获取返回的uri,一个测试如下 。

首先mock一个后端接口 。

?
1
2
3
4
5
6
7
8
9
10
11
@responsebody
@requestmapping (path = "success" )
public string loginsuccess(string email, string nick) {
  return "welcome " + nick;
}
 
@requestmapping (path = "post" , method = {requestmethod.get, requestmethod.options, requestmethod.post})
public string post(httpservletrequest request, @requestparam (value = "email" , required = false ) string email,
   @requestparam (value = "nick" , required = false ) string nick) {
  return "redirect:/success?email=" + email + "&nick=" + nick + "&status=success" ;
}

访问的测试用例,基本上和前面的一样,没有什么特别值得一说的 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@test
public void testpostlocation() {
  string url = "http://localhost:8080/post" ;
  string email = "test@hhui.top" ;
  string nick = "一灰灰blog" ;
 
  multivaluemap<string, string> request = new linkedmultivaluemap<>();
  request.add( "email" , email);
  request.add( "nick" , nick);
 
  // 使用方法三
  uri uri = resttemplate.postforlocation(url, request);
  system.out.println(uri);
}

执行结果如下 。

Spring学习笔记之RestTemplate使用小结

获取到的就是302跳转后端url,细心的朋友可能看到上面中文乱码的问题,如何解决呢?

一个简单的解决方案就是url编码一下 。

?
1
2
3
4
5
6
@requestmapping (path = "post" , method = {requestmethod.get, requestmethod.options, requestmethod.post},
    produces = "charset/utf8" )
public string post(httpservletrequest request, @requestparam (value = "email" , required = false ) string email,
   @requestparam (value = "nick" , required = false ) string nick) throws unsupportedencodingexception {
  return "redirect:/success?email=" + email + "&nick=" + urlencoder.encode(nick, "utf-8" ) + "&status=success" ;
}

ii. 小结 。

上面目前只给出了get/post两种请求方式的基本使用方式,并没有涉及到更高级的如添加请求头,添加证书,设置代理等,高级的使用篇等待下一篇出炉,下面小结一下上面的使用姿势 。

1. get请求 。

get请求中,参数一般都是带在url上,对于参数的填充,有两种方式,思路一致都是根据实际的参数来填充url中的占位符的内容;根据返回结果,也有两种方式,一个是只关心返回对象,另一个则包含了返回headers信心 参数填充 。

1、形如  http://story.hhui.top?id={0} 的 url 。

  • 调用 getforobject(string url, class<t> responsetype, object... urivariables)
  • 模板中的0,表示 urivariables 数组中的第0个, i,则表示第i个
  • 如果没有url参数,也推荐用这个方法,不传urivariables即可

2、形如  http://story.hhui.top?id={id} 的 url 。

  • 调用 getforobject(string url, class<t> responsetype, map<string, ?> urivariables)
  • map参数中的key,就是url参数中 {} 中的内容

其实还有一种传参方式,就是path参数,填充方式和上面一样,并没有什么特殊的玩法,上面没有特别列出 。

返回结果 。

  • 直接获取返回的数据  getforobject
  • 获取待responseheader的数据 getforentity

2. post请求 。

  • post请求的返回也有两种,和上面一样
  • post请求,参数可以区分为表单提交和url参数,其中url参数和前面的逻辑一致
  • post表单参数,请包装在 multivaluemap 中,作为第二个参数 request 来提交
  • post的方法,还有一个 postforlocation,返回的是一个uri对象,即适用于返回网络资源的请求方式

3. 其他 。

最前面提了多点关于网络请求的常见case,但是上面的介绍,明显只处于基础篇,我们还需要关注的有 。

  • 如何设置请求头?
  • 有身份验证的请求,如何携带身份信息?
  • 代理的设置
  • 文件上传可以怎么做?
  • post提交json串(即requestbody) 又可以怎么处理

上面可能还停留在应用篇,对于源码和实现有兴趣的话,问题也就来了 。

  • resttemplaet的实现原理是怎样的
  • 前面url参数的填充逻辑实现是否优雅
  • 返回的对象如何解析
  • ....

小小的一个工具类,其实东西还挺多的,接下来的小目标,就是针对上面提出的点,逐一进行研究 。

总结 。

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我的支持.

原文链接:https://juejin.im/post/5b717eab6fb9a0096e21cc24 。

最后此篇关于Spring学习笔记之RestTemplate使用小结的文章就讲到这里了,如果你想了解更多关于Spring学习笔记之RestTemplate使用小结的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com