SpringCloud(五) 使用Ribbon进行Restful请求
本文内容纲要:
-写在前面
-前提
-测试项目构建
-Get请求
-getForEntity:此方法有三种重载形式,分别为:
-getForObject:此方法也有三种重载形式,这点与getForEntity方法相同:
-Post请求
-postForEntity:此方法有三种重载形式,分别为:
-postForObject:此方法也有三种重载形式,这点与postForEntity方法相同:
-postForLocation:此方法中同样有三种重载形式,分别为:
-Put请求&&Delete请求
-put请求方法如下:
-delete请求方法如下:
-结语
写在前面
本文由markdown格式写成,为本人第一次这么写,排版可能会有点乱,还望各位海涵。
主要写的是使用Ribbon进行Restful请求,测试各个方法的使用,代码冗余较高,比较适合初学者,介意轻喷谢谢。
前提
- 一个可用的Eureka注册中心(文中以之前博客中双节点注册中心,不重要)
- 一个连接到这个注册中心的服务提供者
- 一个ribbon的消费者
注意:文中使用@GetMapping
、@PostMapping
、@PutMapping
、@DeleteMapping
等注解需要升级spring-boot-starter-parent版本到1.5.9.REALEASE以上(1.3.7.RELEASE版本没有这些注解)
建议:每个微服务应用都有自己的spring-boot-maven-plugin
和maven-compiler-plugin
并指定jdk编译版本为1.8,指定方式如下,pom.xml中添加
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
测试项目构建
Eureka注册中心:参考注册中心的搭建
服务提供者:参考注册服务提供者
ribbon消费者:参考服务发现与消费
项目搭建完后,记得按照这几个教程中提到的配置hosts文件
为了防止项目中的RequestMapping相同,这里就删除所有的controller类(服务提供者和消费者),接下来我会将每个restful方法都封装成一个类,方便大家查看
Get请求
getForEntity:此方法有三种重载形式,分别为:
getForEntity(Stringurl,Class<T>responseType)
getForEntity(Stringurl,Class<T>responseType,Object...uriVariables)
getForEntity(Stringurl,Class<T>responseType,Map<String,?>uriVariables)
getForEntity(URIurl,Class<T>responseType)
注意:此方法返回的是一个包装对象ResponseEntity<T>
其中T
为responseType
传入类型,想拿到返回类型需要使用这个包装类对象的getBody()
方法
getForObject:此方法也有三种重载形式,这点与getForEntity方法相同:
getForObject(Stringurl,Class<T>responseType)
getForObject(Stringurl,Class<T>responseType,Object...uriVariables)
getForObject(Stringurl,Class<T>responseType,Map<String,?>uriVariables)
getForObject(URIurl,Class<T>responseType)
注意:此方法返回的对象类型为responseType
传入类型
为了方便测试,这里分别在服务提供者和服务消费者中提供相同的User类,用于方便测试
packagecom.cnblogs.hellxz;
/**
*用于测试的pojo
*/
publicclassUser{
privateStringname;
privateStringsex;
privateStringphone;
publicUser(){}
publicUser(Stringname,Stringsex,Stringphone){
this.name=name;
this.sex=sex;
this.phone=phone;
}
publicStringtoString(){
return"user:{"
+"name:"+name+","
+"sex:"+sex+","
+"phone:"+phone
+"}";
}
publicStringgetName(){
returnname;
}
publicvoidsetName(Stringname){
this.name=name;
}
publicStringgetSex(){
returnsex;
}
publicvoidsetSex(Stringsex){
this.sex=sex;
}
publicStringgetPhone(){
returnphone;
}
publicvoidsetPhone(Stringphone){
this.phone=phone;
}
}
下边我们在服务提供者处创建一个GetRequestController
packagecom.cnblogs.hellxz;
importorg.apache.log4j.Logger;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.cloud.client.ServiceInstance;
importorg.springframework.cloud.client.discovery.DiscoveryClient;
importorg.springframework.web.bind.annotation.*;
/**
*@Author:Hellxz
*@Description:服务提供者
*@Date:2018/4/1811:36
*/
@RestController
publicclassGetRequestController{
@Autowired
privateDiscoveryClientclient;//注入发现客户端
privatefinalLoggerlogger=Logger.getLogger(GetRequestController.class);
/**
*gostraighttest
*/
@GetMapping(value="/hello")
publicStringhello(){
//获取服务实例,作用为之后console显示效果
ServiceInstanceserviceInstance=client.getLocalServiceInstance();
logger.info("/hellohost:"+serviceInstance.getHost()+"service_id:"+serviceInstance.getServiceId());
return"hello";
}
/**
*parametertest
*/
@GetMapping(value="/greet/{dd}")
publicStringgreet(@PathVariableStringdd){
ServiceInstanceserviceInstance=client.getLocalServiceInstance();
logger.info("/hellohost:"+serviceInstance.getHost()+"service_id:"+serviceInstance.getServiceId());
return"hello"+dd;
}
/**
*返回测试对象
*/
@GetMapping("/user")
publicUsergetUser(){
ServiceInstanceserviceInstance=client.getLocalServiceInstance();
logger.info("/user"+serviceInstance.getHost()+"port:"+serviceInstance.getPort()+"serviceInstanceid:"+serviceInstance.getServiceId());
returnnewUser("hellxz","male","123456789");
}
/**
*根据名称返回对象,这里模拟查数据库操作
*/
@GetMapping("/user/{name}")
publicUsergetUserSelect(@PathVariableStringname){
ServiceInstanceserviceInstance=client.getLocalServiceInstance();
logger.info("/user"+serviceInstance.getHost()+"port:"+serviceInstance.getPort()+"serviceInstanceid:"+serviceInstance.getServiceId());
if(name.isEmpty()){
returnnewUser();
}elseif(name.equals("hellxz")){
returnnewUser("hellxz","male","123456789");
}else{
returnnewUser("随机用户","male","987654321");
}
}
}
接下来我们在服务消费者项目中创建GetRequestController
packagecom.cnblogs.hellxz;
importorg.apache.log4j.Logger;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.http.ResponseEntity;
importorg.springframework.web.bind.annotation.*;
importorg.springframework.web.client.RestTemplate;
importorg.springframework.web.util.UriComponents;
importorg.springframework.web.util.UriComponentsBuilder;
importjava.net.URI;
importjava.util.HashMap;
importjava.util.Map;
/**
*@Author:Hellxz
*@Description:ribbon消费者应用Controller,get请求
*@Date:2018/4/1615:54
*/
@RestController
publicclassGetRequestController{
privateLoggerlogger=Logger.getLogger(GetRequestController.class);
@Autowired
//注入restTemplate
privateRestTemplaterestTemplate;
/**
*ResponseEntity<T>getForEntity(Stringurl,Class<T>responseType)
*TgetBody()以下此方法相同
*/
@GetMapping(value="/entity/noparam")
publicStringnoParamGetForEntity(){
//这里注释掉,因为之前想当然使用了直链访问服务提供者的接口,这样是不会返回结果的,而且会报错
//returnrestTemplate.getForEntity("http://localhost:8080/hello",String.class).getBody();
//使用restTemplate调用微服务接口
returnrestTemplate.getForEntity("http://hello-service/hello",String.class).getBody();
}
/**
*ResponseEntity<T>getForEntity(Stringurl,Class<T>responseType,Object...uriVariables)
*/
@GetMapping("/entity/type")
publicUsergetForEntityIdentifyByType(){
//不传参返回指定类型结果
ResponseEntity<User>entity=restTemplate.getForEntity("http://hello-service/user",User.class);
Userbody=entity.getBody();
logger.info("user:"+body);
returnbody;
//以上可简写为
//returnrestTemplate.getForEntity("http://hello-service/user",User.class).getBody();
}
/**
*ResponseEntity<T>getForEntity(Stringurl,Class<T>responseType,Object...uriVariables)
*使用占位符对参数进行替换,内部使用String.format方法实现
*/
@GetMapping(value="/entity")
//如果接收的参数是使用参数没有使用?有则使用@PathVariable,否则用@RequestParam
publicStringgetForEntityByQuestionMarkParam(@RequestParam("name")Stringname){
//主要测试getEntity方法,这里测试直接传参
returnrestTemplate.getForEntity("http://hello-service/greet/{1}",String.class,name).getBody();
}
/**
*getForEntity方法内部会提取map中,以占位符为key的值作为参数回填入url中
*ResponseEntity<T>getForEntity(Stringurl,Class<T>responseType,Map<String,?>uriVariables)
*/
@GetMapping(value="/entity/map/{name}")
//如果接收的参数是使用参数没有使用?有则使用@PathVariable,否则用@RequestParam
publicStringgetForEntityByMap(@PathVariable("name")Stringname){
//主要测试getEntity方法,这里测试map传参
Map<String,String>reqMap=newHashMap();
reqMap.put("name",name);
returnrestTemplate.getForEntity("http://hello-service/greet/{name}",String.class,reqMap).getBody();
}
/**
*ResponseEntity<T>getForObject(URIurl,Class<T>responseType)
*/
@GetMapping("/entity/uri")
publicStringgetForEntityByURI(){
//使用uri进行传参并访问
UriComponentsuriComponents=UriComponentsBuilder.fromUriString("http://hello-service/greet/{name}").build().expand("laozhang").encode();
URIuri=uriComponents.toUri();
returnrestTemplate.getForEntity(uri,String.class).getBody();
}
/**
*TgetForObject(Stringurl,Class<T>responseType)
*/
@GetMapping("/object")
publicUsergetForObjectWithNoParam(){
//相比getForEntity方法,获取对象可以省去调用getBody
returnrestTemplate.getForObject("http://hello-service/user",User.class);
}
/**
*TgetForObject(Stringurl,Class<T>responseType,Map<String,?>uriVariables)
*/
@GetMapping("/object/map")
publicUsergetForObjectByMap(){
//使用map传参
Map<String,String>paramMap=newHashMap<>();
paramMap.put("name","hellxz");
returnrestTemplate.getForObject("http://hello-service/user",User.class,paramMap);
}
/**
*TgetForObject(Stringurl,Class<T>responseType,Object...uriVariables)
*/
@GetMapping("/object/param/{name}")
publicUsergetForObjectByParam(@PathVariableStringname){
returnrestTemplate.getForObject("http://hello-service/user/{name}",User.class,name);
}
/**
*TgetForObject(URIurl,Class<T>responseType)
*/
@GetMapping("/object/uri/{name}")
publicUsergetForObjectByURI(@PathVariableStringname){
UriComponentsuriComponents=UriComponentsBuilder.fromUriString("http://hello-service/user/{name}")
.build().expand(name).encode();
URIuri=uriComponents.toUri();
returnrestTemplate.getForObject(uri,User.class);
}
}
先启动注册中心,然后通过访问消费者对外提供的接口进行测试,这些都是本人实际操作过的了,这里就不写测试了
Post请求
post请求和get请求都有*ForEntity
和*ForObject
方法,其中参数列表有些不同,除了这两个方法外,还有一个postForLocation方法,其中postForLocation以post请求提交资源,并返回新资源的URI
postForEntity:此方法有三种重载形式,分别为:
postForEntity(Stringurl,Objectrequest,Class<T>responseType,Object...uriVariables)
postForEntity(Stringurl,Objectrequest,Class<T>responseType,Map<String,?>uriVariables)
postForEntity(URIurl,Objectrequest,Class<T>responseType)
注意:此方法返回的是一个包装对象ResponseEntity<T>
其中T
为responseType
传入类型,想拿到返回类型需要使用这个包装类对象的getBody()
方法
postForObject:此方法也有三种重载形式,这点与postForEntity方法相同:
postForObject(Stringurl,Objectrequest,Class<T>responseType,Object...uriVariables)
postForObject(Stringurl,Objectrequest,Class<T>responseType,Map<String,?>uriVariables)
postForObject(URIurl,Objectrequest,Class<T>responseType)
注意:此方法返回的对象类型为responseType
传入类型
postForLocation:此方法中同样有三种重载形式,分别为:
postForLocation(Stringurl,Objectrequest,Object...uriVariables)
postForLocation(Stringurl,Objectrequest,Map<String,?>uriVariables)
postForLocation(URIurl,Objectrequest)
注意:此方法返回的是新资源的URI,相比getForEntity
、getForObject
、postForEntity
、postForObject
方法不同的是这个方法中无需指定返回类型,因为返回类型就是URI,通过Object...uriVariables
、Map<String,?>uriVariables
进行传参依旧需要占位符,参看postForEntity部分代码
按照之前的方式,我们分别在提供服务者和消费者的项目中分别创建PostRequestController
如下服务者PostRequestController代码如下:
packagecom.shunneng.springcloudhelloworld;
importorg.apache.log4j.Logger;
importorg.springframework.web.bind.annotation.*;
importorg.springframework.web.util.UriComponents;
importorg.springframework.web.util.UriComponentsBuilder;
importjava.net.URI;
/**
*@Author:Hellxz
*@Description:
*@Date:2018/4/1810:21
*/
@RestController
publicclassPostRequestController{
privateLoggerlogger=Logger.getLogger(PostRequestController.class);
/**
*接收一个对象再返回回去,postForEntity/postForObject方法通用
*/
@PostMapping("/user")
publicUserreturnUserByPost(@RequestBodyUseruser){
logger.info("/use接口"+user);
if(user==null)returnnewUser("这是一个空对象","","");
returnuser;
}
/**
*测试PostForEntity方法的参数,可以直接看输出判断结果了
*/
@PostMapping("/user/{str}")
publicUserreturnUserByPost(@PathVariableStringstr,@RequestBodyUseruser){
logger.info("/user/someparam接口传参name:"+str+""+user);
if(user==null)returnnewUser("这是一个空对象","","");
returnuser;
}
/**
*为postForLocation方法返回URI
*/
@PostMapping("/location")
publicURIreturnURI(@RequestBodyUseruser){
//这里模拟一个url,真实资源位置不一定是这里
UriComponentsuriComponents=UriComponentsBuilder.fromUriString("http://hello-service/location")
.build().expand(user).encode();
URItoUri=uriComponents.toUri();
//这里不知道是什么问题,明明生成uri了,返回之后好像并没有被获取到
logger.info("/locationuri:"+toUri);
returntoUri;
}
}
消费端PostRequestController代码:
packagecom.cnblogs.hellxz;
importorg.apache.log4j.Logger;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.http.ResponseEntity;
importorg.springframework.web.bind.annotation.PostMapping;
importorg.springframework.web.bind.annotation.RestController;
importorg.springframework.web.client.RestTemplate;
importorg.springframework.web.util.UriComponents;
importorg.springframework.web.util.UriComponentsBuilder;
importjava.net.URI;
/**
*@Author:Hellxz
*@Description:Ribbon消费者post请求controller
*@Date:2018/4/189:47
*/
@RestController
publicclassPostRequestController{
privateLoggerlogger=Logger.getLogger(PostRequestController.class);
@Autowired
privateRestTemplaterestTemplate;
/**
*ResponseEntity<T>postForEntity(Stringurl,Objectrequest,Class<T>responseType)
*其中参数url不多说,Objectrequest如果是不是一个HttpEntity对象,会自动转换为HttpEntity对象,视作完整的body来处理;
*如果是HttpEntity对象,那么会被直接当做body处理并且包含header内容。
*以下对于重写的方法就不多说了,使用方法大体同getForEntity,如果仅是简单post对象,那么使用不带Object...variables或Mapvariables的方法即可。
*postForEntity(Stringurl,Objectrequest,Class<T>responseType,Object...uriVariables)
*postForEntity(Stringurl,Objectrequest,Class<T>responseType,Map<String,?>uriVariables)
*
*这里详细说下我遇到的坑:
*1、其他几个重载方法的最后边的Object...variables和Mapvariables都是对之前的url进行操作的,
*也就是说,在post请求的url中使用占位符进行传参,而如果在url中没有使用占位符,那么这些最后传的参数是无效的!
*2、方法中Objectrequest这个对象如果和服务提供者的接收参数类型相同,那么服务提供者仅需使用@RequestBody接收参数即可。
*3、如果二者都使用了,这就比较有趣了,需要一边通过@PathVariable注解接收uri中的参数,一边还需要@RequestBody接收对象或RequestParam按字段接收参数!
*4、如果报错了,请仔细看看我上边写的三条,并注意服务提供者的参数接收注解的使用等。
*/
@PostMapping("/entity")
publicUserpostForEntity(){
Useruser=newUser("hellxz1","1","678912345");
ResponseEntity<User>entity=restTemplate.postForEntity("http://hello-service/user/{str}",user,User.class,"测试参数");
Userbody=entity.getBody();//所有restTemplate.*ForEntity方法都是包装类,body为返回类型对象
returnbody;
}
/**
*使用URI传参,测试结果会显示在服务提供者的终端中
*ResponseEntity<T>postForEntity(URIurl,Objectrequest,Class<T>responseType)
*/
@PostMapping("/entity/uri")
publicUserpostForEntityByURI(){
Useruser=newUser("老张","1","678912345");
//这里只是将url转成URI,并没有添加参数
UriComponentsuriComponents=UriComponentsBuilder.fromUriString("http://hello-service/user")
.build().encode();
URItoUri=uriComponents.toUri();
//使用user传参
Userobject=restTemplate.postForObject(toUri,user,User.class);
returnobject;
}
/**
*这里测试postForObject方法,需要注意的参数如上述方法的描述,区别只是不需要getBody了,这里就不再累述了
*postForObject(Stringurl,Objectrequest,Class<T>responseType,Object...uriVariables)
*postForObject(Stringurl,Objectrequest,Class<T>responseType,Map<String,?>uriVariables)
*/
@PostMapping("/object")
publicUserpostForObject(){
Useruser=newUser("hellxz2","1","123654987");
//这里url传1是为了调用服务者项目中的一个接口
UserresponseBody=restTemplate.postForObject("http://hello-service/user/1",user,User.class);
returnresponseBody;
}
/**
*post请求还有一种:postForLocation,这里也同样有三种重载,除了无需指定返回类型外,用法相同,返回类型均为URI,也就不累述了
*postForLocation(Stringurl,Objectrequest,Object...uriVariables)
*postForLocation(Stringurl,Objectrequest,Map<String,?>uriVariables)
*postForLocation(URIurl,Objectrequest)
*/
@PostMapping("/location")
publicURIpostForLocation(){
Useruser=newUser("hellxz3","1","987654321");
URIuri=restTemplate.postForLocation("http://hello-service/location",user);
//不知道为什么返回来是空,这个方法仅供参考吧,如果知道是什么情况,我会回来改的
logger.info("/locationuri:"+uri);
returnuri;
}
}
Put请求&&Delete请求
put请求相对于get和post请求方法来的更为简单,其中无需指定put请求的返回类型,当然也没有返回值,也是三种重载,和之前写的基本一致,这里就不想多说了,delete请求和put请求都是没有返回值的,这里再特地重复写也没什么意思,这里先分别列出这两个请求的方法,代码写在一个类中了
put请求方法如下:
put(Stringurl,Objectrequest,Object...uriVariables)
put(Stringurl,Objectrequest,Map<String,?>uriVariables)
put(URIurl,Objectrequest)
delete请求方法如下:
delete(Stringurl,Object...uriVariables)
delete(Stringurl,Map<String,?>uriVariables)
delete(URIurl)
在提供服务者项目中添加PutAndDeleteRequestController,代码如下
packagecom.cnblogs.hellxz;
importorg.apache.log4j.Logger;
importorg.springframework.web.bind.annotation.*;
/**
*@Author:Hellxz
*@Description:服务提供者put&delete请求controller
*@Date:2018/4/1914:11
*/
@RestController
publicclassPutAndDeleteRequestController{
privateLoggerlogger=Logger.getLogger(PutAndDeleteRequestController.class);
@PutMapping("/put")
publicvoidput(@RequestBodyUseruser){
logger.info("/put"+user);
}
@DeleteMapping("/delete/{id}")
publicvoiddelete(@PathVariableLongid){
logger.info("/deleteid:"+id);
}
}
在提供服务者项目中添加PutAndDeleteRequestController,代码如下
packagecom.cnblogs.hellxz;
importorg.apache.log4j.Logger;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.web.bind.annotation.*;
importorg.springframework.web.client.RestTemplate;
/**
*@Author:Hellxz
*@Description:put请求、delete请求,重载的参数与上述demo基本相同,不予列出
*@Date:2018/4/1913:43
*/
@RestController
publicclassPutRequestController{
privateLoggerlogger=Logger.getLogger(PostRequestController.class);
@Autowired
privateRestTemplaterestTemplate;
/**
*put请求示例,一般put请求多用作修改
*/
@PutMapping("/put")
publicvoidput(@RequestBodyUseruser){
restTemplate.put("http://hello-service/put",user);
}
/**
*delete请求示例
*/
@DeleteMapping("/del/{id}")
publicvoiddelete(@PathVariableLongid){
restTemplate.delete("http://hello-service/delete/{1}",id);
}
}
结语
这篇博文使用markdown写成,第一次写不知道如何将代码块中加入序号以及折叠代码功能,这可能不是一篇好文章,但是写这篇博文写了快两天,有什么好的建议欢迎评论交流,啥也不说了,如果本文对你有帮助,请帮忙点个推荐,加个关注吧!
声明:本博客无需许可也可以转载,但烦请注明出处
本文内容总结:写在前面,前提,测试项目构建,Get请求,getForEntity:此方法有三种重载形式,分别为:,getForObject:此方法也有三种重载形式,这点与getForEntity方法相同:,Post请求,postForEntity:此方法有三种重载形式,分别为:,postForObject:此方法也有三种重载形式,这点与postForEntity方法相同:,postForLocation:此方法中同样有三种重载形式,分别为:,Put请求&&Delete请求,put请求方法如下:,delete请求方法如下:,结语,
原文链接:https://www.cnblogs.com/hellxz/p/8875452.html