You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Thymeleaf视图中渲染DTO定义的校验提示信息?

Spring Boot + Thymeleaf 校验错误信息不显示问题排查与解决

我正在开发一个Spring Boot项目,希望将DTO中定义的校验错误信息(尤其是content字段)直接通过Thymeleaf显示在视图上。目前校验逻辑正常(例如字段为空时会阻止表单提交),但DTO中@NotEmpty和@Size注解定义的错误信息无法在视图中渲染,负责显示错误的元素始终为空。

实体类

package io.github.haebin827.hiphopreview.kr.domain;

import jakarta.persistence.*;
import lombok.*;
import org.springframework.data.annotation.CreatedDate;

import java.time.LocalDateTime;

@Entity
@Getter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Feedback {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(nullable = false, columnDefinition = "TEXT")
    private String content;

    @CreatedDate
    @Column(updatable = false)
    private LocalDateTime regDate;

    @PrePersist
    protected void onCreate() {
        this.regDate = LocalDateTime.now();
    }
}

DTO类

@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class FeedbackDTO {
    private Integer id;

    @NotEmpty(message = "Content is required.")
    @Size(min = 1, max = 1000, message = "Content should be less than 1000 letters")
    private String content;

    private LocalDateTime regDate;
}

控制器代码

@GetMapping("/feedback")
public void feedbackGET(Model model) {
    model.addAttribute("feedback", new Feedback());
}

@PostMapping("/feedback")
public String feedbackPOST(@Valid @ModelAttribute("feedbackDTO") FeedbackDTO feedbackDTO, BindingResult bindingResult, Model model) {

    if (bindingResult.hasErrors()) {
        return "support/feedback";
    }

    // All the logics to save DTO to the database

    return "redirect:/support/feedback";
}

Thymeleaf视图代码

<!doctype html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      xmlns:th="http://www.thymeleaf.org"
      layout:decorate="~{layout/base.html}">

<div layout:fragment="content" class="col-9 mx-auto" style="text-align: center; margin-top: 100px; margin-bottom: 150px;">
    <div>
        <h3 class="mb-2" style="display: inline-block; color: #333;">Sending a feedback</h3>
        <hr class="mb-6" style="margin-bottom: 40px; margin-top: 40px; border: 1px solid #555;">
        <form id="feedbackForm"
              th:action="@{/support/feedback}"
              th:object="${feedbackDTO}"
              method="post"
              style="text-align: left;"
              class="col-8 mx-auto" novalidate>

            <div class="row mb-4">
                <label for="content" class="col-md-3 col-form-label text-md-end font-weight-bold">
                    Content <span style="color: red;">*</span>:
                </label>
                <div class="col-md-9">
                    <textarea id="content"
                              name="content"
                              class="form-control"
                              rows="4"
                              th:field="*{content}"
                              required></textarea>
                    <div class="item field invalid" th:if="${#fields.hasErrors('content')}" th:errors="*{content}">
                        <!-- DTO message will be appeared here -->
                    </div>
                </div>
            </div>

            <!-- Submit button -->
            <div class="row">
                <div class="col-md-9 offset-md-3 text-end">
                    <button type="submit" class="btn btn-dark rounded-pill">
                        Submit
                    </button>
                </div>
            </div>
        </form>
    </div>
</div>

<script layout:fragment="script" th:inline="javascript">
    document.addEventListener("DOMContentLoaded", function () {
        const form = document.getElementById('feedbackForm');
        form.addEventListener('submit', function (event) {
            if (!form.checkValidity()) {
                event.preventDefault();
                event.stopPropagation();
            }
            form.classList.add('was-validated');
        }, false);
    });
</script>
</html>

问题原因分析

  • 模型属性不匹配:GET请求中往Model添加的是feedback(实体对象),但视图表单绑定的是feedbackDTO。校验失败返回视图时,Thymeleaf找不到对应的DTO对象,无法关联BindingResult中的错误信息。
  • 前端原生校验干扰:表单的novalidate属性配合JS的checkValidity()逻辑,会触发浏览器原生校验提示,掩盖后端返回的自定义错误信息。

修正方案

1. 对齐GET请求的模型属性

修改feedbackGET方法,将Model中的属性改为feedbackDTO,确保视图初始化时就有正确的绑定对象:

@GetMapping("/feedback")
public void feedbackGET(Model model) {
    model.addAttribute("feedbackDTO", new FeedbackDTO());
}

2. 调整前端校验逻辑(可选)

如果想完全使用后端自定义错误信息,可移除前端原生校验相关逻辑:

document.addEventListener("DOMContentLoaded", function () {
    const form = document.getElementById('feedbackForm');
    form.removeAttribute('novalidate');
    // 移除原生校验阻止逻辑,交由后端处理
    form.addEventListener('submit', function (event) {}, false);
});

3. 确认参数顺序(已符合要求,仅做验证)

Spring MVC要求BindingResult必须紧跟在@Valid注解的参数之后,你的代码已满足此规则,无需修改。


内容的提问来源于stack exchange,提问作者Haebin Noh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 02:50:00