如何将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对象。可以通过以下调整实现兼容:
- 给实体类添加无参构造:Lombok的
@AllArgsConstructor会覆盖默认无参构造,需要给Package和Point类新增@NoArgsConstructor注解:
// Package类修改后 @Document(collection = "packages") @Data @AllArgsConstructor @NoArgsConstructor public class Package { // 原有代码不变 } // Point类修改后 @Data @AllArgsConstructor @NoArgsConstructor public class Point { // 原有代码不变 }
- 替换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格式后发送:
- 给表单添加id:方便JS获取表单元素
<form id="packageForm" action="http://localhost:8080/create-package" method="POST"> <!-- 原有表单内容不变 --> </form>
- 添加提交拦截脚本:在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
相关产品推荐
相关产品推荐

