FE없이 SSR, 좌충우돌 Thymeleaf 사용기

Shinny·2022년 8월 16일
0
post-custom-banner

1. Thymeleaf 템플릿 경로 관련 에러 해결

스프링 부트는 src/main/resources/templates 경로에서 템플릿을 찾는다. 하지만 만약에 모든 템플릿이 예를 들어 new-templates 폴더 안에 들어가도록 변경해야하는 요구사항이 들어왔다고 하자. 그러면 어떻게 해야할까? 아래와 같이 spring.thymeleaf.prefix를 변경해주면 된다. 기본적으로 suffix는 .html 로 되어 있다.

spring.thymeleaf.prefix=classpath:/new-templates/
spring.thymeleaf.suffix=.html

하지만 나는 프로젝트 진행 중 아래와 같은 에러 메세지를 만나게 되었다.

Exception processing template "/login/loginPage": 
Error resolving template [/login/loginPage], 
template might not exist or might not be accessible 
by any of the configured Template Resolvers

Why?

왜 일까? 더욱이 문제의 갈피를 잘 못 찾았던 것은, Local에서는 잘 실행이 되었는데, 호스팅을 했을 때 문제가 생긴 까닭이었다. 무엇이 원인이었을까? 그것은 내가 Spring MVC에서 view 를 반환할 때 그 경로를 /login/loginPage 이렇게 해두었기 때문. 인텔리제이 IDE에서는 중복 슬래시(//)도 알아서 처리를 해주지만 jar 파일로 배포를 할 때는 그러한 처리 과정이 없기 때문에 오류가 난 것이었다. 모든 view에서 앞에 있는 /(slash)를 제거해준 뒤 문제를 해결할 수 있었다.

2. Delete, Put Method 처리 방법 해결

<form th:action="@{/posts/{postId}/delete(postId=${postAndComments.id})}" 
th:object="${postAndComments}" th:method="delete">

Thymeleaf 에서는 Delete, Put 방식의 경우 post 방식으로 처리되지만, <input type="hidden" name="_method" value="delete"> or <input type="hidden" name="_method" value="put"> 이 추가되어서 Spring MVC에 의해 적절히 처리된다. 그래서 delete 방식의 경우 th:method=”delete” 로 하고, Controller 단에서는 @PostMapping으로 처리해야 한다.

// 게시글 삭제
@PostMapping("/posts/{postId}/delete")
public String deletePost(@AuthenticationPrincipal UserDetailsImpl userDetails,
                             @PathVariable Long postId) {
	boardService.deletePost(postId, userDetails.getUsername());
	return "redirect:/posts";
    }

3. 기타 특이점

th:object

form에서 submit을 할 때, form의 데이터가 th:object에 설정한 객체로 받아진다.

th:field

각 필드를 매핑해주는 역할을 한다. 설정해 준 값으로, th:object의 객체내부 값과 매칭해준다.

아래는 로그인 페이지 예시이다.

    <form th:object="${loginForm}" th:action="@{login}" method="post">
        <div>
            <label for="username" th:text="#{member.loginId}">아이디</label>
            <input th:type="text" id="username" th:field="*{username}" name="username">
        </div>
        <div>
            <label for="password" th:text="#{member.password}">비밀번호</label>
            <input th:type="password" id="password" th:field="*{password}" name="password">
        </div>
        <div class="checkbox">
            <label><input class="checkbox" type="checkbox" id="remember" name="remember-me">Remember me</label>
        </div>
        <div>
            <div class="form-check">
                <input type="checkbox" id="open" th:field="*{open}">
                <label for="open">자동 로그인</label>
            </div>
        </div>
        <button type="submit">로그인</button>
    </form>

Reference

https://www.baeldung.com/spring-thymeleaf-template-directory

profile
비즈니스 성장을 함께 고민하는 개발자가 되고 싶습니다.
post-custom-banner

0개의 댓글