Free Lines Arrow
본문 바로가기
Spring/spring mvc 1 스터디

[Spring] 웹페이지 만들어 보기

by skahn1215 2021. 12. 2.
728x90
반응형

웹페이지 만들어 보기

배운내용으로 실제 웹페이지를 만들어 본다.

 

 

들어가기전

타임리프 핵심을 공부하고 가보자

 

핵심1

  • th:xxx 가 붙은 부분은 서버사이드에선 렌더링이 된다;
     - 즉 원래 정의되어있는 값을 대체 한다.

 

@{...}

  • url 링크표현식이라고 한다.
  • th:href="@{/css/bootstrap,min.css}"
  • URL 링크 표현식을 사용하면 서블릿 컨텍스트를 자동으로 포함한다.
  • 경로변수에 값을 넣을수 있고 쿼리 파라미터도 지원한다.
     - th:href="@{/basic/items/{itemId}(itemId=${item.id}, query='test')}"
     - http://localhost:8080/basic/items/1?query=test

 

th:onclick

  • onclock="location.href='addForm.html'"
  • th:onclick="|location.href='@{/basic/items/add}'|"

|...|

  • 리터럴 대체
  • 타임리브에서 문자와 표현식은 분리되어 있다.
     - <span th:text="'Welcome to our application, ' + ${user.name} + '!'">
  • 하지만 공백이 들어가면 오류가 발생하는데 다음과 같이 쉽게 쓸수 있다.
     - <span th:text="|Welcome to our application, ${user.name}!|">

 

th:each

  • 반복표현식
  • 반복할때 사용한다. for 문이라고 생각하면 되겠다.

 

${...}

  • 변수표현식
  • <td th:text="${item.price}">10000</td>
  • 모델에 포함된 값이다, 타임리프 변수로 선언한 값을 조회할 수 있다.
  • 프로퍼티 접근법을 사용한다.

 

th:text

  • 내용변경을 할 수 있다.
  • <td th:text="${item.price}">10000</td>
  • 10000 값을 item.price 로 변경한다.

 

 

 

 

 

 

 

상품목록

 

View

  • th:onclick="|location.href='@{/basic/items/add}'|"
     - 클릭시 해당 URL 이동 및 컨트롤러 호출

  • th:href="@{/basic/items/{itemId}(itemId=${item.id})}" 
     - {itemId}(itemId=${item.id}) itemId 에 item 객체의 id 값을 넣어준다
     - /basic/items/1 이렇게 변하게 된다.
<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <!--th 를 쓰게 되면 해당 내용으로 변경된다.-->
    <link th:href="@{/css/bootstrap.min.css}"
            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">
            <!-- th:onclick 쓴다. @{} 를 쓰면 참조가 된다.-->
            <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>
            <!-- each 를 써서 반복을 해준다.-->
            <tr th:each = "item : ${items}">
                <!-- {itemId}(itemId=${item.id}) 문법 itemId 에 값을 넣는다.-->
                <td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.id}">회원id</a></td>
                <td><a href="item.html" th:href="@{/basic/items/{itemId}(itemId=${item.id})}" th:text="${item.itemName}">상품명</a></td>
                <td th:text="${item.price}">10000</td>
                <td th:text="${item.quantity}">10</td>
            </tr>
            </tbody>
        </table>
    </div>
</div> <!-- /container -->
</body>
</html>

 

Controller

  • @RequestMapping("/basic/items")
     - 클래스 위에 선언해줌으로써 기본 URI 값을 정의한다.
     - 뒤에 부터는 class 는 생략 하겠습니다.
  • @PostConstruct
     - 빈이 생성되고 난 후 해당연산을 수행하여 기본데이터를 넣어준다.
@Controller
@RequestMapping("/basic/items")
@RequiredArgsConstructor
public class BasicItemController {
    private final ItemRepository itemRepository;

    @GetMapping
    public String items(Model model) {
        List<Item> items = itemRepository.findAll();
        model.addAttribute("items", items);
        return "basic/items";
    }

    /**
     *  Test 용 데이터 추가.
     */
    @PostConstruct
    public void init() {
        itemRepository.save(new Item("ItemA",10000,10));
        itemRepository.save(new Item("ItemB",20000,20));
    }
}

 

 

 

상품상세

 

View

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.min.css}"
            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" 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'"
                    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> <!-- /container -->
</body>
</html>

 

 

Controller

  • class 생략
    @GetMapping("/{itemId}")
    public String items(@PathVariable long itemId, Model model) {
        Item item = itemRepository.findById(itemId);
        model.addAttribute("item", item);
        return "basic/item";
    }

 

 

상품등록(너무너무 중요하다)

View

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="utf-8">
    <link th:href="@{/css/bootstrap.min.css}"
            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" th:action="@{/basic/items/add}" 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> <!-- /container -->
</body>
</html>

 

Controller

여기가 중요하다.

단계적으로 addItem 함수를 개선했다.

addItemV1

  • @RequestParam 으로 요청 파라미터를 받는다.
  • Model 을 이용하여 View 에게 넘겨줄 객체를 정의해준다.

addItemV2

  • ModelAttribute 를 이용하여 객체로 파라미터를 받는다.
  • ModelAttribute 는 요청파라미터의 값을 프로퍼티 접급법 setXxx 으로 입력해준다.
  • ModelAttribute Model에 지정한 객체를 자동으로 넣어준다.
    코드가 간결해 졌다.

addItemV3

  • ModelAttribute 의 name 생략

addItemV4

  • ModelAttribute 생략

addItemV5

  •  redirect 사용
     - redirect를 사용하는 이유는 다음과 같다.
     - redirect를 사용하지 않으면 아이템 을 추가 할때 다음과 같은 일이 발생한다.

  • 새로 고침을 할 때마다 새로운 아이템이 계속 추가 된다.
     - 이유는 아이템을 추가후 새로고침을 할경우 이전요청을 다시 수행한다.
     - 그렇기 때문에 아이템들이 계속 추가된다.

  • redirect 를 이용하여 아예 상세 페이지로 새로운 요청을 하도록 한다.
//@PostMapping("/add")
    public String addItemV1(@RequestParam String itemName ,
                       @RequestParam int price,
                       @RequestParam int 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")
    // ModelAttribute 의 item 은 뭘까?
    // 아래 처럼 알아서 된다.
    // model.addAttribute("item", item);
    public String addItemV2(@ModelAttribute("item") Item item) {
        itemRepository.save(item);
        return "basic/item";
    }

    // @PostMapping("/add")
    // ModelAttribute 의 item 즉 name 을 빼면?
    // 아래 처럼 알아서 된다.
    // Item -> item
    // HelloData -> helloData 가 된다.
    public String addItemV3(@ModelAttribute Item item) {
        itemRepository.save(item);
        return "basic/item";
    }

    //@PostMapping("/add")
    // 아예 생략도 가능하다.
    // 상품을 저장하고 뷰를 보여 줬다.
    // 상품 저장을 하면 상품상세로 넘어간다.
    // 하지만 url 은 여전히 저장을 나타내기 때문에
    // 새로고침을 하면 계속 저장된다. 계속 아이템이 저장된다.
    public String addItemV4(Item item) {
        itemRepository.save(item);
        return "basic/item";
    }

    @PostMapping("/add")
    public String addItemV5(Item item) {
        itemRepository.save(item);
        return "redirect:basic/item"+item.getId();
    }

 

 

 

전체코드

https://github.com/rnrl1215/spring-mvc-first-toyproject

 

GitHub - rnrl1215/spring-mvc-first-toyproject: 스프링 MVC 1 강의 프로젝트

스프링 MVC 1 강의 프로젝트. Contribute to rnrl1215/spring-mvc-first-toyproject development by creating an account on GitHub.

github.com

 

 

 

참고

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1/dashboard

 

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술 - 인프런 | 강의

웹 애플리케이션을 개발할 때 필요한 모든 웹 기술을 기초부터 이해하고, 완성할 수 있습니다. 스프링 MVC의 핵심 원리와 구조를 이해하고, 더 깊이있는 백엔드 개발자로 성장할 수 있습니다., 원

www.inflearn.com

 

728x90
반응형

'Spring > spring mvc 1 스터디' 카테고리의 다른 글

[Spring] PRG(Post Redirect Get)  (0) 2021.12.03
[Spring] @ModelAttribute 사용하기  (0) 2021.11.27
[Spring] Message Converter  (0) 2021.11.25
[Spring] HTTP 응답  (0) 2021.11.21
[Spring] HTTP 요청메세지 TEXT, JSON  (0) 2021.11.16

댓글