【问题标题】:Error while trying to access the validation error in Thymleaf form尝试访问 Thymeleaf 表单中的验证错误时出错
【发布时间】:2020-04-24 19:34:10
【问题描述】:

属性、setter 和 getter 的命名是否有任何规则? 我有一个模型类,它具有名为 uuidString 属性和 setter 和 getter setUUID(String uuid) getUUID() 但是当尝试使用 Thymleaf 验证输入以显示错误(如果存在)时,它会崩溃
注意:deviceName 属性工作正常
以下是我的 sn-ps 代码:

模型

@Entity
public class Device {

    @Id
    @NotBlank
    private String uuid;

    @NotNull
    @NotBlank
    private String deviceName;

    public String getUUID() {
        return uuid;
    }

    public void setUUID(String uuid) {
        this.uuid = uuid;
    }

    public String getDeviceName() {
        return deviceName;
    }

    public void setDeviceName(String deviceName) {
        this.deviceName = deviceName;
    }
}

表格

<form method="post" action="#" th:action="@{/devices/save}" th:object="${device}">
    <input th:field="*{UUID}" th:classappend="${#fields.hasErrors('*{UUID}')} ?'border-danger'" type="text" name="uuid">
    <input th:field="*{deviceName}" th:classappend="${#fields.hasErrors('deviceName')} ?'border-danger'" type="text" name="deviceName">
</form>

尝试解析模板时出错 模板解析时出错(模板:“类路径资源 [templates/Devices/add-device.html]”) org.thymeleaf.exceptions.TemplateInputException:模板解析时出错(模板:“类路径资源[templates/Devices/add-device.html]”) 在 org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:241) 在 org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parseStandalone(AbstractMarkupTemplateParser.java:100) 在 org.thymeleaf.engine.TemplateManager.parseAndProcess(TemplateManager.java:666) 在 org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1098) 在 org.thymeleaf.TemplateEngine.process(TemplateEngine.java:1072) 在 org.thymeleaf.spring5.view.ThymeleafView.renderFragment(ThymeleafView.java:362) 在 org.thymeleaf.spring5.view.ThymeleafView.render(ThymeleafView.java:189) 在 org.springframework.web.servlet.DispatcherServlet.render(DispatcherServlet.java:1373) 在 org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1118) 在 org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1057) 在 org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) 在 org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) 在 org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:634) 在 org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) 在 javax.servlet.http.HttpServlet.service(HttpServlet.java:741) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:320) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.invoke(FilterSecurityInterceptor.java:126) 在 org.springframework.security.web.access.intercept.FilterSecurityInterceptor.doFilter(FilterSecurityInterceptor.java:90) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.access.ExceptionTranslationFilter.doFilter(ExceptionTranslationFilter.java:118) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.session.SessionManagementFilter.doFilter(SessionManagementFilter.java:137) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter(AnonymousAuthenticationFilter.java:111) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter.doFilter(SecurityContextHolderAwareRequestFilter.java:158) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.savedrequest.RequestCacheAwareFilter.doFilter(RequestCacheAwareFilter.java:63) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:200) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:116) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.csrf.CsrfFilter.doFilterInternal(CsrfFilter.java:117) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.header.HeaderWriterFilter.doHeadersAfter(HeaderWriterFilter.java:92) 在 org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:77) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:105) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:56) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:334) 在 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:215) 在 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:178) 在 org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:358) 在 org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:271) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) 在 org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) 在 org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) 在 java.lang.Thread.run(Thread.java:748)
原因:org.attoparser.ParseException:评估 SpringEL 表达式的异常:“#fields.hasErrors('uuid')”(模板:“Devices/add-device” - 第 28 行,第 87 列) 在 org.attoparser.MarkupParser.parseDocument(MarkupParser.java:393) 在 org.attoparser.MarkupParser.parse(MarkupParser.java:257) 在 org.thymeleaf.templateparser.markup.AbstractMarkupTemplateParser.parse(AbstractMarkupTemplateParser.java:230) ... 88 更多
引起:org.thymeleaf.exceptions.TemplateProcessingException:评估 SpringEL 表达式的异常:“#fields.hasErrors('uuid')”(模板:“Devices/add-device” - 第 28 行,第 87 列) 在 org.thymeleaf.spring5.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:290) 在 org.thymeleaf.standard.expression.VariableExpression.executeVariableExpression(VariableExpression.java:166) 在 org.thymeleaf.standard.processor.AbstractStandardExpressionAttributeTagProcessor.doProcess(AbstractStandardExpressionAttributeTagProcessor.java:144) 在 org.thymeleaf.processor.element.AbstractAttributeTagProcessor.doProcess(AbstractAttributeTagProcessor.java:74) 在 org.thymeleaf.processor.element.AbstractElementTagProcessor.process(AbstractElementTagProcessor.java:95) 在 org.thymeleaf.util.ProcessorConfigurationUtils$ElementTagProcessorWrapper.process(ProcessorConfigurationUtils.java:633) 在 org.thymeleaf.engine.ProcessorTemplateHandler.handleStandaloneElement(ProcessorTemplateHandler.java:918) 在 org.thymeleaf.engine.TemplateHandlerAdapterMarkupHandler.handleStandaloneElementEnd(TemplateHandlerAdapterMarkupHandler.java:260) ... 90 更多
原因:org.springframework.beans.NotReadablePropertyException:bean 类 [com.logica.eguestbookservice.Models.Device] 的无效属性“uuid”:Bean 属性“uuid”不可读或具有无效的 getter 方法:返回类型是否getter 的参数类型是否匹配 setter 的参数类型? 在 org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:622) 在 org.springframework.beans.AbstractNestablePropertyAccessor.getPropertyValue(AbstractNestablePropertyAccessor.java:612) 在 org.springframework.validation.AbstractPropertyBindingResult.getActualFieldValue(AbstractPropertyBindingResult.java:104) 在 org.springframework.validation.AbstractBindingResult.getFieldValue(AbstractBindingResult.java:228) 在 org.springframework.web.servlet.support.BindStatus.(BindStatus.java:129) 在 org.springframework.web.servlet.support.RequestContext.getBindStatus(RequestContext.java:903) 在 org.thymeleaf.spring5.context.webmvc.SpringWebMvcThymeleafRequestContext.getBindStatus(SpringWebMvcThymeleafRequestContext.java:227) ... 113 更多

【问题讨论】:

  • 错误/堆栈跟踪与您的代码不匹配。您的属性名为 UUID 而不是 uuid 后者是字段的名称,而不是属性的名称。属性的名称是通过 getter/setter 来识别的。
  • 这就是为什么我无法解决它,因为我不明白为什么它希望属性为uuid
  • 它没有。如前所述,您的代码与错误不匹配。您应该使用UUID,因为这是属性的名称。
  • 模型中的代码有字符串uuid,但setter函数是setUUID(),这是问题所在,但感谢@Wim,我通过将setter名称更改为setUuid()解决了这个问题
  • 字段的命名方式无关紧要,getter/setter 的名称很重要,因为它是属性的名称。如果您有 setUuid,则该字段可以命名为 foo,该属性命名为 uuid 而不是 foo。所以UUID 应该像从getter/setter 派生的那样工作。但如前所述,您以表格形式发布的内容与错误不符。属性的命名在 Java Bean 规范中定义(参见 oracle.com/technetwork/java/javase/documentation/…)。

标签: spring spring-boot validation spring-mvc thymeleaf


【解决方案1】:

Thymeleaf 很可能遵循 JavaBean 规范,因此您需要将方法命名为 getUuid()setUuid 并将形式更改为:

<input th:field="*{uuid}" th:classappend="${#fields.hasErrors('*{uuid}')} ?'border-danger'" type="text" name="uuid">

【讨论】:

猜你喜欢
  • 2018-11-23
  • 2020-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-08-24
  • 1970-01-01
  • 2018-11-03
  • 1970-01-01
相关资源
最近更新 更多