我试图在Spring Rest Controller中使用PUT请求方法部分更新实体时区分空值和未提供值。
以以下实体为例:
@Entity private class Person { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; /* let's assume the following attributes may be null */ private String firstName; private String lastName; /* getters and setters ... */ }
我的人资料库(Spring数据):
@Repository public interface PersonRepository extends CrudRepository<Person, Long> { }
我使用的DTO:
private class PersonDTO { private String firstName; private String lastName; /* getters and setters ... */ }
我的Spring RestController:
@RestController @RequestMapping("/api/people") public class PersonController { @Autowired private PersonRepository people; @Transactional @RequestMapping(path = "/{personId}", method = RequestMethod.PUT) public ResponseEntity<?> update( @PathVariable String personId, @RequestBody PersonDTO dto) { // get the entity by ID Person p = people.findOne(personId); // we assume it exists // update ONLY entity attributes that have been defined if(/* dto.getFirstName is defined */) p.setFirstName = dto.getFirstName; if(/* dto.getLastName is defined */) p.setLastName = dto.getLastName; return ResponseEntity.ok(p); } }
请求缺少属性
{"firstName": "John"}
预期行为:更新firstName= "John"(保留lastName不变)。
firstName= "John"
lastName
具有空属性的请求
{"firstName": "John", "lastName": null}
预期行为:更新firstName="John"并设置lastName=null。
firstName="John"
lastName=null
我无法区分这两种情况,因为lastName在DTO中,总是null由Jackson 设置。
null
注意:我知道REST最佳实践(RFC 6902)建议使用PATCH而不是PUT进行部分更新,但是在我的特定情况下,我需要使用PUT。
实际上,如果忽略验证,您可以像这样解决您的问题。
public class BusDto { private Map<String, Object> changedAttrs = new HashMap<>(); /* getter and setter */ }