인프런 커뮤니티 질문&답변

jay님의 프로필 이미지
jay

작성한 질문수

실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발

타임리프가 객체를 인식못하는거 같습니다...

해결된 질문

작성

·

6.9K

0

안녕하세요.

강의 너무 잘 듣고있습니다. 감사합니다.

질문은 회원가입시

createMemberForm.html 으로 빈객체 (form)를 model에 담아 던지고 값을 채워서 submit으로 받는 과정에서

받은 객체의 필드값이 모두 null로 들어오더라고요...

그래서 제가 확인한 부분은

1. 타임리프가 잘 동작하는지 확인

2. 오타가 있는지 확인

혹시 이거 말고 다른 부분을 확인해야 하는 부분이 있나요?!

답변 3

2

김영한님의 프로필 이미지
김영한
지식공유자

th:object="${dto}" 이 부분이 문제입니다.

public String reservationCreated(@Valid ReservationSaveRequestDto dto..)

여기에서 다음과 같이 맞추어주시면 됩니다. 이름을 설정하지 않으면 ("reservationSaveRequestDto")이 되어버립니다.

public String reservationCreated(@Valid @ModelAttribute("dto") ReservationSaveRequestDto dto..)

감사합니다.

0

jay님의 프로필 이미지
jay
질문자

댓글 감사드립니다!!
제 스타일 대로 커스텀 하는 과정에서 setter를 지우고 생성자 빌더를 만드는 과정에서 문제가 생겼던거 같습니다.

하나만 더 질문 하겠습니다!!.

@Notnull 속성에  값을 입력하지 않고 submit을 했을때 에러가 발생하면서 

input란에 저희가 만든 class가 발동을 해야 정상 작동이잖아요

화면-html

<form role="form" action="/reservation/save" th:object="${dto}" method="post">

<div class="form-group row">
<label th:for="name" class="col-sm-2 col-form-label">예약자</label>
<div class="col-sm-10">
<input type="text" th:field="*{name}" class="form-control" placeholder="예약자 이름을 입력해주세요."
th:class="${#fields.hasErrors('name')}? 'form-control fieldError' : 'form-control'">
<p th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Incorrect name</p>
</div>
</div>

...
</form>

컨트롤러 -java

@GetMapping("/reservation/save")
public String reservationSave( Model model){
model.addAttribute("dto" , new ReservationSaveRequestDto());
return "reservation/reservationForm";
}
@PostMapping("/reservation/save")
public String reservationCreated(@Valid ReservationSaveRequestDto dto , BindingResult result , Model model){
if(result.hasErrors()) {
model.addAttribute("dto" , new ReservationSaveRequestDto());
return "reservation/reservationForm";
}

// ....로직


return "redirect:/";
}

위에 코드에서 

model.addAttribute("dto" , new ReservationSaveRequestDto());

이부분을 제외하고 돌리면 아래와 같은 에러가 발생합니다

어떠한 이유로 이러는지 알수있을까요? 항상 감사합니다

Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sun Jan 03 19:50:01 KST 2021
There was an unexpected error (type=Internal Server Error, status=500).
An error happened during template parsing (template: "class path resource [templates/reservation/reservationForm.html]")
org.thymeleaf.exceptions.TemplateInputException: An error happened during template parsing (template: "class path resource [templates/reservation/reservationForm.html]") at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241) at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100) at org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:666) at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) at org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072) at org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:362) at org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:189) at org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1371) at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1117) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1056) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) at javax.servlet.http.HttpServlet.service(HttpServlet.java:660) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882) at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:151) at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:86) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:118) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:853) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1587) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748) Caused by: org.attoparser.ParseException: Exception evaluating SpringEL expression: "#fields.hasErrors('name')" (template: "reservation/reservationForm" - line 26, col 36) at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393) at org.attoparser.MarkupParser.parse(MarkupParser.java:257) at org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230) ... 56 more Caused by: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#fields.hasErrors('name')" (template: "reservation/reservationForm" - line 26, col 36) at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290) at org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166) at org.thymeleaf.standard.expression.SimpleExpression.executeSimple(SimpleExpression.java:66) at org.thymeleaf.standard.expression.Expression.execute(Expression.java:109) at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138) at org.thymeleaf.standard.expression.ConditionalExpression.executeConditional(ConditionalExpression.java:209) at org.thymeleaf.standard.expression.ComplexExpression.executeComplex(ComplexExpression.java:77) at org.thymeleaf.standard.expression.Expression.execute(Expression.java:112) at org.thymeleaf.standard.expression.Expression.execute(Expression.java:138) at org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:144) at org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) at org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) at org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) at org.thymeleaf.engine.ProcessorTemplateHandler.handleStandaloneElement(ProcessorTemplateHandler.java:918) at org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleStandaloneElementEnd(TemplateHandlerAdapterMarkupHandler.java:260) at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler$InlineMarkupAdapterPreProcessorHandler.handleStandaloneElementEnd(InlinedOutputExpressionMarkupHandler.java:256) at org.thymeleaf.standard.inline.OutputExpressionInlinePreProcessorHandler.handleStandaloneElementEnd(OutputExpressionInlinePreProcessorHandler.java:169) at org.thymeleaf.templateparser.markup.InlinedOutputExpressionMarkupHandler.handleStandaloneElementEnd(InlinedOutputExpressionMarkupHandler.java:104) at org.attoparser.HtmlVoidElement.handleOpenElementEnd(HtmlVoidElement.java:92) at org.attoparser.HtmlMarkupHandler.handleOpenElementEnd(HtmlMarkupHandler.java:297) at org.attoparser.MarkupEventProcessorHandler.handleOpenElementEnd(MarkupEventProcessorHandler.java:402) at org.attoparser.ParsingElementMarkupUtil.parseOpenElement(ParsingElementMarkupUtil.java:159) at org.attoparser.MarkupParser.parseBuffer(MarkupParser.java:710) at org.attoparser.MarkupParser.parseDocument(MarkupParser.java:301) ... 58 more Caused by: java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'dto' available as request attribute at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:153) at org.springframework.web.servlet.support.RequestContext.getBindStatus(RequestContext.java:903) at org.thymeleaf.spring5.context.webmvc.SpringWebMvcThymeleafRequestContext.getBindStatus(SpringWebMvcThymeleafRequestContext.java:227) at org.thymeleaf.spring5.util.FieldUtils.getBindStatusFromParsedExpression(FieldUtils.java:306) at org.thymeleaf.spring5.util.FieldUtils.getBindStatus(FieldUtils.java:253) at org.thymeleaf.spring5.util.FieldUtils.getBindStatus(FieldUtils.java:227) at org.thymeleaf.spring5.util.FieldUtils.checkErrors(FieldUtils.java:212) at org.thymeleaf.spring5.util.FieldUtils.hasErrors(FieldUtils.java:71) at org.thymeleaf.spring5.expression.Fields.hasErrors(Fields.java:58) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:130) at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:111) at org.springframework.expression.spel.ast.MethodReference.access$000(MethodReference.java:54) at org.springframework.expression.spel.ast.MethodReference$MethodValueRef.getValue(MethodReference.java:390) at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:90) at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:109) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:328) at org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:263) ... 81 more

0

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. 재우님

다음 3가지 코드를 확인해주세요.

```

package jpabook.jpashop.controller;

import jpabook.jpashop.domain.Address;
import jpabook.jpashop.domain.Member;
import jpabook.jpashop.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

import javax.validation.Valid;
import java.util.List;

@Controller
@RequiredArgsConstructor
public class MemberController {

private final MemberService memberService;

@GetMapping("/members/new")
public String createForm(Model model) {
model.addAttribute("memberForm", new MemberForm());
return "members/createMemberForm";
}

@PostMapping("/members/new")
public String create(@Valid MemberForm form, BindingResult result) {

if (result.hasErrors()) {
return "members/createMemberForm";
}

Address address = new Address(form.getCity(), form.getStreet(), form.getZipcode());

Member member = new Member();
member.setName(form.getName());
member.setAddress(address);

memberService.join(member);
return "redirect:/";
}

@GetMapping("/members")
public String list(Model model) {
List<Member> members = memberService.findMembers();
model.addAttribute("members", members);
return "members/memberList";
}

}

```

package jpabook.jpashop.controller;

import lombok.Getter;
import lombok.Setter;

import javax.validation.constraints.NotEmpty;

@Getter @Setter
public class MemberForm {

@NotEmpty(message = "회원 이름은 필수 입니다")
private String name;

private String city;
private String street;
private String zipcode;
}

createMemberForm.html

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments/header :: header" />
<style>
.fieldError {
border-color: #bd2130;
}
</style>
<body>

<div class="container">
<div th:replace="fragments/bodyHeader :: bodyHeader"/>

<form role="form" action="/members/new" th:object="${memberForm}" method="post">
<div class="form-group">
<label th:for="name">이름</label>

<input type="text" th:field="*{name}" class="form-control" placeholder="이름을 입력하세요"
th:class="${#fields.hasErrors('name')}? 'form-control fieldError' : 'form-control'">
<p th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Incorrect date</p>

</div>
<div class="form-group">
<label th:for="city">도시</label>
<input type="text" th:field="*{city}" class="form-control" placeholder="도시를 입력하세요">
</div>
<div class="form-group">
<label th:for="street">거리</label>
<input type="text" th:field="*{street}" class="form-control" placeholder="거리를 입력하세요">
</div>
<div class="form-group">
<label th:for="zipcode">우편번호</label>
<input type="text" th:field="*{zipcode}" class="form-control" placeholder="우편번호를 입력하세요">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<br/>
<div th:replace="fragments/footer :: footer" />
</div> <!-- /container -->

</body>
</html>

감사합니다.

jay님의 프로필 이미지
jay

작성한 질문수

질문하기