gpt4 book ai didi

java - 如何在使用 Java JSON Patch 修补时禁止更新字段

转载 作者:行者123 更新时间:2023-12-01 16:59:08 25 4
gpt4 key购买 nike

我有一个 Spring Boot 项目,其中包含一个名为 Person 的 Pojo 和一个 Controller ,该 Controller 允许用户通过 Id 获取人员并修补 Person 对象,以便可以更新其名称或/和姓氏。

Person Pojo(出于示例目的而简化)

class Person {
@Id @GeneratedValue Long id;
@NotNull @NotBlank String name;
@NotNull @NotBlank String surname
}

在 Controller 中

@PatchMapping(path = "/{personId}", consumes = "application/json-patch+json")
ResponseEntity<Trip> patchPerson(@PathVariable Long personId,
@RequestBody final JsonPatch jsonPatch) throws JsonProcessingException, JsonPatchException {
final Person targetPerson = personRepository.findOne(personId);

final ObjectMapper objectMapper = new ObjectMapper();
final JsonNode patch = objectMapper.convertValue(targetPerson, JsonNode.class);
JsonNode patched = jsonPatch.apply(patch);
final Person updatedPerson = objectMapper.treeToValue(patched, Person.class);

如何最好地实现以下行为?

  • 收到 GET 请求时发送所有字段作为响应。
  • 不允许用户在发送补丁时更新 ID。只能更新姓名。

添加我要发送的示例补丁

[{ "op": "replace", "path":"/id", "value":"200" }]

最佳答案

我建议您在 Controller 中公开 DTO 而不是实体。此外,您可以使用 @JsonView 为不同的 REST 操作提供不同的 View 。请参阅this article用于使用@JsonView

首先,您可以定义 GET 和 PATCH 方法的 View 。由于 GET 方法比 PATCH 需要更多的数据,因此 GetView 可以像这样扩展 PatchView:

public class View {

public interface PatchView {}
public interface GetView extends PatchView {}
}

除了 Person 实体之外,我们还可以有一个 PersonDto 类。 PatchView 将具有名称和确定名称,而 GetView 扩展 PatchView 并具有附加的 id 属性:

class PersonDto {

@JsonView(View.GetView.class)
Long id;

@JsonView(View.PatchView.class)
@NotBlank
String name;

@JsonView(View.PatchView.class)
@NotBlank
String surname;
}

您可以使用Mapstruct用于将 Person 实体转换为 PersoDto 的映射库,反之亦然。

@Mapper(componentModel = "spring")
public interface PersonMapper() {

PersonDto toPersonDto(Person person);

Person toPerson(PersonDto personDto);

@BeanMapping(nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.IGNORE)
Person toPerson(PersonDto personDto, @MappingTarget Person person)
}

此外,在 Controller 中,您可以将 ObjectMapper 配置为在其反序列化配置中包含 PatchView like this SO answer :

@Autowired     // you should use construtor injection instead of @Autowired
private PersonMapper personMapper;

@PatchMapping(path = "/{personId}", consumes = "application/json-patch+json")
ResponseEntity<Trip> patchPerson(@PathVariable Long personId,
@RequestBody JsonPatch jsonPatch) throws JsonProcessingException, JsonPatchException {
Person targetPerson = personRepository.findOne(personId);

// Mapstruct mapper to map Person to PersonDto
PersonDto personDto = personMapper.toPersonDto(targetPerson);

// new ObjectMapper instance
ObjectMapper objectMapper = new ObjectMapper();
// configure ObjectMapper instance to include JsonView in its deserializer config (View.PatchView.class in this case)
objectMapper.disable(MapperFeature.DEFAULT_VIEW_INCLUSION);
objectMapper.setConfig(mapper.getDerializationConfig()
.withView(View.PatchView.class));

// apply Json patch to PersonDto
JsonNode target = objectMapper.convertValue(personDto, JsonNode.class);
JsonNode patched = jsonPatch.apply(target);
PersonDto updatedPersonDto = objectMapper.treeToValue(patched, PersonDto.class);

// convert patched PersonDto back to Person entity using Mapstruct
Person person = personMapper.toPerson(updatedPersonDto, targetPerson);

// your additional logic
}

现在 PATCH 方法将在反序列化时忽略 id 属性。

更新:此解决方法基本上将 @JsonView 中不存在的属性设置为 null,并且在从 DTO 转换回实体时,mapstruct 将忽略 null 值,因此它满足了本文的目的。但是,如果 boolean 类型属性未包含在 @JsonView 中,它们将自动设置为 false。此问题的解决方案是在 DTO 中使用 Boolean(不是原始类型 boolean),在实体中使用原始类型 boolean。它之所以有效,是因为 Boolean 接受 null 值,而 boolean 不接受。如果DTO中的 boolean 属性为null,则mapstruct不会将其转换为实体中映射的 boolean 属性。

关于java - 如何在使用 Java JSON Patch 修补时禁止更新字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61539955/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com