Spring中如何通过@RequestBody判断JSON字段是否存在数据?
如何实现Patch请求的用户信息部分更新
场景说明
现有如下User实体类:
@Getter @Setter public class User { private int id; private String name; private Integer salary; private Integer department_id; }
需求:通过Patch请求实现用户信息的部分更新,要求请求体必须包含id字段,其他字段可选择性传入。例如数据库中存在用户(2, "Dave", 10, null),当发送请求体{"id":2, "salary":20}时,仅更新该用户的薪资字段,而非将name和department_id设为null。
核心问题
直接将请求体反序列化为User对象时,缺失的字段会被设为null,导致误更新原数据库中的非空字段。
解决方案
核心思路是:先从数据库获取原用户对象,仅更新请求体中实际存在的字段,再保存回数据库。以下是两种可行实现方式:
方式一:使用Jackson JsonNode处理请求体
利用Jackson的JsonNode保留请求体的字段存在性信息,再通过ObjectMapper.updateValue方法仅更新存在的字段:
@PatchMapping("/users") public ResponseEntity<User> patchUser(@RequestBody JsonNode requestNode) { // 校验必填id字段 if (!requestNode.has("id")) { return ResponseEntity.badRequest().body(null); } Integer userId = requestNode.get("id").asInt(); // 从数据库获取原用户对象 User originalUser = userRepository.findById(userId) .orElseThrow(() -> new IllegalArgumentException("用户不存在")); // 仅更新请求体中存在的字段 ObjectMapper objectMapper = new ObjectMapper(); objectMapper.updateValue(originalUser, requestNode); // 保存更新后的用户 User updatedUser = userRepository.save(originalUser); return ResponseEntity.ok(updatedUser); }
说明:updateValue方法会遍历JsonNode中的所有字段,仅对原对象中对应字段进行赋值,未在请求体中出现的字段会保持原对象的原值,完美区分“字段缺失”和“字段值为null”的场景。
方式二:通过Map接收请求体+反射更新字段
如果需要更精细化的字段控制(比如跳过主键修改、自定义字段校验),可以用Map<String, Object>接收请求体,再通过反射逐一更新字段:
@PatchMapping("/users") public ResponseEntity<User> patchUser(@RequestBody Map<String, Object> requestMap) { // 校验必填id字段 if (!requestMap.containsKey("id")) { return ResponseEntity.badRequest().body(null); } Integer userId = (Integer) requestMap.get("id"); // 从数据库获取原用户对象 User originalUser = userRepository.findById(userId) .orElseThrow(() -> new IllegalArgumentException("用户不存在")); // 遍历请求体字段,更新原对象 requestMap.forEach((key, value) -> { // 跳过主键id,避免修改 if ("id".equals(key)) { return; } try { Field field = User.class.getDeclaredField(key); field.setAccessible(true); // 赋值时自动处理类型转换(需确保请求值类型与字段匹配) field.set(originalUser, value); } catch (NoSuchFieldException | IllegalAccessException e) { throw new IllegalArgumentException("无效的字段:" + key); } }); // 保存更新后的用户 User updatedUser = userRepository.save(originalUser); return ResponseEntity.ok(updatedUser); }
说明:这种方式可以灵活控制哪些字段允许更新,还能在赋值前添加自定义的校验逻辑(比如薪资不能为负数)。
注意事项
- 主键
id建议设为不可修改,避免请求体传入新id导致数据混乱; - 需对请求体中的字段值做合法性校验,比如数值范围、字符串格式等;
- 若使用Spring Data JPA,
save方法会自动执行更新操作(因为原对象是从数据库查询的持久化实例)。
内容的提问来源于stack exchange,提问作者voodookiidoo
相关产品推荐
相关产品推荐

