스프링 통합과 폼 - 1

JIWOO YUN·2024년 1월 23일
0

SpringMVC2

목록 보기
6/26
post-custom-banner

MVC 1 에서 사용했던 코드에서 타임리프를 추가해서 진행하자.

스프링 통합으로 추가되는 기능들

  1. 스프링의 SpringEL 문법 통합

    1. ${@myBean.doSomething()} 처럼 스프링 빈 호출 지원

  2. 편리한 폼 관리를 위한 추가 속성

    1. th:object(기능강화, 폼 커맨드 객체 선택)
      th:field,th:errors,th:errorclass
  3. 폼 컴포넌트 기능

    1. checkbox,radio button,list 등을 편리하게 사용할 수 있게 기능 지원.
  4. 스프링 메시지, 국제화 기능 편리한 통합

  5. 스프링의 검증, 오류 처리 통합

  6. 스프링의 변환 서비스 통합

입력 폼 처리

  • th:object : 커맨트 객체 지정
  • *{...} -> 선택 변수식. -> th:obejct 에서 선택한 객체에 접근
  • th:field
    • HTML 태그의 id, name,value 속성을 자동으로 처리해줌.

타임리프를 추가해서 변경

    <form action="item.html" th:action th:object="${item}" method="post">
        <div>
            <label for="itemName">상품명</label>
            <input type="text" id="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="가격을 입력하세요">
        </div>
        <div>
            <label for="quantity">수량</label>
            <input type="text" id="quantity" th:field="*{quantity}" class="form-control" placeholder="수량을 입력하세요">
        </div>
</form>

th:object="${item}" : form 에서 사용할 객체 지정

th:field="*{itemName}"

  • ${item.itemName} 과 같은 의미 -> th:obejct 로 item을 선택했기 때문에 선택 변수식 사용가능.
  • th:field id.name.value 속성을 모두 자동으로 만들어줌.

오류 발생했던 것(놓쳤던 것)

  • Neither BindingResult nor plain target object for bean name 'item' available as request attribute

템플릿에서 th:obejct="${item}"에서 item에 대한 정보를 전달 받지 못해서 발생했던 오류

처음 입력 폼 페이지 조회시 입력폼은 전부 비어져있어야하기 때문에 빈객체를 전달 해줘야한다.


요구사항 추가

  • 기본으로 만들어둔 현재 프로젝트에 추가로 주어진 요구사항을 진행.

체크박스 - 단일 1

체크 박스를 이용해서 판매여부를 체크하는 부분을 만들자.
<hr class="my-4">
<div>판매 여부</div>
<div>
    <div class="form-check">
        <input type="checkbox" id="open" name="open" class="form-check-input">
        <label for="open" class="form-check-label">판매 오픈</label>
    </div>
</div>

근데 이렇게 만들 경우 문제가 생긴다.

  1. 체크박스를 체크안하고 넘길경우 null로 아예 전송이 안된다. ==> 경우에 따라서 문제가 생길 수 있음.

문제를 해결하는 방법

  • 히든 필드를 만들어서 _open처럼 기존 체크박스 이름 앞에 언더스코어를 붙여서 전송하면 체크를 해제했다고 인식이 가능하다.
<hr class="my-4">
<div>판매 여부</div>
<div>
    <div class="form-check">
        <input type="checkbox" id="open" name="open" class="form-check-input">
        <input type="hidden" name="_open" value="on"/>
        <label for="open" class="form-check-label">판매 오픈</label>
    </div>
</div>
  • 이렇게 할 경우 _open 만 on 인경우 ==> 체크박스를 선택한것이 아니기 때문에 선택안한것으로 처리하면됨.
  • open 과 _open 둘다 on 인경우 --> 체크박스를 선택한 것이기 때문에 선택한 것으로 처리를 진행하면된다.

체크박스 - 단일 2

  • 체크박스를 만들때 마다 히든 필드를 추가하는 번거로운 작업을 타임리프가 제공하는 폼 기능을 사용시 자동으로 처리가 가능해진다.
<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>

th:field="*{open}" 를 통해서 타임리프 기능을 추가

실행시 자동으로 _open으로 된 hidden 필드 부분을 만들어주는 것을 알 수 있다.

  • 만약 체크가 된경우 -> 타임리프가 알아서 checked를 추가해준다.
  • th:field가 넣어준다.

체크박스 - 멀티

  • 체크박스를 멀티로 사용하여 하나 이상을 체크 할 수 있도록 하기.

@ModelAttribute 를 컨트롤러에 있는 별도의 메서드에 적용할 수 있다.

  • @ModelAttribute("regions")
    public Map<String,String> regions(){
        Map<String,String > regions = new LinkedHashMap<>();
        regions.put("SEOUL","서울");
        regions.put("BUSAN","부산");
        regions.put("JEJU","제주");
    
        return regions;
        //model.addAttribute("regions",regions) 가 들어가게된다.
    }
  • 이렇게 별도로 만들어 두게되면 regions에서 반환한 값이 자동으로 모델에 담기게 된다.

  • 이렇게 하지않고 ,각각의 컨트롤러 메서드에서 모델에 직접 데이터를 담아서 처리하는 것도 상관없다.

  • 동적으로 변하지 않는다면 정적으로 어딘가에 선언해두고 사용하는게 메모리적으로 좋다.

<!-- multi checkbox -->
<div>
    <div>등록 지역</div>
    <div th:each="region : ${regions}" class="form-check form-check-inline">
        <input type="checkbox" th:field="*{regions}" th:value="${region.key}"
               class="form-check-input">
        <label th:for="${#ids.prev('regions')}"
               th:text="${region.value}" class="form-check-label">서울</label>
    </div>
</div>
  • 체크박스가 여러개 만들어져야하기 때문에 for each 문을 사용해서 만들어준다. 변수의 값은 우리가 만든 regions를 주면된다.
  • id 가 타임리프에 의해 동적으로 만들어지기 때문에 label for = "id 값" 으로 label의 대상이 되는 id 값이 임의로 만들어지면 문제가 생길 수 있기 때문에 타임리프는 ids.prev(..),ids.next(...) 을 제공해서 동적으로 생성
  • each 루프안에서 id는 모두 달라야하기 때문에 타임리프는 체크박스를 루프안에서 만들때 임의로 1, 2, 3 숫자를 뒤에 붙여준다.

번호를 임의로 붙여준 모습

  • 마찬가지로 _regions가 만들어진 모습 -> 이것도 보내지 않을 경우 결과는 null 이 되기 때문에
profile
열심히하자
post-custom-banner

0개의 댓글