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

Spring表单未设置creationDate字段提交出现400错误,如何解决?

解决Spring MVC表单提交400错误的问题

你的400错误不是因为creationDate没在表单中设置,而是因为Spring MVC在绑定请求参数到BlogPost对象时遇到了两个核心问题:


问题根源分析

  1. Category字段绑定失败:表单的<form:select>传递的是PostCategory的id(整数类型),但BlogPost中的category字段是PostCategory对象类型。Spring默认无法自动将整数转换为PostCategory实例,这会触发参数绑定异常,直接返回400错误。
  2. CreationDate的潜在更新问题:虽然你在新增时手动设置了creationDate,但修改操作时,由于表单没有传递该字段,绑定后的BlogPost对象中creationDate会是null,执行updateBlogPost时会把数据库中已有的创建日期覆盖为null,这是一个隐藏bug。

解决方案

方案1:注册类型转换器(推荐,更优雅)

实现Spring的Converter接口,让Spring自动将整数(Category ID)转换为PostCategory对象:

  1. 创建转换器类:
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@Component
public class IntegerToPostCategoryConverter implements Converter<Integer, PostCategory> {

    private final PostCategoryServiceImpl postCategoryService;

    // 构造注入Service
    public IntegerToPostCategoryConverter(PostCategoryServiceImpl postCategoryService) {
        this.postCategoryService = postCategoryService;
    }

    @Override
    public PostCategory convert(Integer source) {
        if (source == null) {
            return null;
        }
        return postCategoryService.getPostCategory(source);
    }
}
  1. 配置转换器(如果使用Spring Boot,会自动扫描@Component标记的转换器,无需额外配置;如果是XML配置,需要在<mvc:annotation-driven>节点中注册该转换器)。

这样修改后,Spring会自动将表单传递的Category ID转换为PostCategory对象,你可以删除控制器中blogPost.setCategory(...)这行代码,简化逻辑。


方案2:添加中间字段(快速解决)

在BlogPost实体中添加一个categoryId字段(不需要映射到数据库),用于表单绑定:

@Entity
@Table(name="BlogPost")
public class BlogPost implements Serializable {
    // 原有字段不变...
    
    // 新增中间字段,不映射数据库
    @Transient
    private Integer categoryId;

    // getter和setter
    public Integer getCategoryId() {
        return categoryId;
    }

    public void setCategoryId(Integer categoryId) {
        this.categoryId = categoryId;
    }
}

然后修改表单的<form:select>的path为categoryId:

<form:select path="categoryId">
    <c:forEach items="${allCats}" var="cat" >
        <form:option value="${cat.id}"> ${cat.title} </form:option>
    </c:forEach>
</form:select>

最后在控制器中处理:

@RequestMapping(value = "/saveBlogPost", method = RequestMethod.POST)
public ModelAndView saveBlogPost(@ModelAttribute BlogPost blogPost) {
    if (blogPost.getId() == 0) {
        // 新增时设置分类和创建日期
        blogPost.setCategory(postCategoryServiceImpl.getPostCategory(blogPost.getCategoryId()));
        blogPost.setCreationDate(new Date());
        blogPostServiceImpl.addBlogPost(blogPost);
    } else {
        // 修改时先从数据库获取原有对象,避免覆盖创建日期
        BlogPost existingPost = blogPostServiceImpl.getBlogPost(blogPost.getId());
        // 复制表单提交的字段
        existingPost.setTitle(blogPost.getTitle());
        existingPost.setText(blogPost.getText());
        existingPost.setCategory(postCategoryServiceImpl.getPostCategory(blogPost.getCategoryId()));
        // 保留原有的创建日期
        blogPostServiceImpl.updateBlogPost(existingPost);
    }
    return new ModelAndView("redirect:/");
}

额外修复:CreationDate的更新问题

无论用哪种方案,修改操作时都不要直接使用表单绑定的BlogPost对象执行更新,因为表单没有传递creationDate,会导致该字段被设为null覆盖数据库中的值。正确的做法是先从数据库查询出原对象,再将表单中的字段复制到原对象上,保留原有的creationDate(如方案2的修改逻辑)。


这样处理后,不仅能解决400绑定错误,还能避免创建日期被意外覆盖的问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:54:21