Http客户端请求工具-RestTemplate

RestTemplate一款好用且强大的Http请求工具

上一篇,我介绍了使用CMD窗口的CURL命令之后,我就觉得CURL虽然好用,但是许多功能不能完全满足我们日常的接口测试工作,比如他的中文处理不是很好,就单单这一点就让我很是头痛。


所以,我这次就来了解一下Http请求工具。


前言

首先,我们在这之前,先了解下我们常见的Http请求状态码有哪些,也算是回顾了。
下面是常见的 HTTP 状态码:

  • 200 - 请求成功
  • 301 - 资源(网页等)被永久转移到其它URL
  • 404 - 请求的资源(网页等)不存在
  • 500 - 内部服务器错误

那么,有没有小伙伴会产生一个疑问呢?这些状态码是否有规律呢,答案:是的,可以总结出一些规律也方便我们记忆和总结。那么我们可以将Http状态码可以分为

分类分类描述
1**信息,服务器收到请求,需要请求者继续执行操作
2**成功,操作被成功接收并处理
3**重定向,需要进一步的操作以完成请求
4**客户端错误,请求包含语法错误或无法完成请求
5**服务器错误,服务器在处理请求的过程中发生了错误

回顾完毕之后,我们就需要正式的认识一下什么是Http请求工具了

RestTemplate

常见的Http客户端请求工具有哪些?

  • JDK httpURI Connection
  • Apache httpClient 使用率也很高
  • OkHttp 市面使用率十分高

RestTemplate是一个同步的Web HTTP客户端请求模板,是Spring对HTTP URI Connection的封装

官方文档参考地址:https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/RestTemplate.html

RestTemplate默认使用的是HttpUrlConnection ,可以通过构造方法替换默认的HttpClient,常见的执行引擎包含:

  • Apache HttpComponenets(httpClient)
  • Netty
  • OkHttp
RestTempalte template = new RestTemplate();// 默认是HttpUrlConnection

// 想要切换为别的 比如说是Apache的请求库
RestTemplate template = new RestTempalte(new HttpcComponentsClientHttpRequestFactory());

1.1 如何使用

1.1.1 配置restTemplate的配置类

/**
 * Bean注入配置声明RestTemplate模板
 * @author wangruoxian
 *
 */
@Configuration
public class RestTemplateConfig {

	@Bean
	public RestTemplate restTemplate() {
		return new RestTemplate();
	}
}

在项目中如果要使用RestTemplate的话,我们只需要写一个RestTemplate的配置类,然后在需要使用的类上通过@AutoWired注解注入即可使用。
所以,我们需要在使用上述的方法之前,一定要先写这个配置类

1.2 常用方法

1.2.1 GET请求模板方法

Modifier and TypeMethod and Description描述
ResponseEntitygetForEntity(String url, Class responseType, Map<String,?> uriVariables)通过Get方式发送一个请求
ResponseEntitygetForEntity(String url, Class responseType, Object… uriVariables)通过Get方式发送一个请求
ResponseEntitygetForEntity(URI url, Class responseType)通过Get方式发送一个请求
TgetForObject(String url, Class responseType, Map<String,?> uriVariables)通过Get方式发送一个请求
TgetForObject(String url, Class responseType, Object… uriVariables)通过Get方式发送一个请求

参数说明:

  • URI: 为测试的API的URL映射访问路径
  • Class responseType: 为API方法的返回值的类型
  • Map|uriVariables: map和可变性惨都可以作为参数传递的容器。
① getForObject方法

【示例代码】

@Autowired
private StudentService studentService;

@Autowired
private RestTemplate restTemplate;

@RequestMapping("/queryCondition/{name}/{email}")
public Student queryCondition(@PathVariable("name") String name, @PathVariable("email") String email) {
	Map<String, Object> paraMap = new HashMap<>();
	paraMap.put("name", name);
	paraMap.put("email", email);

	Student queryCondition = studentService.queryCondition(paraMap);
	return queryCondition;
}

@GetMapping("/getForObject")
public Student getForObject() {
	String url = "http://localhost:8099/student/queryCondition/test/123";
	// Map<String, Object> paramMap= new HashMap<>();

	Student student = restTemplate.getForObject(url, Student.class);
	return student;
}

这里我所演示的方法是带有两个参数 的getForObject方法,为了方便测试使用了Rest风格,我们也可以写一个不用Rest风格的API去进行测试,使用ApiFox测试工具进行测试
在这里插入图片描述

② getForEntity方法
@RequestMapping("/queryByName")
public Student queryByName(@RequestParam("name") String name) {
	Student student = studentService.queryByName(name);
	return student;
}

@GetMapping("/getForEntity")
public Student getForEntity() {
	String url = "http://localhost:8099/student/queryByName?name={name}";
		
	Map<String, Object> paramMap = new HashMap<>();
	paramMap.put("name", "孙权");
	ResponseEntity<Student> entity = restTemplate.getForEntity(url, Student.class, paramMap);
		
	System.out.println("entity响应体"+entity);
	HttpStatus statusCode = entity.getStatusCode();
	System.out.println("状态码:"+statusCode);
	int statusCodeValue = entity.getStatusCodeValue();
	System.out.println("状态码所表现的值:"+statusCodeValue);
	HttpHeaders headers = entity.getHeaders();
	System.out.println("响应头信息:"+headers.toString());
		
	return entity.getBody();
}

🔥🔥🔥注意: 我们在使用三个参数方法的时候,在传递参数的时候需要在URL里面使用{}来包裹参数的占位变量,这个变量需要与Map的键的名称一致

在这里插入图片描述
在这里插入图片描述

总结:

  • getForObject方法只能返回方法请求返回的对象值;
  • getForEntity方法不仅可以返回一个对象值,还可以返回状态码,请求头信息等。

1.2.2 POST请求模板方法

Modifier and TypeMethod and Description描述
<T> ResponseEntity<T>postForEntity(String url, Object request, Class responseType, Map<String,?> uriVariables)通过将给定对象发布到URI模板来创建新资源,并将响应作为HttpEntity返回。
<T> ResponseEntity<T>postForEntity(String url, Object request, Class responseType, Object… uriVariables)通过将给定对象发布到URI模板来创建新资源,并将响应作为ResponseEntity返回。
<T> ResponseEntity<T>postForEntity(URI url, Object request, Class responseType)通过将给定对象发布到URI模板来创建新资源,并将响应作为ResponseEntity返回
URIpostForLocation(String url, Object request, Map<String,?> uriVariables)通过将给定对象发布到URI模板来创建新资源,并返回位置标头的值。
<T> TpostForObject(String url, Object request, Class responseType, Map<String,?> uriVariables)通过将给定对象发布到URI模板来创建新资源,并返回在响应中找到的表示形式。
ResponseEntitygetForObject(URI url, Class responseType)通过Get方式发送一个请求
① postForObject方法🔥
RestTemplate的传参

RestTemplate的Post方法与Get方法的区别就在于Post方法传参Map必须是MultiValueMap
Post方法的MultiValueMap即支持基本的类型分开传参,也支持实体传参,类似于下面的形式。

【参数说明】:

  1. url: 请求地址;
  2. request: 请求实体,封装请求头,请求内容,请求参数等信息,对应着map参数集合
  3. responseType: 响应类型,根据服务接口的返回类型决定一定要和测试的方法的返回值类型对应,否则就会报错
  4. uriVariables: url中参数变量值
/**
* post方式 实体传参
*/
@RequestMapping("/addStudent")
public String addStu(Student student) {
	if (studentService.addStu(student)) {
		return "添加一名学生";
	}
	return "添加学生失败...";
}
	
@RequestMapping("/postForOject")
public Student postForObject(Student student) {
	String url = "http://localhost:8099/student/addStudent";
	MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
	map.add("name", student.getName());
	map.add("email", student.getEmail());
	map.add("age", student.getAge());
	map.add("id",student.getId());
	
	Student student = restTemplate.postForObject(url, map, String.class);
	return student;
}

使用ApiFox测试访问测试
在这里插入图片描述
控制台输出结果,发现已经插入成功
在这里插入图片描述

注意:这里的PostForObject的ResponseType必须要和测试方法的返回值类型匹配

在这里插入图片描述
【小结】
参数和get请求的相比,就多了第二个参数(Object request),如果使用最后一个参数传参时,和get请求类似,request设置为null就可以,如果使用第二个参数传参时,就需要考虑request的类型,request参数类型必须是实体对象、MultiValueMap、HttpEntity对象的的一种,其他不可以!!!


那么为什么使用PostForObject的时候,传递参数必须要使用MultiValueMap这个map呢???

这里看到一篇博客后,这里总结以下:

我们如果使用hashMap来进行参数的传递的话,Spring的RestTemplate模板会将我们传进去的参数以Json的形式进行解析存储在Body里面,所以我们请求URL的时候,就会爆出没有参数的异常信息。
这时候就有一个核心的类AbstractJackson2HttpMessageConverter 理解为json的Http消息转化器,里面的一个writeInternal方法
在这里插入图片描述
设用Josn的原因在于,RestTemplate会先根据请求实体HttpEntity的Body内容,遍历当前所支持的所有的消息解析器,并判断是否适配。
在这里插入图片描述
AbstractJackson2HttpMessageConverter这个类里面有个canWrite的方法,在我们使用HashMap传递参数的时候也是可以别解析到的,只不过是被解析到了Body里面,URL是不会获取到的
在这里插入图片描述
那么问题又来了,如何使得URL可以放拿到我们传递的参数呢,此时,我们就需要去 FormHttpMessageConverter里面的canWrite方法找答案

在这里插入图片描述
【小结】
我们在使用PostForObject模拟发送Post请求的时候,就必须要搭配MultiValueMap来进行传参。

【参考博客:】https://blog.csdn.net/qq_33589510/article/details/121527830?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522165586313916780357263110%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=165586313916780357263110&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2blogfirst_rank_ecpm_v1~rank_v31_ecpm-1-121527830-null-null.nonecase&utm_term=resttemplate&spm=1018.2226.3001.4450

@RequestBody传参

需要使用HttpEntity的方式传参

/**
* @RequestBody传参
* @return
*/
@RequestMapping("/addStudent3")
public Student addStu3(@RequestBody Student student) {
	Student student2  =new Student();
	student2.setName(student.getName()+"from RequestBody");
	return student2;
}

@RequestMapping("/postForEntity")
public Student postForEntity() {
	// 申请一个请求头
	HttpHeaders headers  = new HttpHeaders();
	headers.setContentType(MediaType.APPLICATION_JSON);
	// 远程访问的URL 
	String url = "http://localhost:8099/student/addStudent3";
	
	Student student = new Student();
	student.setName("嗨嗨嗨,老爹又回来了");
	// 使用HttpEntity封装传参
	HttpEntity<Student> entity = new HttpEntity<Student>(student,headers);
	Student student2 = restTemplate.postForObject(url, entity, Student.class);
	return student2;
}

注意:使用@ResponseBody传递参数的时候,需要使用HttpEntity进行封装参数和响应头信息,而且不能使用MultiVlaueMap,如果使用,则会报错

在这里插入图片描述

② postForEntity方法🔥
@RequestMapping("/addStudent")
public String addStu(Student student) {
	if (studentService.addStu(student)) {
		return "添加一名学生";
	}
	return "添加学生失败...";
}

@RequestMapping("/addStudent4")
public Student addStu4(
		@RequestParam("name") String name,
		@RequestParam("email") String email,
		@RequestParam("age") Integer age,
		@RequestParam("id") Integer id) {
	Student student = new Student();
	student.setName(name);
	student.setAge(age);
	student.setEmail(email);
	student.setId(id);
	
	return student;
}

/**
* postForEntity
*/
@RequestMapping("/postForEntity2")
public Student postForEntity2() {
	String url = "http://localhost:8099/student/addStudent4";
	MultiValueMap<String, Object>	map = new LinkedMultiValueMap<>();
	map.add("name", "张三");
	map.add("email", "1687567@qq.com");
	map.add("age", 34);
	map.add("id",1456);
ResponseEntity<Student> entity = restTemplate.postForEntity(url, map, Student.class);
		
	HttpStatus statusCode = entity.getStatusCode();
	System.out.println(statusCode);
	int statusCodeValue = entity.getStatusCodeValue();
	System.out.println(statusCodeValue);
	HttpHeaders headers = entity.getHeaders();
	System.out.println(headers);
	return entity.getBody();
}

在这里插入图片描述

在这里插入图片描述

1.2.3 Exchange方法

  • Exchange方法即可以发送get请求,也可以发送Post请求
  • Exchange方法可以做getForEntity,也可以做postForEntity等等。
restTemplate Exchange

🔥🔥exchange 使用时,返回响应数据时用ResponseEntity封装,请求时用HttpEntity封装参数。

方法名称exchange(String url, HttpMethod method,@Nullable HttpEntity<?> requestEntity, Class responseType, Map uriVariables)

【参数说明】:

  1. url: 请求地址;
  2. method: 请求类型(如:POST,PUT,DELETE,GET);
  3. requestEntity: 请求实体,封装请求头,请求内容,请求参数等信息
  4. responseType: 响应类型,根据服务接口的返回类型决定
  5. uriVariables: url中参数变量值
@RequestMapping("/addStudent5")
public Student addStu5(@RequestParam("name") String name,@RequestParam("email") String email,@RequestParam("age") Integer age) {
	Student student = new Student();
	student.setName(name);
	student.setAge(age);
	student.setEmail(email);
		
	student.setId(1001);
		
	return student;
}
	
/**
* exchange方法
*/
@RequestMapping("/exchange")
public Student echanges() {
	String url  ="http://localhost:8099/student/addStudent5";
	MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
	map.add("name", "李思思");
	map.add("email", "lisis@qq.com");
	map.add("age", 34);
		
	// 封装请求参数
	HttpEntity<MultiValueMap> requestEntity =  new HttpEntity<>(map);
	// 封装响应 参数1为url,参数二为请求方式,参数三为封装的请求HttpEntity,参数四为返回值的
	ResponseEntity<Student> exchange = restTemplate.exchange(url, HttpMethod.POST,requestEntity,Student.class);
	return exchange.getBody();
}

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@WAT

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值