hocvietcode.com
  • Trang chủ
  • Học lập trình
    • Lập trình C/C++
    • Cấu trúc dữ liệu và giải thuật
    • Lập trình HTML
    • Lập trình Javascript
      • Javascript cơ bản
      • ReactJS framework
      • AngularJS framework
      • Typescript cơ bản
      • Angular
      • NodeJS
    • Lập trình Mobile
      • Lập Trình Dart Cơ Bản
        • Dart Flutter Framework
    • Cơ sở dữ liệu
      • MySQL – MariaDB
      • Micrsoft SQL Server
      • Extensible Markup Language (XML)
      • JSON
      • MongoDB
    • Lập trình PHP
      • Lập trình PHP cơ bản
      • Laravel Framework
    • Lập trình Java
      • Java Cơ bản
      • Spring Boot
    • Lập trình C#
      • Lập Trình C# Cơ Bản
      • ASP.NET Core MVC
    • Lập trình Python
    • Git và Github
    • Machine Learning
  • WORDPRESS
    • WordPress cơ bản
    • WordPress nâng cao
    • Chia sẻ WordPress
  • Kiến thức hệ thống
    • Microsoft Azure
    • Docker
    • Linux
    • Mạng và truyền thông
  • Chia sẻ IT
    • Tin học văn phòng
      • Microsoft Word
      • Microsoft Excel
    • Marketing
      • Google Adwords
      • Facebook Ads
      • Kiến thức khác
    • Chia sẻ phần mềm
    • Review công nghệ
    • Công cụ – tiện ích
      • Kiểm tra bàn phím online
      • Kiểm tra webcam online
Đăng nhập
  • Đăng nhập / Đăng ký

Please enter key search to display results.

Home
  • Spring Boot
Spring Boot bài 07: Biểu thức Thymeleaf, vòng lặp và hiển thị an toàn
Java và Spring Boot – MVC và REST API

Spring Boot bài 07: Biểu thức Thymeleaf, vòng lặp và hiển thị an toàn

  • 18-10-2026
  • Toanngo92
  • 0 Comments

Giáo trình Spring Boot MVC và REST API · Chương 4/12: Tổ chức giao diện Thymeleaf · Bài 07/28 · Biên soạn tháng 10/2026.

← Bài 06 · Mục lục 12 chương · Bài 08 →

Mục lục

  • Mục tiêu bài học
  • Danh sách dữ liệu và một dòng mẫu
  • Các loại biểu thức thường gặp
  • Escape giúp tránh biến dữ liệu thành mã HTML
  • Giữ lại trạng thái bộ lọc
  • Lỗi thường gặp và lưu ý
  • Ghi nhớ
  • Tài liệu đối chiếu

Mục tiêu bài học

Hiển thị danh sách và trạng thái rỗng, dùng điều kiện và hiểu ranh giới giữa văn bản với HTML.

Danh sách dữ liệu và một dòng mẫu

Template không cần biết trước có bao nhiêu khóa học. th:each lặp qua result.content, gán từng phần tử vào biến course rồi render một dòng tương ứng. Nếu danh sách rỗng, th:if hiển thị thông báo rõ ràng thay vì để người xem đoán trang đang lỗi hay chưa có nội dung.

Nên để Service chuẩn bị thứ tự, phân trang và nội dung cần thiết. Template chỉ phụ trách biểu diễn: không vừa lặp vừa truy vấn database cho từng dòng, không tính lại quy tắc giảm giá hoặc phân quyền ở đây. Điều này giữ giao diện dễ đọc và tránh vô tình tạo hàng chục truy vấn.

<tbody>
  <tr th:each="course : ${result.content}">
    <td><a th:href="@{/courses/{id}(id=${course.id})}"
           th:text="${course.title}"></a></td>
    <td th:text="${course.categoryName}"></td>
    <td th:text="${course.price}"></td>
  </tr>
  <tr th:if="${result.empty}">
    <td colspan="3">Chưa có khóa học phù hợp</td>
  </tr>
</tbody>

Các loại biểu thức thường gặp

${…} lấy dữ liệu trong context; @{…} xây URL; *{…} đọc thuộc tính của đối tượng đang được chọn bởi th:object trong biểu mẫu. Fragment dùng ~{…}; message quốc tế hóa dùng #{…}. Không cần học thuộc mọi cú pháp ngay, nhưng nên phân biệt biểu thức dữ liệu và biểu thức URL.

Với điều kiện đơn giản, có thể dùng th:if hoặc toán tử ba ngôi. Ví dụ giá 0 hiển thị “Miễn phí”, ngược lại hiển thị giá. Khi định dạng tiền cho hệ thống thực tế, phải thống nhất đơn vị tiền, locale và cách làm tròn; một con số không tự mang thông tin VND hay USD.

<span th:if="${course.price.signum() == 0}">Miễn phí</span>
<span th:unless="${course.price.signum() == 0}"
      th:text="${course.price}"></span>

Escape giúp tránh biến dữ liệu thành mã HTML

Nếu người dùng nhập tên khóa học là <script>alert(1)</script>, ta muốn trình duyệt coi đó là tên dạng văn bản, không thực thi script. th:text escape ký tự đặc biệt để thực hiện điều này. th:utext dành cho HTML đã được kiểm soát và làm sạch; không dùng nó để sửa vấn đề “chữ không in đậm được” với dữ liệu người dùng nhập.

Escape theo ngữ cảnh không thay thế mọi biện pháp chống XSS. Không nhét dữ liệu tùy ý vào đoạn JavaScript, URL nguy hiểm hoặc style. Với nội dung bài học có HTML phong phú, cần quy trình sanitize riêng, không chỉ chuyển từ th:text sang th:utext.

Giữ lại trạng thái bộ lọc

Ô tìm kiếm dùng th:value=${q}, lựa chọn sort dùng th:selected để người xem thấy bộ lọc hiện tại. Việc hiển thị đúng trạng thái giúp hiểu vì sao chỉ có vài khóa học. Ở bài phân trang, các liên kết tiếp theo còn phải mang theo những tham số đó.

Khi debug template, xem response HTML cuối cùng trong trình duyệt và so sánh với Model. Không tìm các thuộc tính th:* trong HTML đã render như bằng chứng Thymeleaf chưa chạy: chúng thường đã được xử lý và thay thế. Nếu mở tệp HTML trực tiếp từ ổ đĩa, bạn chỉ thấy bản mẫu tĩnh, không có dữ liệu từ Spring.

Lỗi thường gặp và lưu ý

  • Tên biến vòng lặp chỉ có ý nghĩa trong phạm vi phần tử tương ứng.
  • Không dùng unescaped HTML cho dữ liệu nhập chỉ vì muốn giữ xuống dòng; hãy xử lý cách trình bày phù hợp.

Ghi nhớ

Vòng lặp, điều kiện và escape là ba nền tảng để render danh sách đúng dữ liệu và an toàn.

Tài liệu đối chiếu

  • Using Thymeleaf

← Bài 06 · Mục lục 12 chương · Bài 08 →

Bài viết liên quan:

Java và Spring Boot – MVC và REST API
Spring Boot bài 13: Kết nối MySQL, CRUD và transaction trong Service
Java và Spring Boot – MVC và REST API
Giáo trình Spring Boot MVC và REST API 2026: 12 chương, 28 bài
Java và Spring Boot – MVC và REST API
Spring Boot bài 14: Quan hệ JPA, DTO và tránh truy vấn N+1
Java và Spring Boot – MVC và REST API
Spring Boot bài 15: Tìm kiếm, phân trang và sắp xếp có kiểm soát
Java và Spring Boot – MVC và REST API
Spring Boot bài 16: Upload và download tài liệu có giới hạn
Java và Spring Boot – MVC và REST API
Spring Boot bài 17: Spring Security: đăng nhập, mật khẩu và SecurityFilterChain
Java và Spring Boot – MVC và REST API
Spring Boot bài 18: Phân quyền teacher/student và bảo vệ endpoint
Java và Spring Boot – MVC và REST API
Spring Boot bài 19: CSRF, CORS và gọi API có session đúng cách
Java và Spring Boot – MVC và REST API
Spring Boot bài 20: REST Controller, JSON và DTO cho API danh sách
Java và Spring Boot – MVC và REST API
Spring Boot bài 21: REST CRUD: POST, PUT, DELETE và mã trạng thái
Java và Spring Boot – MVC và REST API
Spring Boot bài 22: Validation API, ProblemDetail và hợp đồng lỗi
Java và Spring Boot – MVC và REST API
Spring Boot bài 23: Gọi dịch vụ HTTP bằng RestClient và đặt timeout

Dịch vụ thiết kế Wesbite

NỘI DUNG MỚI CẬP NHẬT

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 05: Đơn vị và kích thước: px, rem, %, min và max

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 02: Selector và class: chọn đúng phần tử cần sửa

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 01: Kết nối CSS với HTML và sửa quy tắc đầu tiên

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 20: Hoàn thiện website và sửa lỗi bằng DevTools

CSS cơ bản – 20 bài từ HTML đến website responsive với Flexbox, Grid và mobile-first

CSS cơ bản – Bài 03: Vì sao CSS không có tác dụng? Cascade và specificity

Giới thiệu

hocvietcode.com là website chia sẻ và cập nhật tin tức công nghệ, chia sẻ kiến thức, kỹ năng. Chúng tôi rất cảm ơn và mong muốn nhận được nhiều phản hồi để có thể phục vụ quý bạn đọc tốt hơn !

Liên hệ quảng cáo: [email protected]

Kết nối với HỌC VIẾT CODE

© hocvietcode.com - Tech888 Co .Ltd since 2019

Đăng nhập

Trở thành một phần của cộng đồng của chúng tôi!
Registration complete. Please check your email.
Đăng nhập bằng google
Đăng kýBạn quên mật khẩu?

Create an account

Welcome! Register for an account
The user name or email address is not correct.
Registration confirmation will be emailed to you.
Log in Lost your password?

Reset password

Recover your password
Password reset email has been sent.
The email could not be sent. Possible reason: your host may have disabled the mail function.
A password will be e-mailed to you.
Log in Register
×