쌓고 쌓다

로그인 여부에 따라 헤더(네비게이션) 바꾸기 - 템플릿 조각 본문

프로그래밍/thymeleaf

로그인 여부에 따라 헤더(네비게이션) 바꾸기 - 템플릿 조각

승민아 2023. 9. 27. 13:17

목표 기능

html을 보여주는데 로그인 여부에 따라 일부 태그만 교체하길 원한다.

 

먼저 아래와 같이 세션을 통해

"LOGIN_MEMBER" 세션이 존재에 따라 상단 바를 달리하길 원한다.

로그인한 사람을 위한 상단 바를, 게스트라면 게스트 바를 replace 해보자.

 

HomeController

@GetMapping("/")
public String home(@SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model model) {

    if (loginMember == null) {
        model.addAttribute("isLogin", false);
    } else {
        model.addAttribute("isLogin", true);
        model.addAttribute("member", loginMember);
    }

    return "home";
}

Model에 로그인 여부에 따라 "isLogin"으로 true, false를 관리한다.

이때 로그인한 회원이라면 회원 정보를 "member"에 담는다.

 

home.html

<th:block th:if="${isLogin}" >
    <div th:replace="~{template/fragment/loginHeader :: loginNav}">loginMember Header</div>
</th:block>

<th:block th:unless="${isLogin}">
    <div th:replace="~{template/fragment/guestHeader :: guestNav}">guest Header</div>
</th:block>

isLogin에 맞춰 템플릿 조각을 가져온다.

 

replace 사용은 아래와 같다.

th:replace="~{경로 :: 가져올 조각명}"

 

이제 경로에 조각을 만들어 보자.

loginHeader.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>


<!-- loginNav 조각 -->
<header th:fragment="loginNav">
    <h1>status: login</h1>
    <h1 th:text="${member.name}"></h1>
    <form method="post" action="/logout">
        <button type="submit" id="logout">로그아웃</button>
    </form>
</header>


</body>
<script src="/js/bootstrap.min.js"></script>
</html>
  • th:fragment : 조각명을 지정한다.

 

guestHeader.html

<!DOCTYPE html>
<html lang="en" xmlns:th="http://thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link href="/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>


<!-- guestNav 조각 -->
<header th:fragment="guestNav">
    <h1>status: guest</h1>
    <button id="login" class="btn btn-primary">로그인</button>
</header>


<script src="/js/bootstrap.min.js"></script>
</body>
</html>

 

이제 "/"로 로그인 여부에 따라

GET 요청의 응답 페이지를 한번 보자.

 

비 로그인시

 

로그인시

 

 

구현 결과

 

그러나.. 생각해보니 위의 코드에는 문제점이 있다...!

모든 페이지마다 if unless 분기로 확인하는 코드를 작성해야하는 번거로움이 존재한다.

즉. 반복되는 코드를 지저분하게 계속 써줘야한다는 것이다.

 

그래서 레이아웃의 필요성을 느꼈고.

다음은 레이아웃으로 header를 달리해보자.~

 

 

+ 레이아웃을 안하더라도 하나의 header로 사용이 가능했었다..

<!-- home.html -->
<th:block th:replace="~{template/fragment/header :: headerFragment}"></th:block>


<!-- header.html -->
<th:block th:fragment="headerFragment">
    <th:block th:if="${isLogin}">
        <header>
            <h1>status: login</h1>
            <h1 th:text="${member.name}"></h1>
            <form method="post" action="/logout">
                <button type="submit" id="logout">로그아웃</button>
            </form>
        </header>
    </th:block>
    <th:block th:unless="${isLogin}">
        <header>
            <h1>status: guest</h1>
            <button id="login" class="btn btn-primary">로그인</button>
        </header>
    </th:block>
</th:block>

 

+ 모든 Controller에서 Model에 로그인 여부인 isLogin을 넘겨주는 코드를 작성하면 지저분하다!

타임리프에서 세션을 읽는 방법이 있어 세션을 보고 템플릿 조각을 달리 넣어주는 훌륭한 방법이 존재한다.

이 방법에 대해서 다른 게시글로 포스팅하겠다.

 

 

 

- th:if 뒤의 th:replace가 실행되는 문제

기존에 th:block을 안쓰고 th:if, th:unless를 아래와 같이 작성하려고 했으나

<div th:if="${isLogin}" th:replace="~{template/fragment/loginHeader :: loginNav}">loginMember Header</div>
<div th:unless="${isLogin}" th:replace="~{template/fragment/guestHeader :: guestNav}">guest Header</div>

타임리프의 조건문에 상관 없이 뒤의 replace 문법까지 실행시켜버리는 문제점이 있었다.

그래서 th:block으로 만들고 그 안에 또 태그를 만들어 조건문에따라 th:replace를 수행하도록 했다.

 

 

 

 

 

 

 

 

 

 

Comments