當你將應用程式中某些元件分離出來,成為物理上一個可獨立運行的服務,並且像 @RepositoryRestResource 提供了 REST 介面,這就可以讓需要此服務的客戶端透過 HTTP 來請求,以使用該服務。
(當然,這只是範例專案,畢竟幾乎只處理 CRUD 的服務,就粒度來說是有點小了!)
為了便於客戶端使用基於 REST 的服務,Spring 提供了 RestTemplate
,不過,要能使用 RestTemplate
來運用 @RepositoryRestResource 服務,需要知道一些 HATEOAS 的概念,這會是下篇文件的主題,在這邊僅先認識一下 RestTemplate
的基本使用方式。
為了有個實際的測試對象,可以先建立一個簡單的 REST 服務。例如:
package cc.openhome;
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class RestTmplApplication {
public static void main(String[] args) {
SpringApplication.run(RestTmplApplication.class, args);
}
List<Message> messages = new ArrayList<Message>() {{
add(new Message("msg1"));
add(new Message("msg2"));
}};
@GetMapping("messages")
public List<Message> index() {
return messages;
}
@GetMapping("messages/{id}")
public Message show(@PathVariable("id") String id) {
return messages.get(Integer.parseInt(id) - 1);
}
@PostMapping("messages")
public Message create(@RequestBody Message message) {
messages.add(message);
return message;
}
@DeleteMapping("messages/{id}")
public Message delete(@PathVariable("id") String id) {
return messages.remove(Integer.parseInt(id) - 1);
}
}
大部份程式碼你應該都知道作用了,唯一要注意的是 create
,這個處理器接受 JSON 轉換後的 Message
實例,JSON 會是請求本體中的內容,為此必須標註 @RequestBody
。
首先來看看,如何透過 RestTemplate
請求並自動轉為 Message
實例,這透過 getForObject
就可以了:
...略
@SpringBootTest
public class RestTmplApplicationTests {
private RestTemplate restTemplate = new RestTemplate();
@Test
public void show() {
Message message = restTemplate.getForObject("http://localhost:8080/messages/{id}", Message.class, "1");
assertNotNull(message.getText());
}
基本上沒什麼好解釋的,要請求建立一個 Message
實例的話,可以使用 postForObject
,因為要傳送 JSON,必須設定請求標頭,以及 POST
時的 Message
實例,postForObject
會自動將 Message
轉為 JSON 發送出去:
@Test
public void create() {
Message message = new Message("new message");
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<Message> request = new HttpEntity<>(message, headers);
message = restTemplate.postForObject("http://localhost:8080/messages", request, Message.class);
assertEquals(message.getText(), "new message");
}
要請求 REST 介面進行刪除,可以使用 delete
:
@Test
public void delete() {
restTemplate.delete("http://localhost:8080/messages/{id}", "1");
Message message = restTemplate.getForObject("http://localhost:8080/messages/{id}", Message.class, "1");
assertEquals(message.getText(), "msg2");
}
至於要請求取得全部訊息,並封裝為 List<Message>
,稍微多了手續,不過也可以趁機看看 exchange
方法的使用:
@Test
public void index() {
RequestEntity<Void> request = RequestEntity
.get(URI.create("http://localhost:8080/messages/"))
.accept(MediaType.APPLICATION_JSON)
.build();
ResponseEntity<List<Message>> response = restTemplate
.exchange(request,new ParameterizedTypeReference<List<Message>>(){});
List<Message> messages = response.getBody();
assertTrue(messages.size() > 0);
}
你可以在 RestTmpl 找到以上的範例專案。