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 20: REST Controller, JSON và DTO cho API danh sách
Java và Spring Boot – MVC và REST API

Spring Boot bài 20: REST Controller, JSON và DTO cho API danh sách

  • 18-10-2026
  • Toanngo92
  • 0 Comments

Giáo trình Spring Boot MVC và REST API · Chương 9/12: REST API và hợp đồng HTTP · Bài 20/28 · Biên soạn tháng 10/2026.

← Bài 19 · Mục lục 12 chương · Bài 21 →

Mục lục

  • Mục tiêu bài học
  • Cùng nghiệp vụ, khác cách trả kết quả
  • DTO là hợp đồng dữ liệu
  • Cấu trúc phân trang dễ dùng cho client
  • Content negotiation và cách đọc lỗi
  • 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

Tạo endpoint đọc dữ liệu bằng JSON, dùng DTO và envelope phân trang ổn định thay vì trả entity trực tiếp.

Cùng nghiệp vụ, khác cách trả kết quả

CourseWebController trả tên template; CourseApiController dùng @RestController để kết quả được ghi vào response body qua message converter. Hai Controller gọi cùng CourseService, nên không có hai phiên bản quy tắc cập nhật khóa học. @RequestMapping("/api") tạo tiền tố chung cho nhóm endpoint.

GET /api/courses trả danh sách có phân trang. GET /api/courses/{id} trả một khóa học. Đây là các thao tác đọc công khai theo bảng quyền của mẫu. HTTP method mang ý nghĩa: GET cần không tạo thay đổi nghiệp vụ như thêm dòng hoặc gửi email.

Tệp trong mã nguồn mẫu: src/main/java/com/hocvietcode/academy/CourseApiController.java. Đoạn dưới được trích từ tệp này; xem bản tải về để có đủ import và phần còn lại.

@RestController @RequestMapping("/api")
public class CourseApiController {
    private final CourseService service;
    public CourseApiController(CourseService service){this.service=service;}
    @GetMapping("/courses") PageDto<CourseDto> list(@RequestParam(defaultValue="") String q,@RequestParam(defaultValue="0") int page,@RequestParam(defaultValue="10") int size,@RequestParam(defaultValue="id") String sort){return PageDto.from(service.search(q,page,size,sort));}
    @GetMapping("/courses/{id}") CourseDto get(@PathVariable Long id){return service.get(id);}

DTO là hợp đồng dữ liệu

CourseDto gồm id, title, price, categoryId và categoryName. JSON không chứa đối tượng Category với toàn bộ thuộc tính hoặc proxy Hibernate. Việc tách entity và DTO giúp thay đổi schema nội bộ mà không nhất thiết thay hợp đồng công khai.

Request tạo/sửa dùng CourseForm có validation. Response dùng CourseDto có id do server cấp. Dù tên CourseForm gợi giao diện HTML, nó hiện là đối tượng đầu vào dùng chung có phạm vi nhỏ; khi web và API có quy tắc khác nhau, hãy tách request DTO thay vì ép hai luồng dùng một cấu trúc không còn phù hợp.

Tệp trong mã nguồn mẫu: src/main/java/com/hocvietcode/academy/PageDto.java. Đoạn dưới được trích từ tệp này; xem bản tải về để có đủ import và phần còn lại.

package com.hocvietcode.academy;
import java.util.List;
import org.springframework.data.domain.Page;
public record PageDto<T>(List<T> content,int page,int size,long totalElements,int totalPages) {
    public static <T> PageDto<T> from(Page<T> p){return new PageDto<>(p.getContent(),p.getNumber(),p.getSize(),p.getTotalElements(),p.getTotalPages());}
}

Cấu trúc phân trang dễ dùng cho client

PageDto chủ động trả năm trường: content, page, size, totalElements, totalPages. Client không cần biết PageImpl của Spring Data có thêm những thuộc tính nội bộ nào. page vẫn bắt đầu từ 0 như trong endpoint HTML, còn giao diện người dùng có thể hiển thị số trang từ 1.

Thử GET /api/courses?size=1&q=Spring&sort=title bằng trình duyệt hoặc công cụ HTTP. Kết quả phải có mảng content và thông tin tổng. Khi không có bản ghi phù hợp, một danh sách rỗng với 200 là hợp lý; điều đó khác với GET một id không tồn tại trả 404.

curl -i "http://localhost:8080/api/courses?size=1&q=Spring&sort=title"
curl -i "http://localhost:8080/api/courses/1"

Content negotiation và cách đọc lỗi

Client nên gửi Accept: application/json khi muốn JSON. POST JSON cần Content-Type: application/json để server biết cách đọc body; Accept và Content-Type không cùng vai trò. Mã status cho biết kết quả tổng quát, còn body bổ sung dữ liệu hoặc chi tiết lỗi.

Không bọc mọi kết quả trong HTTP 200 rồi nhét success=false vào JSON, vì client, cache và công cụ giám sát sẽ mất tín hiệu chuẩn. Ở bài tiếp theo, 201, 204, 400 và 404 được dùng theo từng thao tác. API cũng không tự trở nên bảo mật chỉ vì URL có tiền tố /api.

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

  • Không trả JpaRepository hoặc entity lazy ra response và để serializer quyết định hợp đồng.
  • GET danh sách rỗng là trường hợp bình thường, không cần 404.

Ghi nhớ

REST Controller chuyển kết quả nghiệp vụ thành HTTP/JSON; DTO giữ cấu trúc response rõ ràng và có thể kiểm thử.

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

  • ResponseBody

← Bài 19 · Mục lục 12 chương · Bài 21 →

Bài viết liên quan:

Java và Spring Boot – MVC và REST API
Spring Boot bài 24: Gửi email và lập lịch tác vụ trong Spring Boot
Java và Spring Boot – MVC và REST API
Spring Boot bài 08: Fragment, layout và tài nguyên CSS trong Spring Boot
Java và Spring Boot – MVC và REST API
Spring Boot bài 25: Unit test Service với JUnit và Mockito
Java và Spring Boot – MVC và REST API
Spring Boot bài 09: Binding biểu mẫu tạo và sửa khóa học
Java và Spring Boot – MVC và REST API
Spring Boot bài 26: Integration test MVC, API, database và Security
Java và Spring Boot – MVC và REST API
Spring Boot bài 10: Validation và BindingResult: báo lỗi ngay trên biểu mẫu
Java và Spring Boot – MVC và REST API
Spring Boot bài 27: Logging, Actuator và quản lý schema bằng Flyway
Java và Spring Boot – MVC và REST API
Spring Boot bài 11: Post/Redirect/Get, flash message và session
Java và Spring Boot – MVC và REST API
Spring Boot bài 28: Đóng gói JAR, Docker và cấu hình triển khai
Java và Spring Boot – MVC và REST API
Spring Boot bài 12: JPA Entity, Repository, H2 và migration đầu tiên
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 13: Kết nối MySQL, CRUD và transaction trong Service

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
×