[Spring] - SpringActionTagProcessor

๐Ÿ’ฌ ์ƒํ™ฉ ์„ค๋ช…

๊ฐ„๋‹จํ•˜๊ฒŒ ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋ฅผ ๋งคํ•‘ํ•˜๊ธฐ ์œ„ํ•ด @GetMapping์œผ๋กœ ์—ฐ๊ฒฐํ•ด์ค€ ๋’ค,
LoginRequestDto๋ฅผ model์— ๋‹ด์•„ View์— ๋ณด๋‚ด์ค€ ์ƒํƒœ์—์„œ ํ•ด๋‹น ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค.

[THYMELEAF][http-nio-8080-exec-1] Exception processing template "login-form": An error happened during template parsing (template: "class path resource [templates/login-form.html]")
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/login-form.html]")
Caused by: org.attoparser.ParseException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringActionTagProcessor' (template: "login-form" - line 30, col 31)
Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Error during execution of processor 'org.thymeleaf.spring5.processor.SpringActionTagProcessor' (template: "login-form" - line 30, col 31)
Caused by: java.lang.IllegalStateException: Cannot create a session after the response has been committed
Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/login-form.html]")] with root cause

๐Ÿ›  ๊ตฌํ˜„ ์ฝ”๋“œ

public class AccountController{
    @GetMapping("/login")
    public String login(Model model) {
        model.addAttribute("loginRequest", new LoginRequest());
        return "login-form";
    }
}
<form class="..."
      th:action="@{/login}" th:object="${loginRequest}" method="POST">

๐Ÿ”Ž ์›์ธ ๋ถ„์„

์šฐ์„  ์—ฌ๋Ÿฌ ๊ฐ€๋Šฅ์„ฑ์„ ๋ณด๊ธฐ ์œ„ํ•ด ํƒ€์ž„๋ฆฌํ”„ ๊ตฌ๋ฌธ์„ ์ง€์›Œ๋ณด๊ธฐ๋„ ํ–ˆ๊ณ , form์— ์žˆ๋Š” Attribute๋ฅผ ๋ชจ๋‘ ์ง€์›Œ๋ณด๊ธฐ๋„ ํ–ˆ๋‹ค.

์ด 2๊ฐ€์ง€์˜ ๊ฐ€๋Šฅ์„ฑ์„ ํ™•์ธํ–ˆ๋‹ค.

  1. method="POST"๋งŒ ์ œ๊ฑฐ
  2. th:action="@{/login}"๋งŒ ์ œ๊ฑฐ

๊ฒฐ๋ก ์ ์œผ๋กœ th:action์„ ํ†ตํ•ด POST ์š”์ฒญ์ด ๋˜๋Š” ๋ถ€๋ถ„์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ ๊ฒƒ์œผ๋กœ ๋ณด์ธ๋‹ค.

โœ… ํ•ด๊ฒฐ ๊ณผ์ •

๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋ดค์ง€๋งŒ, ๋Œ€๋ถ€๋ถ„์˜ ๊ธ€๋“ค์€ th:object, th:field์— ๋Œ€ํ•œ ์˜คํƒ€ ๋ฌธ์ œ์˜€๋‹ค. ๊ตญ๋‚ด ๋ธ”๋กœ๊ทธ๋‚˜ ์ปค๋ฎค๋‹ˆํ‹ฐ์—์„œ๋Š” ๋‹ต์„ ์ฐพ์„ ์ˆ˜ ์—†์–ด์„œ StackOverFlow๋กœ ํ–ฅํ•˜์˜€๊ณ , ๋‹ต์„ ์ฐพ์„ ์ˆ˜ ์žˆ์—ˆ๋‹ค.

public class SecurityConfig{
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                // ...
                .sessionManagement(
                        session -> session
                                .sessionCreationPolicy(SessionCreationPolicy.ALWAYS)
                );
        return http.build();
    }
}

๋กœ๊ทธ์ธ ๊ณผ์ •์„ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ์ž„์˜๋กœ session์„ ๋‚ ๋ฆฐ ์ ์ด ์žˆ๋Š”๋ฐ, ํ•ด๋‹น ๊ณผ์ •์—์„œ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธด ๊ฒƒ ๊ฐ™๋‹ค.
์šฐ์„  ์œ„์™€ ๊ฐ™์ด ์„ธ์…˜์ด ์—†๋‹ค๋ฉด ์„ธ์…˜์„ ์ƒ์„ฑํ•ด์ฃผ๋Š” ๋ฐฉ์‹์œผ๋กœ ํ•ด๊ฒฐํ•œ ๋’ค ๋‚˜์ค‘์— ๋‹ค๋ฅธ ๋ฐฉ๋ฒ•์„ ์ฐพ์œผ๋ฉด ๊ทธ ๋•Œ ์ œ๊ฑฐํ•ด๋„ ๋  ๊ฒƒ ๊ฐ™๋‹ค.

์ฐธ๊ณ  ๋ธ”๋กœ๊ทธ

๋Œ“๊ธ€๋‚จ๊ธฐ๊ธฐ