스프링 MVC 2 정리 - 2. 타임리프 - 스프링 통합과 폼 / 3. 메세지 국제화 (22.8.7)

0

Today I learned

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

김영한 선생님의 스프링 MVC 2편 강의를 듣고 정리한 내용이다.

2. 타임리프 - 스프링 통합과 폼

2.1. 입력 폼 처리

th:object : 커맨드 객체를 지정한다.
*{...} : 선택 변수 식이라고 한다. th:object 에서 선택한 객체에 접근한다.
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="formcontrol" placeholder="이름을 입력하세요">
 </div>

th:field

렌더링 전
<input type="text" th:field="*{itemName}" />

렌더링 후
<input type="text" id="itemName" name="itemName" th:value="*{itemName}" />


  • th:object="${item}" : <form> 에서 사용할 객체를 지정한다. 선택 변수 식( *{...} )을 적용할 수있다.
  • th:field="*{itemName}"
    *{itemName} 는 선택 변수 식을 사용했는데, ${item.itemName} 과 같다. 앞서 th:objectitem 을 선택했기 때문에 선택 변수 식을 적용할 수 있다.

렌더링 전

<input type="text" id="itemName" th:field="*{itemName}" class="form-control"
placeholder="이름을 입력하세요">

렌더링 후

<input type="text" id="itemName" class="form-control" placeholder="이름을
입력하세요" name="itemName" value="">

2.2. 체크박스 - 단일

  • 체크박스는 체크시 HTML에서 open = on이라는 값이 넘어가고 스프링 타입 컨버터가 ontrue 타입으로 변환해준다.

  • 다만 체크박스 선택하지 않을 시 open field 자체가 서버로 전송되지 않는다. 수정의 경우에는 이게 문제가 될 수 있다.

  • 이를 해결 하기 위해 MVC는 히든 필드를 하나 만드는데, 체크 박스 이름 앞에 _를 붙여서 전송하면 체크를 헤제했다고 인식할 수 있다. 체크를 해제한 경우 '_open'만 전송돼서 이를 통해 체크 해제를 판단한다.

<input type="checkbox" id="open" name="open" class="form-check-input">
<input type="hidden" name="_open" value="on" > // 히든필드

2.3. 체크박스 - 단일 (타임리프로 간단하게)

  • 타임필드가 자동으로 위의 코드를 생성해준다
<input type="checkbox" id="open" th:field="*{open}" class="form-check-input">

2.4. 체크박스 - 멀티

  • 위의 체크박스를 확장해서 다중 선택이 가능케 한다.

  • 여기서 ModelAttribute를 기존과는 조금 다르게 활용한다.

  • 체크 박스를 반복해서 보여주어야 하는데, 이를 위해선 각각의 컨트롤러에서 model.addAttribute(...)를 사용해서 체크 박스를 구성하는 데이터를 반복해서 넣어주어야 한다. 이를 위해 컨트롤러에 아래와 같이 ModelAttribute를 이용하면,

	@ModelAttribute("regions")// 일반적인 ModelAttribute와 다른 기능
    public Map<String, String> regions(){
        Map<String, String> regions = new LinkedHashMap<>();
        regions.put("SEOUL", "서울");
        regions.put("BERLIN", "베를린");
        regions.put("LIVERPOOL", "리버풀");
        return regions;
    } // 컨트롤러 호출시 항상 ModelAttribute를 통해 regions의 반환 값이 Model에 자동으로 담긴다.

#ids

th:for="${#ids.prev('regions')}"
멀티 체크박스는 같은 이름의 여러 체크박스를 만들 수 있다. 그런데 문제는 이렇게 반복해서 HTML 태그를 생성할 때, 생성된 HTML 태그 속성에서 name 은 같아도 되지만, id 는 모두 달라야 한다. 따라서 타임리프는 체크박스를 each 루프 안에서 반복해서 만들 때 임의로 1 , 2 , 3 숫자를 뒤에 붙여준다.

HTML의 id 가 타임리프에 의해 동적으로 만들어지기 때문에 <label for="id 값"> 으로 label 의 대상이 되는 id 값을 임의로 지정하는 것은 곤란하다. 타임리프는 ids.prev(...) , ids.next(...) 을 제공해서 동적으로 생성되는 id 값을 사용할 수 있도록 한다.


2.5. 라디오 버튼

  • 여러 선택지 중에 하나만 고르는 것이 라디오 버튼이다. ENUM을 통해서 개발해본다.
  • 먼저 앞서 설명한 ModelAttribute의 기능을 활용한다.
	@ModelAttribute("itemTypes")
    public ItemType[] itemTypes(){
        ItemType[] values = ItemType.values();
        return values; // ENUM의 정보를 배열로 반환 
    }
<div>
	<div>상품 종류</div>
    <div th:each="type : ${itemTypes}" class="form-check form-check-inline">
        <input type="radio" th:field="*{itemType}" th:value="${type.name()}" class="form-check-input">
        <label th:for="${#ids.prev('itemType')}" th:text="${type.description}" class="form-check-label">
            BOOK
        </label>
    </div>
</div>
  • 한번 선택하면 다시 NULL로 그 값을 바꿀수 없다는 특징이 있다. 그래서 별도의 히든 필드 사용의 필요성이 떨어진다.

2.6. 셀렉트 박스

  • 여러 선택지 중에 하나를 선택할 때에 사용한다.

  • 먼저 자바 객체를 만들고 반환해서 ModelAttribute를 활용한다.

<!-- SELECT -->
<div>
    <div>배송 방식</div>
    <select th:field="*{deliveryCode}" class="form-select">
        <option value="">==배송 방식 선택==</option>
        <option th:each="deliveryCode : ${deliveryCodes}" th:value="${deliveryCode.code}"
        		th:text="${deliveryCode.displayName}">FAST</option>
    </select>
</div>
  • th:object를 사용하는지 등의 여부를 주목한다.
<select th:field="${item.deliveryCode}" class="form-select" disabled>
  • disabled를 사용하면 셀렉트 박스를 선택되지 않게 할 수 있다.


3. 메시지 국제화

3.1. 메시지, 국제화 소개

3.1.1. 메시지

HTML 파일에 메시지가 하드코딩 되어있어서 바꾸기 곤란한 경우에, 다양한 메시지를 한 곳에서 관리하여 바꾸기 쉽게 할 수 있는 기능이 메시지 기능이다.

3.1.2. 국제화

메시지에서 설명한 메시지 파일(messages.properteis)을 각 나라별로 별도로 관리하면 서비스를 국제화 할 수 있다(접속 지역에 따라 언어를 다르게 설정)


3.2. 스프링 메시지 소스 설정

  • 직접 등록하는 방식도 있다.
  • 스프링 부트를 사용 하면 부트에서 자동으로 MessageSouce를 스프링 빈으로 등록한다.

application properties에 다음과 같은 코드를 넣으면 스프링 빈에 메세지 소스가 등록이 된다.
spring.messages.basename=messages


3.3. 스프링 메시지 소스 사용

/resources/messages.properties

hello=안녕
hello.name=안녕 {0}

/resources/messages_en.properties

hello=hello
hello.name=hello {0}
@Test
void helloMessage() {
        String result = ms.getMessage("hello", null, null);
        // 지역 설정이 default로 되어있어서 "안녕"이 실행이 됨
        assertThat(result).isEqualTo("안녕");
}
    
@Test
void argumentMessage() {
        String result = ms.getMessage("hello.name", new Object[]{"Spring"}, null);
        // 값을 넘겨서 치환하는데 Object[] 배열을 사용
        assertThat(result).isEqualTo("안녕 Spring");
}

@Test
void enLang() {
 assertThat(ms.getMessage("hello", null, Locale.ENGLISH)).isEqualTo("hello");
}
  • 메시지가 없는 경우에는 NoSuchMessageException 이 발생한다.
  • 메시지가 없어도 기본 메시지(defaultMessage)를 사용하면 기본 메시지가 반환된다.

3.4. 웹 어플리케이션에 메시지 적용하기

메시지를 활용하여 $대신 #을 쓰면 된다.
messages.propertieslabel.item=상품 등록시 아래 코드는

<div th:text="#{label.item}"></h2>

<div>상품</h2> 으로 렌더링 된다.


3.5. 웹 어플리케이션에 국제화 적용하기

크롬 -> 브라우저 설정 -> 언어를 검색하고, 우선 순위를 변경하면 된다.

웹 브라우저의 언어 설정 값을 변경하면 요청시 Accept-Language 의 값이 변경된다.

영어버전 메시지 파일을 수정한 후 크롬의 언어 설정에서 영어를 제일 위로 적용하면 적용되는 것을 확인 할 수 있다.

profile
공부한 내용 정리
post-custom-banner

0개의 댓글