我有一个项目,我正在使用 Spring MVC + Jackson 构建 REST 服务。假设我有以下 java 实体
public class MyEntity {
private Integer id;
private boolean aBoolean;
private String aVeryBigString;
//getter & setters
}
有时,我只想更新 boolean 值,我不认为发送带有大字符串的整个对象只是更新一个简单的 boolean 值是一个好主意。所以,我考虑过使用 PATCH HTTP 方法只发送需要更新的字段。因此,我在 Controller 中声明了以下方法:
@RequestMapping(method = RequestMethod.PATCH)
public void patch(@RequestBody MyVariable myVariable) {
//calling a service to update the entity
}
问题是:我怎么知道哪些字段需要更新?例如,如果客户端只想更新 boolean 值,我将得到一个带有空“aVeryBigString”的对象。我怎么知道用户只想更新 boolean 值,但不想清空字符串?
我已经通过构建自定义 URL “解决”了这个问题。例如,以下 URL:POST/myentities/1/abolean/true 将映射到只允许更新 boolean 值的方法。此解决方案的问题在于它不符合 REST。我不想 100% 符合 REST,但我不喜欢提供自定义 URL 来更新每个字段(特别是考虑到当我想更新多个字段时它会导致问题)。
另一种解决方案是将“MyEntity”拆分为多个资源并仅更新这些资源,但我觉得这没有意义:“MyEntity”是一个普通资源,它不是< strong>由其他资源组成。
那么,有没有一种优雅的方法来解决这个问题?
最佳答案
这可能很晚了,但是为了新手和遇到同样问题的人,让我分享一下我自己的解决方案。
在我过去的项目中,为了简单起见,我只是使用 native java Map。它将捕获所有新值,包括客户端显式设置为 null 的 null 值。此时,很容易确定哪些java属性需要设置为null,不像你使用与你的域模型一样的POJO,你将无法区分客户端设置了哪些字段为null和它们只是不包含在更新中,但默认情况下将为空。
另外,您必须要求http请求发送您要更新的记录的ID,并且不要将其包含在补丁数据结构中。我所做的是将 URL 中的 ID 设置为路径变量,将补丁数据设置为 PATCH 正文。然后使用 ID,您将首先通过域模型获取记录,然后使用 HashMap,您可以使用映射器服务或实用程序来修补相关领域模型的更改。
更新
您可以使用这种泛型代码为您的服务创建一个抽象父类(super class),您必须使用 Java 泛型。这只是可能实现的一部分,希望你能明白。另外最好使用映射器框架,如 Orika 或 Dozer。
public abstract class AbstractService<Entity extends BaseEntity, DTO extends BaseDto> {
@Autowired
private MapperService mapper;
@Autowired
private BaseRepo<Entity> repo;
private Class<DTO> dtoClass;
private Class<Entity> entityCLass;
public AbstractService(){
entityCLass = (Class<Entity>) SomeReflectionTool.getGenericParameter()[0];
dtoClass = (Class<DTO>) SomeReflectionTool.getGenericParameter()[1];
}
public DTO patch(Long id, Map<String, Object> patchValues) {
Entity entity = repo.get(id);
DTO dto = mapper.map(entity, dtoClass);
mapper.map(patchValues, dto);
Entity updatedEntity = toEntity(dto);
save(updatedEntity);
return dto;
}
}
关于java - Spring MVC PATCH方法: partial updates,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17860520/