我试图在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": null}
预期的行为:更新
firstName="John"
并设置lastName=null
。我无法区分这两种情况,因为DTO中的
lastName
始终由Jackson设置为null
。注意:
我知道REST最佳实践(RFC 6902)建议使用PATCH而不是PUT进行部分更新,但是在我的特定情况下,我需要使用PUT。
最佳答案
实际上,如果忽略验证,您可以像这样解决您的问题。
public class BusDto {
private Map<String, Object> changedAttrs = new HashMap<>();
/* getter and setter */
}
dto的set方法,将属性名称和值放入
changedAttrs(因为当
属性具有值(无论是否为null)。