Project/ClassFlix

[Class Flix] EP 19. 타임리프 리팩토링

Home

 

검색창에서 태그의 id 들을 th:field로 교체하기
(사이드 이펙트 발생하는지 판단하기)

 

String 타입의 멤버들은 th:field로 지정하면 멤버변수의 이름으로 id, name, value가 자동으로 생성되지만 String 타입이 아닌 Integer 타입 ratingGoe는 값 자체로 지정이 됩니다. 그래서 JS가 동작하지 않는 문제가 발생합니다. 따라서 String 타입의 멤버들만 th:field로 교체해주었습니다.

 

<div class="card-body">
            <div class="input-group input--medium">
                <label th:for="${condition.siteName}" class="label">사이트 이름</label>
                <input class="input--style-1" type="text" th:field="${condition.siteName}">
            </div>
            <div class="input-group input--large">
                <label th:for="${condition.lectureName}" class="label">강의 이름</label>
                <input class="input--style-1" type="text" th:field="${condition.lectureName}">
            </div>
            <div class="input-group input--medium">
                <label th:for="${condition.teacherName}" class="label">강의자 이름</label>
                <input class="input--style-1" type="text" th:field="${condition.teacherName}">
            </div>
            <div class="input-group input--medium">
                <label th:for="${condition.ratingGoe}" class="label">별 점</label>
                <div class="input-group-icon js-number-input">
                    <div class="icon-con">
                        <span class="plus">+</span>
                        <span class="minus">-</span>
                    </div>
                    <input class="input--style-1 quantity" type="text" id="ratingGoe" th:value="|${condition.ratingGoe}점 이상만|" disabled>
                </div>
            </div>
            <button th:onclick="goSearch([[${page.sortParam}]]);" class="btn-submit" type="submit">search</button>
        </div>

 

 

 

검색창의 rating 표시부분의 value 부분을 스프링에서 보내주는 데이터로 바꾸기

검색파라미터들을 다 <실제사용할 데이터, 뷰에 보여줄 값>으로 보내주려 했으나 타입이 다 달랐고 특히 ratingGoe는 처리가 더 복잡해질 것 같아 냅뒀습니다.

 

 

 

ratingGoe부분의 TextField 외부에서 접근하지 못하도록 하기

disabled를 주었더니 +-로만 제어가능하도록 됐습니다.

 

<input class="input--style-1 quantity" type="text" id="ratingGoe" th:value="|${condition.ratingGoe}점 이상만|" disabled>

 

 

정렬기준들도 스프링에서 보내주는 정렬기준에 따라 화면에 보여주기

  1. SortParam이라는 DTO클래스를 하나 만들어주고
  2. HomeController에서 @ModelAttribute를 통해 보내줍니다.
  3. th:block을 통해 code, displayName을 적절히 보여줍니다.

SortParam

package dongho.classflix.controller.dto;

import lombok.AllArgsConstructor;
import lombok.Data;

/**
 * code는 검색파라미터 역할
 * displayName은 고객에게 보여주는 값
 *
 * createdDate,DESC : 최신순
 * lectureName,ASC : 이름순
 */

@Data
@AllArgsConstructor
public class SortParams {
    private String code;
    private String displayName;
}

 

 

HomeController

    @ModelAttribute("sortParams")
    public List<SortParams> sortParams() {
        List<SortParams> sortParams = new ArrayList<>();
        sortParams.add(new SortParams("createdDate,DESC", "최신순"));
        sortParams.add(new SortParams("lectureName,ASC", "이름순"));
        return sortParams;
    }

 

Home.html

정렬조건 부분이 전보다 코드가 훨씬 짧아졌고 유지보수가 편리해졌습니다.

 

<th:block th:each="sortParam : ${sortParams}">
    <a th:text="${sortParam.displayName}" th:unless="${#strings.equals(page.sortParam, sortParam.code)}"
       th:href="@{/(page=${page.curPage},sort=${sortParam.code})}" class="btn btn-sm btn-default" role="button"></a>
    <a th:text="${sortParam.displayName}" th:if="${#strings.equals(page.sortParam, sortParam.code)}"
       class="btn btn-sm btn-default disabled" role="button"></a>
</th:block>

 

 

 

화면크기 줄이면 검색창 아래로 내려오는 부분해결하기
(디자인 관련부분이므로 후순위)

디자인관련이므로 일단 넘어가겠습니다.

 

정렬기준을 눌러도 기존의 검색조건들이 유지되도록하기

타임리프 리팩토링이므로 넘어가고, 쿠키와 세션을 학습한 뒤 다시 적용해보겠습니다.

 

 

 

 

 

 

 

 

Lecture

 

별점보여주기

별점 1~5부분을 html 하드코딩하지말고 스프링에서 1~5개의 데이터를 보내줘서 뷰로 보여주는걸로 리팩토링
(리뷰 수정부분도 해야함)

 

  1. controller에서 ratings에 별점 구성정보를 담아 @ModelAttribute로 보내줍니다.
  2. html에서 데이터를 받아 표현합니다.

 

LectureController

    @ModelAttribute("ratings")
    public Map<Integer, String> ratings() {
        Map<Integer, String> ratings = new LinkedHashMap<>();
        ratings.put(5, "★★★★★");
        ratings.put(4, "★★★★");
        ratings.put(3, "★★★");
        ratings.put(2, "★★");
        ratings.put(1, "★");
        return ratings;
    }

 

Lecture.html

... 리뷰작성
<select id="formStarRating" th:field="*{rating}" class="form-control">
    <option th:each="rating : ${ratings}" th:value="${rating.key}" th:text="${rating.value}"></option>
</select>
...


... 리뷰수정
<select th:field="*{rating}">
    <option th:each="rating : ${ratings}" th:value="${rating.key}" th:text="${rating.value}"></option>
</select>
...

 

 

LectureForm

 

 

전체적인 디자인을 가운데로 몰린 디자인으로 바꾸기

lectureForm의 css에서 container-center 클래스를 만들어 max-width를 제한해주었습니다.

 

lectureForm css

<style>
    ...
    .container-center {
        max-width: 560px;
    }
</style>

 

lectureForm.html

<div class="container container-center">
	...
</div>

 

 

가운데로 모니까 전보다 깔끔해진 모습.

 

 

 

 

 

 

memberForm

 

  1. label의 for를 ${#ids.prev('')} 로 바꾸기
  2. 성별 스프링에서 보내주는 데이터로 바꾸기
  3. 전체적으로 가운데로 몰리는 디자인으로 바꾸기

 

한번에 수정했습니다.

 

label의 for는 성별데이터를 스프링에서 타임리프로 보내줄때 타임리프의 반복문 상에서 "gender+넘버"로 아이디가 지정될때만 사용해주면 됩니다.

 

먼저 스프링에서 성별데이터를 genderTypes에서 넣어서 타임리프로 보내주도록 수정했습니다.

 

MemberController

    @ModelAttribute("genderTypes")
    public Gender[] genderTypes() {
        return Gender.values();
    }

 

 

memberForm.html

<div>
    <div><b>성별</b></div>
    <div class="radio" th:each="gender : ${genderTypes}">
        <input type="radio" th:field="*{gender}" th:value="${gender.name()}">
        <label th:for="${#ids.prev('gender')}" th:text="${gender.description}"></label>
    </div>
</div>

 

성별데이터를 추가해줄 일은 거의 없겠지만 그래도 스프링에서 보내주는 데이터를 화면은 처리만 하면되므로 유지보수가 편리해집니다.

 

 

 

lectureForm때와 마찬가지로 여기도 css에 .container-center 클래스를 추가해주고 max-width를 제한했습니다.

<style>
    ...
    .container-center {
        max-width: 360px;
    }
</style>

 

 

가운데로 몰아서 전보다 깔끔해지긴 했지만, 성별체크부분의 디자인이 약간 어색합니다.

 

radio-inline 클래스를 넣어봤지만 더 이상해서 그냥 이정도로만 마무리 하겠습니다.

 

 

 

 

 

이 외 추가 수정사항

 

스프링에서 보내주는 데이터들 스태틱 메서드로 만들기

매번 새로운 객체를 생성해 넣어주지 않고 static으로 컴파일될때 한번만 만드는 것이 성능측면에서 약간 더 좋습니다.

 

RatingsCreate

package dongho.classflix.domain;

import java.util.LinkedHashMap;
import java.util.Map;

public class RatingsCreate {
    private static final Map<Integer, String> ratings = new LinkedHashMap<>(){
        {
            put(5, "★★★★★");
            put(4, "★★★★");
            put(3, "★★★");
            put(2, "★★");
            put(1, "★");
        }
    };

    public static Map<Integer, String> getInstance() {
        return ratings;
    }

    private RatingsCreate() {
    }
}

 

 

SortParamsCreate

package dongho.classflix.domain;

import java.util.Arrays;
import java.util.List;

public class SortParamsCreate {
    private static final List<SortParams> sortParams = Arrays.asList(
            new SortParams("createdDate,DESC", "최신순"),
            new SortParams("lectureName,ASC", "이름순")
    );

    public static List<SortParams> getInstance() {
        return sortParams;
    }

    private SortParamsCreate() {
    }
}

 

 

이렇게 static 메서드로 미리 데이터를 넣어두면, 아래와 같이 인스턴스를 항상 만들지 않고 바로바로 꺼내쓸 수 있습니다.

 

 

LectureController

    @ModelAttribute("ratings")
    public Map<Integer, String> ratings() {
        return RatingsCreate.getInstance();
    }

 

 

HomeController

    @ModelAttribute("sortParams")
    public List<SortParams> sortParams() {
        return SortParamsCreate.getInstance();
    }