프로젝트 설정
#port
server.port=9090
#thymeleaf cache
spring.thymeleaf.cache=false
#encoding
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.force=true
server.servlet.encoding.enabled=true
시작
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<ul>
<li> 상품관리
<ul>
<li><a href="/basic/items">상품관리</a></li>
</ul>
</li>
</ul>
</body>
</html>
@Getter @Setter
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) {
super();
this.itemName = itemName;
this.price = price;
this.quantity = quantity;
}
}
@Repository
public class ItemRepository {
// static 사용
private static final Map<Long, Item> store = new HashMap<Long, Item>();
private static long sequence = 0L;
// 저장
public Item save(Item item) {
item.setId(++sequence);
store.put(item.getId(), item); // item DTO에 id 넣기
return item; // 필요없으면 사용하지 않아도 된다.
}
// id로 찾기
public Item findById(Long id) {
return store.get(id);
}
// 전체 찾기
public List<Item> findAll(){
return new ArrayList<Item>(store.values());
}
// 수정
public void update(Long itemId, Item updateParam) {
// item을 먼저 찾는다.
Item findItem = findById(itemId);
findItem.setItemName(updateParam.getItemName());
findItem.setPrice(updateParam.getPrice());
findItem.setQuantity(updateParam.getQuantity());
}
}
@Controller
@RequestMapping("/basic/items")
public class ItemController {
private final ItemRepository itemRepository;
//@RequiredArgsConstructor가 생성자를 대신 만들어주기때문에 생략가능
// @Autowired
// 생성자가 1개만 있으면 @Autowired 생략가능
// public ItemController(ItemRepository itemRepository) {
// this.itemRepository = itemRepository;
// }
@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class ItemController {
private final ItemRepository itemRepository;
@GetMapping
public String items(Model model) {
List<Item> items = itemRepository.findAll();
model.addAttribute("items", items);
return "basic/items";
}
// 테스트용 데이터 추가
@PostConstruct
public void init() {
// System.out.println("초기화 메서드");
itemRepository.save(new Item("teatA", 10000, 10));
itemRepository.save(new Item("teatB", 20000, 20));
}
// 종료 메서드
@PreDestroy
public void destroy() {
// System.out.println("종료 메서드");
}
}
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="utf-8">
<link href="../css/bootstrap.min.css" th: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'" th:onclick="|location.href='@{/basic/items/add}'|" 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 th:each="item : ${items}">
<!-- /basic/items/아이템의 ID -->
<td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">1</a></td>
<!-- /basic/items/아이템의 ID -->
<td><a href="item.html" th:href="@{|/basic/items/${item.id}|}" th:text="${item.itemName}">테스트 상품1</a></td>
<td th:text="${item.price}">10000</td>
<td th:text="${item.quantity}">10</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- /container -->
</body>
</html>
출력
localhost:9090
상품관리
...
// /basic/items/아이템의ID
@GetMapping("/{itemId}") // 변수로 경로 받아오기
public String item(@PathVariable long itemId, Model model) { // 어노테이션 후 파라미터는 선언해준 변수에 맞춰주기
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "basic/item";
}
}
<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" th:value="${item.id}" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}" readonly>
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" name="price" class="form-control" value="10000" th:value="${item.price}" readonly>
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" name="quantity" class="form-control" value="10" th:value="${item.quantity}" 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>
<hr class="my-4">
<div class="row">
<div class="col">
<!-- /basic/items/아이템ID/edit -->
<button class="w-100 btn btn-primary btn-lg" onclick="location.href='editForm.html'" th:onclick="|location.href='@{/basic/items/{itemId}/edit(itemId=${item.id})}'|" type="button">
상품수정
</button>
</div>
<div class="col">
<button class="w-100 btn btn-secondary btn-lg" onclick="location.href='items.html'" th:onclick="|location.href='@{/basic/items}'|" type="button">
목록으로
</button>
</div>
</div>
</div>
...
@GetMapping("/add")
public String addForm(){
return "basic/addForm";
}
<div class="container">
<div class="py-5 text-center">
<h2>상품 등록 폼</h2>
</div>
<h4 class="mb-3">상품 입력</h4>
<form action="item.html" th:action method="post">
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" name="itemName" class="form-control" 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="form-control" 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'" th:onclick="|location.href='@{/basic/items}'|" type="button">
취소
</button>
</div>
</div>
</form>
</div>
...
@PostMapping("/add")
public String save( @RequestParam String itemName, @RequestParam int price, @RequestParam Integer quantity, Model model) {
Item item = new Item();
item.setItemName(itemName);
item.setPrice(price);
item.setQuantity(quantity);
itemRepository.save(item);
model.addAttribute("item",item);
return "basic/item";
}
}
...
@PostMapping("/add")
public String saveV2( @ModelAttribute("item")Item item) {
itemRepository.save(item);
return "basic/item";
}
}
...
@PostMapping("/add")
public String saveV3( @ModelAttribute Item item) {
itemRepository.save(item);
return "basic/item";
}
}
...
@PostMapping("/add")
public String saveV4( Item item) {
itemRepository.save(item);
return "basic/item";
}
}
...
@PostMapping("/add")
public String saveV5( Item item) {
itemRepository.save(item);
return "redirect:/basic/items/" + item.getId();
}
}
...
@PostMapping("/add")
public String saveV6( Item item, RedirectAttributes redirectAttributes ) {
Item saveitem = itemRepository.save(item);
}
redirectAttributes.addAttribute("itemId", saveitem.getId());
redirectAttributes.addAttribute("status", true);
return "redirect:/basic/items/{itemId}";
...
<h2>상품 상세</h2>
</div>
<!-- 추가 -->
<h2 th:if="${param.status}" th:text="'저장완료!'"></h2>
<div>
<label for="itemId">상품 ID</label>
...
...
<script th:inline="javascript">
if([[${param.status}]]){
alert("저장완료");
}
</script>
...
출력
...
@GetMapping("/{itemId}/edit")
public String editForm( @PathVariable Long itemId, Model model) {
Item item = itemRepository.findById(itemId);
model.addAttribute("item", item);
return "basic/editForm";
}
}
<div class="container">
<div class="py-5 text-center">
<h2>상품 수정 폼</h2>
</div>
<form action="item.html" th:object="${item}" th:action method="post">
<div>
<label for="id">상품 ID</label>
<input type="text" id="id" th:field="*{id}" class="form-control" value="1" th:value="${item.id}" readonly>
</div>
<div>
<label for="itemName">상품명</label>
<input type="text" id="itemName" th:field="*{itemName}" class="form-control" value="상품A" th:value="${item.itemName}" >
</div>
<div>
<label for="price">가격</label>
<input type="text" id="price" th:field="*{price}" class="form-control" value="10000" th:value="${item.price}" >
</div>
<div>
<label for="quantity">수량</label>
<input type="text" id="quantity" th:field="*{quantity}" class="form-control" value="10" th:value="${item.quantity}" >
</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'" th:onclick="|location.href='@{/basic/items/{itemId}(itemId=${item.id})}'|" type="button">
취소
</button>
</div>
</div>
</form>
</div>
...
@PostMapping("/{itemId}/edit")
public String edit(@PathVariable Long itemId, @ModelAttribute Item item) {
itemRepository.update(itemId, item);
return "redirect:/basic/items/{itemId}";
}
}