SPRING/INFLEARN

[๊ฐ•์˜] ์‹ค์ „! ์Šคํ”„๋ง ๋ถ€ํŠธ์™€ JPA ํ™œ์šฉ1 - ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ 3

ozllzL 2021. 9. 29. 20:43

 

์™€์•„์•™ ๋

 

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8-JPA-%ED%99%9C%EC%9A%A9-1/dashboard

 

์‹ค์ „! ์Šคํ”„๋ง ๋ถ€ํŠธ์™€ JPA ํ™œ์šฉ1 - ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์‹ค๋ฌด์— ๊ฐ€๊นŒ์šด ์˜ˆ์ œ๋กœ, ์Šคํ”„๋ง ๋ถ€ํŠธ์™€ JPA๋ฅผ ํ™œ์šฉํ•ด์„œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์„ค๊ณ„ํ•˜๊ณ  ๊ฐœ๋ฐœํ•ฉ๋‹ˆ๋‹ค. ์ด ๊ณผ์ •์„ ํ†ตํ•ด ์Šคํ”„๋ง ๋ถ€ํŠธ์™€ JPA๋ฅผ ์‹ค๋ฌด์—์„œ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•ด์•ผ ํ•˜๋Š”์ง€ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค., ๋ณธ

www.inflearn.com

 

7. ์›น ๊ณ„์ธต ๊ฐœ๋ฐœ

- ํ™ˆ ํ™”๋ฉด๊ณผ ๋ ˆ์ด์•„์›ƒ

//HomeController.java
@Controller
@Slf4j // log์‚ฌ์šฉ
public class HomeController {

    @RequestMapping("/")
    public String home(){
        log.info("home controller");
        return "home";
    }
}

๋ฅผ ๋งŒ๋“ค๊ณ  home.html, footer, header, bodyheader ๋“ฑ html ํŒŒ์ผ๋“ค ๋งŒ๋“ค์–ด์„œ ๋„ฃ์–ด์คŒ

https://getbootstrap.com/docs/5.1/getting-started/download/

 

Download

Download Bootstrap to get the compiled CSS and JavaScript, source code, or include it with your favorite package managers like npm, RubyGems, and more.

getbootstrap.com

์—ฌ๊ธฐ์„œ 

์ด๊ฑฐ ๋ฐ›์•„์„œ

 

static ํ•˜์œ„์— ๋ณต์‚ฌ ๋ถ™์—ฌ๋„ฃ๊ธฐ ํ•ด์ค€๋‹ค. ์ ์šฉ ์•ˆ๋˜๋Š” ๊ฒฝ์šฐ ๋นŒ๋“œ ๋‹ค์‹œํ•˜๊ธฐ

๊ทธ๋ฆฌ๊ณ  ๊ฐ•์‚ฌ๋‹˜์ด ์ฃผ์‹  css์ฝ”๋“œ๊นŒ์ง€ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

๋ฌด์–ธ๊ฐ€ ์ž˜๋ชป๋˜์—ˆ์ง€๋งŒ ์ˆ˜์—…์—” ํฐ ์ง€์žฅ์ด ์—†๋Š” ๊ฒƒ ๊ฐ™์•„ ๋„˜์–ด๊ฐ€๊ธฐ๋กœ ํ•œ๋‹ค.

 

- ํšŒ์› ๋“ฑ๋ก

@NotEmpty๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ด ๋ฌธ๊ตฌ๋ฅผ build.gradle์— ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ•œ๋‹ค.
implementation 'org.springframework.boot:spring-boot-starter-validation'

//MemberForm.java
@Getter@Setter
public class MemberForm {

    @NotEmpty(message = "ํšŒ์› ์ด๋ฆ„์€ ํ•„์ˆ˜ ์ž…๋‹ˆ๋‹ค.")
    private String name;

    private String city;
    private String street;
    private String zipcode;

}
//MemberController.java
@Controller
@RequiredArgsConstructor
public class MemberController {
    private final MemberService memberService;

    @GetMapping("/members/new")
    public String createForm(Model model){
        model.addAttribute("memberForm", new MemberForm());
        return "members/createMemberForm";
    }

    @PostMapping("/members/new")
    public String create(@Valid MemberForm form, BindingResult result){

        if(result.hasErrors()){
            return  "members/createMemberForm";
        }

        Address address = new Address(form.getCity(), form.getStreet(), form.getZipcode());

        Member member = new Member();
        member.setName(form.getName());
        member.setAddress(address);

        memberService.join(member);
        return "redirect:/";
    }
}

error validation

Member๋ฅผ ์“ฐ์ง€ ์•Š๊ณ  Formdata๋ฅผ ์“ฐ๋Š” ์ด์œ 

: Member๊ฐ€ ์ง€์ €๋ถ„ํ•ด์ง€๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๊ณ , ์ „๋ถ€ ์ˆ˜์ •ํ•  ์ด์œ ๋Š” ์—†๊ธฐ์— ํ•„์š”ํ•œ๊ฒƒ๋งŒ

์—”ํ‹ฐํ‹ฐ๊ฐ€ ํ™”๋ฉด ์ข…์†ํ™”๊ฐ€ ๋˜๊ณ , ์œ ์ง€ ๋ณด์ˆ˜๊ฐ€ ํž˜๋“ค์–ด์ง„๋‹ค.

 

- ํšŒ์› ๋ชฉ๋ก ์กฐํšŒ

์—ญ์‹œ html์€ ๋ณต๋ถ™์œผ๋กœ ๋„ฃ์–ด์ฃผ๊ณ 

//MemberController.java
@Controller
@RequiredArgsConstructor
public class MemberController {

	...
    
    @GetMapping("/members")
    public String list(Model model){
        List<Member> members = memberService.findMembers();
        model.addAttribute("members", members);
        return "members/memberList";
    }
}

ํ•˜.. ์—ฌ๊ธฐ form์ด๋ผ๊ณ  ์จ์„œ ์˜ค๋ฅ˜ ํ•œ์ฐธ์ฐพ์•˜๋„ค

- ์ƒํ’ˆ ๋“ฑ๋ก

//ItemController.java
@RequiredArgsConstructor
@Controller
public class ItemController {

    private final ItemService itemService;

    @GetMapping("/items/new")
    public String createForm(Model model) {
        model.addAttribute("form", new BookForm());
        return "items/createItemForm";
    }

    @PostMapping(value = "/items/new")
    public String create(BookForm form) {

        Book book = new Book();
        book.setName(form.getName());
        book.setPrice(form.getPrice());
        book.setStockQuantity(form.getStockQuantity());
        book.setAuthor(form.getAuthor());
        book.setIsbn(form.getIsbn());

        itemService.saveItem(book);
        return "redirect:/";
    }

}

์—ญ์‹œ htmlํŒŒ์ผ ์ถ”๊ฐ€ ํ›„ ์ž˜๋œ๋‹ค!

 

- ์ƒํ’ˆ ๋ชฉ๋ก

//ItemController.java
@RequiredArgsConstructor
@Controller
public class ItemController {

	...

    @GetMapping(value = "/items")
    public String list(Model model) {
        List<Item> items = itemService.findItems();
        model.addAttribute("items", items);
        return "items/itemList";
    }
}

์•„๊นŒ๋ž‘ ๋‹ค๋ฅธ ๋ฐ์ดํ„ฐ๋ฅผ ๋„ฃ์–ด์„œ ๋ฐ์ดํ„ฐ๋Š” ๋‹ค๋ฅด๋‹ค

- ์ƒํ’ˆ ์ˆ˜์ •

//ItemController.java
@RequiredArgsConstructor
@Controller
public class ItemController {

	...

    @GetMapping(value = "/items/{itemId}/edit")
    public String updateItem(@ModelAttribute("itemId") Long itemId, Model model) {
        Book book = (Book) itemService.findOne(itemId);

        BookForm form = new BookForm();
        form.setId(book.getId());
        form.setName(book.getName());
        form.setPrice(book.getPrice());
        form.setStockQuantity(book.getStockQuantity());
        form.setAuthor(book.getAuthor());
        form.setIsbn(book.getIsbn());

        model.addAttribute("form", form);
        return "items/updateItemForm";
    }

    @PostMapping(value = "/items/{itemId}/edit")
    public String updateItem(@ModelAttribute("form") BookForm form) {

        Book book = new Book();
        book.setId(form.getId());
        book.setName(form.getName());
        book.setPrice(form.getPrice());
        book.setStockQuantity(form.getStockQuantity());
        book.setAuthor(form.getAuthor());
        book.setIsbn(form.getIsbn());

        itemService.saveItem(book);
        return "redirect:/items";
    }
}

์ˆ˜์ • ์‹œ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ๋„˜์–ด์˜จ item ์—”ํ‹ฐํ‹ฐ ์ธ์Šคํ„ด์Šค๋Š” ์ค€์˜์† ์ƒํƒœ์ด๋‹ค. ์˜์†์„ฑ ์ปจํ…Œ์ŠคํŠธ๋ผ ํ•  ์ˆ˜ ์—†๊ณ  ์ˆ˜์ •ํ•ด๋„ ๋ณ€๊ฒฝ๊ฐ์ง€๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

- ๋ณ€๊ฒฝ๊ฐ์ง€์™€ ๋ณ‘ํ•ฉ

์ค€์˜์† ์—”ํ‹ฐํ‹ฐ

์˜์†์„ฑ ์ปจํ…์ŠคํŠธ๊ฐ€ ๊ด€๋ฆฌํ•˜์ง€ ์•Š๋Š” ์—”ํ‹ฐํ‹ฐ

ex ) ์œ„์˜ book ๊ฐ์ฒด, DB์— ํ•œ๋ฒˆ ๊ฐ”๋‹ค ์™”๊ธฐ์— ์‹๋ณ„์ž๊ฐ€ ์กด์žฌํ•œ๋‹ค

 

์ค€์˜์† ์—”ํ‹ฐํ‹ฐ ์ˆ˜์ •ํ•˜๋Š” ๋ฒ•

1) ๋ณ€๊ฒฝ ๊ฐ์ง€ ๊ธฐ๋Šฅ

@Transactional
//itemParam: ํŒŒ๋ฆฌ๋ฏธํ„ฐ๋กœ ๋„˜์–ด์˜จ ์ค€์˜์† ์ƒํƒœ์˜ ์—”ํ‹ฐํ‹ฐ
void update(Item itemParam) { 
    //๊ฐ™์€ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์กฐํšŒํ•œ๋‹ค.
    Item findItem = em.find(Item.class, itemParam.getId());  
    //๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค.
    findItem.setPrice(itemParam.getPrice());
}

ํŠธ๋žœ์žญ์…˜ ์ปค๋ฐ‹ ์‹œ์ ์— ๋ณ€๊ฒฝ ๊ฐ์ง€ Dirty Checking

 

2) ๋ณ‘ํ•ฉ ์‚ฌ์šฉ

@Transactional
void update(Item itemParam) { 
	Item mergeItem = em.merge(item);
}

merge ๋ณด๋‹จ ๋ณ€๊ฒฝ๊ฐ์ง€. null๋กœ ์—…๋ฐ์ดํŠธ ๋  ์œ„ํ—˜์ด ์žˆ์Œ

 

 

- ์ฃผ๋ฌธ ๋ชฉ๋ก ๊ฒ€์ƒ‰, ์ทจ์†Œ

//OrderController.java
@Controller
@RequiredArgsConstructor
public class OrderController {

    private final OrderService orderService;
    private final MemberService memberService;
    private final ItemService itemService;

    @GetMapping(value = "/order")
    public String createForm(Model model) {
        List<Member> members = memberService.findMembers();
        List<Item> items = itemService.findItems();
        model.addAttribute("members", members);
        model.addAttribute("items", items);
        return "order/orderForm";
    }

    @PostMapping(value = "/order")
    public String order(@RequestParam("memberId") Long memberId,
                        @RequestParam("itemId") Long itemId, @RequestParam("count") int count) {
        orderService.order(memberId, itemId, count);
        return "redirect:/orders";
    }

    @GetMapping(value = "/orders")
    public String orderList(@ModelAttribute("orderSearch") OrderSearch
                                    orderSearch, Model model) {
        List<Order> orders = orderService.findOrders(orderSearch);
        model.addAttribute("orders", orders);
        return "order/orderList";
    }

    @PostMapping(value = "/orders/{orderId}/cancel")
    public String cancelOrder(@PathVariable("orderId") Long orderId) {
        orderService.cancelOrder(orderId);
        return "redirect:/orders";
    }
}