Mục lục
RestTemplate là mộ trong những thành phần cốt lõi của Spring framework cho phép thực thi các HTTP request và nhận các các response tương ứng.
Trong bài viết này, chúng ta sẽ cùng nhau tìm cách sử dụng RestTemplate để triển khai một POST request với nội dung là một chuỗi JSON.
Project Setup
Trong bài viết này, mình sẽ hướng dẫn các bạn thông qua project Spring boot với maven. Do vậy chúng ta cần có các dependency sau:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>
Tiếp theo, chúng ta sẽ thêm Person class đại diện cho một object giao tiếp giữa client và Rest API.
package com.deft.model; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @NoArgsConstructor @Getter @Setter public class Person { private Integer id; private String name; }
Tiếp theo triển khai PersonService chứa các business logic, Service này chỉ đơn giản nhận vào Person object và trả lại chính nó.
package com.deft.service; import com.deft.model.Person; public interface PersionService { Person save(Person person); }
Và Implement
package com.deft.service; import com.deft.model.Person; import org.springframework.stereotype.Service; @Service public class PersonServiceImpl implements PersionService { @Override public Person save(Person person) { return person; } }
Tiếp theo, PersonController để xử lý các request gửi đến.
package com.deft.controller; import com.deft.model.Person; import com.deft.service.PersionService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.servlet.http.HttpServletResponse; @RestController @RequestMapping("/person") public class PersonController { @Autowired private PersionService persionService; @PostMapping public Person create(@RequestBody Person person, HttpServletResponse response) { response.setHeader("Location", "/person"); return persionService.save(person); } }
Trong PersonController, chúng ta đã sử dụng @RequestBody annotaton để chú thích trên tham số đầu vào, nó sẽ giúp chúng ta chuyển đổi từ chuỗi JSON trong request sang Person object cách tự động. Hàm này sau đó cũng trả về Person object vừa nhận được do gọi đến PersonService#save().
RestTemplate – Post Request
Với RestTemplate, chúng ta có thể triển khai POST request thông qua một số cách tuỳ thuộc vào nhu cầu trong các trường hợp nhất định. Có 3 method chính RestTemplate cung cấp để gửi POST request là postForObject, postForEntity, và postForLocation.
Trong phần này, chúng ta sẽ viết unit-test sử dụng RestTemplate request đến Spring boot API mà chúng ta đã dựng sẵn. Vậy nên, hãy lưu ý khởi chạy ứng dụng trước rồi mới chạy unit-test.
Trước khi triển khai unit-test chúng ta cần chuẩn bị một số dữ liệu trước cần cho một unit-test chạy.
package com.deft; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import net.minidev.json.JSONObject; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestInstance; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.web.client.RestTemplate; import java.io.IOException; import static org.junit.jupiter.api.Assertions.assertNotNull; @SpringBootTest @TestInstance(TestInstance.Lifecycle.PER_CLASS) class ResttemplatePostExampleApplicationTests { private RestTemplate restTemplate; private HttpHeaders headers; private JSONObject personJsonObject; private final ObjectMapper objectMapper = new ObjectMapper(); private String createPersonUrl; @BeforeAll void setup() { createPersonUrl = "http://localhost:8080/person"; restTemplate = new RestTemplate(); headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); personJsonObject = new JSONObject(); personJsonObject.put("id", 1); personJsonObject.put("name", "John"); } }
Method setup() được đánh dấu với @BeforeAll annotation kết hợp với @TestInstance(TestInstance.Lifecycle.PER_CLASS) giúp nó chạy trước mỗi khi có một unit-test method chạy nhầm đảm bảo dữ liệu sẵn sàng cho các hàm kiểm tra này.
Post JSON – postForObject
Phương thức postForObject của RestTemplate dùng để thực thi một POST request trong đó kết quả trả về từ REST API sẽ được tự động chuyển đổi sang kiểu dữ liệu được chỉ định từ trước đó.
@Test void postForObjectTest() throws IOException { HttpEntity<String> request = new HttpEntity<>(personJsonObject.toString(), headers); String personResultAsJsonStr = restTemplate.postForObject(createPersonUrl, request, String.class); JsonNode root = objectMapper.readTree(personResultAsJsonStr); assertNotNull(personResultAsJsonStr); assertNotNull(root); assertNotNull(root.path("name").asText()); }
Method postForObject() trả về response body với kiểu String như đã được chỉ định. Chúng ta cũng có thể nhận lại một Person object bằng cách
Person person = restTemplate.postForObject(createPersonUrl, request, Person.class); assertNotNull(person); assertNotNull(person.getName());
Post JSON – postForEntity
So với postForObject(), postForEntity() trả về response dưới dạng ResponseEntity.
@Test public void postForEntityTest() throws IOException { HttpEntity<String> request = new HttpEntity<>(personJsonObject.toString(), headers); ResponseEntity<String> responseEntityStr = restTemplate. postForEntity(createPersonUrl, request, String.class); JsonNode root = objectMapper.readTree(responseEntityStr.getBody()); assertNotNull(responseEntityStr.getBody()); assertNotNull(root.path("name").asText()); }
Tương tự như postForObject, postForEntity có tham số responseType để chuyển đổi response body sang Java type.
ResponseEntity<Person> responseEntityPerson = restTemplate. postForEntity(createPersonUrl, request, Person.class); assertNotNull(responseEntityPerson.getBody()); assertNotNull(responseEntityPerson.getBody().getName());
Post JSON – postForLocation
Tương tự như postForObject và postForEntity, postForLocation cũng được dùng để thực thi một POST request, tuy nhiên kết quả trả về là giá trị của thuộc tính Location trong header của response. Đó là lý do mà các bạn có thể thấy mình đã gán giá trị cho Location của response object.
@PostMapping public Person create(@RequestBody Person person, HttpServletResponse response) { response.setHeader("Location", "/person"); return persionService.save(person); } }
Bây giờ, chúng ta có thể triển khai unit-test đơn giản như sau:
@Test void postForLocationTest() { HttpEntity<String> request = new HttpEntity<>(personJsonObject.toString(), headers); URI locationHeader = restTemplate.postForLocation(createPersonUrl, request); assertNotNull(locationHeader); }
Kết bài
Như vậy là chúng ta đã biết cách triển khai một POST request sử dụng RestTemplate với dữ liệu là một chuỗi JSON thông qua nhiều cách khác nhau.
Các bạn có thể tham khảo mã nguồn được công khai trên gitlab: resttemplate-post-example
Nguồn