球衣。在 REST 请求的响应中隐藏某些 POJO 字段的好方法
Jersey. Nice way of hiding some of a POJO's fields in a response for a REST request
让我们假设以下示例。
POJO class:
@XmlRootElement
public class User {
private String id;
private String email;
private String password;
private String firstName;
private String lastName;
// getters and setters
}
资源class:
@Path("user")
public class UserResource {
private UserRepository userRepository = new UserRepositoryStub();
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public User createUser(User user) {
return userRepository.create(user);
}
@GET
@Path("{objectId}")
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public Response getManagedObject(@PathParam("objectId") String objectId) {
if (objectId == null) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
User user = userRepository.findUser(objectId);
if (user == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
// Possible, but seems that not nice solution
// user.setPassword(null);
return Response.ok().entity(user).build();
}
}
在这个简单的示例中,我希望 GET 请求 {url}/user/12345 不 return 密码 字段。我评论了一个我不喜欢的解决方案。
一般来说,在处理 API 时,我希望为每个请求配置 POJO 字段的可见性。有实现这一目标的优雅方式吗?
创建一个 TransferObject,即 TO 或 DTO,其中包含您希望用户在 JSON 响应中显示的字段。您可以在字段上使用 @JsonIgnore,JSON 解析器不会解析该字段,因此不会包含在响应中。
假设您希望 POST 方法(解编组)包含密码 -
但不是 GET 方法(封送处理)——并且您使用的是 JAXB,您可以编写 XmlAdapter.
它的主要用途是在可映射和不可映射之间进行转换类,但它可以在这里发挥作用。
public class PasswordAdapter extends XmlAdapter<String, String> {
@Override
public String unmarshal(String v) throws Exception {
return v;
}
@Override
public String marshal(String v) throws Exception {
return "***";
}
}
然后为密码指定适配器 属性:
class User {
//...
@XmlJavaTypeAdapter(PasswordAdapter.class);
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
一般的做法是在两者之间有一个服务层。然后你有一个 dto 对象,它是一个转换为你的 resource/entity/repository/whatever 对象的外部世界的 io 对象。您需要在这两种类型的对象之间提供 conversion/mapper/whatever 并且在进入 dto 到资源方向时不设置密码。通常对 rest 接口中的 id 做同样的事情。您不希望任何人更新资源并通过在输入对象中提供 id 来更新不同的对象。这就是事情通常的完成方式,即使这意味着额外的代码,这通常是微不足道的。可以使用 Dozer 框架或类似的东西使用配置来简化。
从设计的角度来看 resource/persistence 层应该只包含原子操作。如果您需要为单个资源执行多个操作,会发生什么情况?您必须将它放在资源 class 中的单个方法中。这样您就可以将 rest/io 逻辑与服务层中应该包含的内容混合在一起。更容易犯错,更难为
编写独立的单元测试
让我们假设以下示例。 POJO class:
@XmlRootElement
public class User {
private String id;
private String email;
private String password;
private String firstName;
private String lastName;
// getters and setters
}
资源class:
@Path("user")
public class UserResource {
private UserRepository userRepository = new UserRepositoryStub();
@POST
@Consumes(MediaType.APPLICATION_JSON)
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public User createUser(User user) {
return userRepository.create(user);
}
@GET
@Path("{objectId}")
@Produces({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})
public Response getManagedObject(@PathParam("objectId") String objectId) {
if (objectId == null) {
return Response.status(Response.Status.BAD_REQUEST).build();
}
User user = userRepository.findUser(objectId);
if (user == null) {
return Response.status(Response.Status.NOT_FOUND).build();
}
// Possible, but seems that not nice solution
// user.setPassword(null);
return Response.ok().entity(user).build();
}
}
在这个简单的示例中,我希望 GET 请求 {url}/user/12345 不 return 密码 字段。我评论了一个我不喜欢的解决方案。
一般来说,在处理 API 时,我希望为每个请求配置 POJO 字段的可见性。有实现这一目标的优雅方式吗?
创建一个 TransferObject,即 TO 或 DTO,其中包含您希望用户在 JSON 响应中显示的字段。您可以在字段上使用 @JsonIgnore,JSON 解析器不会解析该字段,因此不会包含在响应中。
假设您希望 POST 方法(解编组)包含密码 - 但不是 GET 方法(封送处理)——并且您使用的是 JAXB,您可以编写 XmlAdapter.
它的主要用途是在可映射和不可映射之间进行转换类,但它可以在这里发挥作用。
public class PasswordAdapter extends XmlAdapter<String, String> {
@Override
public String unmarshal(String v) throws Exception {
return v;
}
@Override
public String marshal(String v) throws Exception {
return "***";
}
}
然后为密码指定适配器 属性:
class User {
//...
@XmlJavaTypeAdapter(PasswordAdapter.class);
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
一般的做法是在两者之间有一个服务层。然后你有一个 dto 对象,它是一个转换为你的 resource/entity/repository/whatever 对象的外部世界的 io 对象。您需要在这两种类型的对象之间提供 conversion/mapper/whatever 并且在进入 dto 到资源方向时不设置密码。通常对 rest 接口中的 id 做同样的事情。您不希望任何人更新资源并通过在输入对象中提供 id 来更新不同的对象。这就是事情通常的完成方式,即使这意味着额外的代码,这通常是微不足道的。可以使用 Dozer 框架或类似的东西使用配置来简化。
从设计的角度来看 resource/persistence 层应该只包含原子操作。如果您需要为单个资源执行多个操作,会发生什么情况?您必须将它放在资源 class 中的单个方法中。这样您就可以将 rest/io 逻辑与服务层中应该包含的内容混合在一起。更容易犯错,更难为
编写独立的单元测试