스프링 MVC - 1편 - 웹 페이지 만들기 - (2) 상품 도메인 개발 및 HTML
인프런 스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술편을 학습하고 정리한 내용 입니다.
상품 도메인 개발
Item - 상품 객체
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package hello.itemservice.domain.item;
import lombok.Data;
@Data
public class Item {
private Long id;
private String itemName;
private Integer price;
private Integer quantity;
public Item() {
}
public Item(String itemName, Integer price, Integer quantity) {
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
ItemRepository - 상품 저장소
hello.itemservice.domain.item.ItemRepository
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
27
28
29
30
31
@Repository
public class ItemRepository {
private static final Map<Long, Item> store = new HashMap<>();
private static long sequence = 0L;
public Item save(Item item) {
item.setId(++sequence);
store.put(item.getId(), item);
return item;
}
public Item findById(Long id) {
return store.get(id);
}
public List<Item> findAll() {
return new ArrayList<>(store.values());
}
public void update(Long itemId, Item updateParam) {
Item findItem = findById(itemId);
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
public void clearStore() {
store.clear();
}
}
참고로 DB는 안쓰고 메모리에서만 동작하도록 하는데
1
2
private static final Map<Long, Item> store = new HashMap<>();
private static long sequence = 0L;
다음과 같이 전역변수로 HashMap, long 등을 사용할 때는 멀티쓰레드 동시성 문제를 생각하면서 사용하자. (ConcurrentHashMap, AtomicLong)
간단하게 저장, 단일 찾기, 전체 조회, 업데이트, 그리고 맵을 초기화 할 메서드 하나만 만들었다.
이제 테스트 코드를 작성해 보자.
ItemRepositoryTest - 상품 저장소 테스트
hello.itemservice.domain.item.ItemRepositoryTest
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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
class ItemRepositoryTest {
ItemRepository itemRepository = new ItemRepository();
@AfterEach
void afterEach() {
itemRepository.clearStore();
}
@Test
void save() throws Exception {
//given
Item item = new Item("itemA", 10000, 10);
//when
Item savedItem = itemRepository.save(item);
//then
Item findItem = itemRepository.findById(item.getId());
assertThat(findItem).isEqualTo(savedItem);
}
@Test
void findAll() throws Exception {
//given
Item item1 = new Item("item1", 10000, 10);
Item item2 = new Item("item2", 20000, 20);
itemRepository.save(item1);
itemRepository.save(item2);
//when
List<Item> result = itemRepository.findAll();
//then
assertThat(result.size()).isEqualTo(2);
assertThat(result).contains(item1, item2);
}
@Test
void updateItem() throws Exception {
//given
Item item = new Item("item1", 10000, 10);
Item savedItem = itemRepository.save(item);
Long itemId = savedItem.getId();
//when
Item updateItem = new Item("item2", 20000, 30);
itemRepository.update(itemId, updateItem);
//then
Item findItem = itemRepository.findById(itemId);
assertThat(findItem.getItemName()).isEqualTo(updateItem.getItemName());
assertThat(findItem.getPrice()).isEqualTo(updateItem.getPrice());
assertThat(findItem.getQuantity()).isEqualTo(updateItem.getQuantity());
}
}
이렇게 간단하게 저장 및 단일 조회, 전체 조회, 업데이트를 테스트 해봤다.

결과도 잘 나온다.
그런데 진짜 요즘엔 인텔리제이가 너무 좋아졌다..

이게 말이되나…? ㅋㅋ
상품 서비스 HTML
핵심 비즈니스 로직을 개발하는 동안, 웹 퍼블리셔는 HTML 마크업을 완료했다. 다음 파일들을 경로에 넣고 잘 동작하는지 확인해보자.
부트스트랩 참고로 HTML을 편리하게 개발하기 위해 부트스트랩을 사용했다. 먼저 필요한 부트스트랩 파일을 설치하자.
- 부트스트랩 공식 사이트
- 부트스트랩을 다운로드 받고 압축을 풀자
- 다운로드 링크
- 압축을 풀고
bootstrap.min.css파일을 복사해서 다음 폴더에 추가하자. resources/static/css/bootstrap.min.css

참고
부트스트랩(Bootstrap)은 웹 사이트를 쉽게 만들 수 있게 도와주는 HTML, CSS, JS 프레임워크이다.
하나의 CSS로 휴대폰, 태블릿, 데스크탑까지 다양한 기기에서 작동한다.
다양한 기능을 제공하여 사용자가 쉽게 웹사이트를 제작, 유지, 보수할 수 있도록 도와준다
- 출처 : 위키백과
HTML, CSS 파일
/resources/static/css/bootstrap.min.css→부트스트랩다운로드/resources/static/html/items.html→아래 참조/resources/static/html/item.html/resources/static/html/addForm.html/resources/static/html/editForm.html
/resources/static/html/items.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<div class="container" style="max-width: 600px">
<div class="py-5 text-center">
<h2>상품 목록</h2>
</div>
<div class="row">
<div class="col">
<button class="btn btn-primary float-end"
onclick="location.href='addForm.html'" type="button">상품 등록
</button>
</div>
</div>
<hr class="my-4">
<div>
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>상품명</th>
<th>가격</th>
<th>수량</th>
</tr>
</thead>
<tbody>
<tr>
<td><a href="item.html">1</a></td>
<td><a href="item.html">테스트 상품1</a></td>
<td>10000</td>
<td>10</td>
</tr>
<tr>
<td><a href="item.html">2</a></td>
<td><a href="item.html">테스트 상품2</a></td>
<td>20000</td>
<td>20</td>
</tr>
</tbody>
</table>
</div>
</div> <!-- /container -->
</body>
</html>
/resources/static/html/item.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" rel="stylesheet">
<style>
.container {
max-width: 560px;
}
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>상품 상세</h2>
</div>
<div>
<label for="itemId">상품 ID</label>
<input type="text" id="itemId" name="itemId" class="form-control"
value="1" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="form-control"
value="상품A" readonly>
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control"
value="10000" readonly>
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="form-control"
value="10" readonly>
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg"
onclick="location.href='editForm.html'" type="button">상품 수정</button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='items.html'" type="button">목록으로</button>
</div>
</div>
</div> <!-- /container -->
</body>
</html>
/resources/static/html/addForm.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" rel="stylesheet">
<style>
.container {
max-width: 560px;
}
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>상품 등록 폼</h2>
</div>
<h4 class="mb-3">상품 입력</h4>
<form action="item.html" method="post">
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="formcontrol" placeholder="이름을 입력하세요">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control"
placeholder="가격을 입력하세요">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="formcontrol" placeholder="수량을 입력하세요">
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg" type="submit">상품 등
록</button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='items.html'" type="button">취소</button>
</div>
</div>
</form>
</div> <!-- /container -->
</body>
</html>
/resources/static/html/editForm.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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" rel="stylesheet">
<style>
.container {
max-width: 560px;
}
</style>
</head>
<body>
<div class="container">
<div class="py-5 text-center">
<h2>상품 수정 폼</h2>
</div>
<form action="item.html" method="post">
<div>
<label for="id">상품 ID</label>
<input type="text" id="id" name="id" class="form-control" value="1"
readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="formcontrol" value="상품A">
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control"
value="10000">
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="formcontrol" value="10">
</div>
<hr class="my-4">
<div class="row">
<div class="col">
<button class="w-100 btn btn-primary btn-lg" type="submit">저장</
button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg"
onclick="location.href='item.html'" type="button">취소</button>
</div>
</div>
</form>
</div> <!-- /container -->
</body>
</html>
참고로 /resources/static 에 넣어두었기 때문에 스프링 부트가 정적 리소스를 제공한다.
그런데 정적 리소스여서 해당 파일을 탐색기를 통해 직접 열어도 동작하는 것을 확인할 수 있다.
참고
이렇게 정적 리소스가 공개되는/resources/static폴더에 HTML을 넣어두면, 실제 서비스에서도 공개된다.
서비스를 운영한다면 지금처럼 공개할 필요 없는 HTML을 두는 것은 주의하자.

잘 나온다. (정적 리소스)
댓글남기기