Chúng ta vẫn thường dùng annotation @Controller để phát triển các ứng dụng Spring MVC nhưng kể từ version 4.x, Spring giới thiệu một annotation khác tên là @RestController. Vậy mục đích của annotation @RestController là gì? Sự khác nhau giữa annotation @Controller và annotation @RestController như thế nào? Trong bài viết này, chúng ta hãy cùng tìm hiểu nhé các bạn!
Đầu tiên, mình sẽ tạo mới một Maven project để làm ví dụ:
Bạn nào chưa biết cách tạo thì làm theo hướng dẫn của bài viết này nhé các bạn!
Các dependencies mặc định mình đã thay đổi version như sau:
1 2 3 4 5 6 7 8 9 |
<properties> <maven.compiler.source>21</maven.compiler.source> <maven.compiler.target>21</maven.compiler.target> <org.springframework-version>6.1.9</org.springframework-version> <org.slf4j-version>2.0.13</org.slf4j-version> <org.junit-version>5.10.2</org.junit-version> <jakarta.servlet-api-version>6.1.0</jakarta.servlet-api-version> </properties> |
Để chạy project này, mình sẽ sử dụng Maven Jetty Plugin:
1 2 3 4 5 |
<plugin> <groupId>org.eclipse.jetty</groupId> <artifactId>jetty-maven-plugin</artifactId> <version>11.0.21</version> </plugin> |
OK, bắt đầu thôi các bạn!
Như các bạn đã biết, trong Spring MVC, Controller là class sẽ chịu trách nhiệm prepare Model và chọn View để hiển thị data trong Model lên View. Trong ví dụ mình vừa tạo, chúng ta có class HomeController là một Controller class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.huongdanjava.springmvc; import java.text.DateFormat; import java.util.Date; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; /** * Handles requests for the application home page. */ @Controller public class HomeController { private static final Logger logger = LoggerFactory.getLogger(HomeController.class); /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) { logger.info("Welcome home! The client locale is {}.", locale); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate ); return "home"; } } |
Nó thêm data “serverTime” vào Model và chọn View là tập tin home.jsp nằm trong thư mục /src/main/webapp/WEB-INF/views để render giao diện.
Kết quả sẽ như sau:
Bên cạnh nhiệm vụ prepare Model và chọn View này, Controller class còn có thể ghi dữ liệu trực tiếp vào luồng response mà không cần chọn view gì hết. Để làm được điều này, trong phương thức handle request, chúng ta phải thêm một annotation nữa là @ResponseBody.
Ví dụ như giờ mình thêm annotation @ResponseBody cho phương thức home() trong class HomeController như sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
/** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) @ResponseBody public String home(Locale locale, Model model) { logger.info("Welcome home! The client locale is {}.", locale); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate ); return "home"; } |
thì khi chạy các bạn sẽ không còn thấy kết quả như trước nữa. Thay vì nội dung của tập tin home.jsp với Model data, kết quả lúc này chỉ vỏn vẹn là “home” như phần return trong phương thức home().
Đây là những gì mà chúng ta thường làm để phát triển các ứng dụng RESTful Web Service phải không các bạn? Chúng ta chỉ return data ở các định dạng như JSON, XML,… ngoài ra thì không cần View gì cả.
Để thuận tiện cho việc phát triển các ứng dụng RESTful Web Service, Spring đã giới thiệu thêm annotation @RestController từ version 4.x. Với annotation @RestController thay thế cho annotation @Controller, chúng ta không cần phải khai báo annotation @ResponseBody nữa.
Bây giờ nếu mình thay thế annotation @Controller bằng annotation @RestController và remove annotation @ResponseBody trong phương thức home() đi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
package com.huongdanjava.springmvc; import java.text.DateFormat; import java.util.Date; import java.util.Locale; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; /** * Handles requests for the application home page. */ @RestController public class HomeController { private static final Logger logger = LoggerFactory.getLogger(HomeController.class); /** * Simply selects the home view to render by returning its name. */ @RequestMapping(value = "/", method = RequestMethod.GET) public String home(Locale locale, Model model) { logger.info("Welcome home! The client locale is {}.", locale); Date date = new Date(); DateFormat dateFormat = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, locale); String formattedDate = dateFormat.format(date); model.addAttribute("serverTime", formattedDate ); return "home"; } } |
thì kết quả vẫn như vậy.
Nếu các bạn xem code của annotation @RestController, các bạn sẽ thấy rõ sự combine này.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
package org.springframework.web.bind.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; import org.springframework.stereotype.Controller; @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @ResponseBody public @interface RestController { @AliasFor( annotation = Controller.class ) String value() default ""; } |
Thái Thiên
Bài viêt rất hay và dễ hiểu. Thanks bạn
Hoàng
Anh có thể làm 1 bài hướng dẫn về restful webservice kết hợp giữa Spring boot và Angular hay react lại với nhau được ko ạ?
Khanh Nguyen
OK bạn, để có thời gian mình viết nhé!
X981
Như vậy @RestController là phục vụ cho restful webservice đúng không bạn.
Khanh Nguyen
Đúng rồi đó bạn!