本文由markdown格式寫成,爲本人第一次這麼寫,排版可能會有點亂,還望各位海涵。
主要寫的是使用Ribbon進行Restful請求,測試各個方法的使用,代碼冗餘較高,比較適合初學者,介意輕噴謝謝。html
@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消費者:參考服務發現與消費java
項目搭建完後,記得按照這幾個教程中提到的配置hosts文件web
爲了防止項目中的RequestMapping相同,這裏就刪除全部的controller類(服務提供者和消費者),接下來我會將每一個restful方法都封裝成一個類,方便你們查看spring
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(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類,用於方便測試數據庫
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; } }
下邊咱們在服務提供者處建立一個GetRequestControllerapache
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"); } } }
接下來咱們在服務消費者項目中建立GetRequestControllerrestful
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); } }
先啓動註冊中心,而後經過訪問消費者對外提供的接口進行測試,這些都是本人實際操做過的了,這裏就不寫測試了markdown
post請求和get請求都有*ForEntity
和*ForObject
方法,其中參數列表有些不一樣,除了這兩個方法外,還有一個postForLocation方法,其中postForLocation以post請求提交資源,並返回新資源的URIapp
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)
maven
ResponseEntity<T>
其中T
爲responseType
傳入類型,想拿到返回類型須要使用這個包裝類對象的getBody()
方法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(String url, Object request, Object... uriVariables)
postForLocation(String url, Object request, Map<String, ?> uriVariables)
postForLocation(URI url, Object request)
getForEntity
、getForObject
、postForEntity
、postForObject
方法不一樣的是這個方法中無需指定返回類型,由於返回類型就是URI,經過Object... uriVariables
、Map<String, ?> uriVariables
進行傳參依舊須要佔位符,參看postForEntity部分代碼按照以前的方式,咱們分別在提供服務者和消費者的項目中分別建立PostRequestController
以下服務者PostRequestController代碼以下:
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代碼:
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) * * 這裏詳細說下我遇到的坑: * 一、其餘幾個重載方法的最後邊的Object...variables和Map variables都是對以前的url進行操做的, * 也就是說,在post請求的url中使用佔位符進行傳參,而若是在url中沒有使用佔位符,那麼這些最後傳的參數是無效的! * 二、方法中Object request這個對象若是和服務提供者的接收參數類型相同,那麼服務提供者僅需使用@RequestBody接收參數便可。 * 三、若是兩者都使用了,這就比較有趣了,須要一邊經過@PathVariable註解接收uri中的參數,一邊還須要@RequestBody接收對象或RequestParam按字段接收參數! * 四、若是報錯了,請仔細看看我上邊寫的三條,並注意服務提供者的參數接收註解的使用等。 */ @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請求相對於get和post請求方法來的更爲簡單,其中無需指定put請求的返回類型,固然也沒有返回值,也是三種重載,和以前寫的基本一致,這裏就不想多說了,delete請求和put請求都是沒有返回值的,這裏再特意重複寫也沒什麼意思,這裏先分別列出這兩個請求的方法,代碼寫在一個類中了
put(String url, Object request, Object... uriVariables)
put(String url, Object request, Map<String, ?> uriVariables)
put(URI url, Object request)
delete(String url, Object... uriVariables)
delete(String url, Map<String, ?> uriVariables)
delete(URI url)
在提供服務者項目中添加PutAndDeleteRequestController,代碼以下
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,代碼以下
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寫成,第一次寫不知道如何將代碼塊中加入序號以及摺疊代碼功能,這可能不是一篇好文章,可是寫這篇博文寫了快兩天,有什麼好的建議歡迎評論交流,啥也不說了,若是本文對你有幫助,請幫忙點個推薦,加個關注吧!
聲明:本博客無需許可也能夠轉載,但煩請註明出處