Written By : Nguyễn Văn Linh
Gmail : Linhthai130100@gmail.com
1. Giới thiệu
Thymeleaf là một công cụ mẫu Java để xử lý và tạo HTML, XML, JavaScript, CSS và văn bản.
Trong hướng dẫn này, chúng ta sẽ thảo luận về cách sử dụng Thymeleaf với Spring cùng với một số trường hợp sử dụng cơ bản trong lớp xem của ứng dụng Spring MVC.
Thư viện cực kỳ dễ mở rộng và khả năng tạo khuôn mẫu tự nhiên của nó đảm bảo chúng ta có thể tạo mẫu nguyên mẫu mà không cần kết thúc phía sau. Điều này làm cho sự phát triển rất nhanh khi so sánh với các công cụ mẫu phổ biến khác như JSP.
Link bài viết tham khảo :Introduction to Using Thymeleaf in Spring
2. Tích hợp Thymeleaf với Spring
Đầu tiên, hãy xem các cấu hình cần thiết để tích hợp với Spring. Thư viện thymeleaf-spring là bắt buộc để tích hợp.
Chúng tôi sẽ thêm các phần phụ thuộc sau vào tệp Maven POM của chúng tôi:
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring5</artifactId>
<version>3.0.11.RELEASE</version>
</dependency>
Lưu ý rằng, đối với một dự án Spring 4, chúng ta phải sử dụng thư viện thymeleaf-spring4 thay vì thymeleaf-spring5 .
Lớp SpringTemplateEngine thực hiện tất cả các bước cấu hình.
Chúng ta có thể cấu hình lớp này dưới dạng bean trong tệp cấu hình Java:
@Bean
@Description("Thymeleaf Template Resolver")
public ServletContextTemplateResolver templateResolver() {
ServletContextTemplateResolver templateResolver = new ServletContextTemplateResolver();
templateResolver.setPrefix("/WEB-INF/views/");
templateResolver.setSuffix(".html");
templateResolver.setTemplateMode("HTML5");
return templateResolver;
}
@Bean
@Description("Thymeleaf Template Engine")
public SpringTemplateEngine templateEngine() {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(templateResolver());
templateEngine.setTemplateEngineMessageSource(messageSource());
return templateEngine;
}
Tiền tố và hậu tố thuộc tính bean templateResolver cho biết vị trí của các trang xem trong thư mục ứng dụng web và phần mở rộng tên tệp của chúng, tương ứng.
Giao diện ViewResolver trong Spring MVC ánh xạ tên chế độ xem được bộ điều khiển trả về cho các đối tượng chế độ xem thực tế. ThymeleafViewResolver triển khai giao diện ViewResolver và nó được sử dụng để xác định các khung nhìn Thymeleaf sẽ hiển thị, được đặt tên cho khung nhìn.
Bước cuối cùng trong quá trình tích hợp là thêm ThymeleafViewResolver dưới dạng bean:
@Bean
@Description("Thymeleaf View Resolver")
public ThymeleafViewResolver viewResolver() {
ThymeleafViewResolver viewResolver = new ThymeleafViewResolver();
viewResolver.setTemplateEngine(templateEngine());
viewResolver.setOrder(1);
return viewResolver;
}
3. Thymeleaf trong Spring Boot
Spring Boot cung cấp cấu hình tự động cho Thymeleaf bằng cách thêm phụ thuộc spring-boot-starter-thymeleaf :
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
Không cần cấu hình rõ ràng. Theo mặc định, các tệp HTML phải được đặt ở vị trí resources/templates.
4. Hiển thị Giá trị Từ Nguồn Thông báo (Tệp Thuộc tính)
Chúng tôi có thể sử dụng thuộc tính thẻ th: text = ”# {key}”
để hiển thị các giá trị từ các tệp thuộc tính.
Để điều này hoạt động, chúng ta cần định cấu hình tệp thuộc tính dưới dạng messageSource bean:
@Bean
@Description("Spring Message Resolver")
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
Đây là mã HTML Thymeleaf để hiển thị giá trị được liên kết với khóa welcome.message :
<span th:text="#{welcome.message}" />
5. Hiển thị các thuộc tính của mô hình
5.1. Thuộc tính đơn giản
Chúng ta có thể sử dụng thuộc tính thẻ th: text = ”$ {propertyname}”
để hiển thị giá trị của các thuộc tính mô hình.
Hãy thêm một thuộc tính model với name serverTime trong lớp controller:
model.addAttribute("serverTime", dateFormat.format(new Date()));
Và đây là mã HTML để hiển thị giá trị của thuộc tính serverTime :
Current time is <span th:text="${serverTime}" />
5.2. Thuộc tính Bộ sưu tập
Nếu thuộc tính model là một tập hợp các đối tượng, chúng ta có thể sử dụng thuộc tính thẻ th: each để lặp qua nó.
Hãy xác định một lớp mô hình Sinh viên với hai trường, id và tên :
public class Student implements Serializable {
private Integer id;
private String name;
// standard getters and setters
}
Bây giờ chúng ta sẽ thêm danh sách sinh viên làm thuộc tính model trong lớp controller:
List<Student> students = new ArrayList<Student>();
// logic to build student data
model.addAttribute("students", students);
Cuối cùng, chúng ta có thể sử dụng mã mẫu Thymeleaf để lặp qua danh sách sinh viên và hiển thị tất cả các giá trị trường:
<tbody>
<tr th:each="student: ${students}">
<td th:text="${student.id}" />
<td th:text="${student.name}" />
</tr>
</tbody>
6. Đánh giá có điều kiện
6.1. if and unless
Chúng tôi sử dụng thuộc tính th: if = ”$ {condition}”
để hiển thị một phần của dạng xem nếu điều kiện được đáp ứng. Và chúng tôi sử dụng thuộc tính thứ: th:unless = ”$ {condition}”
để hiển thị một phần của chế độ xem nếu điều kiện không được đáp ứng.
Hãy thêm trường giới tính vào mô hình Sinh viên :
public class Student implements Serializable {
private Integer id;
private String name;
private Character gender;
// standard getters and setters
}
Giả sử trường này có hai giá trị có thể có (M hoặc F) để biểu thị giới tính của học sinh.
Nếu chúng tôi muốn hiển thị các từ “Nam” hoặc “Nữ” thay vì một ký tự, chúng tôi có thể thực hiện việc này bằng cách sử dụng mã Thymeleaf này:
<td>
<span th:if="${student.gender} == 'M'" th:text="Male" />
<span th:unless="${student.gender} == 'M'" th:text="Female" />
</td>
6.2. switch and case
Chúng tôi sử dụng thuộc tính th: switch
và th: case
để hiển thị nội dung có điều kiện bằng cách sử dụng cấu trúc câu lệnh switch.
Hãy viết lại mã trước đó bằng cách sử dụng các thuộc tính th: switch và th: case
<td th:switch="${student.gender}">
<span th:case="'M'" th:text="Male" />
<span th:case="'F'" th:text="Female" />
</td>
7. Xử lý đầu vào của người dùng
Chúng tôi có thể xử lý đầu vào biểu mẫu bằng các thuộc tính th: action = ”@ {url}” và th: object = ”$ {object}” . Chúng tôi sử dụng th: action để cung cấp URL hành động biểu mẫu và th: đối tượng để chỉ định một đối tượng mà dữ liệu biểu mẫu đã gửi sẽ bị ràng buộc.
Các trường riêng lẻ được ánh xạ bằng thuộc tính th: field = ”* {name}” , trong đó tên là thuộc tính phù hợp của đối tượng.
Đối với lớp Sinh viên , chúng ta có thể tạo một biểu mẫu đầu vào:
<form action="#" th:action="@{/saveStudent}" th:object="${student}" method="post">
<table border="1">
<tr>
<td><label th:text="#{msg.id}" /></td>
<td><input type="number" th:field="*{id}" /></td>
</tr>
<tr>
<td><label th:text="#{msg.name}" /></td>
<td><input type="text" th:field="*{name}" /></td>
</tr>
<tr>
<td><input type="submit" value="Submit" /></td>
</tr>
</table>
</form>
Trong đoạn mã trên, / saveStudent là URL hành động của biểu mẫu và sinh viên là đối tượng chứa dữ liệu biểu mẫu đã gửi.
Lớp StudentController xử lý việc gửi biểu mẫu:
@Controller
public class StudentController {
@RequestMapping(value = "/saveStudent", method = RequestMethod.POST)
public String saveStudent(@ModelAttribute Student student, BindingResult errors, Model model) {
// logic to process input data
}
}
Chú thích @RequestMapping ánh xạ phương thức bộ điều khiển với URL được cung cấp trong biểu mẫu. Phương thức có chú thích saveStudent () thực hiện xử lý bắt buộc đối với biểu mẫu đã gửi. Cuối cùng, chú thích @ModelAttribute liên kết các trường biểu mẫu với đối tượng sinh viên .
8. Hiển thị lỗi xác thực
Chúng ta có thể sử dụng hàm # fields.hasErrors () để kiểm tra xem một trường có bất kỳ lỗi xác thực nào không. Và chúng tôi sử dụng hàm # fields.errors () để hiển thị lỗi cho một trường cụ thể. Tên trường là tham số đầu vào cho cả hai hàm này.
Hãy xem mã HTML để lặp lại và hiển thị lỗi cho từng trường trong biểu mẫu:
<ul>
<li th:each="err : ${#fields.errors('id')}" th:text="${err}" />
<li th:each="err : ${#fields.errors('name')}" th:text="${err}" />
</ul>
Thay vì tên trường, các hàm trên chấp nhận ký tự thẻ đại diện * hoặc hằng số all để biểu thị tất cả các trường. Chúng tôi đã sử dụng thuộc tính th: each để lặp lại nhiều lỗi có thể có cho mỗi trường.
Đây là mã HTML trước đó được viết lại bằng ký tự đại diện * :
<ul>
<li th:each="err : ${#fields.errors('*')}" th:text="${err}" />
</ul>
Và ở đây chúng tôi đang sử dụng hằng số :
<ul>
<li th:each="err : ${#fields.errors('all')}" th:text="${err}" />
</ul>
Tương tự, chúng ta có thể hiển thị các lỗi toàn cục trong Spring bằng cách sử dụng hằng số chung.
Đây là mã HTML để hiển thị các lỗi chung:
<ul>
<li th:each="err : ${#fields.errors('global')}" th:text="${err}" />
</ul>
Ngoài ra, chúng ta có thể sử dụng thuộc tính th: error để hiển thị các thông báo lỗi.
Mã trước đó để hiển thị lỗi trong biểu mẫu có thể được viết lại bằng cách sử dụng thuộc tính th: error :
<ul>
<li th:errors="*{id}" />
<li th:errors="*{name}" />
</ul>
9. Sử dụng chuyển đổi
Chúng tôi sử dụng cú pháp dấu ngoặc kép {{}} để định dạng dữ liệu cho hiển thị. Điều này làm cho việc sử dụng các bộ định dạng được cấu hình cho loại trường đó trong bean convertService của tệp ngữ cảnh.
Hãy xem cách định dạng trường tên trong lớp Sinh viên :
<tr th:each="student: ${students}">
<td th:text="${{student.name}}" />
</tr>
Đoạn mã trên sử dụng lớp NameFormatter , được cấu hình bằng cách ghi đè phương thức addFormatters () từ giao diện WebMvcConfigurer .
Vì mục đích này, lớp @Configuration của chúng tôi ghi đè lớp WebMvcConfigurerAdapter :
@Configuration
public class WebMVCConfig extends WebMvcConfigurerAdapter {
// ...
@Override
@Description("Custom Conversion Service")
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new NameFormatter());
}
}
Lớp NameFormatter thực hiện giao diện Spring Formatter .
Chúng tôi cũng có thể sử dụng tiện ích #conversions để chuyển đổi các đối tượng để hiển thị. Cú pháp của hàm tiện ích là # convert.convert (Đối tượng, Lớp) trong đó Đối tượng được chuyển đổi thành loại Lớp .
Đây là cách hiển thị trường phần trăm đối tượng sinh viên với phần phân số đã bị loại bỏ:
<tr th:each="student: ${students}">
<td th:text="${#conversions.convert(student.percentage, 'Integer')}" />
</tr>
10. Kết luận
Trong bài viết này, chúng tôi đã giới thiệu cho các bạn cách tích hợp và sử dụng Thymeleaf trong ứng dụng Spring MVC.
Chúng tôi cũng đã thấy các ví dụ về cách hiển thị các trường, chấp nhận đầu vào, hiển thị lỗi xác thực và chuyển đổi dữ liệu để hiển thị.
Phiên bản làm việc của mã được hiển thị trong bài viết này có sẵn trong kho lưu trữ GitHub .
Bình luận