Sử dụng nhiều ViewResolver trong Spring Boot Java
Trong bài viết này sẽ giúp các bạn hiểu rõ hơn về cách sử dụng nhiều ViewResolver trong Spring Boot và cách chúng hoạt động với nhau như thế nào.
ViewResolver là một thành phần quan trọng trong Spring Boot, được sử dụng để xác định cách thức hiển thị các view cho người dùng. Trong khi đó, Spring Boot cung cấp khá nhiều loại ViewResolver khác nhau phù hợp với từng nhu cầu khác nhau. Tuy nhiên, trong một số trường hợp, chúng ta có thể cần sử dụng nhiều ViewResolver để xử lý các yêu cầu khác nhau.
1. ViewResolver là gì?
ViewResolver là một thành phần quan trọng trong framework Spring Boot, nó được sử dụng để xác định cách thức hiển thị các view (giao diện người dùng) cho người dùng. Trong Spring Boot, khi một yêu cầu được gửi đến một controller, controller sẽ trả về một đối tượng view (thường là một trang web HTML) để hiển thị cho người dùng. Tuy nhiên, để xác định được view nào cần được hiển thị, Spring Boot sử dụng ViewResolver.
ViewResolver sẽ tìm kiếm và xác định view cụ thể mà controller trả về dựa trên các quy tắc được cấu hình trước đó trong ứng dụng.
Bài viết này được đăng tại [free tuts .net]
Ví dụ, trong trường hợp sử dụng Spring Boot với thư viện tích hợp sẵn Thymeleaf, có thể sử dụng ThymeleafViewResolver để xác định view mà controller trả về là một trang web được tạo ra bằng Thymeleaf.
Một số loại ViewResolver cơ bản trong Spring Boot
Có nhiều loại ViewResolver khác nhau trong Spring Boot, chúng cung cấp các cách thức khác nhau để tìm kiếm và xác định view. Việc chọn ViewResolver phù hợp sẽ phụ thuộc vào loại view mà ứng dụng của bạn sử dụng và yêu cầu cụ thể của dự án. Dưới đây là một số loại ViewResolver cơ bản trong Spring Boot:
-
InternalResourceViewResolver: sử dụng để xác định các file JSP để hiển thị cho người dùng. Nó tìm kiếm các file JSP trong thư mục "WEB-INF/views" và có thể được cấu hình để thêm tiền tố hoặc hậu tố cho tên file JSP.
-
ThymeleafViewResolver: sử dụng để xác định các file HTML được tạo ra bằng Thymeleaf. Nó có thể được cấu hình để tìm kiếm các file HTML trong các thư mục khác nhau và hỗ trợ nhiều tính năng mạnh mẽ của Thymeleaf, bao gồm cả các biểu thức thymeleaf và các thẻ thymeleaf.
-
ResourceBundleViewResolver: sử dụng để xác định các file view trong các file properties của ứng dụng. Nó cho phép tách rời mã ứng dụng và các file view, giúp dễ dàng cập nhật và bảo trì các file view.
-
JsonViewResolver: sử dụng để xác định view là một đối tượng JSON được trả về cho người dùng. Nó cho phép tạo ra các API RESTful dễ dàng và trả về đối tượng JSON đơn giản và dễ đọc cho người dùng.
-
XlsxViewResolver: sử dụng để xác định view là một tệp Excel (xlsx) được tạo ra bằng Apache POI. Nó cho phép tạo ra các báo cáo dạng bảng tính và xuất chúng thành tệp Excel để người dùng có thể tải xuống và sử dụng.
Tùy thuộc vào yêu cầu và loại view của ứng dụng, các loại ViewResolver khác nhau trong Spring Boot có thể được sử dụng để xác định cách thức hiển thị các view cho người dùng.
2. Các bước tạo dự án sử dụng nhiều ViewResolver trong Spring Boot
Hôm nay mình sẽ hướng dẫn các bạn tạo dự án áp dụng nhiều ViewResolver trong Spring Boot, cụ thể ba loại ViewResolver mình sẽ kết hợp trong dự án là: InternalResourceViewResolver, ThymeleafViewResolver và FreeMarker cho tầng view
Bước 1: Tạo mới một project với Maven Project.
Bạn hãy mở Eclipse và chọn File > New > Maven Project.
Bước 2: Chọn cấu hình cho project.
Chọn Create a simple project (skip archetype selection) và nhấn Next.
Bước 3: Đặt tên cho project và chọn đường dẫn để lưu trữ project.
Nhập thông tin về Group ID, Artifact ID, và Version. Group ID là tên của nhóm hoặc công ty của bạn, Artifact ID là tên của project và Version là phiên bản của project. Nhấn Next để tiếp tục.
Bước 4: Lựa chọn cấu hình phù hợp cho dự án.
Vì chúng ta sẽ sử dụng 3 loại ViewResolver của 3 công nghệ JSP, Thymeleaf và FreeMarker nên chúng ta sẽ phải add cấu hình của 3 loại vào.
Lựa chọn Thymeleaf, FreeMarker và Web sau đó ấn Finish
Sau khi thực hiện đầy đủ các bước trên thì project sẽ được tạo thành công.
3. Cấu hình file pom.xml
Tiếp theo đây mình sẽ hướng dẫn các bạn thêm thư viện vào file pom.xml, bạn có thể tham khảo code một file pom.xml đầy đủ ở bài viết này, sau khi có file pom.xml thì bạn hãy tiến hành add thư viện của các ViewResolver phù hợp vào.
Vì ở đây là ví dụ của mình phải add 3 thư viện JSP, Thymeleaf, FreeMarker vào project nên bên trong file pom.xml phải có 3 dependency của 3 thư viện thì chương trình mới thực thi chạy dự án được.
Đầu tiên là thư viện của Thymeleaf, tiếp đến là thư viện của Web và sau cùng là thư viêjn của FreeMarker, các bạn có thể tham khảo trong đoạn code sau:
<!-- Thymeleaf --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <!-- FreeMarker --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-freemarker</artifactId> </dependency> <!-- Web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- JSP --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> <!-- JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency>
4. Cấu hình các ViewResolver
Tại sao phải cấu hình lại ViewResolver?
Khi phát triển một dự án Spring Boot, bạn thường chỉ sử dụng một công nghệ cho tầng View, và Spring Boot sẽ tự động cấu hình cho bạn một ViewResolver phù hợp với công nghệ đó. Tuy nhiên, nếu bạn muốn sử dụng nhiều công nghệ khác nhau cho tầng View trong cùng một dự án, bạn sẽ cần phải tự cấu hình các ViewResolver tương ứng để Spring Boot có thể hiểu và xử lý đúng cách.
Ví dụ, nếu bạn muốn sử dụng cả JSP và Thymeleaf trong dự án của mình, bạn sẽ cần cấu hình hai ViewResolver khác nhau: một cho JSP và một cho Thymeleaf. Bạn có thể cấu hình các ViewResolver này trong tệp cấu hình của Spring Boot bằng cách sử dụng các lớp như InternalResourceViewResolver cho JSP và ThymeleafViewResolver cho Thymeleaf.
Để nói một cách ngắn gọn hơn thì đối với Spring Boot nếu bạn sử dụng nhiều công nghệ cho tầng View trong dự án Spring Boot của mình, bạn cần tự cấu hình các ViewResolver tương ứng để Spring Boot có thể hiểu và xử lý đúng cách.
Sau đây là sơ đồ luồng đi (flow) của một ứng dụng khi sử dụng một ViewResolver:
Đối với sơ đồ luồng đi của một ứng dụng Spring khi sử dụng nhiều ViewResolver thì sẽ có chút thay đổi, sẽ có nhiều ViewResolver tham gia vào luồng đi (flow) của ứng dụng. Các ViewResolver được sắp xếp theo thứ tự ưu tiên (0, 1, 2, ..). Nếu ViewResolver (0) không tìm thấy "View Name" cần thiết, ViewResolver (1) sẽ được sử dụng, ...
Giải pháp:
Để cấu hình ba công nghệ JSP, Thymeleaf và FreeMarker trong cùng một ViewResolver trong Spring Boot, bạn có thể sử dụng đối tượng MultiViewResolver của Spring. MultiViewResolver sẽ cho phép bạn định nghĩa một danh sách các ViewResolver và Spring sẽ lần lượt xử lý các ViewResolver này để tìm kiếm View tương ứng.
Đối với JSP, chúng ta sử dụng đối tượng InternalResourceViewResolver, đối với Thymeleaf, chúng ta sử dụng đối tượng ThymeleafViewResolver và đối với FreeMarker, chúng ta sử dụng đối tượng FreeMarkerViewResolver. Mỗi ViewResolver được cấu hình để xử lý một loại view cụ thể và chúng ta đã thiết lập các đường dẫn và thuộc tính khác cho từng loại view.
Dưới đây là một ví dụ cụ thể về cách cấu hình MultiViewResolver cho ba công nghệ JSP, Thymeleaf và FreeMarker trong Spring Boot:
@Configuration public class ViewResolverConfig { @Autowired private ApplicationContext applicationContext; @Bean public ViewResolver multiViewResolver() { MultiViewResolver resolver = new MultiViewResolver(); List<ViewResolver> resolvers = new ArrayList<>(); // JSP view resolver InternalResourceViewResolver jspResolver = new InternalResourceViewResolver(); jspResolver.setPrefix("/WEB-INF/jsp/"); jspResolver.setSuffix(".jsp"); jspResolver.setViewClass(JstlView.class); resolvers.add(jspResolver); // Thymeleaf view resolver ThymeleafViewResolver thymeleafResolver = new ThymeleafViewResolver(); thymeleafResolver.setTemplateEngine(thymeleafTemplateEngine()); resolvers.add(thymeleafResolver); // FreeMarker view resolver FreeMarkerViewResolver freeMarkerResolver = new FreeMarkerViewResolver(); freeMarkerResolver.setPrefix(""); freeMarkerResolver.setSuffix(".ftl"); freeMarkerResolver.setViewClass(FreeMarkerView.class); resolvers.add(freeMarkerResolver); resolver.setViewResolvers(resolvers); resolver.setOrder(0); return resolver; } @Bean public SpringTemplateEngine thymeleafTemplateEngine() { SpringTemplateEngine templateEngine = new SpringTemplateEngine(); templateEngine.setTemplateResolver(thymeleafTemplateResolver()); return templateEngine; } @Bean public SpringResourceTemplateResolver thymeleafTemplateResolver() { SpringResourceTemplateResolver templateResolver = new SpringResourceTemplateResolver(); templateResolver.setApplicationContext(applicationContext); templateResolver.setPrefix("/WEB-INF/thymeleaf/"); templateResolver.setSuffix(".html"); templateResolver.setTemplateMode(TemplateMode.HTML); templateResolver.setCharacterEncoding("UTF-8"); return templateResolver; } @Bean public FreeMarkerConfigurer freeMarkerConfigurer() { FreeMarkerConfigurer configurer = new FreeMarkerConfigurer(); configurer.setTemplateLoaderPath("/WEB-INF/freemarker/"); return configurer; } }
Sau đây mình sẽ giải thích cụ thể về ví dụ trên.
Trong ví dụ này, chúng ta đã định nghĩa một ViewResolver có tên là multiViewResolver
bằng cách sử dụng đối tượng MultiViewResolver. Chúng ta đã tạo một danh sách các ViewResolver bao gồm ba ViewResolver khác nhau cho ba công nghệ khác nhau: JSP, Thymeleaf và FreeMarker.
Tiếp theo, chúng ta cũng đã định nghĩa các Bean khác để hỗ trợ việc cấu hình các công nghệ view này. Đối với Thymeleaf, chúng ta đã định nghĩa các Bean SpringTemplateEngine và SpringResourceTemplateResolver. Đối với FreeMarker, chúng ta đã định nghĩa Bean FreeMarkerConfigurer để cấu hình FreeMarker.
Sau đó, chúng ta đã sử dụng phương thức setViewResolvers() để thiết lập danh sách các ViewResolver và đặt độ ưu tiên cho MultiViewResolver.
Với cấu hình này, khi bạn trả về một tên view từ một phương thức điều khiển trong ứng dụng của bạn, Spring Boot sẽ xử lý danh sách các ViewResolver để tìm kiếm view tương ứng với tên view. Nếu không có ViewResolver nào có thể xử lý view, bạn sẽ nhận được một lỗi.
Ví dụ, nếu tên view của bạn là "example", MultiViewResolver sẽ tìm kiếm view tương ứng với tên "example" trên các đường dẫn "/WEB-INF/jsp/example.jsp", "/WEB-INF/thymeleaf/example.html" và "/WEB-INF/freemarker/example.ftl" để trả về view tương ứng.
5. Controller và Views
Tầng Controller trong ứng dụng Spring sử dụng nhiều ViewResolver
Tầng Controller trong ứng dụng Spring không sử dụng nhiều ViewResolver. Tầng Controller được sử dụng để xử lý các yêu cầu của người dùng và trả về các kết quả tương ứng, bao gồm tên của các view cần hiển thị. Việc xử lý các yêu cầu và trả về các kết quả được thực hiện trong tầng Views, thông qua sử dụng các ViewResolver. Các ViewResolver này được sử dụng để xác định cách thức hiển thị các kết quả trả về, bao gồm cách thức xử lý các tệp mẫu và trả về nội dung đã được xử lý đến người dùng.
Do đó, khi sử dụng nhiều ViewResolver, chúng ta cần cấu hình các ViewResolver tương ứng trong tầng Views để xử lý các loại view khác nhau. Sau đó, tầng Controller sẽ trả về tên của các view cần hiển thị, và các ViewResolver sẽ xử lý các view này và trả về nội dung đã được xử lý để hiển thị đến người dùng.
package org.SpringBoot.viewresolvers.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @Controller public class MainController { @RequestMapping(value = { "/testJsp" }, method = RequestMethod.GET) public String testJspView() { return "testJsp"; } @RequestMapping(value = { "/testThymeleaf" }, method = RequestMethod.GET) public String testThymeleafView() { return "th_page1"; } @RequestMapping(value = { "/testFreeMarker" }, method = RequestMethod.GET) public String testFreeMarkerView() { return "testFreeMarker"; } }
Tầng Views trong ứng dụng Spring sử dụng nhiều ViewResolver
Trong ứng dụng Spring, tầng Views có thể sử dụng nhiều ViewResolver để xử lý các loại view khác nhau. Mỗi ViewResolver được cấu hình để xử lý một loại view cụ thể, ví dụ như JSP, Thymeleaf, FreeMarker, và mỗi ViewResolver sẽ được sắp xếp theo thứ tự ưu tiên.
Khi tầng Controller trả về một tên view, Spring sẽ tìm kiếm view tương ứng trong danh sách các ViewResolver theo thứ tự ưu tiên. Nếu một ViewResolver có thể xử lý view, nó sẽ trả về view tương ứng và quá trình tìm kiếm sẽ kết thúc. Nếu không có ViewResolver nào có thể xử lý view, Spring sẽ trả về một lỗi.
Việc sử dụng nhiều ViewResolver có thể hữu ích khi bạn muốn hỗ trợ nhiều loại view trong ứng dụng của mình.
Ví dụ, bạn có thể sử dụng JSP để hiển thị các trang động, Thymeleaf để hiển thị các trang tĩnh và FreeMarker để hiển thị email template. Bằng cách sử dụng nhiều ViewResolver, bạn có thể cấu hình ứng dụng của mình để hỗ trợ các loại view khác nhau một cách dễ dàng.
Để có thể dễ hình dung hơn, bạn có thể tham khảo ví dụ sau:
Đầu tiên mình phải tạo một file html ở trong folder Thymeleaf để tạo view cho Thymeleaf:
Tiếp theo mình sẽ code giao diện cho file này:
<!DOCTYPE html> <html lang="en"> <head> <title>Thymeleaf</title> </head> <body> <h2>Thymeleaf Page</h2> <p>templates/th_page1.html</p> </body> </html>
Và đối với JSP và FreeMarker cũng tạo ra các file html tương tự.
Sau đây là đoạn code giao diện của JSP và FreeMarker:
<!DOCTYPE html> <html lang="en"> <head> <title>FreeMarker</title> </head> <body> <h2>FreeMarker Page</h2> <p>templates/freemarker/testFreeMarker.ftl</p> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <title>JSP</title> </head> <body> <h2>JSP Page</h2> <p>WEB-INF/jsp/testJsp.jsp</p> </body> </html>
6. Các câu hỏi thường gặp
Tại sao lại cần sử dụng nhiều ViewResolver trong Spring Boot?
Có thể có nhiều lý do để sử dụng nhiều ViewResolver trong Spring Boot, nhưng phổ biến nhất là để hỗ trợ nhiều công nghệ khác nhau cho tầng Views. Ví dụ, một ứng dụng có thể sử dụng JSP, Thymeleaf và FreeMarker để hiển thị các trang khác nhau, và sử dụng các ViewResolver tương ứng để xử lý các công nghệ này.
Làm thế nào để cấu hình nhiều ViewResolver trong Spring Boot?
Để cấu hình nhiều ViewResolver trong Spring Boot, chúng ta có thể sử dụng các bean Spring để cấu hình các ViewResolver tương ứng. Ví dụ, chúng ta có thể sử dụng các bean InternalResourceViewResolver, ThymeleafViewResolver và FreeMarkerViewResolver để cấu hình các ViewResolver cho JSP, Thymeleaf và FreeMarker tương ứng.
Làm thế nào để xác định ViewResolver được sử dụng cho một loại view cụ thể?
Để xác định ViewResolver được sử dụng cho một loại view cụ thể, chúng ta có thể sử dụng thuộc tính "order" của các ViewResolver để xác định thứ tự ưu tiên. ViewResolver với order thấp hơn sẽ được sử dụng trước để xử lý view tương ứng.
Có thể sử dụng các ViewResolver từ các thư viện bên thứ ba trong Spring Boot không?
Có, chúng ta có thể sử dụng các ViewResolver từ các thư viện bên thứ ba trong Spring Boot, bằng cách thêm các phụ thuộc tương ứng vào file pom.xml. Tuy nhiên, chúng ta cần đảm bảo rằng các ViewResolver này tương thích với Spring Boot và các phiên bản của Spring Framework được sử dụng trong dự án của chúng ta.
7. Kết bài viết
Trong bài viết này, chúng tôi đã giới thiệu cách sử dụng nhiều ViewResolver trong Spring Boot và cung cấp một ví dụ cụ thể để minh họa. Hy vọng rằng những thông tin này sẽ giúp bạn hiểu rõ hơn về cách sử dụng nhiều ViewResolver trong Spring Boot và áp dụng chúng vào các dự án của mình.