Dự án bao gồm 3 thành phần chính:
- Backend: Ứng dụng Spring Boot viết bằng Java 21.
- Frontend: Ứng dụng giao diện người dùng viết bằng Node.js 20.9.0.
- Admin: Hệ thống quản trị sử dụng
pnpm
.
Đảm bảo bạn đã cài đặt các công cụ sau:
- Java 21
Tải và cài đặt từ trang chính thức của Java. - Node.js 20.9.0
Tải và cài đặt từ trang chính thức của Node.js. - pnpm
Cài đặt toàn cục thông quanpm
:npm install -g pnpm
src/
├── frontend/ # Ứng dụng giao diện người dùng
├── admin/ # Ứng dụng quản trị
└── backend/ # Dịch vụ API
cd backend
./mvnw clean install
docker compose up -d
docker exec -i postgres-postgres-1 psql -U root -d postgres < ./backup.sql
// chạy src
vào folder backend > AppAplication > run
// chạy src admin > mở gitbash
cd admin
npm install -g pnpm
pnpm install
pnpm dev
// chay src frontend > mở gitbash
cd frontend
npm install
npm run dev
Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
- Tiếp nhận và xử lý yêu cầu HTTP từ client.
- Trả về phản hồi HTTP cho client.
- Xây dựng API theo kiến trúc RESTful.
- Hỗ trợ các phương thức HTTP như:
GET
POST
PUT
DELETE
- Và nhiều phương thức khác.
- Cung cấp framework để xây dựng ứng dụng web theo mô hình MVC (Model-View-Controller).
- Hỗ trợ việc quản lý và xử lý yêu cầu HTTP.
- Tự động cấu hình các thành phần quan trọng như:
DispatcherServlet
(Xử lý luồng yêu cầu trong Spring MVC).HttpMessageConverters
(Chuyển đổi dữ liệu giữa HTTP request/response và các đối tượng Java).- Và nhiều thành phần khác hỗ trợ hoạt động của ứng dụng.
Dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
- Xác minh danh tính của người dùng.
- Hỗ trợ nhiều phương thức xác thực như:
- Username & Password (Form-based authentication).
- Basic Authentication (Sử dụng tiêu đề HTTP).
- JWT (JSON Web Token).
- OAuth2.
- Kiểm tra quyền truy cập tài nguyên dựa trên vai trò hoặc quyền của người dùng.
- Hỗ trợ phân quyền dựa trên:
- Role (vai trò).
- Custom permissions (quyền tuỳ chỉnh).
- Cung cấp khả năng bảo vệ các endpoint trong ứng dụng:
- Cấu hình bảo mật cho từng đường dẫn cụ thể.
- Định nghĩa chính sách truy cập như:
permitAll()
(Cho phép truy cập tự do).authenticated()
(Yêu cầu xác thực trước khi truy cập).
- Tự động cấu hình các thành phần quan trọng như:
SecurityFilterChain
(Hệ thống bộ lọc bảo mật).AuthenticationManager
(Quản lý xác thực).PasswordEncoder
(Mã hóa mật khẩu).- Và nhiều thành phần khác để hỗ trợ bảo mật.
- React là một thư viện JavaScript mã nguồn mở do Facebook phát triển.
- Được sử dụng để xây dựng giao diện người dùng (UI) tương tác và hiệu suất cao.
- Cấu trúc dựa trên component (thành phần), cho phép tái sử dụng mã.
- Virtual DOM: Cải thiện hiệu suất bằng cách cập nhật giao diện nhanh chóng.
- Component-based Architecture: Xây dựng ứng dụng từ các thành phần nhỏ, dễ quản lý.
- Declarative Syntax: Dễ dàng mô tả giao diện và trạng thái ứng dụng.
- Strong Ecosystem: Có thể kết hợp với các thư viện như Redux, React Router, và hơn thế nữa.
- Ant Design là một thư viện giao diện người dùng (UI) mạnh mẽ và phong phú.
- Được phát triển bởi Alibaba, cung cấp các thành phần UI theo phong cách hiện đại và nhất quán.
- Component Library: Hơn 50+ thành phần UI như Button, Table, Modal, Form, v.v.
- Customizable Theme: Dễ dàng tùy chỉnh giao diện thông qua cấu hình chủ đề.
- Responsive Design: Hỗ trợ thiết kế giao diện đáp ứng (responsive) trên nhiều thiết bị.
- Internationalization (i18n): Hỗ trợ đa ngôn ngữ.
- Bootstrap là một framework CSS mã nguồn mở, phổ biến để phát triển giao diện web nhanh chóng.
- Được phát triển bởi Twitter, tập trung vào khả năng responsive và thiết kế nhất quán.
- Grid System: Hệ thống lưới 12 cột hỗ trợ thiết kế responsive.
- Pre-styled Components: Bao gồm các thành phần được thiết kế sẵn như Button, Card, Navbar, Dropdown, v.v.
- Customizable: Cho phép tùy chỉnh thông qua SASS hoặc CSS.
- Cross-browser Compatibility: Tương thích tốt với nhiều trình duyệt.
frontend
├── README.md
├── config
│ └── axios.js
├── eslint.config.js
├── index.html
├── package-lock.json
├── package.json
├── public
├── src
│ ├── App.jsx
│ ├── assets
│ │ └── react.svg
│ ├── components
│ │ ├── footer.jsx
│ │ └── header.jsx
│ ├── hooks
│ │ ├── useUser.js
│ │ └── useWallet.js
│ ├── main.jsx
│ ├── pages
│ │ ├── Contact.jsx
│ │ ├── Feedback.jsx
│ │ ├── about.jsx
│ │ ├── change-password.jsx
│ │ ├── home.jsx
│ │ ├── login.jsx
│ │ ├── my-orders.jsx
│ │ ├── my-works.jsx
│ │ ├── order-details.jsx
│ │ ├── orders.jsx
│ │ ├── payment-return.jsx
│ │ ├── profile.jsx
│ │ ├── project.jsx
│ │ ├── register.jsx
│ │ ├── service-detail.jsx
│ │ ├── service.jsx
│ │ └── wallet.jsx
│ └── service
│ ├── auth.js
│ ├── contact.js
│ ├── feedback.js
│ ├── order.js
│ ├── service.js
│ ├── serviceFeedback.js
│ ├── upload.js
│ ├── user.js
│ └── wallet.js
└── vite.config.js
Chứa các tệp và thư mục chính của ứng dụng frontend.
- Tệp mô tả dự án, bao gồm thông tin như cách cài đặt, sử dụng, hoặc các hướng dẫn liên quan.
- Tệp cấu hình
axios
để thực hiện các yêu cầu HTTP trong ứng dụng, thường bao gồm cấu hình cơ sở URL, các interceptor, hoặc token.
- Cấu hình ESLint để đảm bảo mã nguồn tuân theo các quy tắc mã hóa đã đặt ra, giúp cải thiện chất lượng code.
- Tệp HTML chính, là nơi ứng dụng React được "mount" (chèn vào). Đây là điểm vào cho frontend.
- package.json: Danh sách các dependency và script của dự án.
- package-lock.json: Ghi lại chi tiết phiên bản các dependency, đảm bảo tính nhất quán khi cài đặt.
- Chứa các tài nguyên tĩnh như hình ảnh, favicon, hoặc các tệp tĩnh khác không được xử lý bởi webpack/vite.
Thư mục chứa mã nguồn chính của ứng dụng React.
- Thành phần gốc của ứng dụng React. Nơi cấu hình các thành phần con hoặc định tuyến.
- Chứa tài sản tĩnh như hình ảnh, biểu tượng, hoặc tệp CSS/JS dùng trong ứng dụng.
- Chứa các thành phần UI tái sử dụng:
- header.jsx: Thành phần hiển thị header của ứng dụng.
- footer.jsx: Thành phần hiển thị footer của ứng dụng.
- Chứa các custom hook, giúp tách logic ra khỏi giao diện:
- useUser.js: Quản lý thông tin người dùng.
- useWallet.js: Quản lý logic liên quan đến ví.
- Điểm vào chính của ứng dụng React, nơi
App.jsx
được render vào DOM.
- Chứa các thành phần giao diện (pages) tương ứng với từng chức năng:
- Contact.jsx: Trang liên hệ.
- Feedback.jsx: Trang phản hồi.
- home.jsx: Trang chủ.
- login.jsx: Trang đăng nhập.
- register.jsx: Trang đăng ký.
- profile.jsx: Trang thông tin cá nhân.
- wallet.jsx: Trang quản lý ví tiền.
- my-orders.jsx: Trang đơn hàng của tôi.
- order-details.jsx: Trang chi tiết đơn hàng.
- service.jsx: Trang dịch vụ.
- service-detail.jsx: Trang chi tiết dịch vụ.
- payment-return.jsx: Trang xử lý phản hồi sau khi thanh toán.
- Và nhiều trang khác.
- Chứa các tệp xử lý logic API, thường được gọi từ
axios.js
:- auth.js: Quản lý API liên quan đến xác thực.
- contact.js: Quản lý API liên hệ.
- feedback.js: Quản lý API phản hồi.
- order.js: Quản lý API đơn hàng.
- service.js: Quản lý API dịch vụ.
- upload.js: Quản lý API tải lên tệp.
- user.js: Quản lý API người dùng.
- wallet.js: Quản lý API ví.
- Tệp cấu hình cho Vite, một công cụ xây dựng frontend nhanh, hỗ trợ Hot Module Replacement (HMR) và tối ưu hóa quá trình phát triển.
-
Người dùng yêu cầu thanh toán:
- Người dùng chọn phương thức thanh toán VNPay trên giao diện.
-
Tạo URL thanh toán VNPay:
- Backend tạo URL thanh toán VNPay dựa trên các thông tin giao dịch.
- Gửi yêu cầu đến API VNPay để lấy URL thanh toán.
-
Chuyển hướng người dùng đến cổng thanh toán VNPay:
- Frontend chuyển hướng người dùng đến URL VNPay mà backend trả về.
- Người dùng nhập thông tin và thực hiện thanh toán trên cổng VNPay.
-
Xử lý callback từ VNPay:
- Sau khi thanh toán xong, VNPay gọi API callback của bạn để gửi kết quả giao dịch.
- Backend kiểm tra chữ ký (checksum) và trạng thái giao dịch để xác nhận giao dịch.
-
Hiển thị kết quả cho người dùng:
- Backend trả về kết quả giao dịch cho frontend.
- Frontend hiển thị kết quả thanh toán thành công hoặc thất bại cho người dùng.
Bạn cần thông tin cấu hình từ VNPay:
vnp_TmnCode
: Mã terminal của bạn.vnp_HashSecret
: Chuỗi bí mật dùng để tạo chữ ký.vnp_PayUrl
: URL API thanh toán VNPay.vnp_ReturnUrl
: URL để người dùng quay lại sau khi thanh toán.
@PostMapping(path = "/vn-pay")
public String createOrder(
@RequestBody() PaymentRequest paymentRequest,
HttpServletRequest request)
throws JsonProcessingException {
String baseUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
paymentRequest.setUserId(userService.getCurrentUser().getId().toString());
// Convert the payment request to a JSON string
ObjectMapper objectMapper = new ObjectMapper();
String body = objectMapper.writeValueAsString(paymentRequest);
// Create the order and get the redirection URL
return paymentService.createOrder(paymentRequest.getAmount(), body, baseUrl);
}
Xử lý yêu cầu từ phía client để tạo đơn hàng và trả về URL thanh toán VNPay.
-
Lấy thông tin URL server:
- Bao gồm
scheme
, tên miền, và cổng, được sử dụng để cấu hìnhbaseUrl
.
- Bao gồm
-
Thêm thông tin người dùng:
- Lấy
userId
của người dùng hiện tại thông quauserService.getCurrentUser()
và gán vàoPaymentRequest
.
- Lấy
-
Chuyển đổi dữ liệu:
- Sử dụng
ObjectMapper
để chuyển đổi đối tượngPaymentRequest
thành chuỗi JSON.
- Sử dụng
-
Tạo đơn hàng:
- Gọi phương thức
paymentService.createOrder()
để tạo đơn hàng với các tham số:paymentRequest.getAmount()
: Số tiền cần thanh toán.body
: Chuỗi JSON chứa thông tin đơn hàng.baseUrl
: Đường dẫn gốc của server.
- Gọi phương thức
- Trả về URL từ VNPay để frontend chuyển hướng người dùng đến trang thanh toán.
@GetMapping(path = "/vnpay-payment")
public void returnOrder(HttpServletRequest request, HttpServletResponse response) throws IOException {
// Convert the payment request parameter to a JSON string
ObjectMapper objectMapper = new ObjectMapper();
// Parse the JSON string to a PaymentRequest object
PaymentRequest paymentRequest = objectMapper.readValue(
request.getParameter("vnp_OrderInfo"),
PaymentRequest.class);
log.info("payment request: {}", paymentRequest.toString());
// Process the payment return
int result = paymentService.orderReturn(request, paymentRequest);
// Process the payment return
String clientUrl = result == 1
? "http://localhost:5173/payment-return?type=success"
: "http://localhost:5173/payment-return?type=fail";
response.sendRedirect(clientUrl);
}
Xử lý thông tin callback từ VNPay sau khi người dùng hoàn tất thanh toán.
-
Lấy Thông Tin Callback:
- Lấy tham số
vnp_OrderInfo
từ request callback và chuyển thành chuỗi JSON.
- Lấy tham số
-
Chuyển Đổi Dữ Liệu:
- Dùng
ObjectMapper
để parse JSON thành đối tượngPaymentRequest
.
- Dùng
-
Kiểm Tra Trạng Thái Giao Dịch:
- Gọi phương thức
paymentService.orderReturn()
với các tham số:request
: Chứa thông tin callback từ VNPay gửi về.paymentRequest
: Thông tin chi tiết về giao dịch được parse từ JSON.
- Gọi phương thức
-
Xử Lý Kết Quả Giao Dịch:
- Nếu giao dịch thành công (
result == 1
):- Chuyển hướng người dùng đến trang thành công:
/payment-return?type=success
.
- Chuyển hướng người dùng đến trang thành công:
- Nếu giao dịch thất bại:
- Chuyển hướng người dùng đến trang thất bại:
/payment-return?type=fail
.
- Chuyển hướng người dùng đến trang thất bại:
- Nếu giao dịch thành công (
Điều hướng người dùng đến trang kết quả giao dịch tương ứng trên frontend.