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

如何将HTML表单数据通过POST传递给Spring Boot的Package接口?

问题描述

我有一个部署在localhost:8080/create-your-package的HTML表单页面,表单包含寄件人(startingPoint)和收件人(destinationPoint)的地址输入项,对应Point类的city、street等字段。我的Spring Boot应用提供了localhost:8080/create-package的POST接口,该接口通过@RequestBody接收Package类型参数。尝试原生表单提交和JS脚本都无法将表单数据封装为Package对象并成功发送请求,求可行解决方案。


相关代码

Package实体类

package com.courier.application.model;

import jakarta.validation.Valid;
import lombok.*;
import org.bson.types.ObjectId;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "packages")
@Data
@AllArgsConstructor
public class Package {
    @Id
    private ObjectId packageId;
    @Valid
    private Point startingPoint;
    @Valid
    private Point destinationPoint;
    private String expectedShippingTime;
    private String trackingCode;
}

Point实体类

package com.courier.application.model;

import lombok.AllArgsConstructor;
import lombok.Data;

import jakarta.validation.constraints.Size;
import jakarta.validation.constraints.NotBlank;

@Data
@AllArgsConstructor
public class Point {
    @NotBlank
    @Size(min = 2, max = 25)
    private String city;
    @NotBlank
    @Size(min = 2, max = 25)
    private String street;
    @NotBlank
    @Size(min = 1, max = 7)
    private String apartment;
    @NotBlank
    @Size(min = 3, max = 7)
    private String postalCode;
}

HTML表单代码

<!DOCTYPE html>
<html lang="pl">
<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/css/package-create.css">
    <title>PaczkaTrack - stwórz paczkę</title>
</head>
<body>
<h1>Formularz paczki</h1>
<form action="http://localhost:8080/create-package" method="POST">
    <h2>Nadawca</h2>
    <label for="startingPoint.city">Miasto</label>
    <input type="text" id="startingPoint.city" name="startingPoint.city" required>

    <label for="startingPoint.street">Ulica</label>
    <input type="text" id="startingPoint.street" name="startingPoint.street" required>

    <label for="startingPoint.apartment">Apartment</label>
    <input type="text" id="startingPoint.apartment" name="startingPoint.apartment" required>

    <label for="startingPoint.postalCode">Kod</label>
    <input type="text" id="startingPoint.postalCode" name="startingPoint.postalCode" required>

    <h2>Odbiorca</h2>

    <label for="destinationPoint.city">Miasto</label>
    <input type="text" id="destinationPoint.city" name="destinationPoint.city" required>

    <label for="destinationPoint.street">Ulica</label>
    <input type="text" id="destinationPoint.street" name="destinationPoint.street" required>

    <label for="destinationPoint.apartment">Apartment</label>
    <input type="text" id="destinationPoint.apartment" name="destinationPoint.apartment" required>

    <label for="destinationPoint.postalCode">Kod</label>
    <input type="text" id="destinationPoint.postalCode" name="destinationPoint.postalCode" required>

    <input type="submit" value="Dodaj pake!">
</form>
</body>
</html>

Controller代码

package com.courier.application.controller;

import com.courier.application.error.PackageNotFoundException;
import com.courier.application.error.PackageSentToWrongAddressException;
import com.courier.application.model.Package;
import com.courier.application.service.PackageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import java.util.Optional;

@RestController
@Validated
public class PackageController {

    @Autowired
    PackageService packageService;

    @GetMapping("/find-package")
    public Optional<Package> findPackageByTrackingCode(String trackingCode) throws PackageNotFoundException {
        return packageService.findByTrackingCode(trackingCode);
    }

    @PostMapping("/create-package")
    public Package createPackage(@Valid @RequestBody Package createdPackage) throws PackageSentToWrongAddressException {
        return packageService.saveCreatedPackage(createdPackage);
    }
}

解决方案

方法一:修改Controller支持原生表单提交

@RequestBody默认接收application/json格式数据,但原生表单提交的是application/x-www-form-urlencoded格式,Spring无法自动绑定到Package对象。可以通过以下调整实现兼容:

  1. 给实体类添加无参构造:Lombok的@AllArgsConstructor会覆盖默认无参构造,需要给Package和Point类新增@NoArgsConstructor注解:
// Package类修改后
@Document(collection = "packages")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Package {
    // 原有代码不变
}

// Point类修改后
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Point {
    // 原有代码不变
}
  1. 替换Controller注解:把@RequestBody换成@ModelAttribute,Spring会自动识别startingPoint.city这种嵌套命名格式,完成对象绑定:
@PostMapping("/create-package")
public Package createPackage(@Valid @ModelAttribute Package createdPackage) throws PackageSentToWrongAddressException {
    return packageService.saveCreatedPackage(createdPackage);
}

修改后直接提交原生表单即可完成数据封装。


方法二:用JS将表单数据转为JSON发送(保留原Controller)

如果不想修改后端,可通过JS拦截表单提交,将数据组装成JSON格式后发送:

  1. 给表单添加id:方便JS获取表单元素
<form id="packageForm" action="http://localhost:8080/create-package" method="POST">
    <!-- 原有表单内容不变 -->
</form>
  1. 添加提交拦截脚本:在HTML的<body>末尾插入以下代码:
<script>
document.getElementById('packageForm').addEventListener('submit', function(e) {
    e.preventDefault(); // 阻止原生提交行为

    // 组装JSON结构数据
    const formData = new FormData(this);
    const packageData = {
        startingPoint: {
            city: formData.get('startingPoint.city'),
            street: formData.get('startingPoint.street'),
            apartment: formData.get('startingPoint.apartment'),
            postalCode: formData.get('startingPoint.postalCode')
        },
        destinationPoint: {
            city: formData.get('destinationPoint.city'),
            street: formData.get('destinationPoint.street'),
            apartment: formData.get('destinationPoint.apartment'),
            postalCode: formData.get('destinationPoint.postalCode')
        }
    };

    // 发送JSON请求
    fetch('http://localhost:8080/create-package', {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json'
        },
        body: JSON.stringify(packageData)
    })
    .then(response => {
        response.ok ? (alert('Paczkę dodano pomyślnie!'), this.reset()) : alert('Wystąpił błąd podczas dodawania paczki');
    })
    .catch(error => {
        console.error('Błąd:', error);
        alert('Wystąpił błąd połączenia');
    });
});
</script>

此方法会将表单数据转为application/json格式发送,完全匹配@RequestBody的接收要求。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 07:34:51