Spring實(shí)戰(zhàn)(十六)-使用Spring MVC創(chuàng)建REST API

本文基于《Spring實(shí)戰(zhàn)(第4版)》所寫。

Rest含義:

  • 表述性(Representational):REST資源實(shí)際上可以用各種形式來進(jìn)行表述,包括XML、JSON(JavaScript Object Notation)甚至HTML—最適合資源使用者的任意形式;
  • 狀態(tài)(State):當(dāng)使用REST的時(shí)候,我們更關(guān)注資源的狀態(tài)而不是對(duì)資源采取的行為;
  • 轉(zhuǎn)移(Transfer):REST涉及到轉(zhuǎn)移資源數(shù)據(jù),它以某種表述性形式從一個(gè)應(yīng)用轉(zhuǎn)移到另一個(gè)應(yīng)用。

REST的動(dòng)作(HTTP的方法)以及匹配的CRUD動(dòng)作:

  • Create: POST
  • Read: GET
  • Update: PUT或PATCH
  • DELETE: DELETE

Spring支持以下方式來創(chuàng)建REST資源:

  • 控制器可以處理所有的HTTP方法,包含四個(gè)主要的REST方法:GET、PUT、DELETE以及POST。Spring 3.2及以上版本還支持PATCH方法;
  • 借助@PathVariable注解,控制器能夠處理參數(shù)化的URL(將變量輸入作為URL的一部分);
  • 借助Spring的視圖和視圖解析器,資源能夠以多種方式進(jìn)行表述,包括將模型數(shù)據(jù)渲染為XML、JSON、Atom以及RSS的View實(shí)現(xiàn);
  • 可以使用ContentNegotiatingViewResolver來選擇最適合客戶端的表述;
  • 借助@ResponseBody注解和和各種HttpMethodConverter實(shí)現(xiàn),能夠替換基于視圖的渲染方式;
  • 類似地,@RequestBody注解以及HttpMethodConverter實(shí)現(xiàn)可以將傳入的HTTP數(shù)據(jù)轉(zhuǎn)化為傳入控制器處理方法的Java對(duì)象;
  • 借助RestTemplate,Spring應(yīng)用能夠方便地使用Rest資源。

Spring提供了兩種方法將資源的Java表述轉(zhuǎn)換為發(fā)送給客戶端的表述形式:

  • 內(nèi)容協(xié)商(Content negotiation):選擇一個(gè)視圖,它能夠?qū)⒛P弯秩緸槌尸F(xiàn)給客戶端表述形式。不過由于它只能決定資源該如何渲染到客戶端,并沒有涉及到客戶端要發(fā)送什么樣的表述給控制器使用,比如客戶端發(fā)送JSON或XML,它就無法提供幫助了。而且還有其他限制,不建議使用。
  • 消息轉(zhuǎn)換器(Message conversion):通過一個(gè)消息轉(zhuǎn)換器將控制器所返回的對(duì)象轉(zhuǎn)換為呈現(xiàn)給客戶端的表述形式。

使用HTTP信息轉(zhuǎn)換器

當(dāng)使用消息轉(zhuǎn)換功能時(shí),DispatcherServlet不再將模型數(shù)據(jù)傳送到視圖中。實(shí)際上,根本就沒有模型,也沒有視圖,只有控制器產(chǎn)生的數(shù)據(jù),以及消息轉(zhuǎn)換器轉(zhuǎn)換數(shù)據(jù)之后所產(chǎn)生的資源表述。

Spring自帶了各種各樣的轉(zhuǎn)換器,比如客戶端通過請(qǐng)求的Accept頭信息表明它能接受“application/json”,并且Jackson JSON在類路徑下,那么處理方法返回的對(duì)象將交給MappingJacksonHttpMessageConverter,并由它轉(zhuǎn)換為返回客戶端的JSON表述形式。大部分轉(zhuǎn)換器都是自動(dòng)注冊(cè)的,不需要Spring配置。但是為了支持它們,需要添加一些庫到應(yīng)用程序的類路徑下。

如果使用了消息轉(zhuǎn)換功能的話,我們需要告訴Spring跳過正常的模型/視圖流程,并使用消息轉(zhuǎn)換器。最簡(jiǎn)單的方式是為控制器方法添加@ResponseBody注解。例如,如下程序:

@RequestMapping(method=RequestMethod.GET, produces="application/json")
public @ResponseBody List<Spittle> spittles (
@RequestParam(value="max",defaultValue=MAX_LONG_AS_SPRING)) long max,
@RequestParam(value="count",defaultValue="20") int count) {
      return spittleRepository.findSpittles(max, count);
}

@ResponseBody注解會(huì)告知Spring,我們要將返回的對(duì)象作為資源發(fā)送給客戶端,并將其轉(zhuǎn)換為客戶端可接受的表述形式。更具體地講,DispatcherServlet將會(huì)考慮到請(qǐng)求中Accept頭部信息,并查找能夠?yàn)榭蛻舳颂峁┧璞硎鲂问降南⑥D(zhuǎn)換器(根據(jù)類路徑下實(shí)現(xiàn)庫)。

需要注意的是,默認(rèn)情況下,Jackson JSON庫在將返回的對(duì)象轉(zhuǎn)換為JSON資源表述時(shí),會(huì)使用反射。如果重構(gòu)了Java類型,比如添加、移除或重命名屬性,那么產(chǎn)生的JSON也將會(huì)發(fā)生變化。但是,我們可以在Java類型上使用Jackson的映射注解,改變產(chǎn)生JSON的行為。

談及Accept頭部信息,在@RequestMapping注解中,我們使用了produces屬性表明這個(gè)方法只處理預(yù)期輸出為JSON的請(qǐng)求,其他任何類型的請(qǐng)求,都不會(huì)被這個(gè)方法處理。這樣的請(qǐng)求會(huì)被其他的方法來進(jìn)行處理,或者返回客戶端HTTP 406響應(yīng)。

與@ResponseBody類似,@RequestBody也能告訴Spring查找一個(gè)消息轉(zhuǎn)換器,將來自客戶端的資源表述為對(duì)象。例如:

@RequestMapping(method=RequestMethod.POST, consumes="application/json")
public @ResponseBody Spittle saveSpittle(@RequestBody Spittle spittle) {
    return spittleRepository.save(spittle);
}

通過使用注解,@RequestMapping表明它只能處理“/spittles”(在類級(jí)別的@RequestMapping中進(jìn)行了聲明)的POST請(qǐng)求。POST請(qǐng)求體中預(yù)期要包含一個(gè)Spittle的資源表述。因?yàn)镾pittle參數(shù)上使用了@RequestBody,所以Spring將會(huì)查看請(qǐng)求中的Content-Type頭部信息,并查找能夠?qū)⒄?qǐng)求轉(zhuǎn)換為Spittle的消息轉(zhuǎn)換器。

例如,如果客戶端發(fā)送的Spittle數(shù)據(jù)是JSON表述形式,那么Content-Type頭部信息可能就會(huì)是“application/json”。在這種情況下,DispatcherServlet會(huì)查找能夠?qū)SON轉(zhuǎn)換為Java對(duì)象的消息轉(zhuǎn)換器。

注意,@RequestMapping有一個(gè)consumes屬性,我們將其設(shè)置為“application/json”。consumes屬性的工作方式類似于produces,不過它會(huì)關(guān)注請(qǐng)求的Content-Type頭部信息。它會(huì)告訴Spring這個(gè)方法只會(huì)處理對(duì)“/spittles”的POST請(qǐng)求,并且要求請(qǐng)求的Content-Type頭部信息為“application/json”。如果無法滿足這些條件的話,會(huì)有其他方法來處理請(qǐng)求。

Spring 4.0引入了@RestController注解。如果在控制器類上使用@RestController來代替@Controller的話,Spring將會(huì)為該控制器的所有處理方法應(yīng)用消息轉(zhuǎn)換功能。我們不必為每個(gè)方法都添加@ResponseBody了。添加@RestController注解,此類中所有處理器方法都不需要使用@ResponseBody注解了,因?yàn)榭刂破魇褂昧薂RestController,所有它的方法所返回的對(duì)象將會(huì)通過消息轉(zhuǎn)換機(jī)制,產(chǎn)生客戶端所需的資源表述。

發(fā)送錯(cuò)誤信息到客戶端

如果一個(gè)處理器方法本應(yīng)返回一個(gè)對(duì)象,但由于查找不到相應(yīng)的對(duì)象而返回null。我們考慮一下在這種場(chǎng)景下應(yīng)該發(fā)生什么。至少,狀態(tài)碼不應(yīng)是200,而應(yīng)該是404,告訴客戶端它們所要求的內(nèi)容沒有找到。如果響應(yīng)體中能夠包含錯(cuò)誤信息而不是空的話就更好了。

Spring提供了多種方式來處理這樣的場(chǎng)景:

  • 使用@ResponseStatus注解可以指定狀態(tài)碼;
  • 控制器方法可以返回ResponseEntity對(duì)象,該對(duì)象能夠包含更多響應(yīng)相關(guān)的元數(shù)據(jù);
  • 異常處理器能夠應(yīng)對(duì)錯(cuò)誤場(chǎng)景,這樣處理器方法就能關(guān)注于正常的狀況。

使用ResponseEntity

作為@ResponseBody的替代方案,控制器方法可以返回一個(gè)ResponseEntity對(duì)象。ResponseEntity中可以包含響應(yīng)相關(guān)的元數(shù)據(jù)(如頭部信息和狀態(tài)碼)以及要轉(zhuǎn)換成資源表述的對(duì)象。

@RequestMapping(value="/{id}", method=RequestMethod.GET)
public ResponseEntity<Spittle> spittleById(@PathVariable long id) {
    Spittle spittle = spittleRepository.findOne(id);
    HttpStatus status = spittle != null ? HttpStatus.OK : HttpStatus.NOT_FOUND;
    return new RepositoryEntity<Spittle>(spittle, status);
}

注意,如果返回ResponseEntity的話,那就沒有必要在方法上使用@ResponseBody注解了。

如果我們希望在響應(yīng)體中包含一些錯(cuò)誤信息。我們需要定義一個(gè)包含錯(cuò)誤信息的Error對(duì)象:

public class Error {
    private int code;
    private String message;
    
    public Error(int code ,String message) {
        this.code = code;
        this.message = message;
    }

    public String getCode() {
        return code;
    }

    public String getMessage() {
        return message;
    }
}

然后,我們可以修改spittleById(),讓它返回Error:

@RequestMapping(value="/{id}", method=RequestMethod.GET)
public ResponseEntity<?> spittleById(@PathVariable long id ) {
    Spittle spittle = spittleRepository.findOne(id);
    if (spittle == null) {
        Error error = new Error(4, "Spittle [" + id + "] not found");
        return new ResponseEntity<Error> (error, HttpStatus.NOT_FOUND);
    }
    return new ResponseEntity<Spittle>(spittle, HttpStatus.OK);
}

處理錯(cuò)誤

我們重構(gòu)一下代碼來使用錯(cuò)誤處理器。首先,定義能夠?qū)ο骃pittleNotFoundException的錯(cuò)誤處理器:

@ExceptionHandler(SpittleNotFoundException.class)
public ResponseEntity<Error> spittleNotFound(SpittleNotFoundException e) {
    long spittleId = e.getSpittleId();
    Error error = new Error(4, "Spittle [" + spittleId + "] not found");
    return new ResponseEntity<Error> (error, HttpStatus.NOT_FOUND);
}

@ExceptionHandler注解能夠用到控制器方法中,用來處理特定的異常。至于SpittleNotFoundException,它是一個(gè)很簡(jiǎn)單異常類:

public class SpittleNotFoundException extends RuntimeException {
    private long spittleId;
    public SpittleNotFoundException(long spittleId) {
        this.spittleId = spittleId;
    }

    public long getSpittleId() {
        return spittleId;
    }
}

現(xiàn)在,我們可以移除掉spittleById() 方法中大多數(shù)的錯(cuò)誤代碼:

@RequestMapping(value="/{id}" , method=RequestMethod.GET)
public ResponseEntity<Spittle> spittleById(@PathVariable long id) {
    Spittle spittle = spittleRepository.findOne(id);
    if (spittle == null) { throw new SpittleNotFoundException(id); }
    return new ResponseEntity<Spittle>(spittle, HttpStatus.OK);
}

更簡(jiǎn)潔的版本是(控制器類上使用@RestController)

@RequestMapping(value="/{id}" , method=RequestMethod.GET)
public Spittle spittleById(@PathVariable long id) {
    Spittle spittle = spittleRepository.findOne(id);
    if (spittle == null) { throw new SpittleNotFoundException(id); }
    return spittle;
}

鑒于錯(cuò)誤處理器的方法會(huì)始終返回Error,并且HTTP狀態(tài)碼為404,那么現(xiàn)在我們可以對(duì)spittleNotFound() 方法進(jìn)行類似的清理(控制器類上使用@RestController):

@ExceptionHandler(SpittleNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Error spittleNotFound(SpittleNotFoundException e) {
    long spittleId = e.getSpittleId();
    return  Error error = new Error(4, "Spittle [" + spittleId + "] not found");
}

在響應(yīng)中設(shè)置頭部信息

如果我們需要在POST請(qǐng)求后,返回201且把資源的URL返回給客戶端,可以用@ResponseEntity實(shí)現(xiàn)

@RequestMapping(method=RequestMethod.POST, consumes="application/json")
public ResponseEntity<Spittle> saveSpittle(@RequestBody Spittle spittle) {
    Spittle spittle = spittleRepository.save(spittle);
    HttpHeaders headers = new HttpHeaders();
    URI locationUri = URI.create("http://localhost:8080/spittr/spittles/" + spittle.getId());
    headers.setLocation(locationUri);
    ResponseEntity<Spittle> responseEntity = 
                new ResponseEntity<Spittle>(spittle, headers, HttpStatus.CREATED);
    return responseEntity;
}

其實(shí)我們沒有必要手動(dòng)構(gòu)建URL,Spring 提供了UriComponentsBuilder。它是一個(gè)構(gòu)建類,通過逐步指定URL中的各種組成部分(如host、端口、路徑以及查詢),我們能夠使用它來構(gòu)建UriComponents實(shí)例。

為了使用UriComponentsBuilder,我們需要做的就是在處理器方法中將其作為一個(gè)參數(shù),如下面的程序清單所示。

@RequestMapping(method=RequestMethod.POST, consumes="application/json")
public ResponseEntity<Spittle> saveSpittle(@RequestBody Spittle spittle,
                               UriComponentsBuilder ucb) {
    Spittle spittle = spittleRepository.save(spittle);
    HttpHeaders headers = new HttpHeaders();
    URI locationUri = ucb.path("/spittles/").path(String.valueOf(spittle.getId()))
                                .build().toUri();
    headers.setLocation(locationUri);
    ResponseEntity<Spittle> responseEntity = 
                new ResponseEntity<Spittle>(spittle, headers, HttpStatus.CREATED);
    return responseEntity;
}

在處理器方法所得到的UriComponentsBuilder中,會(huì)預(yù)先配置已知的信息如host、斷端口以及Servlet內(nèi)容。

注意,路徑的構(gòu)建分為兩步。第一步調(diào)用path()方法,將其設(shè)置“/spittles/”,也就是這個(gè)控制器所能處理的基礎(chǔ)路徑。然后,在第二次調(diào)用path()的時(shí)候,使用了已使用Spittle的ID。在路徑設(shè)置完成之后,調(diào)用build()方法來構(gòu)建UriComponents對(duì)象,根據(jù)這個(gè)對(duì)象調(diào)用toUri()就能得到新創(chuàng)建Spittle的URI。

了解RestTemplate的操作

RestTemplate可以減少我們使用HttpClient創(chuàng)建客戶端所帶來的樣板式代碼。它定義了36個(gè)(只有11個(gè)獨(dú)立方法,其他都是重載這些方法)與REST資源交互的方法,其中的大多數(shù)都對(duì)應(yīng)于HTTP的方法。下表展示了這11個(gè)獨(dú)立方法

方法 描述
delete() 在特定的URL上對(duì)資源執(zhí)行HTTP DELETE操作
exchange() 在URL上執(zhí)行特定的HTTP方法,返回包含對(duì)象的ResponseEntity,這個(gè)對(duì)象是從響應(yīng)體中映射得到的
execute() 在URL上執(zhí)行特定的HTTP方法,返回一個(gè)從響應(yīng)體映射得到的對(duì)象
getForEntity() 發(fā)送一個(gè)HTTP GET請(qǐng)求,返回的ResponseEntity包含了響應(yīng)體所映射成的對(duì)象
getForObject() 發(fā)送一個(gè)HTTP GET請(qǐng)求,返回的請(qǐng)求體將映射為一個(gè)對(duì)象
headForHeaders() 發(fā)送HTTP HEAD請(qǐng)求,返回包含特定資源URL的HTTP頭
optionsForAllow() 發(fā)送HTTP OPTIONS請(qǐng)求,返回對(duì)特定的URL的Allow頭信息
postForEntity() POST數(shù)據(jù)到一個(gè)URL,返回包含一個(gè)對(duì)象的ResponseEntity,這個(gè)對(duì)象是從響應(yīng)體中映射得到的
postForLocation() POST數(shù)據(jù)到一個(gè)URL,返回新創(chuàng)建資源的URL
postForObject() POST數(shù)據(jù)到一個(gè)URL,返回根據(jù)響應(yīng)體匹配形成的對(duì)象
put() PUT資源到特定的URL

GET資源

getForObject()都有三種形式的重載

<T> T getForObject(URI url, Class<T> responseType) 
                                  throws RestClientException;
<T> T getForObject(String url, Class<T> responseType, Object... uriVariables) 
                                  throws RestClientException;   
<T> T getForObject(String url, Class<T> responseType,
                                  Map<String,?>  uriVariables)  throws RestClientException;   

檢索資源

public Profile fetchFacebookProfile(String id) {
    RestTemplate rest = new RestTemplate();
    return rest.getForObject("http://graph.facebook.com/{spritter}",Profile.class, id);
}

另一種方案

public Profile fetchFacebookProfile(String id) {
    Map<String, String> urlVariables = new HashMap<>();
    urlVariables.put("id", id);
    RestTemplate rest = new RestTemplate();
    return rest.getForObject("http://graph.facebook.com/{spritter}",
                                            Profile.class, urlVariables);
}

getForEntity()都有三種形式的重載

<T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) 
                                  throws RestClientException;
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, 
                                  Object... uriVariables)  throws RestClientException;   
<T> ResponseEntity<T> getForEntity(String url, Class<T> responseType,
                                  Map<String,?>  uriVariables)  throws RestClientException;   

抽取響應(yīng)的元數(shù)據(jù)

public Spittle fetchSpittle(long id) {
    RestTemplate rest = new RestTemplate();
    ResponseEntity<Spittle> response = rest.getForEntity(
          "http://localhost:8080/spittr-api/spittles/{id}",
          Spittle.class, id);
    if(response.getStatusCode() == HttpStatus.NOT_MODIFIED) {
          throw new NotModifiedException();  
    }
    return response.getBody();
}

PUT資源

put() 有三種形式:

void put(URI url, Object request) throws RestClientException;
void put(String url, Object request, Object... uriVariables)
                                    throws RestClientException;
void put(String url, Object request, Map<String, ?> uriVariables)
                                    throws RestClientException;

例如

public void updateSpittle( Spittle spittle) throws SpitterException {
    RestTemplate rest = new RestTemplate();
    String url = "http://localhost:8080/spittr-api/spittles/" + spittle.getId();
    rest.put(URI.create(url), spittle);
}
public void updateSpittle( Spittle spittle) throws SpitterException {
    RestTemplate rest = new RestTemplate();
    String url = "http://localhost:8080/spittr-api/spittles/{id}";
    rest.put(url, spittle,  spittle.getId());
}

DLELTE資源

delete()方法有三個(gè)版本

void delete(String url ,Object... uriVariables) throws RestClientException;
void delete(String url ,Map<String, ?> uriVariables) throws RestClientException;
void delete(URI url) throws RestClientException;

POST資源數(shù)據(jù)

postForObject() 方法的三個(gè)變種簽名如下:

<T> T postForObject(URI url, Object request, Class<T> responseType)
                            throws RestClientException;
<T> T postForObject(String url, Object request, Class<T> responseType,
                            Object... uriVariables)  throws RestClientException;
<T> T postForObject(String url, Object request, Class<T> responseType,
                            Map<String, ?> uriVariables)  throws RestClientException;

在所有情況下,第一個(gè)參數(shù)都是資源要POST的URL,第二個(gè)參數(shù)是要發(fā)送的對(duì)象,而第三個(gè)參數(shù)是預(yù)期返回的Java類型。在將URL作為String類型的兩個(gè)版本中,第四個(gè)參數(shù)指定了URL變量(要么是可變參數(shù)列表,要么是一個(gè)Map)。

例如

public Spitter postSpitterForObject(Spitter spitter) {
    RestTemplate rest = new RestTemplate();
    return rest.postForObject("http://localhost:8080/spittr-api/spitters",
                spitter, Spitter.class);
}

postForEntity() 方法的三個(gè)變種簽名如下:

<T> ResponseEntity<T> postForEntity(URI url, Object request, 
              Class<T> responseType) throws RestClientException;
<T> ResponseEntity<T> postForEntity(String url, Object request, 
              Class<T> responseType,  Object... uriVariables)  
              throws RestClientException;
<T> ResponseEntity<T> postForEntity(String url, Object request, 
              Class<T> responseType, Map<String, ?> uriVariables)  
              throws RestClientException;

例如:

RestTemplate rest = new RestTemplate();
ResponseEntity<Spitter> response = rest.postForEntity(
        "http://localhost:8080/spittr-api/spitters",
        spitter, Spitter.class);
Spitter spitter = response.getBody();
URI url = response.getHeaders().getLocation();

如果只是需要的是Location頭信息的值,那么使用RestTemplate的postForLocation()方法會(huì)更簡(jiǎn)單。以下是postForLocation()的三個(gè)方法簽名:

URI postForLocation(String url, Object request, Object... uriVariables)
                throws RestClientException;
URI postForLocation(String url, Object request, Map<String,?> uriVariables)
                throws RestClientException;
URI postForLocation(URI url, Object request) throws RestClientException;

例如:

public String postSpitter(Spitter spitter) {
    RestTemplate rest = new RestTemplate();
    return rest.postForLocation(
         "http://localhost:8080/spittr-api/spitters",
          spitter).toString();
}

交換資源

如果想在發(fā)送給服務(wù)端的請(qǐng)求中設(shè)置頭信息的話,那就是RestTemplate的exchange()的用武之地了。

exchange()也有三個(gè)簽名格式

<T> ResponseEntity<T> exchange(URI url, HttpMethod method,
                      HttpEntity<?> requestEntity, Class<T> responseType) 
                      throws RestClientException;
<T> ResponseEntity<T> exchange(String url, HttpMethod method,
                      HttpEntity<?> requestEntity, Class<T> responseType,
                      Object... uriVariables) throws RestClientException;
<T> ResponseEntity<T> exchange(String url, HttpMethod method,
                      HttpEntity<?> requestEntity, Class<T> responseType,
                      Map<String,?> uriVariables) throws RestClientException;

exchange() 方法使用HttpMethod參數(shù)來表明要使用的HTTP動(dòng)作。根據(jù)這個(gè)參數(shù)的值,exchange()能夠執(zhí)行與其他RestTemplate方法一樣的工作。

例如,從服務(wù)器端獲取Spitter資源的一種方式是使用RestTemplate的getForEntity()方法,如下所示:

ResponseEntity<Spitter> response = rest.getForEntity(
      "http://localhost:8080/spittr-api/spitters/{spitter}",
      Spitter.class, spitterId);
Spitter spitter = response.getBody();

在下面的代碼片段中,可以看到exchange() 也可以完成這項(xiàng)任務(wù):

ResponseEntity<Spitter> response = rest.exchange(
      "http://localhost:8080/spittr-api/spitters/{spitter}",
      HttpMethod.GET, null ,Spitter.class, spitterId);
Spitter spitter = response.getBody();

如果不指明頭信息,exchange() 對(duì)Spitter的GET請(qǐng)求會(huì)帶有如下的頭信息:

GET /Spitter/spitters/habuma HTTP/1.1
Accept: application/xml, test/xml, application/*+xml, application/json
Content-Length: 0
User-Agent: Java/1.6.0_20
Host: location:8080
Connection: keep-alive

如果我們需要將“application/json”設(shè)置為Accept頭信息的唯一值。

設(shè)置請(qǐng)求頭信息是很簡(jiǎn)單的,只需要構(gòu)造發(fā)送給exchange()方法的 HttpEntity對(duì)象即可,HttpEntity中包含承載頭信息的MultiValueMap:

MultiValueMap<String, String> headers = new LinkedMultiValueMap<>();
headers.add("Accept", "application/json");
HttpEntity<Object> requestEntity = new HttpEntity<Object>(headers);

如果這是一個(gè)PUT或POST請(qǐng)求,我們需要為HttpEntity設(shè)置在請(qǐng)求體中發(fā)送的對(duì)象—對(duì)于GET請(qǐng)求來說,這是沒有必要的。

現(xiàn)在我們可以傳入HttpEntity來調(diào)用exchange();

ResponseEntity<Spitter> response = rest.exchange(
      "http://localhost:8080/spittr-api/spitters/{spitter}",
      HttpMethod.GET, headers ,Spitter.class, spitterId);
Spitter spitter = response.getBody();
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,695評(píng)論 19 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架,建立于...
    Hsinwong閱讀 22,970評(píng)論 1 92
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 47,288評(píng)論 6 342
  • 12月22日下午4點(diǎn),由中文系主辦、心泉文學(xué)社承辦的“圓夢(mèng)行”征文大賽頒獎(jiǎng)典禮在北院文科樓第七階梯教室舉行。出席本...
    于papa閱讀 199評(píng)論 0 0
  • 16軌道 芹菜開花了,幾棵辣椒苗在茁壯成長(zhǎng)中,有棵花有些枯,可適當(dāng)淋些水。有小草要除哈。 16自動(dòng)化1 不知幾時(shí),...
    JuN_78b0閱讀 619評(píng)論 0 2

友情鏈接更多精彩內(nèi)容