Spring无法正确读取JavaScript传递的JSON数据问题排查
问题:Spring Boot接收前端JSON参数时DTO属性始终为空/默认值
环境与代码
Spring Controller
@PostMapping("/updateStaff") @ResponseBody public ResponseEntity<String> updateStaff( @RequestBody UpdateStaffDto nhanVien ) { try { NhanVien existedNhanVien = nhanVienRepository.findById(nhanVien.getIdCode()).orElse(null); log.warn("Id:" + nhanVien.getIdCode()); if (existedNhanVien != null) { log.warn("nhanVien found"); String newMatKhau = (nhanVien.getMatKhau()!=null && !nhanVien.getMatKhau().isBlank()) ? Common.sha256Hash(nhanVien.getMatKhau()) : ""; String newVaiTro = (nhanVien.getVaiTro()!=null && !nhanVien.getVaiTro().isBlank()) ? nhanVien.getVaiTro() : ""; if(!newMatKhau.equals(existedNhanVien.getMatKhau())) { existedNhanVien.setMatKhau(newMatKhau); } if(!newVaiTro.equals(existedNhanVien.getVaiTro())) { existedNhanVien.setVaiTro(newVaiTro); } existedNhanVien.setDateUpdated(new Date()); nhanVienRepository.save(existedNhanVien); return ResponseEntity.ok().build(); } } catch (DataIntegrityViolationException e) { log.error("Error: " + e); } catch (NullPointerException e) { log.error("System error: " + e); } log.warn("nhanVien not found"); return ResponseEntity.badRequest().build(); }
DTO类
package com.springdemo.library.model.dto; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @NoArgsConstructor @AllArgsConstructor @Getter public class UpdateStaffDto { private int IdCode; private String matKhau; private String vaiTro; }
前端jQuery代码
$('#update-staff-form').on('submit', function (e) { e.preventDefault(); let matKhau = $("#password-update").val(); let xacNhanMatKhau = $("#confirm-password-update").val(); if(matKhau === xacNhanMatKhau) { modifyStaff(JSON.stringify({ IdCode: $('#staff-id-update').val(), // 此处传入的值为3,浏览器控制台打印也显示为3 matKhau: matKhau, // 随机字符串 vaiTro: $('#role-update').val() // 值为0 }),'/Library/management/updateStaff' ); } else { $('#unmatched-password-message') .text("Xác nhận mật khẩu chưa khớp với mật khẩu bạn đã nhập, vui lòng nhập lại").css('color', 'red'); } }); function modifyStaff(data, url) { $.ajax({ url: url, method: 'POST', contentType: 'application/json', data: data, success: function () { $('#time-update').text(formatDate(new Date())); window.location.reload(); alert("Đã thêm tài khoản thành công"); }, error: function (jqXHR, textStatus, errorThrown) { console.warn('Error:', textStatus, errorThrown); alert("Có lỗi"); } }); }
问题现象
前端传入的IdCode值为3,matKhau为随机字符串,vaiTro为0,但后端Controller中接收的UpdateStaffDto实例里,IdCode始终为0,matKhau和vaiTro为空/默认值。尝试移除@RequestBody和JSON.parse均无效。
原因分析与解决方法
核心原因
- 属性命名不匹配:DTO中的
IdCode采用大驼峰命名,Spring默认的Jackson序列化/反序列化规则遵循小驼峰匹配,前端传入的JSON键是IdCode,Jackson会尝试映射到idCode(小驼峰),导致无法匹配,最终使用属性默认值。 - 缺少Setter方法:DTO仅标注
@Getter,Jackson反序列化需要Setter方法注入属性值,没有Setter则无法完成数据赋值。
解决步骤
方法一:统一小驼峰命名(推荐)
修改DTO属性为小驼峰,同步前端JSON键名:
- DTO修改:
@NoArgsConstructor @AllArgsConstructor @Getter @Setter // 添加Setter注解 public class UpdateStaffDto { private int idCode; // 改为小驼峰 private String matKhau; private String vaiTro; }
- 前端修改JSON键:
modifyStaff(JSON.stringify({ idCode: $('#staff-id-update').val(), // 改为小驼峰 matKhau: matKhau, vaiTro: $('#role-update').val() }),'/Library/management/updateStaff' );
方法二:保留原命名,添加Jackson注解
若不想修改命名,在DTO属性上添加@JsonProperty指定JSON键名,同时补充Setter:
@NoArgsConstructor @AllArgsConstructor @Getter @Setter // 添加Setter public class UpdateStaffDto { @JsonProperty("IdCode") // 指定匹配的JSON键名 private int IdCode; private String matKhau; private String vaiTro; }
前端无需修改JSON键。
额外注意点
- 确保Spring Boot Web Starter依赖已引入(默认包含Jackson相关组件)。
- 前端必须设置
contentType: 'application/json',否则后端无法识别JSON请求体。 - 前端
$('#staff-id-update').val()返回字符串,可通过parseInt()转为数字类型,避免反序列化潜在问题:idCode: parseInt($('#staff-id-update').val())
内容的提问来源于stack exchange,提问作者minhson Bui
相关产品推荐
相关产品推荐

