@RequestBody và @ResponseBody có lẽ là một trong những annotation được sử dụng nhiều nhất trong Spring Rest API. Dùng để ánh xạ dữ liệu truyền từ client lên server và ngược lại.
Trong bài viết này chúng ta sẽ cùng nhau tìm hiểu về cách sử dụng 2 annotation này và làm một số ví dụ minh hoạ để hiểu rõ hơn về cách hoạt động của những annotation này.
@RequestBody trong Spring
@RequestBody được dùng để ánh xạ HttpRequest body sang một domain object tự động.
Giả sử chúng ta có Spring controller với login() method nhận vào LoginForm object.
@RestController public class RequestBodyExampleController { @PostMapping("/login") public ResponseEntity login (@RequestBody LoginForm form) { System.out.println("User name: " + form.getUsername()); System.out.println("Password: " + form.getPassword()); return ResponseEntity.ok(HttpStatus.OK); } }
Spring sẽ tự động ánh xạ dữ liệu JSON trong HttpRequest body sang một Java Type object tương ứng.
Mặc định, tên và kiểu dữ liệu trong JSON phải trùng khớp với tên và kiểu dữ liệu trong Java Type object.
public class LoginForm { private String username; private String password; // ... }
Như ví dụ trên, thì client khi request đến /login api thì JSON tương ứng phải là username và password.
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST --data '{"username": "deft", "password": "123456"}' "http://localhost:8080/login" --- "OK"
@ResponseBody
@ResponseBody annotation được dùng để thông báo với controller rằng Java Object trả về cho client sẽ tự động ánh xạ sang JSON và chuyển vào HttpResponse.
Giả sử chúng ta có Response object được dùng để trả kết quả về cho client.
public class ResponseTransfer { private String text; // standard getters/setters }
Và một controller class
@Controller @RequestMapping("/login-response") public class ResponseBodyExampleController { @ResponseBody @PostMapping public ResponseTransfer postResponseController( @RequestBody LoginForm loginForm) { return new ResponseTransfer("Thanks For Posting!!!"); } }
Kết quả khi mình request lên login-response api sẽ như sau:
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST --data '{"username": "deft", "password": "123456"}' "http://localhost:8080/login-response" HTTP/1.1 200 Content-Type: application/json Transfer-Encoding: chunked Date: Thu, 24 Dec 2020 16:16:39 GMT ---- {"text":"Thanks For Posting!!!"}
Các bạn nhớ để ý rằng mình chú thích ResponseBodyExampleController là @Controller chứ không phải là @RestController vì bản thân @RestController đã bao gồm @ResponseBody sẽ được áp dụng cho toàn bộ các method bên trong nên không cần phải chú thích @ResponseBody khi sử dụng @RestController đâu nhé.
@ResponseBody với Content-Type
Khi sử dụng @ResponseBody annotation, chúng ta còn có thể chỉ định content-type trả về cho client như ví dụ trước content-type là JSON, chúng ta có thể thay bằng XML chẳng hạn thông qua thuộc tính produces trong @RequestMapping, hoặc@PostMapping, @GetMapping là các annotation dạng rút gọn của nó.
@PostMapping(value = "/content", produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public ResponseTransfer postResponseJsonContent( @RequestBody LoginForm loginForm) { return new ResponseTransfer("JSON Content!"); }
Trong ví dụ, mình đã sử dụng hằng số MediaType.APPLICATION_JSON_VALUE. Ngoài ra, chúng ta có thể sử dụng application / json trực tiếp.
Tiếp theo ,mình triển khai một phương thức với cùng đường dẫn /content api nhưng trả về nội dung XML:
@PostMapping(value = "/content", produces = MediaType.APPLICATION_XML_VALUE) @ResponseBody public ResponseTransfer postResponseXmlContent( @RequestBody LoginForm loginForm) { return new ResponseTransfer("XML Content!"); }
Bây giờ, tuỳ thuộc vào tham số Accept trong header mà bạn truyền lên, mà postResponseJsonContent() haypostResponseXmlContent() sẽ được gọi tương ứng.
Hãy xem Accept là application/json thì kết quả sẽ là
curl -i -H "Accept: application/json" -H "Content-Type: application/json" -X POST --data '{"username": "deft", "password": "123456"}' "http://localhost:8080/login-response/content" HTTP/1.1 200 Content-Type: application/json Transfer-Encoding: chunked Date: Thu, 24 Dec 2020 16:31:30 GMT ----- {"text":"JSON Content!"}
Còn với XML
curl -i -H "Accept: application/xml" -H "Content-Type: application/json" -X POST --data '{"username": "deft", "password": "123456"}' "http://localhost:8080/login-response/content" HTTP/1.1 200 Content-Type: application/xml Transfer-Encoding: chunked Date: Thu, 24 Dec 2020 16:44:56 GMT <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <responseTransfer><text>XML Content!</text></responseTransfer>
Một số lưu ý khi các bạn sử dụng định dạng XML thì thêm dependency hỗ trợ chuyển đổi XML
<dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency>
Và thêm @XmlRootElement annotation vào ResponseTransfer class.
@XmlRootElement public class ResponseTransfer {...}
Kết bài
Như vậy là chúng ta đã tìm hiểu được 2 annotation thường xuyên được sử dụng trong Spring là @RequestBody và @ResponseBody. Lưu ý ở trên mình dùng terminal để request server. Các bạn có thể sử dụng các tool khác như Postman cũng được cho dễ sử dụng.
Mã nguồn được mình công khai trên gitlab để các bạn có thể tiện theo dõi và kiểm thử: source-code
Nguồn tham khảo
Spring Boot Rest XML example – Web service with XML Response
https://www.baeldung.com/spring-request-response-body