java 스프링부트 ( spring boot ) / 목록 ( 1 )

김동명·2022년 12월 12일
0

스프링부트

목록 보기
6/19

프로젝트 설정

  • application.properties
#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

시작

  • index.htaml
<!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>
  • item.domain.item 패키지 생성

  • item 패키지 > Item.java
    • lombok getter,setter
    • 파라미터 유/무 생성자
@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;
	}
}    

  • item 패키지 > ItemRepository.java 생성
    • DB x / 메모리 사용 프로젝트
@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());
    }
}    

  • item.domain.controller 패키지 생성

  • controller 패키지 > ItemController.java 생성
  • @RequiredArgsConstructor : lombok에서 제공되는 기능, final이 붙은 멤버변수만 사용해서 생성자를 자동으로 만들어준다.
@Controller
@RequestMapping("/basic/items")
public class ItemController {

	private final ItemRepository itemRepository;
    
//@RequiredArgsConstructor가 생성자를 대신 만들어주기때문에 생략가능    
//    	@Autowired
	// 생성자가 1개만 있으면 @Autowired 생략가능
//	public ItemController(ItemRepository itemRepository) { 
//		this.itemRepository = itemRepository;
//	}  

1. 목록 이동


  • ItemController.java 수정
    • items mapping 추가
    • test용 데이터 추가 // DB가 아닌 메모리를 이용하기 때문에 고정 데이터 추가
    • @postConstruct
      • 객체의 초기화 부분
      • 객체가 생성된 후 별도의 초기화 작업을 위해 실행하는 메소드를 선언한다.
      • WAS가 띄워질때 실행된다.
    • @PreDestroy : 마지막 소멸 단계
@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("종료 메서드");
	}
}    
  • templates> basic 폴더 > items.html
  • thymeleaf로 고정 데이터 값 불러오기
  • 상품상세 페이지 thymeleaf 이용해서 th:href 설정
<!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

    • 상품관리




2. 목록 상세 이동


  • ItemController.java 수정
  • @PathVariable
...
	// /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";
	}
}
  • basic 폴더 > item.html 생성
    • 상품 상세 출력
    • 목록 경로 ( thymeleaf )
    • 상품 수정 ( thymeleaf )
	<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>
  • 출력
    • 상세 클릭시




3. 상품 등록

3-1. 페이지 이동

  • ItemController.java 수정
    • @GetMapping("/add") 추가
...
@GetMapping("/add")
public String addForm(){
	return "basic/addForm";
}

  • basic 폴더 > addForm.html 생성
  • form 태그 th:action : 같은 url에 전송하고, 방법만 달라지는 경우는 url을 쓰지 않아도 된다.
  • 취소 url
	<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>

### 3-2. 상품 등록 방법( 1 )
  • Itemcontroller.java 수정
...
	@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";
	}
}    

3-3. 상품 등록 방법 ( 2 )

  • ItemController.java 수정
    • @ModerlAttribute : 요청 파라미터 처리
      -> Item 객체를 생성하고, 요청 파라미터의 값을 프로퍼트 접근법 ( set..)으로 입력해준다.
      -> moder.addAttribute("item", item); 의 " item " => @ModelAttribute( " item " )
...
	@PostMapping("/add")
	public String saveV2( @ModelAttribute("item")Item item) {
    
    itemRepository.save(item);
	return "basic/item";    
    }
}    

3-4. 상품 등록 방법 ( 3 )

  • ItemController.java 수정
    • @ModelAttribute 에서 name 생략
      -> 생략시 model에 저장되는 name은 클래스명의 첫 글자만 소문자로 등록 Item -> item
...
	@PostMapping("/add")
	public String saveV3( @ModelAttribute Item item) {					
		itemRepository.save(item);		
		return "basic/item";
	}
}

3-5. 상품 등록 방법 ( 4 )

  • ItemController.java 수정
    • @ModelAttribute 자체도 생략 가능, 그러나 가독성을 위해 권장하지 않음
...
	@PostMapping("/add")
	public String saveV4( Item item) {					
		itemRepository.save(item);		
		return "basic/item";
	}
}

3-6. 상품 등록 방법 ( 5 )

  • ItemController.java 수정
    • redirect 방식으로 넘겨주어야 새로고침등 불필요한 행동시 추가 생성 되는 것을 막을 수 있다.
...
	@PostMapping("/add")
	public String saveV5( Item item) {					
		itemRepository.save(item);		
		return "redirect:/basic/items/" + item.getId();
	}
}    

3-7. 상품 등록 방법 ( 6 )

  • ItemController.java
    • RedirectAttributes 사용시
      • redirect:/basic/items/{itemId} 에서
        -> @PathVariable : {itemId}
        -> 나머지는 파라미터로 처리 : ?status=true
        즉 매핑시켜서 적어준 값들은 경로로 들어가고 그외 직접 적어주지 않은 값들은 파라미터로 들어간다.
...
	@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}";

  • item.html 수정
...
<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>
...          
          

출력




4. 상품 수정

4-1. 페이지 이동

  • ItemController.java
...
	@GetMapping("/{itemId}/edit")
	public String editForm( @PathVariable Long itemId, Model model) {
		Item item = itemRepository.findById(itemId);
		model.addAttribute("item", item);
		return "basic/editForm";
	}
}
  • basic 폴더 > editForm.html 생성
	<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>

4-2. 상품 수정

  • ItemController.java 수정
...
	@PostMapping("/{itemId}/edit")
	public String edit(@PathVariable Long itemId, @ModelAttribute Item item) {
		itemRepository.update(itemId, item);
		return "redirect:/basic/items/{itemId}";
	}
}
profile
코딩공부

0개의 댓글