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

Spring MVC中POST请求时Controller对象未填充致数据保存失败

Spring MVC表单提交后数据无法保存的问题排查

问题描述

开发Spring MVC应用时,在JSP表单点击save按钮后数据无法保存,触发如下错误:

Request processing failed; nested exception is org.springframework.dao.DataIntegrityViolationException: could not execute statement; SQL [n/a]; constraint [null];

控制台输出显示,插入方法接收的Pass_in_trip对象大部分属性为空,仅place字段有值:

Pass_in_trip [key=null, trip=Trip [trip_no=0, comp=Company [id_comp=0, name=null], plane=null, town_from=null, town_to=null, time_out=null, time_in=null, passInTrips=[]], passenger=Passenger [name=null, passengerId=0, passInTrips=[]], place=6f, date=null]

错误原因分析

  • 表单参数绑定错误:JSP中直接传递整个实体对象字符串(如<select name="trip">),Spring无法将字符串转换为Trip/Passenger实例,只能生成空对象;日期字段type="datetime"兼容性差,无法自动转为Timestamp类型。
  • 复合主键未初始化:Pass_in_trip使用@EmbeddedId复合主键,但提交时未传递主键字段值,Spring无法自动生成复合主键,导致key为null触发数据库约束异常。
  • 未使用Spring表单标签:引入了Spring form标签库但未使用<form:form>,无法利用Spring数据绑定特性处理嵌套属性。

解决方案

1. 修改JSP表单,使用Spring Form标签修正绑定

替换普通表单为Spring form标签,下拉框传递实体主键,日期字段调整为兼容格式:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Pass_in_trip</title>
<style>
form fieldset {
    width: 40%;
}

form fieldset label {
    display: block;
}

form fieldset input, form fieldset select, form fieldset textarea {
    width: 100%;
}
</style>
</head>
<body>
    <h1>Pass_in_trip</h1>
    <form:form modelAttribute="pass_in_trip" method="POST">
        <fieldset>
            <div>
                <label>Flight:</label>
                <form:select path="trip.trip_no">
                    <c:forEach var="trip" items="${trip}">
                        <form:option value="${trip.trip_no}" label="№ ${trip.trip_no}  ${trip.town_from}  ${trip.town_to}"/>
                    </c:forEach>
                </form:select>
            </div>
            <div>
                <label>Passenger:</label>
                <form:select path="passenger.passengerId">
                    <c:forEach var="passenger" items="${passenger}">
                        <form:option value="${passenger.passengerId}" label="${passenger.passengerId} ${passenger.name}"/>
                    </c:forEach>
                </form:select>
            </div>
            <div>
                <label>Date: </label>
                <form:input type="datetime-local" path="date" value="${pass_in_trip.date != null ? #dates.format(pass_in_trip.date, 'yyyy-MM-dd\'T\'HH:mm') : ''}"/>
            </div>
            <div>
                <label>Place:</label>
                <form:input type="text" path="place" value="${pass_in_trip.place}"/>
            </div>
            <div>
                <input type="submit" value="Save">
            </div>
        </fieldset>
    </form:form>
</body>
</html>

2. 修改Controller,初始化表单对象并处理复合主键

在GET方法中初始化Pass_in_trip对象,POST方法手动设置复合主键:

@PreAuthorize("hasRole('ROLE_Admin')")
@RequestMapping(value = "insert", method = RequestMethod.GET)
public String insertnewform(Model uiModel) {
    Pass_in_trip pass_in_trip = new Pass_in_trip();
    pass_in_trip.setKey(new KeysPass_in_trip());
    uiModel.addAttribute("pass_in_trip", pass_in_trip);
    uiModel.addAttribute("trip", service.findallTrip());
    uiModel.addAttribute("passenger", service.findallPassenger());
    return "/pass_in_trip/insert";
}

@PreAuthorize("hasRole('ROLE_Admin')")
@RequestMapping(value = "insert", method = RequestMethod.POST)
public String insert(@ModelAttribute("pass_in_trip") Pass_in_trip pass_in_trip, BindingResult bindingResult, Model uiModel,
        RedirectAttributes redirectatributes) {
    System.out.println(pass_in_trip);

    if (bindingResult.hasErrors()) {
        uiModel.addAttribute("trip", service.findallTrip());
        uiModel.addAttribute("passenger", service.findallPassenger());
        return "/pass_in_trip/insert";
    }
    
    // 手动设置复合主键值
    KeysPass_in_trip key = new KeysPass_in_trip();
    key.setTripId(pass_in_trip.getTrip().getTrip_no());
    key.setPsgId(pass_in_trip.getPassenger().getPassengerId());
    pass_in_trip.setKey(key);
    
    service.save(pass_in_trip);
    redirectatributes.addFlashAttribute("message", "保存成功");
    return "redirect:/pass_in_trip/";
}

3. 确保实体类Getter/Setter完整

Pass_in_trip、Trip、Passenger及KeysPass_in_trip的所有属性必须包含对应的Getter和Setter方法,Spring依赖这些方法完成数据绑定。

4. 日期类型转换配置(可选)

若日期绑定仍有问题,添加Spring日期转换器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new Converter<String, Timestamp>() {
            @Override
            public Timestamp convert(String source) {
                if (source == null || source.isEmpty()) {
                    return null;
                }
                try {
                    LocalDateTime localDateTime = LocalDateTime.parse(source, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                    return Timestamp.valueOf(localDateTime);
                } catch (DateTimeParseException e) {
                    throw new IllegalArgumentException("Invalid date format. Please use yyyy-MM-dd'T'HH:mm");
                }
            }
        });
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 22:01:03