Tải bản đầy đủ (.docx) (28 trang)

Mọi điều cần biết về Spring Framework cơ bản

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.31 MB, 28 trang )

Spring Frame work
1. Kiến trúc cơ bản của một web app được xây dựng bằng
Spring có những gì?
A.
B.
-

Spring Intializer
Là những cơng cụ giúp khởi tạo spring một cách nhanh chóng và tự động
Công cụ sd dễ dàng và phổ biến nhất là starter.spring.io
JPA (Java Persistence API)
JPA là một interface đặc biệt dùng để làm việc với cơ sở dử liệu quan hệ
JPA cung cấp 1 mơ hình POJO cho phép ánh xạ các table với các columns thành các class với
các fields
C. Hibernate
- Hibernate là thư viện ORM mã nguồn mở giúp lập trình viên map các object (POJO) với hệ
quản trị csdl quan hệ. Vì thao tác thơng qua các đối tượng nên Hibernate không cần quan
tâm tới đang sd hệ quản trị csdl nào
D. H2 Databse
- H2 là hệ quản trị csdl được nhúng trực tiếp vào project spring boot với nhiệm vụ để test,
demo JPA và Hibernate
E. Thymeleaf
- Thymeleaf là một Java XML/HTML template engine được sử dụng làm tầng view trong cấu trúc
MVC (tương tự JPA)

2. Dependency Injection with Spring
A. SOLID Principle in OOP
-

-


-

Nguyên lý SOLID là tập hợp 5 nguyên lý giúp code tối ưu và “cứng” hơn trong OOP
Single Responsibility Principle : mỗi class chỉ thực hiện 1 trách nhiệm, nhiệm vụ duy nhất, và chỉ
sửa đổi class với 1 lý do duy nhất
Open/Closed Principle : Có thể thoải mái mở rộng một class nhưng ko được sưa đổi bên trong
class đó. Hiểu đơn giản là khi ta muốn thêm chức năng cho chương trình thì ta tạo class mới mở
rộng từ class cũ (kế thừa hoặc sở hiểu class củ) không nên sửa đổi class củ
Liskov Substitution Principle: Trong 1 chương trình, các object của class con có thể thay thế class
cha mà khơng làm thay đổi tính đúng đắn của chương trình
o Ví dụ: ta có 1 class Vit, các class VitXiem, VitBau kế thừa từ class Vit và chạy bình
thường , tuy nhiên nếu ta thêm class VitMay cần pin mới chạy được. Khi cho VitMay kế
thừa class Vit thì sẽ gây lỗi vì class Vit khơng có pin. Đây là 1 TH vi phạm nguyên lý
Interface Segregation Principle : Thay vì dùng 1 Interface lớn ta nên tách thành nhiều Interface
nhỏ với nhiều mục đích khác nhau và cụ thể
Dependency Inversion Principle:
o Các module (file, class, project..) cấp cao không nên phụ thuộc vào các module cấp thấp.
Cả 2 nên phụ thuộc vào abstaction. Nghĩa là nên có 1 abstraction để kết nối giữa 2
module thay vì 2 module kết nối trực tiếp với nhau


o

Interface (abstraction) không nên phụ thuộc vào chi tiết mà ngược lại.(các class giao
tiếp với nhau thông qua interface chứ không phải implementation). Nghĩa là các
implementation sẽ phụ thuộc vào interface ntn chứ interface sẽ độc lập khỏi
implementation
 Ví dụ : ta có bóng đèn đốt và bóng đèn huỳnh quang (implementation) cả 2
đều có đi trịn (interface) và 2 bóng đến có thể tùy thích đổi chỗ cho nhau
bởi vì ở ghim chỉ quan tâm là đi gì (chỉ quan tâm interface)


B. Dependency Injection
1. Khái niệm Dependency Injection
-

-

-

Dependency (phụ thuộc) : là 2 class có mối quan hệ phụ thuộc với nhau . Ví dụ class A dùng
method của class B, ta gọi đó là sự phụ thuộc hay dependency
Dependeny Injection : là kỹ thuật lập trình cho phép ta inject (tiêm) một dependency vào object
trong quá trình runtime
o Có 3 loại depency injection :
 Construcor injection : các dependency sẽ được cung cấp qua constructor
 Setter Injection : các dependency sẽ được cung cấp qua setter
 Interface Injection
 Trong đó Constructor injection được sử dụng nhiều nhất
IoC (Inversion of Control): là một kỹ thuật đảo ngược điều khiển một cách linh hoạt. Dễ hiểu hơn
thì IoC là kỹ thuật cho phép dependencies có thể được inject trong lúc runtime
Một điều quan trọng về đặc tính của framework đó là những methods do người dùng tự định
nghĩa để thêm vào sẽ khơng được gọi bởi chính framework mà được gọi bởi chính code của
người lập trình. Vai trị chính của framework là phân phối hoạt động của ứng dụng. IoC sẽ cung
cấp cho framework công cụ mạnh mẽ để đối xử với các methods thêm vào từ người dùng
IoC Container : IoC Container là phần dùng để thực hiện IoC

2. ApplicationContext, Bean và Anotation cơ bản trong Spring
-

-


ApplicationContext và bean: Spring Container (Spring IoC Container) sẽ tạo ra các đối tượng
quản lý các đối tượng và quản lý dòng đời của chúng. Các đối tượng này được gọi là Bean. Spring
Container đc dùng phổ biến nhất là ApplicationContext. Hay nói dễ hiểu Spring đặt tên cho
container là AplicationContext và các dependency trong container là bean
Note: hàm SpringApplication.run() trong class App sẽ khởi tạo một Container nên ta có thể dùng
ApplicationContext để lưu container thành 1 biến
@Component: là anotation để chú thích các class giúp Spring nhận diện đó là 1 Bean. Nói cách
khác là khai báo 1 bean cho Spring
Cơ chế tìm bean của Spring: Spring sẽ tìm các class cùng cấp hoặc thấp hơn class App để tìm các
class có anotation component và khởi tạo một object từ class đó và thêm vào bean


-

-

-

-

@Autowired : là anotation để kha báo rằng phương thức hoặc thuộc tính này cần đc inject
từ class bên ngồi. Khi Spring khởi tạo bean từ class có anotation này sẽ tự động inject
object cần thiết vào
Lưu ý : khi Spring chỉ khởi tạo bean 1 lần chính vì vậy khi inject nó sẽ inject chính object đã
được tạo trước đó, muốn Spring inject một object mới thì ta dùng anotation
@Scope("prototype") ngay trước tên class
@Qualifizer : anotation này được dùng khi một bean có nhiều thể hiện khác nhau, vi thế khi
injected spring sẽ ko biết inject thể hiện nào, do đó qualifize sẽ gợi ý cho spring nên injected
thể hiện nào. Syntax : @Qualifizer(“class_name”)

@Primary : primary dùng để set 1 bean thành primary bean, khi mà một bean có nhiều thể
hiện ta có thể set 1 thể hiện là primary khi đó khi injected spring sẽ tự động injected primary
bean vào, nếu muốn injected các thể hiện khác ta dùng @Qualifizer

3. Spring Profile
-

-

-

Profile là một features có trong Spring core được dùng để config app cho từng enviroment
của người dùng. Ví dụ chức năng i18n thì ứng vs một ngơn ngữ thì một bean sẽ được
injected vào, để spring biết được người dùng đó đang dùng ngơn ngữ nào để injected đúng
beans thì cần dùng tới profile
Để set một beans là một profile ta dùng anotation profile
Syntax : @Profile(“profilename”)
Có chế hoạt động như sau : khi Spring chạy nó sẽ đọc trong file
resoures/application.property xem profilename nào đang được áp dụng. Khi biết
profilename nào đang được áp dụng thì Spring sẽ chỉ nhận beans từ những profilename đó
cịn các profilename khác sẽ được phết lờ ko quan tâm bởi spring
Câu lệnh để set profile trong file application.property : spring.profiles.active = profilename
Default Profile : defautl profile là profile mặc định được sử dụng khi người dùng ko có bất kì
config profile nào
o Syntax: @Profile({“profilename”, “default”})

4. Spring Bean Life Cycle
-

Vòng đời của một bean (bean life cycle) là khoảng thời gian từ lúc nó được khởi tạo đến khi

nó bị destoy. Bean life cycle sẽ được quản lý mới container, khi chương trình được chạy thì


đầu tiền container sẽ khởi động và container sẽ khởi tạo beans, và trước khi container tắt nó
cũng sẽ destroy beans

-

-

Trong đó ta có thể can thiệp vào quá life cycle của bean. Ngồi ra ta có thể thấy trong vịng
đời thì có rất nhiêu aware interface. Aware interface được dùng bởi framework để khởi tạo
vịng đời cho beans, thơng thường ltv sẽ ko cần dùng và nghĩ tới đó
Có 3 cách để can thiệp vào vòng đời của beans
o C1: dùng XML (chả ai dùng)
o C2: implement interface BeanPostProcesser và ghi đè 2 methods là
postProcessBeforeInstillization() để truy cập vào khoảng thời gian trước khi object
được tạo từ benas đc khởi tạo và postProcessAfterInstillization() để truy cập vào
khoảng thời gian trước khi destroy bean (dùng rất ít trong thực tể)
o C3: dùng anotation(được dùng nhiều nhất)
 @PostContruct : can thiệp vào khoảng thời gian trước khi object của beans
được khởi tạo
 @PreDetroy : can thiệp vào khoảng thời gian trước khi bean bị phá hủy
 Cơ chế : trước khi khởi tạo object của benas khối code sau @PostContruct sẽ
được thực thi. Và trước khi beans bị destroy thì khối code sau @PreDestroy
sẽ được thực thi

5. Spring Framework Configruation
-


-

Ta có 3 cách để có thể config được spring
o Dùng file XML
o Dùng anotation (@Compenent, @Cnotroller, @Service,...)
o Dùng java class (@Configuration và @Bean để tạo class config)
Trong đó dùng java class được sd phổ biến

A. Spring Framework Stereotypes
-

Spring Stereotypes là những Anotation được dùng để định nghĩa Bean này có chức năng cụ
thể gì
Gồm 3 stereotypes anotation chính
o @Controller : định nghĩa bean này là controller có chức năng điều hướng các request
o @Service : định nghĩa bean này là service có chức năng thực hiện các nghiệp vụ logic


@Repository: định nghĩa bean này là respo có chức năng giao tiếp với DB, thực hiện
các querry theo yêu cầu của Service(tương tự như DAO)
Nếu chưa rõ chức năng của bean ta có thể dùn @Component chỉ để biến nó thành bean
o

-

B. Component Scan
-

-


-

Cơ chế mặc định của spring khi khởi tạo bean là nó sẽ scan các class cùng cấp hoặc thấp cấp
hơn file app
Nếu muốn thay đổi hành vi mặc định của Spring đẻ class ở vị trí khác hay cụ thể là cao cấp
hơn file app thì ta dùng anotation @ComponentScan hoặc sử dụng scanBasePackages tromg
@SpringBootApplication.
Syntax:
o @ComponentScan(“className”) hoặc @Component({“className1”, “className2”})
o @SpringBootApplication(scanBasePackages = “className”) hoặc
@SpringBootApplication(scanBasePackages = {“className1”, “className2”})
Trong đó : className là tên file muốn biến thành bean

C. Dùng Java class để Config Bean
-

Trong thực tế đôi khi để config cho bean thì ta tự tay tạo ra một class để cấu hình cho spring
giúp ta dễ dàng handle được beans hơn
Để có thể dùng java class để config spring ta dùng 2 anotation là @Configuration và @Bean
@Configuration để cho spring biết đây là class config
@Bean là anotation nằm trên các methods cho phép spring biết được đây là bean và thực
hiện đưa bean này vào content
Ví dụ :

D. Dùng XML để Config Bean
-

Để config bean bằng file XML ta tạo 1 file mới trong folder resources và dùng tag bean
Syntax : <bean name=”className” class=”path”/>
Trong đó : className là tên class muốn biến thành bean và class là đường dẫn tới class đó

Sau khi khai bào file XML xong, ta import file XML vào file app để spring biết được là ta muốn
dùng thêm XML nào
Syntax: @ImportResources(“classpath:fileName”)

E. Spring Bean Scope
-

Scope của một bean là nơi định nghĩa vòng đời, và cách nó được khởi tạo và quản lý bởi IoC
trong 1 ngữ cảnh cụ thể. Có 6 kiểu scope
o Singleton
o Prototype
o Request
o Session
o Application
o Websocket


-

-

Singleton scope là scope mặc định của một ứng dụng spring. Một bean được đn với
singleton scope sẽ khiên IoC container khởi tạo duy nhất 1 instance cho bean đó, và instance
này sẽ được sd cho tất cả yêu cầu đến bean
o Syntax khai báo singleton scope : @Scope(“singleton”) hoặc để mặc định ko cần khai
báo
Prototype scope sẽ trả về các instance khác nhau mỗi khi có một yêu cầu mới để sử dụng
chúng đc gửi về IoC Container
o Syntax : @Scope(“prototype”)


6. External Properties với Spring Framework
A. External Properties
-

-

-

Để import các properties từ bên ngoài vào spring và sử dụng nó gán cho object thì ta dùng
đến @PropertypeSource và @Value
Đầu tiên ta cần phải có 1 file .properties improt từ bên ngồi hoặc tự tạo. Nội dung file đó
chính là các cặp key – value chứa dữ liệu để đưa vào spring, các key phải được đặt tên có dấu
chấm (.)
o Ví dụ:

Để đọc được data từ file .properties trước tiên ta dùng @PropertypeSource để khai báo ta
muốn đọc từ file nào
o Syntax: @PropertypeSource(“classpath:fileName”)
o Lưu ý : anotation này dùng bên dưới @Confiuguration
Để gán giá trị cho từng properties của class thì ta dùng @Value, anotation này nằm trên một
biến bất kỳ và nó sẽ lấy data trong file .properties và gán cho biến bên dưới nó
o Syntax: @Value(“value”)
o Nó sẽ gán value cho biến bên dưới vì thế để đọc được dữ liệu từ file .properties thì
ta dùng ${} kết hợp với tên key của giá trị đó.
o Synatx: @Value(“${key}”)

B. Multi Properties Files
-

Để thêm nhiều .properties file vào 1 class ta có 2 cách

Cách 1: nối thêm vào @PropertypeSource
o Syntax: @PropertypeSource({“classpath:fileName1”, “classpath:fileName2”})
Cách 2: dùng @PropertypeSources chứa nhiều @PropertypeSource nhỏ khác
o Syntax: @PropertypeSources {
@PropertypeSource(“classpath:fileName1”)
@PropertypeSource(“classpath:fileName2”)
}

C. Dùng Spring Boot để exernal properties
-

Spring Boot cung cấp cho ta khả năng external properties thông qua file
application.properties


-

Ta chỉ cần ghi dữ liệu vào application.properties và dùng @Value thì Spring Boot sẽ tự động
đọc từ application.properties để gán giá trị cho biến nằm dưới @Value, không cần dùng đến
@PropertypeSource và file .properties nào khác

D. YAML
-

-

Yaml là một dạng file định dạng dữ liệu trung giang được thiết kế để người dùng và nnlt có
thể hiểu được. Yaml chính là JSON nhưng mở rộng hơn
Các quy tắt khi viết Yaml
o Thục đầu dịng dùng spacebar khơng dùng tab

o Để viết một list các danh sách hay chính là mảng thì dùng “-” trước mỗi phần tử của
mảng
o File yaml có đi là yml
Ví dụ một file yml

-

Một số operate tùy chỉnh trong yml

-


-

Note: Để spring Boot tự động độc file yml như 1 properties file thì ta đặt tên file là
application.yml thì khi đó file này sẽ hđ tương tự như application.properties
o

Ví dụ 1 file application.properties chuyển sang application.yml

E. Note và tóm lại
-

Note: Vì các file tên là application (.properties/.yml) sẽ được chạy đầu tiên, nên các file khác
có thể ghi đè lên. Lý do vì sao các file khác ln ghi đè lên các file application


-

Tóm lại: để đọc được các properties từ bên ngồi và chèn vào spring thì ta có 3 cách

o

Dùng file .properties và @Value và @PropertyResouce

o

Dùng file application.properties của Spring Boot và @Value

o

Dùng application.yml và @Value

7. Thymeleaf
A. Thymeleaf cơ bản
-

Thymeleaf là một template engine trong java có nhiệm vụ generate ra HTML/XML,… (đóng
vai trị là tầng view tương tự như JSP và dễ dàng dùng và hơn JSP)

-

Đầu tiên để khai báo 1 file HTML sử dụng Thymeleaf ta cần khai báo xmlns trong thẻ html

-

o

Syntax: <html lang="en" xmlns:th="">

o


Khi này ta mới có thể sử dụng các attribute của Thymaleaf

Cú pháp của Thymaleaf sẽ là các attribute nằm trong thẻ html và bắt đầu bằng th:
o

Ví dụ: thuộc tính th:text sẽ ghi vào nội dung của thẻ đó

B. Model object
-

Model là một object sẽ được Spring gắn kèm với request

-

Điều này sẽ giúp ta có thể thêm dữ liệu lên request thông qua model

-

Để thêm dữ liệu vào model ta dùng phương thức .addAttribute()

-

o

Syntax: model.addAttribute(“ten_bien”, “value”)

o

Trong đó : tên_biến với giá trị là value sẽ được thêm vào model và khi nào cần dùng

tới biến này ta chỉ việc gọi ra thông qua tên_bien

o

Tương tự setAttribute bên Servlet

Tại Thymeleaf để đọc dử liêu từ model ta dùng standard expression
o

${tên_bien} : để lấy giá trị của tên_biến

o

*{tên_biến}: lấy giá trị của một biến được chỉ định

o

#{…} : để lấy massege

o

@{…} : để lấy đường dẫn URL

C. @RequestMaping, @GetMaping và @PostMaping
-

Cả @GetMaping và @PostMaping đều là anotaion giúp controller gửi request cho Thymeleaf.
Chỉ khác là một cái dùng method get một cái dùng method request

-


Cịn @RequestMaping có thể sử dụng cả 2 methods

-

Cấu trúc của một phương thức để gọi tới Thymaleaf như sau


-

Trong đó:
o

@GetMaping hoặc @PostMapping sẽ nhận tham số là các chuỗi đường dẫn đến
Thymaleaf đó. Như ví dụ trên thì đường dẫn đến index sẽ là localhost:8080/ hoặc
localhost:8080 hoặc localhost:8080/index

o

@GetMaping hoặc @PostMapping sẽ được dùng trên một phương thức String và
return của phương thức đó chính là tên file Thymaleaf muốn gọi tới

o

Phương thức bên dưới @GetMaping hoặc @PostMapping có thể nhận tham số là
Model để có thể add thêm dữ liệu vào Model để gửi đi cho Themyleaf

D. Cơ chế
-


Ta có thể thấy đường đi của request trong hình sau

E. Spring Dev Tool
-

Spring cung cấp một côn cụ là Dev Tool cho phép việc restart project khi đang code một cách
nhanh chóng

-

Ta chỉ cần chọn phần build/Build Project để dùng Spring Dev Tool restart project

F. Gửi datat từ Thymeleaf cho Contoller
-

Có 2 cách ta có thể gửi dữ liệu từ Thymeleaf cho Controller


-

-

Đầu tiên ta có thể dùng th:name và th:value cho tag đó (tương tự JSP)
o

Cơ chế : ta sẽ dùng th:name để đặt tên cho tag đó khi gửi qua request và dùng
th:value để set giá trị cho th:name. Nếu một tag input chỉ có th:name thì value của
nó là nội dung trong phần input người dùng nhập

o


Ở Controller thì ngay methods bên dưới RequestMaping ta thêm tham số cho
methods đó là data ta nhận đc từ request. Lưu ý ta cần dùng @RequestParam để
khai báo rằng đây là dử liệu nhận từ Thymeleaf và tham số của @RequestParram là
th:name của data đó

o

Ví dụ:

o

Trong đó @RequestParam sẽ scan trong request có param nào có tên là tittle khơng
nếu có nó sẽ lưu vào biến title

Cách 2 là ta dùng th:object và th:fields để gửi dữ liệu dưới dạng object
o

Cơ chế : ở Controller ta gửi kèm 1 object rỗng của object ta muốn thêm dử liệu, ở
Thymeleaf ta dùng th:object và th:field để thêm dử liệu cho object đó và đồng thời
gửi đi dữ liệu dưới dạng object

o

Để nhận object từ thymeleaf tại controller thì ta dùng @ModalAttribute

o

Ví dụ:


o

Trong đó ta thấy : recpie là một object

G. Gửi request kèm id
-

Để gửi request từ thymeleaf sang controller có kèm id ta có thể sử dụng tốn tử “+” một
biến vào sau url

-

Đây là ví dụ:

o
-

Trong đó hàm getID sẽ lấy id và cộng vào url gửi về cho controller

Tại controller muốn lấy giá trị id này ra ta dùng @PathVariable() và tại url của anotation
maping ta thêm expresion operater để bao lấy phần biến


o

Ví dụ:

o
o


Trong trường hợp ta truyển nhiều biến qua url thì có thể dùng thêm
@PathVariable(name = “ten_bien”)

8. JPA và Hibernate
A. Khái niệm cơ bản của JPA
-

JPA là một interface đặc biệt dùng để làm việc với cơ sở dử liệu quan hệ

-

JPA cung cấp 1 mơ hình POJO cho phép ánh xạ các table với các columns thành các class với
các fields
POJO là một class Java thuần trong đó mỗi thuộc tính đề có getter setter và tất cả thuộc tính
đều private

-

-

Fetch type là cách dữ liệu được query, có 2 kiểu fetch type
o

Lazy fetch type: dữ liệu sẽ ko đc querry mãi cho đến khi nó đc tham chiếu

o

Eager fetch type : dữ liệu sẽ được querry ngay từ đầu

@Lob : là anotation giúp tăng giá trị lưu trữ của một kdl


B. Undirectional và Bidirectional
-

Undirectional hay mối quan hệ một chiều : là khi 2 table có mqh với nhau nhưng chỉ 1 table
biết nó có liên hệ với table kia, cịn table kia thì ko hề biết bảng nào có liên hệ với nó (oneway)

-

Bidirectional hay mqh 2 chiều: nghĩa là cả 2 table đều biết chúng có mqh với nhau

-

Thông thường nên sd bidirectional để giúp ta điều hướng object từ cả 2 hướng

C. Cascade Type
-

Khi một bản ghi thay đổi thì nó tự động update các bản ghi tham chiếu tới nó. Điều này được
gọi là cascade

-

Để khai báo loại cascade trong Spring ta khai báo trong phần tham số sau anotation thể hiện
quan hệ của JPA (@OnetoMany , @ManytoMany,...)

-

Các loại cascade



-

Syntax : @OnetoMany/ManytoMany/ManytoOne (cascade = Cascadetype.type)
o

Trong đó type là các kiểu cascade ở bảng trên

D. @Entity và @OnetoMany/ManytoMany/ManytoOne
-

@Entity để khai báo rằng POJO này là một thực thể

-

@OnetoMany/ManytoMany/ManytoOne đc dùng trên các thuộc tính (thuộc tính này là
instance của 1 entity) và để khai báo rằng mqh của entity này với entity hiện tại. Hay dễ hiểu
là thể hiện mối quan hệ giữa các entity
o

-

Ví dụ:

Đối với @OnetoMany và @ManytoMany vì entity này sẽ có quan hệ với một tập hợp nhiều
entity khác nên khi khai báo phải khai báo một list, set, array....(best practise là set vì set sẽ
ko cho phép trùng dữ liệu)
o

Tips : ta có thể khai báo một new HashSet() rỗng để tránh exception nullPointer


o

Ví dụ:


-

MappedBy : ở ví dụ trên ta thấy từ khóa mappedBy từ khóa này giúp thiết lập một mqh 2
chiều, tức là cả 2 đều sẽ biết nó có mqh với nhau ntn. Giá trị của mappedBy sẽ là tên của
phương thức mà entity phía bên kia lưu cho entity này, MappedBy thường đi kèm với
OnetoMany và ManytoMany

-

Ngoài ra ta có thể dùng @Id để khai báo rằng thuộc tính này là Id và kèm theo
@GenerateValue(strategy = GenerationType.INDENTITY) để khai báo rằng id sẽ tự động tăng
thêm khi có record mới và giá trị trong id là độc nhất (tương tự AUTO_INCREMENT trong
SQL)

E. Enum
-

Enum hay cụ thể là Enumerate là một Java class trong đó các thuộc tính của enum đều là
một hằng số (nó được gán là public static final sẵn ta chỉ cần khái báo tên). Để khai báo enum
ta thêm từ khóa enum trước tên class

-

Ví dụ:


-

Trong JPA để ánh xạ một Enum thành một table thì ta dùng @Enumerate tại class mà tham
chiếu tới enum, ko dùng trực tiếp tại enum

-

Có 2 loại dữ liệu để JPA ghi enum xuống database

-

o

Dùng ORDINAl : nghĩa là có thứ tự , nó sẽ chỉ lưu thứ tự của Enum khi ghi xuống
database (kiểu này nếu ta thêm một biến vào enum thì sẽ có lỗi)

o

Dùng STRING: kiểu này nó sẽ lưu giá trị của enum xuống db thay vì thứ tự (nên ta có
thể thêm sửa xóa enum tùy thích)

Ví dụ:

F. Hiểu hơn mối quan hệ và mappedBy thông qua mối quan hệ
nhiều - nhiều
-

Ở mối quan hệ nhiều nhiều thì chỉ cần khai báo anotation thì JPA sẽ tự động join ra một table
mới trong db để thực hiện mối quan hệ


-

Tuy nhiên nếu cả 2 entity đều có @ManytoMany thì mặc định JPA sẽ join ra 2 bảng tương
ứng với 2 anotation ở 2 entity, để hạn chế điều đó ta dụng từ khóa mappedBy

-

Hiểu sâu hơn mappedBy có chức năng ngăn JPA join ra thêm table dư thừa, mappedBy sẽ nói
cho JPA biết là thuộc tính này của entity đã đc join với thuộc tính ở entity khác rồi, nên ko
cần join thêm bảng mới nữa. Đó cũng chính là lí do vì sao giá trị của mappedBy sẽ là tên
thuộc tính của entity hiện tại trong entity phía bên kia


-

Để đổi tên bảng join mới ta dùng @JoinTable(name= ”new_name”) và @JoinColumns(name
= “new_name”) để đổi tên cột trong Join table này và lưu ý tên ko đc cách nhau bằng dấu
cách mà phải cách nhau bằng dấu underscore (_)

-

Ví dụ:
o

Phía đc mappedBy

o

Phía mappedBy


o

Ta có thể thấy giá trị trong mappedBy là categories chính là tên thuộc tính bên phía
được mappedBy. Ý muốn nói là enity Category chính là thằng categories trong Recipe

G. Khởi tạo dữ liệu cho db
-

Để khởi tạo dữ liệu cho db đầu tiên ta cần 1 file schema.sql để tạo bảng và một file data.sql
để insert dữ liệu. Cả 2 file sẽ phải nằm ở /resources

-

Để có thể sử dụng đồng thời 2 file ta khai báo thuộc tính này trong application.properties

-

Ví dụ về 2 file:
o

File schema.sql


o

-

File data.sql


Và đây là kết quả

H. JPA Repository
-

Để có thể thực hiện query dữ liệu bằng jpa thì ta tạo một interface đgl Repository và extends
lại interface CRUDRepository hoặc JPARepository 2 interface này sẽ cung cấp một số
methods giúp ta querry với db.


-

CRUDRepository sẽ nhận 2 tham số kdl: 1 là POJO cảu table muốn lấy dữ liệu và 2 là kdl của
thuộc tính id của POJO đó

-

Ví dụ ta muốn lấy dữ liệu từ bảng catagory thì ta khai báo như sau:

-

Ngoài ra ta thêm @Repository để giúp Spring hiểu

I. Optional
-

Optional dễ hiểu là một container bao bọc một class. Nếu class nó bao bọc Null thì Optional
sẽ ko quăng ra Exception mà chuyển giá trị null đó thành 1 giá trị khác

-


Optional được sd trong JPA để đảm bảo querry dữ liệu nếu hơng lấy đc dữ liệu thì vẫn hơng
quang Exception, ứng dụng vẫn chạy bình thường

I. Querry Data with JPA
-

Như đề cập ở trên thì interface CRUDRepository sẽ cung cấp cho ta một số method querry
với db. Trong đó có findById là sẽ querry theo Id

-

Ngồi ra ta có thể ghi đè thêm 1 số phương thức giúp ta querry dễ dàng hơn. Bằng cách
dùng Optional và tên methods có dạng findByColumns_name

-

Ví dụ :

o

Trong đó ở methods trên ta sẽ find dựa trên description và nó nhận vào một String
để có thể find

-

Khi đã có methods tiếp theo ta sẽ gọi tới để sử dụng. Để gọi ta ta cần phải inject repository
muốn dùng vào. Và để đọc dữ liệu ta dùng methods get(). Get() sẽ giúp ta convert từ
optional sang object


-

Ví dụ : (ở vd này ta inject vào controller)


o

Trong đó:


Ta sẽ find ra category có description là America và uom có desciption là
Teaspoon



Sau đó để đọc dữ liệu lấy được ta dùng hàm get(). Ở VD trên ta kèm theo
getId() để đọc id

9. Lombok
-

Lombok là gì: lombok là một thư viện của java giúp tự sinh code như tự sinh setter/getter,
constructor,… thông qua anotation

-

Để dùng đc lombok trong dự án ta phải khai báo nó trong file pom.xml

-


Một số anottaion thường dùng của Lombok:

-

o

@Getter/Setter : để tự tạo getter setter ta có thể dùng trước thuộc tính để chỉ áp
dụng cho thuộc tính đó hoặc dùng trước một class để áp dụng cho tồn bộ thuộc
tính trong class

o

@NoArgsConstructor : tạo Constructor rỗng

o

@RequiredArgsConstructor : khởi tạo Constructor cho các thuộc tính final hoặc được
đánh dấu nà @NonNull

o

@AllArgsConstructor : khởi tạo Constructor cho tất cả thuộc tính

o

@ToString : khởi tạo hàm toString

o

@EqualsAndHashCode : khởi tạo hàm Equals và HashCode


o

@Date : là kết hợp của các anotation trên

o

@Slf4j : để ghi file log

Khi JPA có quan hệ 2 chiều thì tại @EqualsAndHashCode sẽ sinh ra lỗi tràn bộ nhớ. Để khắc
phục ta thêm exclude = “tên thuộc tính 2 chiều” là tham số cho @EqualsAndHashCode

10. Testing Spring Application
A. Các khai niệm cơ bản trong Testing
-

Test fixture : là một trạng thái cố định của tập các object được dùng như cơ sở cho việc
testing. Mục đích của test fixture để đảm bảo rằng có một enviroment cố định để chạy các
test vì thế kết quả có thể lặp lại. Nó bao gồm:
o

setUp() : method sẽ được thực thi khi bắt đâu test

o

tearDown() : method sẽ được thực thi khi kết thúc test


-


Unittest : là một loại kiểm thử phần mềm trong đó các unit của phần mềm được kiểm thử.
Kiểm thử đơn vị được thực hiện trong quá trình phát triển ứng dụng. Mục tiêu của Unit test
là cô lập một phần code và xác minh tính chính xác của đơn vị đó.

-

Intergration Test : được thiết kế để test hành vi giữa các đối tượng và một phần của hệ
thống. Nó sẽ chậm hơn unit test

-

Functional Test : về cơ bản dễ hiểu là sẽ test thử quá trình chạy của application, có thể test
được các feature chỉ có trong quá trình chạy như db connection, driver,…

-

TDD – Test Driven Development (Phát triển hướng kiểm thử): nghĩa là test được viết trc, nếu
fails thì fix lại test sau

-

BDD – Behavior Driven Development (Phát triển hướng hành vi): có nguồn gốc từ TDD và nó
sẽ chỉ định các test của bất kỳ unit nào trong phần mềm sao cho phù hợp với hành vi mong
muốn của unit đó

-

Mock : là một implementation giả của 1 class bất kỳ đc dùng để test

-


Spy : là một mock đặc biệt, nó cho phép ta overide lại method đã chọn trong real class

B. Dùng JUnit để test Spring Framework
-

Để dùng JUnit thì ta phải khai báo trong dependences của pom. Tuy nhiên Spring itializer đã
khai báo sẵn cho ta

-

Để khởi tạo file test cho 1 class ta bơi đậm tên class đó , nhấn vào icon đèn và nhấn create
test

-

@BeforeEach và @BeforeAll :

-

o

@BeforeEach : sẽ chạy methods bên dưới anotatin này trước mỗi 1 test

o

@BeforeAll : sẽ chạy methods bên dưới anotatin này, sau đó chạy tất cả cá test sau
(nghĩa là chỉ chạy method dưới anotation này 1 lần duy nhất)

Ví dụ về 1 test:



o

Trong đó ta có thể thấy :

o

@BeforeEach được dùng cho hàm setUp để nó khởi tạo object trước mỗi lần chạy
test

o

AsserEquals() : dùng để kiểm tra 2 giá trị có bằng nhau ko, nếu bằng nhau thì test
passed

C. Mockito
-

Mockito là 1 thư viện giúp JUnit có thể dùng mock

-

Khi ta muốn test 1 class có DI thì ta phải tiêm dependency vào, tuy nhiên đây chỉ là test nên
ta ko thể tiêm dependency real. Chính lúc này mock xuát hiện giúp ta fake dependency và
inject vào

-

Để khai báo 1 thuộc tính là mock ta dùng @Mock


-

Để khởi tạo Mock ta dùng methods Mock.mock(“tên_class”.class) trong hàm setUp

-

Ví dụ:


-

Ta có thể thực hiện test như bth, tuy nhiên tất cả giá trị trong mock class đều là rỗng. Nên để
giả lập giá trị cho mock ta dùng when().thenReturn()
o

Syntax: when(class.methods).thenReturn(value)

o

Câu lệnh trên sẽ giả lập giá trị trả về của methods là value

-

Ví dụ:

-

Ở ví dụ trên ta có thể thấy, ta giả lập giá trị trả về của findAll() là một hashSet ta tự khai báo ở
trên


-

Ngoài ra Mockito cịn có methods verify giúp ta kiểm tra số lần methods giả lập đc gọi
o

Syntax: verify(mockClass, times(int)).methods

o

Trong đó : nó sẽ kiểm tra methods giả lập của mockClass được gọi tới bao nhiều lần
néu đúng thì passed test

D. MockMVC
-

Spring boots cũng cung cấp cho ta một thứ để test các layer đó là MockMVC (ko biết chắc
hay ko nhưng MockMVC thường đc dùng để test các request đến controller)

-

Để khởi tạo một mockMVC ta dùng MockMVCBuilders
o

Syntax: MockMvc nameMock =
MockMvcBuilders.standaloneSetup(name_Controller).build();


-


Ta dùng methods perform để giả lập một đường request tới controller
o

Syntax: nameMock.perform(get(“url”))

o

Trong đó methods get() sẽ giúp ta truyền request đến url cụ thể

-

Ta dùng các medthods andExpect để kiểm thử

-

ví dụ về một MockMVC:

o

Trong đó ta dùng :


Status().isOK() : để kiểm tra tình trạng kết nối



View().name(“view_name”) : để kiểm tra có trả về view giống như mong
muốn ko

E. Intergration Test

-

Ở các phần trên ta đều dùng unit test với mock. Tuy nhiên với intergration test ta sẽ inject
bean thật vào để test, nên sẽ ko cần dùng đến mock mà ta phải injected bean vào (ko biết
chắc hay ko nhưng hình như dùng để test JPA hay rộng hên là repo)

-

Đầu tiên ta có các anotation nằm ở đầu class
o

@RunWith(SpringRunner.class) : vì ta dùng feature của Spring Boots Test nên bắt
buộc ta phải có anotation này để làm cầu nối với JUnit (JUnit5 thì bị thay thành
@ExtendWith(SpringExtension.class))

o

@SpringBootTest : như đã nói ở trên vì ta sẽ inject bean thật nên ta cần phải khởi
tạo bean. Đó cũng chính là công dụng của anotation này, anotation này sẽ khởi tạo
cả application để có thể lấy đc các bean

o

@DataJpaTest: giúp ta set up đầy đủ mọi thứ để test JPA (thơng thường có
@DataJpaTest thì ko có @SpringBootTest)

-

Vì cần inject nên ta dùng @Autowired để inject, cịn lại thì ta test như unit test bình thường


-

Ví dụ về một Ingretion Test:


-

Trong đó ta có thể thấy:
o

Repo là bean đc inject vào

o

Và trong JUnit 5 thì ko cần @RunWith

F. Circle CI
-

Cirlce CI là dịch vụ test project sẵn, tham khảo tại />
11. CRUD with Spring MVC
A. Data Binding in Spring MVC
-

Command Oject / Backing Bean : là một object POJO được dùng để lấy tất cả thông tin từ
form ở tầng view. Khi ta nhấn submit ở form thì data đầu tiên sẽ đc gửi đến đây, và khi ta
hiển thị thơng tin ra form ta cũng dùng command object
o

-


Ví dụ:

Convert Object : là object phụ trách nhiệm vụ chuyển data từ form vào entity và ngược lại
o

Để tạo 1 Convert Object thì ta phải implement Converter<S, T> của pakcage
springframework.core.convert


Ta có thể thấy 2 tham số của interface Converter là S nghĩa là object muốn
chuyển đổi và T là object muốn chuyển đổi thành


o

Vì Convert Object được dùng trong inject nên ta khai báo @Component để biến nó
thành bean

o

Ví dụ về Convert Object:

-

Data Binding : spring sẽ tự động map các dữ liệu ở form sao cho trùng khớp với command
object, điều này đgl data binding hay phụ thuộc dữ liệu. Ví dụ : nếu ta nhập trường fullName
của form thì trường này sẽ đc tự động map với properties fullName của command object

-


Lưu ý : nếu command object có dữ liệu liên quan đến object khác thì ta dùng command
object của object đó để thay thể, đảm bảo tính nhất qn dữ liệu

12. Exception Handle
-

Để handle các exception thì Spring cung cấp cho ta 3 cách
o

Dùng @ResponseStatus : để thay đổi http status code theo ý muốn mỗi khi có
exception

o

SimpleMappingExceptionResolver : dùng để map một exception với 1 view

o

@ExceptionHandler : cho phép ta thực hiện đc cả 2 việc trên

A. @ResponseStatus
-

@ResponseStatus : sẽ cho phép ta thay đổi http status code mỗi khi exception được throw

-

Anotaion sẽ thường đc đặt trên 1 class exception ta tự định nghĩa


-

Ví dụ về 1 class dùng @ResponseStatus


-

Trong đó : khi NotFoundException được throw thì thay vì hiện status code là 500, ta đã dùng
@ResponseStatus để thay nó thành 404 – Not Found

B. @ExceptionHandler
-

@ExceptionHandler là antotaion đc dùng trong controller, khi có exception tương ứng đc
throw nó sẽ truyển request qua anotaion này và anotaion này sẽ chuyển hướng tới 1 view .
Hay nói cách khác là map exception với view

-

@ ExceptionHandler sẽ nhận tham số là ExceptionName.class nghĩa là ta sẽ khai báo cho
Spring biết rằng khi có ExceptionName đc throw thì methods bên dưới anotation này đc gọi

-

Ví dụ

-

Trong đó ta có thể thấy class ModelAndView cho phép ta handle Model và View sẽ được
redirect tới


-

Ngồi ra ta có thể truyển Exception object vào methos trên và chuyển nó sang cho view để
view lấy ra messeeg.

-

Ví dụ:


×