[Spring] ์คํ๋ง ์์ PetClinic ํ๋ก์ ํธ ๋ถ์ ๋ฐ ๊ธฐ๋ฅ ๋ณ๊ฒฝ
1. ํ๋ก์ ํธ ๋ก๊ทธ ๋ ๋ฒจ ๋ณ๊ฒฝ
๋ก๊ทธ๋ฅผ ํตํด ํ๋ก์ ํธ์ ์คํ ํ๋ฆ์ ์ดํด๋ณผ ์ ์๋ค.
PetClinic ํ๋ก์ ํธ๋ ๊ธฐ๋ณธ ๋ก๊ทธ ๋ ๋ฒจ์ด INFO๋ก ๋์ด์์ด์ ์์ธํ ๋ก๊ทธ๋ฅผ ํ์ธํ ์ ์๋ค.
์ดํ๋ฆฌ์ผ์ด์ ์์ ์ด๊ฒ์ ๊ฒ ๋๋ฌ๋ด๋ ๋ฑํ ์ถ๋ ฅ๋๋ ๋ก๊ทธ๊ฐ ์๋ค.
๋ก๊ทธ ๋ ๋ฒจ์ DEBUG๋ก ๋ณ๊ฒฝํ์.
Spring boot ํ๋ก์ ํธ๋ src/main/resources/application.properties ํ์ผ์ ๋ก๊ทธ ๋ ๋ฒจ์ ์ค์ ํ๋ค.
application.properties
1
2
3
|
# Logging
#logging.level.org.springframework=INFO
logging.level.org.springframework.web=DEBUG
|
cs |
๊ธฐ์กด์๋ logging.level.org.springframework=INFO๋ก ์ค์ ๋ผ์๊ณ ๊ทธ ์๋ logging.level.org.springframework.web=DEBUG๋ ์ฃผ์์ฒ๋ฆฌ๊ฐ ๋์ด์๋ค.
๋ก๊ทธ ๋ ๋ฒจ์ DEBUG๋ก ๋ฐ๊พธ๊ธฐ ์ํด ์์ ๊ฐ์ด ...INFO๋ฅผ ์ฃผ์์ฒ๋ฆฌํ๊ณ ...DEBUG์ ์ฃผ์์ฒ๋ฆฌ๋ฅผ ํ์ด์ค๋ค.
๊ทธ๋ฆฌ๊ณ PetClinic์ ์ฌ์คํํ๋ฉด,
์ด์ ์์ธํ DEBUG ๋ก๊ทธ๊ฐ ์ถ๋ ฅ๋๊ธฐ ์์ํ๋ค.
2. ํ๋ก์ ํธ ํ๋ฆ ๋ถ์
ํ๋ก์ ํธ๋ฅผ ์คํํ๋ฉด DispatcherServlet์ด ์ด๊ธฐํ๋๋ค.
FIND OWNERS๋ฅผ ํด๋ฆญํด๋ณด์.
์์ฒญ URL์ด /owners/find๋ก ์ ์ก๋๋ค.
๋ก๊ทธ๋ฅผ ๋ณด๋ฉด DispatcherServlet์ด ํด๋น GET "/owners/find" ์์ฒญ์ ๋ฐ์ ๋ด๋น ์ปจํธ๋กค๋ฌ์ธ OwnerController๋ฅผ ํธ์ถํ๋ค.
OwnerController์ initFindForm()์ @GetMapping ์ด๋ ธํ ์ด์ ์ผ๋ก "/owners/find"์ด ์ง์ ๋์ด ์๋ค.
"/owners/find" URL๋ก GET ์์ฒญ์ด ์ค๋ฉด ์ด ๋ฉ์๋์ ๋งคํํ๋ค๋ ์๋ฏธ์ด๋ค.
initFindForm()์ owners/findOwners ๋ทฐ๋ฅผ ๋ฆฌํดํ๋ค.
์ด ๋ทฐ ํ์ผ์ ํ๋ก์ ํธ resources/templates/owners/findOwners.html์ ์๋ค.
findOwners ๋ทฐ๊ฐ ์ด ํ๋ฉด์ ํด๋นํ๋ค.
๋ค๋ฅธ ๊ธฐ๋ฅ๋ ์ด์ ๊ฐ์ด ๋ถ์ํ๋ฉด ๋๋ค.
3. ๊ธฐ๋ฅ ๋ณ๊ฒฝํ๊ธฐ
1) FIND OWNERS ๋ฉ๋ด์์ Last name์ First name์ผ๋ก ๋ณ๊ฒฝํ๊ธฐ
PetClinic ํ๋ก์ ํธ์๋ ์ด๋ฏธ owner๋ค์ ๋ฐ์ดํฐ๊ฐ ๋ฑ๋ก๋์ด ์๋ค.
๊ฒ์์ ์์ฒญํด์ ์์ฒญ URL๊ณผ ๋ก๊ทธ๋ฅผ ํ์ธํด๋ณด์.
Jean Coleman์ด๋ผ๋ ์ด๋ฆ์ owner๊ฐ ์กด์ฌํ์ง๋ง ํ์ฌ๋ Last name์ ๊ฒ์ํ๋ฏ๋ก ๊ฒฐ๊ณผ๊ฐ ๋์ค์ง ์๋๋ค.
๋ก๊ทธ๋ฅผ ํตํด owner ๊ฒ์ ์์ฒญ ์ OwnerController์ processFindForm()์ด ์ฒ๋ฆฌํ๋ค๋ ๊ฒ์ ์ ์ ์๋ค.
ํด๋น ๋ฉ์๋์ ๋ด์ฉ์ ๋ค์๊ณผ ๊ฐ๋ค.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@GetMapping("/owners")
public String processFindForm(Owner owner, BindingResult result, Map<String, Object> model) {
// allow parameterless GET request for /owners to return all records
if (owner.getLastName() == null) {
owner.setLastName(""); // empty string signifies broadest possible search
}
// find owners by last name
Collection<Owner> results = this.owners.findByLastName(owner.getLastName());
if (results.isEmpty()) {
// no owners found
result.rejectValue("lastName", "notFound", "not found");
return "owners/findOwners";
}
else if (results.size() == 1) {
// 1 owner found
owner = results.iterator().next();
return "redirect:/owners/" + owner.getId();
}
else {
// multiple owners found
model.put("selections", results);
return "owners/ownersList";
}
}
|
cs |
firstName์ ๋ํด ๊ฒ์์ ์ํํ๋๋ก ์๋์ ๊ฐ์ด ๋ณ๊ฒฝํด์ค๋ค.
Owner ํด๋์ค์ firstName์ getter์ setter๋ ์ด๋ฏธ ์์ผ๋ฏ๋ก ์ถ๊ฐํ์ง ์์๋ ๋์ง๋ง
findByFirstName() ๋ฉ์๋๋ ์์ด์ ์ถ๊ฐ๋ก ์ ์ํด์ผํ๋ค.
findByLastName()์ด ์ ์๋์ด์๋ OwnerRepository ์ธํฐํ์ด์ค์ ์๋์ ๊ฐ์ด findByFirstName()์ ์๋ก ์ ์ํ๋ค.
์ฌ๊ธฐ์ @Param์ผ๋ก ์ ์ํ ํ๋ผ๋ฏธํฐ firstName์ ์์ @Query์์ ์ฐธ์กฐํ ์ ์๋ค.
๋ง์ง๋ง์ผ๋ก ๋ทฐ์์ ๊ธฐ์กด ํ๋ผ๋ฏธํฐ๋ช lastName์ firstName์ผ๋ก ๋ณ๊ฒฝํ๋ค.
์ด์ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ฌ์คํํด์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด๋ณด์.
First name์ผ๋ก owner๋ฅผ ๊ฒ์ํด๋ณด์.
2) ๋ถ๋ถ ์ผ์น ๊ฒ์์ผ๋ก ๋ณ๊ฒฝํ๊ธฐ
ํ์ฌ๋ ์ฟผ๋ฆฌ๊ฐ LIKE :firstName%๊ณผ ๊ฐ์ด ๋์ด์์ด ๋ฌธ์์ด์ ์๋ถ๋ถ์ ์์ ํ ์ผ์นํด์ผ ๊ฒ์ ๊ฒฐ๊ณผ๊ฐ ๋์จ๋ค.
๊ฐ๋จํ ์ฟผ๋ฆฌ๋ฅผ ๋ณ๊ฒฝํด์ ํด๋น ๊ฒ์ ๊ธฐ๋ฅ์ ๋ณ๊ฒฝํ ์ ์๋ค.
Owner ๊ฒ์ ์ฟผ๋ฆฌ๊ฐ ์ ์๋์ด ์๋ OwnerRepository ์ธํฐํ์ด์ค๋ก ์ด๋ํ๋ค.
findByFirstName() ๋ฉ์๋์ ์ฟผ๋ฆฌ๋ฅผ ์์ ๊ฐ์ด ๋ณ๊ฒฝํ๋ค.
์ด์ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ฌ์คํํ๊ณ ๋ค์ first name์ ์ผ๋ถ ๋ฌธ์์ด๋ก ๊ฒ์์ ์์ฒญํด๋ณด์.
3) Add Owner ๊ธฐ๋ฅ์ Age ํ๋ ์ถ๊ฐํ๊ธฐ
ํ์ฌ add owner์ ํ๋๋ ์์ ๊ฐ๋ค.
์ฌ๊ธฐ์ Age๋ฅผ ์ถ๊ฐํด๋ณด์.
๋จผ์ ๋ทฐ์ form์ Age๋ฅผ ์ ๋ ฅํ๋ input ํ๊ทธ๋ฅผ ์ถ๊ฐํ๋ค.
Owner ํด๋์ค์ ์ธ์คํด์ค ๋ณ์ age์ getter, setter๋ฅผ ์ถ๊ฐํ๋ค.
resources/db/hsqldb/schema.sql
1
2
3
4
5
6
7
8
9
|
CREATE TABLE owners (
id INTEGER IDENTITY PRIMARY KEY,
first_name VARCHAR(30),
last_name VARCHAR_IGNORECASE(30),
age INTEGER NOT NULL,
address VARCHAR(255),
city VARCHAR(80),
telephone VARCHAR(20)
);
|
cs |
owners ํ ์ด๋ธ์ age ์ปฌ๋ผ์ ์ถ๊ฐํ๋ค.
์ฐธ๊ณ ๋ก ์ด๋ค ์คํค๋ง ํ์ผ์ ์ฐธ์กฐํ๋์ง๋ resources/application.properties ํ์ผ์์ ํ์ธํ ์ ์๋ค.
resources/db/hsqldb/data.sql
1
2
3
4
5
6
7
8
9
10
|
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (1, 'George', 'Franklin', 30, '110 W. Liberty St.', 'Madison', '6085551023');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (2, 'Betty', 'Davis', 41, '638 Cardinal Ave.', 'Sun Prairie', '6085551749');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (3, 'Eduardo', 'Rodriquez', 21, '2693 Commerce St.', 'McFarland', '6085558763');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (4, 'Harold', 'Davis', 32, '563 Friendly St.', 'Windsor', '6085553198');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (5, 'Peter', 'McTavish', 55, '2387 S. Fair Way', 'Madison', '6085552765');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (6, 'Jean', 'Coleman', 74, '105 N. Lake St.', 'Monona', '6085552654');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (7, 'Jeff', 'Black', 19, '1450 Oak Blvd.', 'Monona', '6085555387');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (8, 'Maria', 'Escobito', 29, '345 Maple St.', 'Madison', '6085557683');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (9, 'David', 'Schroeder', 67, '2749 Blackhawk Trail', 'Madison', '6085559435');
INSERT INTO owners(id, first_name, last_name, age, address, city, telephone) VALUES (10, 'Carlos', 'Estaban', 40, '2335 Independence La.', 'Waunakee', '6085555487');
|
cs |
ํ ์ด๋ธ ์คํค๋ง๋ฅผ ๋ณ๊ฒฝํ์ผ๋ฏ๋ก ์ดํ๋ฆฌ์ผ์ด์ ์ด ์์๋ ๋ ์คํ๋๋ INSERT๋ฌธ์ ๋ณ๊ฒฝํ๋ค.
์ด์ ๊ฒ์ ๊ฒฐ๊ณผ๋ owner ๋ชฉ๋ก์์ age๊ฐ ์ถ๊ฐ๋๊ฒ์ ํ์ธํ ์ ์๋๋ก ๊ด๋ จ ๋ทฐ๋ฅผ ๋ณ๊ฒฝํ๋ค.
resources/templates/owners/ownerDetails.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<table class="table table-striped" th:object="${owner}">
<tr>
<th>Name</th>
<td><b th:text="*{firstName + ' ' + lastName}"></b></td>
</tr>
<tr>
<th>Age</th>
<td th:text="*{age}" /></td>
</tr>
<tr>
<th>Address</th>
<td th:text="*{address}" /></td>
</tr>
<tr>
<th>City</th>
<td th:text="*{city}" /></td>
</tr>
<tr>
<th>Telephone</th>
<td th:text="*{telephone}" /></td>
</tr>
</table>
|
cs |
resources/templates/owners/ownerList.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
<table id="owners" class="table table-striped">
<thead>
<tr>
<th style="width: 150px;">Name</th>
<th style="width: 100px;">age</th>
<th style="width: 200px;">Address</th>
<th>City</th>
<th style="width: 120px">Telephone</th>
<th>Pets</th>
</tr>
</thead>
<tbody>
<tr th:each="owner : ${selections}">
<td>
<a th:href="@{/owners/__${owner.id}__}" th:text="${owner.firstName + ' ' + owner.lastName}"/></a>
</td>
<td th:text="${owner.age}"/>
<td th:text="${owner.address}"/>
<td th:text="${owner.city}"/>
<td th:text="${owner.telephone}"/>
<td><span th:each="pet : ${owner.pets}" th:text="${pet.name} "/></td>
</tr>
</tbody>
</table>
|
cs |
์ด์ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ฌ์์ํด์ ๊ฒฐ๊ณผ๋ฅผ ํ์ธํด๋ณด์.
๐ก ๋ทฐ(html)๋ง ๋ณ๊ฒฝํ ๊ฒฝ์ฐ์๋ ์ฌ์์ํ์ง์๊ณ build๋ง ํด๋ ๋ณ๊ฒฝ ์ฌํญ์ด ์ ์ฉ๋๋ค.
References
์ธํ๋ฐ - ๋ฐฑ๊ธฐ์ ๋์ ์์ ๋ก ๋ฐฐ์ฐ๋ ์คํ๋ง ์ ๋ฌธ(๊ฐ์ ํ)์ ์๊ฐํ๋ฉฐ ์ ๋ฆฌํ ํฌ์คํ ์ ๋๋ค.
'Spring' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] ์คํ๋ง PSA (0) | 2020.03.01 |
---|---|
[Spring] ์คํ๋ง AOP ๊ฐ๋ ์ดํด ๋ฐ ์ ์ฉ ๋ฐฉ๋ฒ (4) | 2020.02.29 |
[Spring] ์์กด์ฑ ์ฃผ์ (DI, Dependency Injection)์ ์ธ๊ฐ์ง ๋ฐฉ๋ฒ (0) | 2020.02.28 |
[Spring] ์คํ๋ง ๋น(Bean)์ ๊ฐ๋ ๊ณผ ์์ฑ ์๋ฆฌ (6) | 2020.02.28 |
[Spring] ์คํ๋ง ์์ ํ๋ก์ ํธ PetClinic ๋น๋ ๋ฐ ์คํํ๊ธฐ (0) | 2020.02.27 |
๋๊ธ