RestTemplate入門

RestTemplate入門

 本篇主要講解RestTemplate的基本使用,它是Spring提供的用來訪問Rest服務的客戶端,RestTmplate提供了不少便捷的方法,能夠大大提供開發效率,本篇只涉及基本使用,內部原理後續再展開java

 1.RestTemplate簡述

 RestTemplate是Spring提供的用於發送HTTP請求的客戶端工具,它遵循Restful原則,RestTemplate默認依賴JDK的Http鏈接工具HttpUrlConnection,你也能夠替換不一樣的源,好比OkHttp、Apache HttpComponents 等等。。正則表達式

 2.HttpMessageConverter

 在說RestTemplate以前,先介紹HttpMessageConverter,RestTemplate默認使用的轉化HttpMessageConverter去將Http消息轉換成POJO 或者 POJO轉化成Http消息。在建立RestTemplate的時候會默認添加一組HttpMessageConveter的實現。json

 HttpMessageConverter源碼:app

public interface HttpMessageConverter<T> {
    //指示此轉換器是否能夠讀取給定的類。
	boolean canRead(Class<?> clazz, [@Nullable](https://my.oschina.net/u/2896689) MediaType mediaType);

    //指示此轉換器是否能夠寫給定的類。
	boolean canWrite(Class<?> clazz, [@Nullable](https://my.oschina.net/u/2896689) MediaType mediaType);

    //返回List<MediaType>
	List<MediaType> getSupportedMediaTypes();

    //讀取一個inputMessage
	T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
        throws IOException, HttpMessageNotReadableException;

    //往output message寫一個Object
	void write(T t, [@Nullable](https://my.oschina.net/u/2896689) MediaType contentType, HttpOutputMessage outputMessage)
        throws IOException, HttpMessageNotWritableException;

}

 RestTemplate中如何添加HttpMessageConverter的工具

 構造器源碼:post

static {
	ClassLoader classLoader = RestTemplate.class.getClassLoader();
	romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", classLoader);
	jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", classLoader);
	jackson2Present =
			ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", classLoader) &&
					ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", classLoader);
	jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", classLoader);
	jackson2SmilePresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.smile.SmileFactory", classLoader);
	jackson2CborPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.cbor.CBORFactory", classLoader);
	gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", classLoader);
	jsonbPresent = ClassUtils.isPresent("javax.json.bind.Jsonb", classLoader);
}


public RestTemplate() {
	this.messageConverters.add(new ByteArrayHttpMessageConverter());
	this.messageConverters.add(new StringHttpMessageConverter());
	this.messageConverters.add(new ResourceHttpMessageConverter(false));
	try {
		this.messageConverters.add(new SourceHttpMessageConverter<>());
	}
	catch (Error err) {
		// Ignore when no TransformerFactory implementation is available
	}
	this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

	if (romePresent) {
		this.messageConverters.add(new AtomFeedHttpMessageConverter());
		this.messageConverters.add(new RssChannelHttpMessageConverter());
	}

	if (jackson2XmlPresent) {
		this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
	}
	else if (jaxb2Present) {
		this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
	}

	if (jackson2Present) {
		this.messageConverters.add(new MappingJackson2HttpMessageConverter());
	}
	else if (gsonPresent) {
		this.messageConverters.add(new GsonHttpMessageConverter());
	}
	else if (jsonbPresent) {
		this.messageConverters.add(new JsonbHttpMessageConverter());
	}

	if (jackson2SmilePresent) {
		this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
	}
	if (jackson2CborPresent) {
		this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
	}

	this.uriTemplateHandler = initUriTemplateHandler();
}

 從RestTemplate的構造器源碼中咱們能夠看到構造方法中 根據ClassUtils.isPresent判斷當前項目是否存在某些jar包向RestTemplate中添加不一樣的 HttpMessageConverter實現,Spring默認會添加 StringHttpMessageConverter , MappingJackson2XmlHttpMessageConverter等等ui

Xnip20191210_231205.png

 3.getForObject()

 首先來看Get請求 RestTemplate提供了2種方法其中一種就是 getForObject()方法this

public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables){}
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
public <T> T getForObject(URI url, Class<T> responseType)

  3.1 不帶參數的Get請求

客戶端
 String url = "http://localhost:9999/testGetMethod";
 String str = restTemplate.getForObject(url , String.class);、

服務端
@RequestMapping("/testGetMethod")
public String testGetMethod(){
    return "hello";
}

  3.2 帶參數的Get請求 (按{}順序綁定參數)

客戶端
 String url = "http://localhost:9999/testGetMethod/{talk}/{name}"; 
	//或者testGetMethod/{1}/{2} {裏面的參數無所謂,只是根據下面的Object... uriVariables 逐一綁定到上面{} 中去的}

 String str = restTemplate.getForObject(url , String.class,"hello" , "johnny");

服務端
  @RequestMapping("/testGetMethod/{talk}/{name}")
public String testGetMethod(@PathVariable("talk") String talk ,
                            @PathVariable("name") String name){
    log.info("【{} : {}】" , talk , name);
    return "hello";
}

說明{} http://localhost:9999/testGetMethod/{talk}/{name} 裏面的參數名稱無所謂,只是根據下面的Object... uriVariables 逐一綁上去的,具體綁定源碼請看 DefaultUriBuilderFactory的fromUriString方法內部是根據正則表達式進行綁定的,最終將返回 URI,URI的string屬性 就是綁定後要訪問的路徑 Xnip20191210_234530.pnggoogle

//不早了 先寫這麼多吧 明天把下面的補齊 ,先去睡覺了!!! //繼續補齊。。url

  3.3 帶參數的Get請求(按Map的key綁定{}參數)

String url = "http://localhost:9999/testGetMethod/{talk}/{name}";
 Map<String,String> map = new HashMap<>(); 
 map.put("talk" , "hello"); 
 map.put("name" , "johnny"); 
 String str = restTemplate.getForObject(url , String.class,map);

  能夠看出來是經過Map綁定參數的,這個和上面不同的是 map的key 必定要和 url中 {} 中的 保持一致 ,若是不一致會報錯

String url = "http://localhost:9999/testGetMethod/{talk}/{name}"; 
 map.put("talk2" , "hello");

Xnip20191210_234530.png

源碼

Xnip20191212_135605.png

 4.getForEntity()

 RestTemplate 提供的Get請求的第二種方法 ,基本和getForObject一致 ,就是返回類型不一樣,它是在getForObject返回的基礎上再包裝了一層 ResponseEntity 用於包含Http請求的所有信息

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables){}
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables){}
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType){}

  4.1 不帶參數的Get請求

String url = "http://localhost:9999/testGetMethodForEntity/";
    ResponseEntity<Student> responseEntity = restTemplate.getForEntity(url , Student.class);
    responseEntity.getStatusCode();
    responseEntity.getHeaders();
    responseEntity.getBody();
    log.info("【responseEntity : {}】" , responseEntity);

Xnip20191212_214059.png

  4.2 帶參數的Get請求 (按{}順序綁定參數)

String url = "http://localhost:9999/testGetMethodForEntity/{name}/{age}";
    ResponseEntity<Student> responseEntity = restTemplate.getForEntity(url , Student.class , "johnny" , "23");
    log.info("【responseEntity : {}】" , responseEntity);

  4.3 帶參數的Get請求 (按Ma的keyp綁定{}參數)

String url = "http://localhost:9999/testGetMethodForEntity/{name}/{age}";
    Map<String,String> map = new HashMap<>();
    map.put("name","johnny");
    map.put("age" , "23");
    ResponseEntity<Student> responseEntity = restTemplate.getForEntity(url , Student.class ,"map");
    log.info("【responseEntity : {}】" , responseEntity);

可是,一般狀況下咱們並不想要Http請求的所有信息,只須要相應體便可.對於這種狀況,RestTemplate提供了 getForObject() 方法用來只獲取 響應體信息. getForObject 和 getForEntity 用法幾乎相同,指示返回值返回的是 響應體,省去了咱們 再去 getBody() .

 5.postForObject()

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 {}

  5.1 post請求 提交參數 Student 對象

客戶端代碼:

    String url = "http://localhost:9999/testPostMethodForObject";
    Student student = new Student();
    student.setName("johnny");
    student.setAge("23");

    String msg = restTemplate.postForObject(url , student , String.class);

服務端代碼:
     @RequestMapping("/testPostMethodForObject")
    public String testGetMethodForEntity(@RequestBody Student student){
     log.info("【studeng: {}】"  , student);
     return "success";
   }

 6.postForEntity()

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 {}

  6.1 post請求 提交參數 Student 對象

@RequestMapping("/testPostMethodForEntity")
public void testPostMethodForEntity(){

    String url = "http://localhost:9999/testPostMethodForEntity";
    Student student = new Student();
    student.setName("johnny");
    student.setAge("23");

    ResponseEntity<String> responseEntity = restTemplate.postForEntity(url , student , String.class);
    log.info(responseEntity.getBody());
}

 7. ResponseExtractor 源碼

 能夠看出來postForEntity和postForObject 幾乎同樣。

 惟有 ResponseExtractor<T> 不一樣

Xnip20191212_220311.png

Xnip20191212_221136.png

HttpMessageConverterExtractor.extractData()方法

Xnip20191212_220906.png

ResponseEntityResponseExtractor.extractData()方法

Xnip20191212_220722.png

 總結:

  本篇主要講解RestTemplate的基本的 Get Post 的用法,簡單的涉及了一點源碼,其實內部源碼不少 很深 包括和解析url模板 綁定參數的 UriBuilderFactory UriTemplateHandler 等等 , 建議去跟着跑一遍會更加熟悉 用起來也更加輕鬆。

我的博客系統:https://www.askajohnny.com 歡迎訪問! 本文由博客一文多發平臺 OpenWrite 發佈!

相關文章
相關標籤/搜索