写在前面
本文由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中添加
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
<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(string url, class<t> responsetype)
- getforentity(string url, class<t> responsetype, object... urivariables)
- getforentity(string url, class<t> responsetype, map<string, ?> urivariables)
- getforentity(uri url, class<t> responsetype)
注意:此方法返回的是一个包装对象responseentity<t>其中t为responsetype传入类型,想拿到返回类型需要使用这个包装类对象的getbody()方法
getforobject:此方法也有三种重载形式,这点与getforentity方法相同:
- getforobject(string url, class<t> responsetype)
- getforobject(string url, class<t> responsetype, object... urivariables)
- getforobject(string url, class<t> responsetype, map<string, ?> urivariables)
- getforobject(uri url, class<t> responsetype)
注意:此方法返回的对象类型为responsetype传入类型
为了方便测试,这里分别在服务提供者和服务消费者中提供相同的user类,用于方便测试
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
|
package com.cnblogs.hellxz;
/**
* 用于测试的pojo
*/
public class user {
private string name;
private string sex;
private string phone;
public user(){}
public user(string name, string sex, string phone) {
this .name = name;
this .sex = sex;
this .phone = phone;
}
public string tostring(){
return "user:{"
+ "name: " + name + ", "
+ "sex: " + sex + ", "
+ "phone: " + phone
+ " }" ;
}
public string getname() {
return name;
}
public void setname(string name) {
this .name = name;
}
public string getsex() {
return sex;
}
public void setsex(string sex) {
this .sex = sex;
}
public string getphone() {
return phone;
}
public void setphone(string phone) {
this .phone = phone;
}
}
|
下边我们在服务提供者处创建一个getrequestcontroller
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
58
59
60
61
62
63
64
65
66
67
68
|
package com.cnblogs.hellxz;
import org.apache.log4j.logger;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.cloud.client.serviceinstance;
import org.springframework.cloud.client.discovery.discoveryclient;
import org.springframework.web.bind.annotation.*;
/**
* @author : hellxz
* @description: 服务提供者
* @date : 2018/4/18 11:36
*/
@restcontroller
public class getrequestcontroller {
@autowired
private discoveryclient client; //注入发现客户端
private final logger logger = logger.getlogger(getrequestcontroller. class );
/**
* go straight test
*/
@getmapping (value = "/hello" )
public string hello(){
//获取服务实例,作用为之后console显示效果
serviceinstance serviceinstance = client.getlocalserviceinstance();
logger.info( "/hello host:" +serviceinstance.gethost()+ " service_id:" +serviceinstance.getserviceid());
return "hello" ;
}
/**
* parameter test
*/
@getmapping (value = "/greet/{dd}" )
public string greet( @pathvariable string dd){
serviceinstance serviceinstance = client.getlocalserviceinstance();
logger.info( "/hello host:" +serviceinstance.gethost()+ " service_id:" +serviceinstance.getserviceid());
return "hello " +dd;
}
/**
* 返回测试对象
*/
@getmapping ( "/user" )
public user getuser(){
serviceinstance serviceinstance = client.getlocalserviceinstance();
logger.info( "/user " +serviceinstance.gethost()+ " port:" +serviceinstance.getport()+ " serviceinstanceid:" +serviceinstance.getserviceid());
return new user( "hellxz" , "male" , "123456789" );
}
/**
* 根据名称返回对象,这里模拟查数据库操作
*/
@getmapping ( "/user/{name}" )
public user getuserselect( @pathvariable string name){
serviceinstance serviceinstance = client.getlocalserviceinstance();
logger.info( "/user " +serviceinstance.gethost()+ " port:" +serviceinstance.getport()+ " serviceinstanceid:" +serviceinstance.getserviceid());
if (name.isempty()){
return new user();
} else if (name.equals( "hellxz" )){
return new user( "hellxz" , "male" , "123456789" );
} else {
return new user( "随机用户" , "male" , "987654321" );
}
}
}
|
接下来我们在服务消费者项目中创建getrequestcontroller
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
package com.cnblogs.hellxz;
import org.apache.log4j.logger;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.http.responseentity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.resttemplate;
import org.springframework.web.util.uricomponents;
import org.springframework.web.util.uricomponentsbuilder;
import java.net.uri;
import java.util.hashmap;
import java.util.map;
/**
* @author : hellxz
* @description: ribbon消费者应用controller,get请求
* @date : 2018/4/16 15:54
*/
@restcontroller
public class getrequestcontroller {
private logger logger = logger.getlogger(getrequestcontroller. class );
@autowired
//注入resttemplate
private resttemplate resttemplate;
/**
* responseentity<t> getforentity(string url, class<t> responsetype)
* t getbody() 以下此方法相同
*/
@getmapping (value= "/entity/noparam" )
public string noparamgetforentity(){
//这里注释掉,因为之前想当然使用了直链访问服务提供者的接口,这样是不会返回结果的,而且会报错
//return resttemplate.getforentity("http://localhost:8080/hello",string.class).getbody();
//使用resttemplate调用微服务接口
return resttemplate.getforentity( "http://hello-service/hello" , string. class ).getbody();
}
/**
* responseentity<t> getforentity(string url, class<t> responsetype, object... urivariables)
*/
@getmapping ( "/entity/type" )
public user getforentityidentifybytype(){
//不传参返回指定类型结果
responseentity<user> entity = resttemplate.getforentity( "http://hello-service/user" , user. class );
user body = entity.getbody();
logger.info( "user:" +body);
return body;
//以上可简写为
// return resttemplate.getforentity("http://hello-service/user", user.class).getbody();
}
/**
* responseentity<t> getforentity(string url, class<t> responsetype, object... urivariables)
* 使用占位符对参数进行替换,内部使用string.format方法实现
*/
@getmapping (value= "/entity" )
//如果接收的参数是使用参数没有使用?有则使用@pathvariable,否则用@requestparam
public string getforentitybyquestionmarkparam( @requestparam ( "name" ) string name){
//主要测试getentity方法,这里测试直接传参
return resttemplate.getforentity( "http://hello-service/greet/{1}" , string. class , name).getbody();
}
/**
* getforentity方法内部会提取map中,以占位符为key的值作为参数回填入url中
* responseentity<t> getforentity(string url, class<t> responsetype, map<string, ?> urivariables)
*/
@getmapping (value= "/entity/map/{name}" )
//如果接收的参数是使用参数没有使用?有则使用@pathvariable,否则用@requestparam
public string getforentitybymap( @pathvariable ( "name" ) string name){
//主要测试getentity方法,这里测试map传参
map<string, string> reqmap = new hashmap();
reqmap.put( "name" ,name);
return resttemplate.getforentity( "http://hello-service/greet/{name}" , string. class ,reqmap).getbody();
}
/**
* responseentity<t> getforobject(uri url, class<t> responsetype)
*/
@getmapping ( "/entity/uri" )
public string getforentitybyuri(){
//使用uri进行传参并访问
uricomponents uricomponents = uricomponentsbuilder.fromuristring( "http://hello-service/greet/{name}" ).build().expand( "laozhang" ).encode();
uri uri = uricomponents.touri();
return resttemplate.getforentity(uri, string. class ).getbody();
}
/**
* t getforobject(string url, class<t> responsetype)
*/
@getmapping ( "/object" )
public user getforobjectwithnoparam(){
//相比getforentity方法,获取对象可以省去调用getbody
return resttemplate.getforobject( "http://hello-service/user" , user. class );
}
/**
* t getforobject(string url, class<t> responsetype, map<string, ?> urivariables)
*/
@getmapping ( "/object/map" )
public user getforobjectbymap(){
//使用map传参
map<string, string> parammap = new hashmap<>();
parammap.put( "name" , "hellxz" );
return resttemplate.getforobject( "http://hello-service/user" , user. class , parammap);
}
/**
* t getforobject(string url, class<t> responsetype, object... urivariables)
*/
@getmapping ( "/object/param/{name}" )
public user getforobjectbyparam( @pathvariable string name){
return resttemplate.getforobject( "http://hello-service/user/{name}" ,user. class , name);
}
/**
* t getforobject(uri url, class<t> responsetype)
*/
@getmapping ( "/object/uri/{name}" )
public user getforobjectbyuri( @pathvariable string name){
uricomponents uricomponents = uricomponentsbuilder.fromuristring( "http://hello-service/user/{name}" )
.build().expand(name).encode();
uri uri = uricomponents.touri();
return resttemplate.getforobject(uri,user. class );
}
}
|
先启动注册中心,然后通过访问消费者对外提供的接口进行测试,这些都是本人实际操作过的了,这里就不写测试了
post请求
post请求和get请求都有*forentity和*forobject方法,其中参数列表有些不同,除了这两个方法外,还有一个postforlocation方法,其中postforlocation以post请求提交资源,并返回新资源的uri
postforentity:此方法有三种重载形式,分别为:
- postforentity(string url, object request, class<t> responsetype, object... urivariables)
- postforentity(string url, object request, class<t> responsetype, map<string, ?> urivariables)
- postforentity(uri url, object request, class<t> responsetype)
注意:此方法返回的是一个包装对象responseentity<t>其中t为responsetype传入类型,想拿到返回类型需要使用这个包装类对象的getbody()方法
postforobject:此方法也有三种重载形式,这点与postforentity方法相同:
- postforobject(string url, object request, class<t> responsetype, object... urivariables)
- postforobject(string url, object request, class<t> responsetype, map<string, ?> urivariables)
- postforobject(uri url, object request, class<t> responsetype)
注意:此方法返回的对象类型为responsetype传入类型
postforlocation:此方法中同样有三种重载形式,分别为:
- postforlocation(string url, object request, object... urivariables)
- postforlocation(string url, object request, map<string, ?> urivariables)
- postforlocation(uri url, object request)
注意:此方法返回的是新资源的uri,相比getforentity、getforobject、postforentity、postforobject方法不同的是这个方法中无需指定返回类型,因为返回类型就是uri,通过object... urivariables、map<string, ?> urivariables进行传参依旧需要占位符,参看postforentity部分代码
按照之前的方式,我们分别在提供服务者和消费者的项目中分别创建postrequestcontroller
如下服务者postrequestcontroller代码如下:
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
|
package com.shunneng.springcloudhelloworld;
import org.apache.log4j.logger;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.util.uricomponents;
import org.springframework.web.util.uricomponentsbuilder;
import java.net.uri;
/**
* @author : hellxz
* @description:
* @date : 2018/4/18 10:21
*/
@restcontroller
public class postrequestcontroller {
private logger logger = logger.getlogger(postrequestcontroller. class );
/**
* 接收一个对象再返回回去,postforentity/postforobject方法通用
*/
@postmapping ( "/user" )
public user returnuserbypost( @requestbody user user){
logger.info( "/use接口 " +user);
if (user == null ) return new user( "这是一个空对象" , "" , "" );
return user;
}
/**
* 测试postforentity方法的参数,可以直接看输出判断结果了
*/
@postmapping ( "/user/{str}" )
public user returnuserbypost( @pathvariable string str, @requestbody user user){
logger.info( "/user/someparam 接口传参 name:" +str + " " +user);
if (user == null ) return new user( "这是一个空对象" , "" , "" );
return user;
}
/**
* 为postforlocation方法返回uri
*/
@postmapping ( "/location" )
public uri returnuri( @requestbody user user){
//这里模拟一个url,真实资源位置不一定是这里
uricomponents uricomponents = uricomponentsbuilder.fromuristring( "http://hello-service/location" )
.build().expand(user).encode();
uri touri = uricomponents.touri();
//这里不知道是什么问题,明明生成uri了,返回之后好像并没有被获取到
logger.info( "/location uri:" +touri);
return touri;
}
}
|
消费端postrequestcontroller代码:
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
|
package com.cnblogs.hellxz;
import org.apache.log4j.logger;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.http.responseentity;
import org.springframework.web.bind.annotation.postmapping;
import org.springframework.web.bind.annotation.restcontroller;
import org.springframework.web.client.resttemplate;
import org.springframework.web.util.uricomponents;
import org.springframework.web.util.uricomponentsbuilder;
import java.net.uri;
/**
* @author : hellxz
* @description: ribbon消费者post请求controller
* @date : 2018/4/18 9:47
*/
@restcontroller
public class postrequestcontroller {
private logger logger = logger.getlogger(postrequestcontroller. class );
@autowired
private resttemplate resttemplate;
/**
* responseentity<t> postforentity(string url, object request, class<t> responsetype)
* 其中参数url不多说,object request如果是不是一个httpentity对象,会自动转换为httpentity对象,视作完整的body来处理;
* 如果是httpentity对象,那么会被直接当做body处理并且包含header内容。
* 以下对于重写的方法就不多说了,使用方法大体同getforentity,如果仅是简单post对象,那么使用不带object...variables或map variables的方法即可。
* postforentity(string url, object request, class<t> responsetype, object... urivariables)
* postforentity(string url, object request, class<t> responsetype, map<string, ?> urivariables)
*
* 这里详细说下我遇到的坑:
* 1、其他几个重载方法的最后边的object...variables和map variables都是对之前的url进行操作的,
* 也就是说,在post请求的url中使用占位符进行传参,而如果在url中没有使用占位符,那么这些最后传的参数是无效的!
* 2、方法中object request这个对象如果和服务提供者的接收参数类型相同,那么服务提供者仅需使用@requestbody接收参数即可。
* 3、如果二者都使用了,这就比较有趣了,需要一边通过@pathvariable注解接收uri中的参数,一边还需要@requestbody接收对象或requestparam按字段接收参数!
* 4、如果报错了,请仔细看看我上边写的三条,并注意服务提供者的参数接收注解的使用等。
*/
@postmapping ( "/entity" )
public user postforentity(){
user user = new user( "hellxz1" , "1" , "678912345" );
responseentity<user> entity = resttemplate.postforentity( "http://hello-service/user/{str}" , user, user. class , "测试参数" );
user body = entity.getbody(); //所有resttemplate.*forentity方法都是包装类,body为返回类型对象
return body;
}
/**
* 使用uri传参,测试结果会显示在服务提供者的终端中
* responseentity<t> postforentity(uri url, object request, class<t> responsetype)
*/
@postmapping ( "/entity/uri" )
public user postforentitybyuri(){
user user = new user( "老张" , "1" , "678912345" );
//这里只是将url转成uri,并没有添加参数
uricomponents uricomponents = uricomponentsbuilder.fromuristring( "http://hello-service/user" )
.build().encode();
uri touri = uricomponents.touri();
//使用user传参
user object = resttemplate.postforobject(touri, user, user. class );
return object;
}
/**
* 这里测试postforobject方法,需要注意的参数如上述方法的描述,区别只是不需要getbody了,这里就不再累述了
* postforobject(string url, object request, class<t> responsetype, object... urivariables)
* postforobject(string url, object request, class<t> responsetype, map<string, ?> urivariables)
*/
@postmapping ( "/object" )
public user postforobject(){
user user = new user( "hellxz2" , "1" , "123654987" );
//这里url传1是为了调用服务者项目中的一个接口
user responsebody = resttemplate.postforobject( "http://hello-service/user/1" , user, user. class );
return responsebody;
}
/**
* post请求还有一种:postforlocation,这里也同样有三种重载,除了无需指定返回类型外,用法相同,返回类型均为uri,也就不累述了
* postforlocation(string url, object request, object... urivariables)
* postforlocation(string url, object request, map<string, ?> urivariables)
* postforlocation(uri url, object request)
*/
@postmapping ( "/location" )
public uri postforlocation(){
user user = new user( "hellxz3" , "1" , "987654321" );
uri uri = resttemplate.postforlocation( "http://hello-service/location" , user);
//不知道为什么返回来是空,这个方法仅供参考吧,如果知道是什么情况,我会回来改的
logger.info( "/location uri:" +uri);
return uri;
}
}
|
put请求&&delete请求
put请求相对于get和post请求方法来的更为简单,其中无需指定put请求的返回类型,当然也没有返回值,也是三种重载,和之前写的基本一致,这里就不想多说了,delete请求和put请求都是没有返回值的,这里再特地重复写也没什么意思,这里先分别列出这两个请求的方法,代码写在一个类中了
put请求方法如下:
- put(string url, object request, object... urivariables)
- put(string url, object request, map<string, ?> urivariables)
- put(uri url, object request)
delete请求方法如下:
- delete(string url, object... urivariables)
- delete(string url, map<string, ?> urivariables)
- delete(uri url)
在提供服务者项目中添加putanddeleterequestcontroller,代码如下
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
|
package com.cnblogs.hellxz;
import org.apache.log4j.logger;
import org.springframework.web.bind.annotation.*;
/**
* @author : hellxz
* @description: 服务提供者 put&delete请求controller
* @date : 2018/4/19 14:11
*/
@restcontroller
public class putanddeleterequestcontroller {
private logger logger = logger.getlogger(putanddeleterequestcontroller. class );
@putmapping ( "/put" )
public void put( @requestbody user user){
logger.info( "/put " +user);
}
@deletemapping ( "/delete/{id}" )
public void delete( @pathvariable long id){
logger.info( "/delete id:" +id);
}
}
|
在提供服务者项目中添加putanddeleterequestcontroller,代码如下
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
|
package com.cnblogs.hellxz;
import org.apache.log4j.logger;
import org.springframework.beans.factory.annotation.autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.resttemplate;
/**
* @author : hellxz
* @description: put请求、delete请求,重载的参数与上述demo基本相同,不予列出
* @date : 2018/4/19 13:43
*/
@restcontroller
public class putrequestcontroller {
private logger logger = logger.getlogger(postrequestcontroller. class );
@autowired
private resttemplate resttemplate;
/**
* put请求示例,一般put请求多用作修改
*/
@putmapping ( "/put" )
public void put( @requestbody user user){
resttemplate.put( "http://hello-service/put" ,user);
}
/**
* delete请求示例
*/
@deletemapping ( "/del/{id}" )
public void delete( @pathvariable long id){
resttemplate.delete( "http://hello-service/delete/{1}" , id);
}
}
|
结语
这篇博文使用markdown写成,第一次写不知道如何将代码块中加入序号以及折叠代码功能,这可能不是一篇好文章,但是写这篇博文写了快两天,有什么好的建议欢迎评论交流,
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:http://www.cnblogs.com/hellxz/p/8875452.html