Bài viết được sự cho phép của tác giả Nguyễn Hữu Khanh
Trong bài viết trước, mình đã giới thiệu với các bạn những ý tưởng cơ bản của Clean Architecture. Trong bài viết này, mình sẽ đi vào chi tiết cách hiện thực Clean Architecture với một ứng dụng Java sẽ như thế nào, các bạn nhé!
Ở đây, như các bạn thấy, mình có định nghĩa thêm một package là adapter. Trong idea của Clean Architecture thì lớp adapter sẽ nằm bên ngoài lớp use-cases nhưng ở đây, chúng ta có thể gộp lớp adapter này nằm trong module use-cases cũng được, không cần phải thêm một module adapter để định nghĩa các interface, không cần thiết lắm. Nhưng nếu các bạn muốn follow chặt chẽ idea của Clean Architecture thì có thể introduce thêm module adapter nữa cũng được.
Như các bạn thấy, mình cũng khai báo thêm Hibernate dependency cho phần implementation của JPA và thư viện Lombok để việc định nghĩa các entity đơn giản hơn!
Ở đây, như các bạn thấy, mình có thêm một class là StudentMapper để convert data từ database sang entity và sau đó, nếu entity này được sử dụng ở đâu đó, ví dụ như module rest, chúng ta sẽ có một class Mapper khác để convert từ entity sang dto của rest để trả về cho người dùng.
Việc sử dụng class Mapper này sẽ giúp chúng ta giảm sự phụ thuộc giữa các module với nhau, chúng ta có thể dễ dàng thêm mới hoặc loại bỏ bớt module mà chúng ta sẽ dùng cho ứng dụng, với ít sự thay đổi code nhất.
Module rest
Sau khi đã lấy được data từ database, bây giờ là lúc chúng ta hiện thực module rest, đảm nhận vai trò expose API cho người dùng sử dụng.
Tập tin pom.xml của module rest có nội dung như sau:
Mình sử dụng spring-web dependency để định nghĩa các RESTful API, use-cases dependency để gọi tới các use cases của ứng dung và thư viện lombok chỉ để đơn giản cho việc định nghĩa các dto.
Ở đây, mình đang autowired FindStudentByNameUseCase là do mình đang tận dụng benifit của ứng dụng này với Spring framework, chúng ta sẽ định nghĩa các use cases trong Spring container. Nếu ứng dụng của các bạn sử dụng những framework khác thì việc sử dụng use cases sẽ phụ thuộc vào các framework đó.
Module configuration
Như mình nói, để ứng dụng có thể chạy được, chúng ta cần có module configuration.
Nếu các bạn để ý, mình đã định nghĩa các module rest và db generic nhất có thể, và việc cấu hình ứng dụng trong module configuration sẽ quyết định ứng dụng của chúng ta chạy như thế nào! Ví dụ ở đây, mình đang sử dụng MySQL để chạy ứng dụng, sau này nếu mình muốn chuyển sang một database system khác như PostgreSQL chẳng hạn, việc mình cần làm là chỉ cần thay đổi ở module configuration này mà thôi, …
Tập tin pom.xml của parent project có nội dung như sau:
<?xml version="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.4.RELEASE</version><relativePath/><!-- lookup parent from repository --></parent><groupId>com.huongdanjava</groupId><artifactId>clean-architecture-example</artifactId><version>1.0-SNAPSHOT</version><packaging>pom</packaging><modules><module>rest</module><module>use-cases</module><module>db</module><module>entities</module><module>configuration</module></modules><dependencyManagement><dependencies><dependency><groupId>com.huongdanjava</groupId><artifactId>use-cases</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.huongdanjava</groupId><artifactId>db</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>com.huongdanjava</groupId><artifactId>rest</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.hibernate</groupId><artifactId>hibernate-core</artifactId><version>5.4.22.Final</version></dependency></dependencies></dependencyManagement></project>
Đến đây thì chúng ta đã hoàn thành ứng dụng ví dụ của mình.
Giả sử mình có table student và data được tạo trong database server MySQL như sau:
CREATE TABLE`student`(`id`bigint(20)NOTNULLAUTO_INCREMENT,`name`varchar(50)NOTNULL,`age`bigint(2)NOTNULL,PRIMARY KEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=latin1;INSERT INTO student SET name='Khanh',age=33;
thì khi chạy ứng dụng và request tới http://localhost:9090/student/find?name=Khanh, các bạn sẽ thấy kết quả như sau: