
- 비즈니스 로직을 만들면 test로 실험을 해서 내가 만든 로직이 이상이 없는 지를 확인하는 것(tdd, 테스트주도설계) 도메인 주도 설계
- 해당 강의에서는 JPA를 사용하지 않았지만 JPA에서 사용하는 기본 기능을 사용한다는 점.
- resorces/static 경로에 html 등을 넣어두면 외부에서도 접근이 가능하기 때문에 별로 추천하지 않는다.
- 타임리프 문법 중 th:action 태그를 비워두게 되면 현재 URI의 값으로 요청을 보낸다는 것. 그래서 같은 요청값이여도 get방식이냐 post방식이냐에 따라서 다른 요청을 보낸다는 것.
@RequiredArgsConstructor 사용 전@Autowired 를 사용해서 스프링 Bean에 의존성을 주입한다. @Controller
@RequestMapping("/basic/items")
public class BasicItemController {
private final ItemRepository itemRepository;
@Autowired
public BasicItemController(ItemRepository itemRepository) {
this.itemRepository = itemRepository;
}
}
@RequiredArgsConstructor 사용 후@RequiredArgsConstructor 가 final이 붙은 repository를 자동으로 스프링 Bean에 등록해준다. @Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {
private final ItemRepository itemRepository;
}
결론
코드가 간결해질 뿐만 아니라 훨씬 더 명시적으로 변한다.
가정을 해봅시다.
- html의 form에서 데이터가 넘어온다는 가정.
- body에 넘어오는 데이터(파라미터)는 총 3개로
itemName,price,quantity이다.- 실제 강의에서는 JPA를 사용하지 않았지만, JPA를 사용한다고 해도 충분히 코드가 잘 작동됨.
@ModelAttribute 사용 전@RequestParam을 이용해서 모든 파라미터값을 명시해줘야한다. @PostMapping("/add")
public String addItemV1(@RequestParam("itemName") String itemName,
@RequestParam("price") int price,
@RequestParam("quantity") 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";
}
@ModelAttribute 사용 후@RequestParam 을 이용해서 모든 파라미터값을 명시할 필요가 없다. @PostMapping("/add")
public String addItemV2(@ModelAttribute("item") Item item) {
itemRepository.save(item);
return "basic/item";
}
@ModelAttribute는 생략이 가능하다. @PostMapping("/add")
public String addItemV2(Item item) {
itemRepository.save(item);
return "basic/item";
}
됐고 그래서
@ModelAttribute가 뭔데..?
@ModelAttribute는 form으로 넘겨진 데이터를 객체를 만들어 model에 담아서 제공한다.@ModelAttribute는model.addAttribute("example", example)의 역할을 함께한다.
🌋 RedirectAttributes의 개념
redirect:/를 사용할 때ModelAttributes와 비슷한 개념이라고 생각하면 된다. 하지만,
그럼ModelAttributes를 사용하면 되지. 뭐하러RedirectAttributes를 사용하냐? 라고 말할 수 있다.
아래의 그림은 내가 chatGPT에게 물어본 두개의 역할과 목적의 차이점이다.
🪂 RedirectAttributes의 특징 및 사용법
@PostMapping("/add") public String addItemV6(Item item, RedirectAttributes redirectAttributes){ Item savedItem = itemRepository.save(item); redirectAttributes.addAttribute("itemId", savedItem.getId()); redirectAttributes.addAttribute("status", true); return "redirect:/basic/items/{itemId}"; }위와 같은 코드가 있다. 코드를 보면서 예시를 들자면,
- 첫 번째로, RedirectAttributes는 반환값을 치환해주는 역할을 한다.(URI 인코딩도 함께 해줌.)
- 두 번째로, RedirectAttributes는 치환할 값이 없으면 쿼리파라미터(GET)방식으로 값을 넘겨주게 된다.
- 위와 같은 코드가 URI는 다음과 같다.
http://localhost:8080/basic/items/51?status=true<!-- 추가 --> <h2 th:if="${param.status}" th:text="'저장 완료'"></h2>status가 true라는 점을 이용해 다음과 같은 타임리프(Thymeleaf)조건문을 사용하는 것도 가능하다.
🌎 공부를 하다 생긴 의문점
redirect:/ ~를 사용하는 정확한 이유는 무엇인가?우리가 보통
@PostMapping을 사용할 때create를 한다고 알고 있다.
그리고 이럴 때redirect:/ ~를 많이 쓰는데 이러한 기법을PRG(post redirect get)기법이라고 한다.
그렇다면 이런 기법을 왜 사용하는 걸까? 바로 무분별한create를 막기 위함이다.
원래는 우리가Controller에서 view를 반환할 때 String으로 반환을 하곤 하는데, 이건 문제점이 있다.
예를 들어@PostMapping을 처리하는 view에서 F5(새로고침)을 하면 어떻게 될까?
아마 무수한@PostMapping요청으로 인해서 필요없는 데이터가 DB에 쌓이거나 에러가 날 것이다.
이런 점을 막기 위해서 우리는 새로운 Mapping 요청인redirect:/ ~를 사용하는 것이다.
이때@PostMapping의 반환값을@GetMapping으로redirect해주게 되면 위의 예시와 같은 상황은 일어나지 않을 것이다.
결론적으로 이러한 경우를 위해 생긴 개념(기법)이PRG(post redirect get)기법이다.