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

表单提交至数据库时Title与Content未存储问题排查

问题描述

点击「게시글 작성(帖子发布)」按钮后页面重定向至首页,但数据库中仅id、author、publishedDateTime字段有值,表单填写的title和content为null,无法定位问题。


相关代码

Post 实体类

@Entity
@Getter @EqualsAndHashCode(of = "id")
@Builder @AllArgsConstructor @NoArgsConstructor
public class Post {

    @Id @GeneratedValue
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY)
    private Account author;

    private String title;

    @Lob @Basic(fetch = FetchType.EAGER)
    private String content;

    private LocalDateTime publishedDateTime;

    private LocalDateTime modifiedDateTime;

    public void addAuthor(Account account) {
        this.publishedDateTime = LocalDateTime.now();
        this.author = account;
    }
}

PostForm 表单类

@Data
public class PostForm {

    @NotBlank
    @Length(max = 100)
    private String title;

    @NotBlank
    private String content;
}

PostController 控制器

@Controller
@RequiredArgsConstructor
public class PostController {

    private final PostService postService;
    private final PostRepository postRepository;
    private final ModelMapper modelMapper;

    @GetMapping("/announcement/write")
    public String newAnnouncementForm(@CurrentAccount Account account, Model model) {
        model.addAttribute(account);
        model.addAttribute(new PostForm());
        return "post/form";
    }

    @PostMapping("/announcement/write")
    public String writeNewAnnouncement(@CurrentAccount Account account, @Valid PostForm postForm, Errors errors, Model model) {
        if (errors.hasErrors()) {
            model.addAttribute(account);
            return "post/form";
        }

        Post newPost = postService.createNewPost(modelMapper.map(postForm, Post.class), account);
        return "redirect:/";
    }
}

PostService 业务层

@Service
@Transactional
@RequiredArgsConstructor
public class PostService {

    private final PostRepository postRepository;

    public Post createNewPost(Post post, Account account) {
        Post newPost = postRepository.save(post);
        newPost.addAuthor(account);
        return newPost;
    }
}

PostRepository 数据访问层

@Transactional(readOnly = true)
public interface PostRepository extends JpaRepository<Post, Long> {
}

前端表单页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head th:replace="fragments.html :: head"></head>
<body>
    <div th:replace="fragments.html :: main-nav"></div>
    <div class="container">
        <div class="py-5 text-center">
            <h2>게시글 작성</h2>
        </div>
        <div class="row justify-content-center">
            <form class="needs-validation col-sm-8" th:action="@{/announcement/write}" th:object="${postForm}" method="post" novalidate>
                <div class="form-group">
                    <label for="title">제목</label>
                    <input id="title" type="text" th:field="*{title}" class="form-control"
                           placeholder="제목" aria-describedby="titleHelp" required max="100">
                    <small class="invalid-feedback">제목을 입력하세요.</small>
                    <small class="form-text text-danger" th:if="${#fields.hasErrors('title')}" th:errors="*{title}">Title Error</small>
                </div>

                <div class="form-group">
                    <label for="content">내용</label>
                    <textarea id="content" type="textarea" th:field="*{content}" class="form-control"
                              placeholder="내용을 작성해주세요." aria-describedby="contentHelp" required></textarea>
                    <small class="invalid-feedback">내용를 입력하세요.</small>
                    <small class="form-text text-danger" th:if="${#fields.hasErrors('content')}" th:errors="*{content}">Content Error</small>
                </div>

                <div class="form-group">
                    <button class="btn btn-primary btn-block" type="submit" aria-describedby="submitHelp">게시글 작성</button>
                </div>
            </form>
        </div>
    </div>
    <div th:replace="fragments.html :: footer"></div>
    <script th:replace="fragments.html :: form-validation"></script>
    <script src="/node_modules/summernote/dist/summernote-bs4.js"></script>
    <script type="application/javascript">
        $(function () {
            $('#content').summernote({
                fontNames: ['Arial', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Noto Sans KR', 'Merriweather'],
                placeholder: '내용을 입력해주세요.',
                tabsize: 2,
                height: 600
            });
        });
    </script>
</body>
</html>

问题修复方案

1. 补充Post实体的Setter方法

Post实体仅标注了@Getter,没有提供Setter方法,导致ModelMapper无法将PostForm中的title和content映射到Post对象。

修复代码:
给Post实体添加@Setter注解:

@Entity
@Getter @Setter // 添加Setter
@EqualsAndHashCode(of = "id")
@Builder @AllArgsConstructor @NoArgsConstructor
public class Post {
    // 原有代码不变
}

或者手动为title和content添加Setter方法:

public void setTitle(String title) {
    this.title = title;
}

public void setContent(String content) {
    this.content = content;
}

2. 调整Service层的保存顺序

当前Service先保存空属性的Post,再设置作者信息,虽然JPA会自动同步持久化对象的修改,但更合理的方式是先完成所有属性赋值再执行保存操作,避免潜在的持久化上下文问题。

修复代码:

@Service
@Transactional
@RequiredArgsConstructor
public class PostService {

    private final PostRepository postRepository;

    public Post createNewPost(Post post, Account account) {
        post.addAuthor(account); // 先设置作者和发布时间
        return postRepository.save(post); // 再执行保存
    }
}

3. 同步Summernote编辑器内容到textarea

前端使用Summernote时,编辑器会替换原生textarea,默认情况下表单提交时不会自动同步编辑器内容到textarea,导致content字段为空。

修复代码:
在表单提交前添加同步逻辑:

$(function () {
    $('#content').summernote({
        fontNames: ['Arial', 'Arial Black', 'Comic Sans MS', 'Courier New', 'Noto Sans KR', 'Merriweather'],
        placeholder: '내용을 입력해주세요.',
        tabsize: 2,
        height: 600
    });

    // 表单提交前同步编辑器内容
    $('form').submit(function() {
        $('#content').val($('#content').summernote('code'));
    });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 13:23:10