diff --git a/README.md b/README.md index f81c3e8..8fc6839 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,6 @@ - [Giới thiệu](#gioi-thieu) - [Công nghệ sử dụng](#cong-nghe) -- [Yêu cầu môi trường](#-yêu-cầu-môi-trường) - [Cấu trúc dự án](#-cấu-trúc-dự-án) - [🚀 Release](#-release) - [🔨 Build từ mã nguồn](#-build-từ-mã-nguồn) @@ -83,17 +82,6 @@ --- -## 💻 Yêu cầu môi trường - -| Công cụ | Phiên bản tối thiểu | -|---|---| -| Java (JDK) | **25** | -| Maven | 3.9+ | -| Docker | 24+ | -| Docker Compose | 2.x | - ---- - ## 📁 Cấu trúc dự án ``` @@ -143,20 +131,39 @@ bigbid/ ## 🚀 Release +### Yêu cầu môi trường +| Công cụ | Phiên bản tối thiểu | +|---|---| +| Java (JDK) | **25** | +| Docker | 24+ | + ### Bước 1 — Tải bản Release [![Release](https://img.shields.io/badge/Download-Release-blue?style=for-the-badge&logo=github)](https://github.com/Pumpkin-Nguyen/bigbid/releases) ### Bước 2 — Khởi động MySQL bằng Docker +## MacOS / Linux ```bash docker volume create db_data && docker run -d --name bigbid-db -p 3306:3306 -e MYSQL_ROOT_PASSWORD=anhemf36 -e MYSQL_DATABASE=bigbid -v db_data:/var/lib/mysql --restart always mysql:8.4 ``` +## Window +```bash +docker volume create db_data; ` +docker run -d --name bigbid-db ` + -p 3306:3306 ` + -e MYSQL_ROOT_PASSWORD=anhemf36 ` + -e MYSQL_DATABASE=bigbid ` + -v db_data:/var/lib/mysql ` + --restart always ` + mysql:8.4 +``` + ### Bước 3: Khởi động server và client ```bash -java -jar bigbid-server-1.0.0.jar --spring.profiles.active=prod +java -jar bigbid-server-1.0.0.jar ``` --- @@ -168,6 +175,14 @@ java -jar bigbid-client-1.0.0.jar ## 🔨 Build từ mã nguồn +### Yêu cầu môi trường +| Công cụ | Phiên bản tối thiểu | +|---|---| +| Java (JDK) | **25** | +| Maven | 3.9+ | +| Docker | 24+ | +| Docker Compose | 2.x | + ### Clone repository ```bash @@ -191,19 +206,19 @@ cd bigbid-server #### macOS / Linux ```bash -cp src/main/resources/application-prod.yaml.example \ -src/main/resources/application-prod.yaml +cp src/main/resources/application.yaml.example \ +src/main/resources/application.yaml ``` #### Windows ```bash -copy src/main/resources/application-prod.yaml.example ` -src/main/resources/application-prod.yaml +copy src/main/resources/application.yaml.example ` +src/main/resources/application.yaml ``` --- -### Bước 3 — Điền các config tại file `application-prod.yaml` +### Bước 3 — Điền các config tại file `application.yaml` --- @@ -219,7 +234,7 @@ src/main/resources/application-prod.yaml ``` #### Run ```bash -java -jar target/bigbid-server-1.0.0.jar --spring.profiles.active=prod +java -jar target/bigbid-server-1.0.0.jar ``` --- @@ -284,13 +299,6 @@ java -jar target/bigbid-client-1.0.0.jar - [x] Thông báo kết quả phiên qua WebSocket --- - ## 📎 Báo cáo và Demo - -| Tài liệu | Đường dẫn | -|--------------------------|-----------| -| 📄 **Báo cáo PDF** | | -| 🎥 **Video Demo** | | -| 💻 **GitHub Repository** | | - +- https://drive.google.com/drive/folders/1IBAXfG7eJSammKFNKEgccJiwrgA384K_ --- \ No newline at end of file diff --git a/bigbid-client/pom.xml b/bigbid-client/pom.xml index f33d35e..ef8fee2 100644 --- a/bigbid-client/pom.xml +++ b/bigbid-client/pom.xml @@ -1,5 +1,5 @@ + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 @@ -36,6 +36,31 @@ 25 + + org.openjfx + javafx-graphics + 25 + win + + + org.openjfx + javafx-graphics + 25 + linux + + + org.openjfx + javafx-graphics + 25 + mac + + + org.openjfx + javafx-graphics + 25 + mac-aarch64 + + org.projectlombok lombok diff --git a/bigbid-client/src/main/java/com/bigbid/client/controller/AuctionDetailController.java b/bigbid-client/src/main/java/com/bigbid/client/controller/AuctionDetailController.java index c2f97c4..1c766e9 100644 --- a/bigbid-client/src/main/java/com/bigbid/client/controller/AuctionDetailController.java +++ b/bigbid-client/src/main/java/com/bigbid/client/controller/AuctionDetailController.java @@ -41,7 +41,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import tools.jackson.databind.ObjectMapper; @Slf4j @Component @@ -68,7 +67,6 @@ public class AuctionDetailController { private final AuctionService auctionService; private final AuthGuard authGuard; private final WebSocketClient webSocketClient; - private final ObjectMapper objectMapper; private final XYChart.Series bidHistorySeries = new XYChart.Series<>(); @@ -249,8 +247,7 @@ private void loadAuctionBidHistory() { }); } - private void applyBidHistory( - List bidHistory) { + private void applyBidHistory(List bidHistory) { if (bidHistory == null || bidHistory.isEmpty()) { return; } @@ -265,8 +262,7 @@ private void applyBidHistory( .forEach(this::appendBidPoint); } - private void appendBidPoint( - com.bigbid.client.model.response.BidTransactionResponse bidTransaction) { + private void appendBidPoint(BidTransactionResponse bidTransaction) { LocalDateTime timestamp = bidTransaction.getTimestamp(); long xValue = toEpochMillis(timestamp != null ? timestamp : LocalDateTime.now()); long yValue = bidTransaction.getAmount(); diff --git a/bigbid-client/src/main/java/com/bigbid/client/controller/LoginController.java b/bigbid-client/src/main/java/com/bigbid/client/controller/LoginController.java index 9834777..1589a23 100644 --- a/bigbid-client/src/main/java/com/bigbid/client/controller/LoginController.java +++ b/bigbid-client/src/main/java/com/bigbid/client/controller/LoginController.java @@ -170,7 +170,7 @@ private void handleRegister() { return; } - if (LocalDate.now().minusYears(16).isAfter(dob)) { + if (dob.minusYears(16).isAfter(LocalDate.now())) { AlertHelper.showWarning( "Age Requirement", "You must be at least 16 years old to register."); return; diff --git a/bigbid-server/src/main/java/com/bigbid/server/exception/ErrorCode.java b/bigbid-server/src/main/java/com/bigbid/server/exception/ErrorCode.java index 1ed1a38..b072ea5 100644 --- a/bigbid-server/src/main/java/com/bigbid/server/exception/ErrorCode.java +++ b/bigbid-server/src/main/java/com/bigbid/server/exception/ErrorCode.java @@ -12,6 +12,7 @@ public enum ErrorCode { DATA_INTEGRITY_VIOLATION(9997, "Data error", HttpStatus.BAD_REQUEST), INVALID_KEY(9998, "Uncategorized error", HttpStatus.BAD_REQUEST), UNCATEGORIZED_EXCEPTION(9999, "Uncategorized error", HttpStatus.INTERNAL_SERVER_ERROR), + FILE_SIZE_LIMIT(9998, "File size limit exceeded", HttpStatus.BAD_REQUEST), // USER EXCEPTION (1000-1099) USER_EXISTED(1002, "User existed", HttpStatus.BAD_REQUEST), diff --git a/bigbid-server/src/main/java/com/bigbid/server/exception/GlobalExceptionHandler.java b/bigbid-server/src/main/java/com/bigbid/server/exception/GlobalExceptionHandler.java index 6e458a4..76e5632 100644 --- a/bigbid-server/src/main/java/com/bigbid/server/exception/GlobalExceptionHandler.java +++ b/bigbid-server/src/main/java/com/bigbid/server/exception/GlobalExceptionHandler.java @@ -13,6 +13,7 @@ import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.multipart.MaxUploadSizeExceededException; import com.bigbid.server.dto.ApiResponse; @@ -25,9 +26,9 @@ public class GlobalExceptionHandler { public static final String MIN_ATTRIBUTE = "min"; @ExceptionHandler(value = RuntimeException.class) - ResponseEntity handleRuntimeException(RuntimeException exception) { + ResponseEntity> handleRuntimeException(RuntimeException exception) { log.error("Exception: ", exception); - ApiResponse apiResponse = new ApiResponse(); + ApiResponse apiResponse = new ApiResponse<>(); apiResponse.setCode(ErrorCode.UNCATEGORIZED_EXCEPTION.getCode()); apiResponse.setMessage(ErrorCode.UNCATEGORIZED_EXCEPTION.getMessage()); @@ -35,10 +36,21 @@ ResponseEntity handleRuntimeException(RuntimeException exception) { return ResponseEntity.badRequest().body(apiResponse); } + @ExceptionHandler(value = MaxUploadSizeExceededException.class) + ResponseEntity> handleMaxUploadSizeExceededException( + MaxUploadSizeExceededException exception) { + ApiResponse apiResponse = new ApiResponse<>(); + + apiResponse.setCode(ErrorCode.FILE_SIZE_LIMIT.getCode()); + apiResponse.setMessage(ErrorCode.FILE_SIZE_LIMIT.getMessage()); + + return ResponseEntity.badRequest().body(apiResponse); + } + @ExceptionHandler(value = AppException.class) - ResponseEntity handleAppException(AppException exception) { + ResponseEntity> handleAppException(AppException exception) { ErrorCode errorCode = exception.getErrorCode(); - ApiResponse apiResponse = new ApiResponse(); + ApiResponse apiResponse = new ApiResponse<>(); apiResponse.setCode(errorCode.getCode()); apiResponse.setMessage(errorCode.getMessage()); @@ -46,56 +58,56 @@ ResponseEntity handleAppException(AppException exception) { } @ExceptionHandler(value = AccessDeniedException.class) - ResponseEntity handlingAccessDeniedException(AccessDeniedException exception) { + ResponseEntity> handlingAccessDeniedException(AccessDeniedException exception) { ErrorCode errorCode = ErrorCode.UNAUTHORIZED; return ResponseEntity.status(errorCode.getStatusCode()) .body( - ApiResponse.builder() + ApiResponse.builder() .code(errorCode.getCode()) .message(errorCode.getMessage()) .build()); } @ExceptionHandler(value = HttpMessageNotReadableException.class) - ResponseEntity handleHttpMessageNotReadableException( + ResponseEntity> handleHttpMessageNotReadableException( HttpMessageNotReadableException exception) { ErrorCode errorCode = ErrorCode.INVALID_REQUEST_BODY; log.error("Exception: ", exception); return ResponseEntity.status(errorCode.getStatusCode()) .body( - ApiResponse.builder() + ApiResponse.builder() .code(errorCode.getCode()) .message(errorCode.getMessage()) .build()); } @ExceptionHandler(value = DataIntegrityViolationException.class) - ResponseEntity handleDataIntegrityViolationException( + ResponseEntity> handleDataIntegrityViolationException( DataIntegrityViolationException exception) { ErrorCode errorCode = ErrorCode.DATA_INTEGRITY_VIOLATION; return ResponseEntity.status(errorCode.getStatusCode()) .body( - ApiResponse.builder() + ApiResponse.builder() .code(errorCode.getCode()) .message(errorCode.getMessage()) .build()); } @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class) - ResponseEntity handleHttpRequestMethodNotSupportedException( + ResponseEntity> handleHttpRequestMethodNotSupportedException( HttpRequestMethodNotSupportedException exception) { ErrorCode errorCode = ErrorCode.NOT_FOUND; return ResponseEntity.status(errorCode.getStatusCode()) .body( - ApiResponse.builder() + ApiResponse.builder() .code(errorCode.getCode()) .message(errorCode.getMessage()) .build()); } @ExceptionHandler(value = MethodArgumentNotValidException.class) - ResponseEntity handleValidation(MethodArgumentNotValidException exception) { + ResponseEntity> handleValidation(MethodArgumentNotValidException exception) { String enumKey = exception.getFieldError().getDefaultMessage(); ErrorCode errorCode = ErrorCode.INVALID_KEY; @@ -116,7 +128,7 @@ ResponseEntity handleValidation(MethodArgumentNotValidException exc } catch (IllegalArgumentException e) { } - ApiResponse apiResponse = new ApiResponse(); + ApiResponse apiResponse = new ApiResponse<>(); apiResponse.setCode(errorCode.getCode()); apiResponse.setMessage( Objects.nonNull(attributes) diff --git a/bigbid-server/src/main/resources/application-prod.yaml.example b/bigbid-server/src/main/resources/application.yaml.example similarity index 100% rename from bigbid-server/src/main/resources/application-prod.yaml.example rename to bigbid-server/src/main/resources/application.yaml.example