inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

스프링 MVC 2편 - 백엔드 웹 개발 활용 기술

체크 박스 - 멀티

[질문글아님!] addForm. editForm, item html 파일 참고하세요!

661

작성자 없음

작성한 질문수 0

1

제가 공부하면서 주석으로 정리한 것 있는데

하찮은 실력이지만 다른 공부하시는 분들께 도움이 될 수 있을까 해서 공부한 내용을 올려봅니다!

범위는 "체크박스-멀티"까지 내용입니다!

 

addForm.html

<!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>

    <form action="item.html" th:action method="post" th:object="${item}">
    <!--
    ${item} : addForm() 에서 model 에 담겨서 넘어온 새로운 객체 (아래 코드 주석)
    model.addAttribute("item", new Item());
    -->
        <div>
            <label for="itemName">상품명</label>
            <input type="text" id="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요">
            <!--
            <input type="text" id="itemName" name="itemName" th:field="*{itemName}" class="form-control" placeholder="이름을 입력하세요">
            -->
        </div>
        <div>
            <label for="price">가격</label>
            <input type="text" id="price" th:field="*{price}" class="form-control" placeholder="가격을 입력하세요">
            <!--
            <input type="text" id="price" name="price" class="form-control" placeholder="가격을 입력하세요">
            -->
        </div>
        <div>
            <label for="quantity">수량</label>
            <input type="text" id="quantity" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요">
            <!--
            <input type="text" id="quantity" name="quantity" class="form-control" placeholder="수량을 입력하세요">
            -->
        </div>

        <hr class="my-4">

        <!-- single checkbox -->
        <div>판매 여부</div>
        <div>
            <div class="form-check">
                <!--
                히든필드 추가
                <input type="checkbox" id="open" name="open" class="form-check-input" />
                <input type="hidden" id="_open" name="_open" value="on" />
                -->

                <!--
                HTML checkbox 는 체크하지 않으면 서버로 값 자체를 보내지 않는다. (히든필드 사용하지 않을 경우)
                HTML 메시지: itemName=11&price=11&quantity=11
                spring: item.open = null

                즉. HTML checkbox 는 사용하기 불편할 수 있다. 그래서 spring 은 히든필드를 운용한다.

                HTML checkbox 는 체크되지 않으면 서버로 히든필드만 전송한다. 그럼 spring 은 필드가 false 라고 판단한다.
                HTML 메시지: itemName=22&price=22&quantity=22&_open=on
                spring: item.open = false

                HTML checkbox 가 체크되면 필드와 히든필드를 서버로 전송된다.
                HTML 메시지: itemName=33&price=33&quantity=33&open=on&_open=on. 그럼 spring 은 필드가 true 라고 판단한다.
                spring: item.open = true
                -->

                <input type="checkbox" id="open" th:field="*{open}" class="form-check-input" />
                <!--
                th 를 사용하면 알아서 히든필드를 만들어내기 때문에 HTML checkbox 를 편하게 사용할 수 있다.
                -->

                <label for="open" class="form-check-label">판매 오픈</label>
            </div>
        </div>

        <!-- multi checkbox -->
        <div>
            <div>등록 지역</div>
            <div th:each="region : ${regions}" class="form-check form-check-inline">
                <!--
                @ModelAttribute 에 담겨서 넘어온 것(regions()) 반복문 돌리기
                ${regions} : Map<String, String>. 사용자가 선택해서 넘어온 것이 아니라 FormItemController 에서 @ModelAttribute 자체가 그대로 넘어왔기 때문.
                -->
                <input type="checkbox" th:field="*{regions}" th:value="${region.key}" class="form-check-input">
                <!--
                th 가 name, value, id 을 만들어줌. 이 때, id는 field 에 숫자가 붙여져 고유하게 만들어진다.
                *{regions} : ${item.regions}의 생략 버전. Map<String, String>. 사용자가 선택해서 넘어온 것이 아니라 FormItemController 에서 @ModelAttribute 자체가 그대로 넘어왔기 때문.
                ${region.key} : 위 div 태그의 Map의 key 중 하나. "SEOUL", "BUSAN", "JEJU" 중 하나 (반복문이니깐). 사용자가 각 체크박스를 체크해서 POST 요청 보낼 때 regions.key가 날아감. 이후 item.regions 에 값이 바인딩될 것.
                -->
                <label th:for="${#ids.prev('regions')}" th:text="${region.value}" class="form-check-label">서울</label>
                <!--
                ${#ids.prev('필드명')} : 바로 이전 태그에서 사용되었던 id를 그대로 가져와서 사용. 물론 위 태그에서 th가 id 자동생성해줬다.
                ${region.value} : 위 div 태그의 Map의 value 중 하나. "서울", "부산", "제주" 중 하나 (반복문이니깐)
                -->
            </div>
        </div>



        <div>
            <div>상품 종류</div>
            <div th:each="type : ${itemTypes}" class="form-check form-check-inline">
                <!--
                @ModelAttribute 에 담겨서 넘어온 것(itemTypes()) 반복문 돌리기
                ${regions} : ItemTypes[]. 사용자가 선택해서 넘어온 것이 아니라 FormItemController 에서 @ModelAttribute 자체가 그대로 넘어왔기 때문.
                -->
                <input type="radio" th:field="*{itemType}" th:value="${type.name()}" class="form-check-input">
                <!--
                *{itemType} :
                -->
                <label th:for="${#ids.prev('itemType')}" th:text="${type.description}" class="form-check-label"> BOOK </label>
                <!--

                -->
            </div>
        </div>

        <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='@{/form/items}'|"
                        type="button">취소</button>
            </div>
        </div>

    </form>

</div> <!-- /container -->
</body>
</html>

 

editForm.html

<!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>

    <form action="item.html" th:action method="post" th:object="${item}">
    <!--
    ${item} : editForm() 에서 model 에 담겨서 넘어온 특정 객체 (아래 코드 주석)
    Item item = itemRepository.findById(itemId);
    model.addAttribute("item", item);
    -->
        <div>
            <label for="id">상품 ID</label>
            <input type="text" id="id" class="form-control" th:field="*{id}" readonly>
            <!--
            th 가 name, value, id 를 만들어준다.
            <input type="text" id="id" name="id" class="form-control" value="1" th:value="${item.id}" readonly>
            -->
        </div>
        <div>
            <label for="itemName">상품명</label>
            <input type="text" id="itemName" class="form-control" th:field="*{itemName}">
            <!--
            th 가 name, value, id 를 만들어준다.
            <input type="text" id="itemName" name="itemName" class="form-control" value="상품A" th:value="${item.itemName}">
            -->
        </div>
        <div>
            <label for="price">가격</label>
            <input type="text" id="price" class="form-control" th:field="*{price}">
            <!--
            th 가 name, value, id 를 만들어준다.
            <input type="text" id="price" name="price" class="form-control" value="10000" th:value="${item.price}">
            -->
        </div>
        <div>
            <label for="quantity">수량</label>
            <input type="text" id="quantity" class="form-control" th:field="*{quantity}">
            <!--
            th 가 name, value, id 를 만들어준다.
            <input type="text" id="quantity" name="quantity" class="form-control" value="10" th:value="${item.quantity}">
            -->
        </div>

        <hr class="my-4">
        <!-- single checkbox -->
        <div>판매 여부</div>
        <div>
            <div class="form-check">
                <input type="checkbox" id="open" th:field="*{open}" class="form-check-input">
                <label for="open" class="form-check-label">판매 오픈</label>
            </div>
        </div>

        <!-- multi checkbox -->
        <div>
            <div>등록 지역</div>
            <div th:each="region : ${regions}" class="form-check form-check-inline">
                <!--
                @ModelAttribute 에 담겨서 넘어온 것(regions()) 반복문 돌리기
                ${regions} : Map<String, String>. 사용자가 선택해서 넘어온 것이 아니라 FormItemController 에서 @ModelAttribute 자체가 그대로 넘어왔기 때문.
                -->
                <input type="checkbox" th:field="*{regions}" th:value="${region.key}" class="form-check-input">
                <!--
                th 가 name, value, id 을 만들어줌. 이 때, id는 field 에 숫자가 붙여져 고유하게 만들어진다.
                *{regions} : ${item.regions}의 생략 버전. 빈 리스트. 사용자가 각 체크박스를 체크해서 POST 요청 보낼 때 regions.key가 날아감. item.regions 에 값이 바인딩될 것.
                ${region.key} : 위 div 태그의 Map의 key 중 하나. "SEOUL", "BUSAN", "JEJU" 중 하나 (반복문이니깐). 사용자가 각 체크박스를 체크해서 POST 요청 보낼 때 regions.key가 날아감. 이후 item.regions 에 값이 바인딩될 것.
                -->
                <label th:for="${#ids.prev('regions')}" th:text="${region.value}" class="form-check-label">서울</label>
                <!--
                ${#ids.prev('필드명')} : 바로 이전 태그에서 사용되었던 id를 그대로 가져와서 사용. 물론 위 태그에서 th가 id 자동생성해줬다.
                ${region.value} : 위 div 태그의 Map의 value 하나. "서울", "부산", "제주" 중 하나 (반복문이니깐)
                -->
            </div>
        </div>

        <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='@{/form/items/{itemId}(itemId=${item.id})}'|"
                        type="button">취소</button>
            </div>
        </div>

    </form>

</div> <!-- /container -->
</body>
</html>

 

item.html

<!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>

    <!-- 추가 -->
    <h2 th:if="${param.status}" th:text="'저장 완료'"></h2>

    <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">
    <!-- single checkbox -->
    <div>판매 여부</div>
    <div>
        <div class="form-check">
            <input type="checkbox" id="open" th:field="${item.open}" class="form-check-input" disabled>
            <!--
            th 가 name, value, id 을 만들어줌
            체크박스가 체크되어 있다면 checked="checked" 속성까지 만들어줌. 체크되지 않았다면 속성 만들어지지 않음.
            -->
            <label for="open" class="form-check-label">판매 오픈</label>
        </div>
    </div>

    <!-- multi checkbox -->
    <div>
        <div>등록 지역</div>
        <div th:each="region : ${regions}" class="form-check form-check-inline"> <!-- @ModelAttribute 에 담았던 것 반복문 돌리기 -->
            <!--
            @ModelAttribute 에 담겨서 넘어온 것(regions()) 반복문 돌리기
            ${regions} : Map<String, String>. 사용자가 선택해서 넘어온 것이 아니라 FormItemController 에서 @ModelAttribute 자체가 그대로 넘어왔기 때문.
            -->
            <input type="checkbox" th:field="${item.regions}" th:value="${region.key}" class="form-check-input" disabled>
            <!--
            th 가 name, value, id 을 만들어줌. 이 때, id는 field 에 숫자가 붙여져 고유하게 만들어진다.
            ${item.regions} : List. 사용자가 선택했던 요소들이 담긴 리스트이므로 ["SEOUL", "BUSAN"] 등의 리스트.
            ${region.key} : 위 div 태그의 Map의 key 하나. "SEOUL", "BUSAN", "JEJU" 중 하나 (반복문이니깐)
            value("SEOUL", "BUSAN", "JEJU" 중 하나)가 field(Map<String, String>) 의 요소에 존재한다면 th가 checked="checked" 속성을 만들어줌.
            -->
            <label th:for="${#ids.prev('regions')}" th:text="${region.value}" class="form-check-label">서울</label>
            <!--
            ${#ids.prev('필드명')} : 바로 이전 input 태그에서 사용되었던 id를 그대로 가져와서 사용. 물론 위 태그에서 th가 id 자동생성해줬다.
            ${region.value} : 위 div 태그의 Map의 value 하나. "서울", "부산", "제주" 중 하나 (반복문이니깐)
            -->
        </div>
    </div>


    <div class="row">
        <div class="col">
            <button class="w-100 btn btn-primary btn-lg"
                    onclick="location.href='editForm.html'"
                    th:onclick="|location.href='@{/form/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='@{/form/items}'|"
                    type="button">목록으로</button>
        </div>
    </div>

</div> <!-- /container -->
</body>
</html>

spring mvc

답변 1

0

cjkimhello97

잘못된 부분이 있어서 수정해서 다시 올리겠습니다!

이미지 업로드와 db 트랜잭션 묶는법

0

46

1

Could not resolve org.springframework.boot:spring-boot-starter-validation:2.4.4

0

55

2

MessageSourceTest 코드

0

49

1

인터셉터 에러 설정

0

48

1

resolveArgument()메서드 질문

0

58

1

43강 검증1 에서 실패 로직 관련 질문있습니다.

0

60

2

타임리프 3.X 버전 rendering, serializer 에러 해결 방법

2

133

3

스프링 빈에 등록이 안되는거 같은데 어떻게 하면 좋을까요?ㅠㅠ

0

93

3

pdf 오타 문의

0

57

1

ItemUpdateForm 검증 관련 질문입니다.

0

50

1

22page 링크 주소 변경

0

59

2

특정 데이터와 파일을 함께 저장 시, 테이블 구조 질문

0

53

1

섹션3번 수업에 대한 질문입니다.

0

80

2

@Autowired 보다 더 좋은 방법이 어떤 걸까요?

0

87

2

타입컨버터 가 람다랑 비슷해 보이는데 저의 생각이 맞는지?.

0

66

1

자바스크립트 인라인에서 객체 직렬화 시 오류가 납니다

0

143

3

스프링부트 - 오류페이지2 에서 500.html 에서 쓰인 객체 질문

0

65

1

톰캣 에러 페이지가 안보입니다.

0

105

2

apiEceptionController에서 센드 에러 호출하면 안되는지?

0

81

1

세션 타임아웃시 쿠키 삭제 방법이 없나요?

0

119

2

ApiExceptionController 질문드립니다.

0

64

1

셀렉박스 챕터에서 option value에 ==배송 방식 선택== 이것을 넣은 이유가 궁금함, 이렇게 구상해도 되는지?

0

66

1

MemberRepository 필드의 fianl 선언 유무

0

85

2

혹시 index.html 에서는 fragment 사용이 안되는건가요

0

59

1