Spring Data REST:单个资源的投影表示 [英] Spring Data REST: projection representation of single resource
问题描述
我有一个简单的UserRepository
,使用Spring Data REST
进行了公开.
这是User
实体类:
I have a simple UserRepository
which exposed using Spring Data REST
.
Here is the User
entity class:
@Document(collection = User.COLLECTION_NAME)
@Setter
@Getter
public class User extends Entity {
public static final String COLLECTION_NAME = "users";
private String name;
private String email;
private String password;
private Set<UserRole> roles = new HashSet<>(0);
}
我创建了一个UserProjection
类,该类看起来如下:
I've created a UserProjection
class which looks the following way:
@JsonInclude(JsonInclude.Include.NON_NULL)
@Projection(types = User.class)
public interface UserProjection {
String getId();
String getName();
String getEmail();
Set<UserRole> getRoles();
}
这是存储库类:
@RepositoryRestResource(collectionResourceRel = User.COLLECTION_NAME, path = RestPath.Users.ROOT,
excerptProjection = UserProjection.class)
public interface RestUserRepository extends MongoRepository<User, String> {
// Not exported operations
@RestResource(exported = false)
@Override
<S extends User> S insert(S entity);
@RestResource(exported = false)
@Override
<S extends User> S save(S entity);
@RestResource(exported = false)
@Override
<S extends User> List<S> save(Iterable<S> entites);
}
我还在配置中指定了用户投影,以确保将其使用.
I've also specified user projection in configuration to make sure it will be used.
config.getProjectionConfiguration().addProjection(UserProjection.class, User.class);
因此,当我在/users 路径上进行 GET 时,我得到以下响应(应用投影):
So, when I do GET on /users path, I get the following response (projection is applied):
{
"_embedded" : {
"users" : [ {
"name" : "Yuriy Yunikov",
"id" : "5812193156aee116256a33d4",
"roles" : [ "USER", "ADMIN" ],
"email" : "yyunikov@gmail.com",
"points" : 0,
"_links" : {
"self" : {
"href" : "http://127.0.0.1:8080/users/5812193156aee116256a33d4"
},
"user" : {
"href" : "http://127.0.0.1:8080/users/5812193156aee116256a33d4{?projection}",
"templated" : true
}
}
} ]
},
"_links" : {
"self" : {
"href" : "http://127.0.0.1:8080/users"
},
"profile" : {
"href" : "http://127.0.0.1:8080/profile/users"
}
},
"page" : {
"size" : 20,
"totalElements" : 1,
"totalPages" : 1,
"number" : 0
}
}
但是,当我尝试对单个资源进行 GET 调用时,例如/users/5812193156aee116256a33d4 ,我收到以下响应:
However, when I try to make a GET call for single resource, e.g. /users/5812193156aee116256a33d4, I get the following response:
{
"name" : "Yuriy Yunikov",
"email" : "yyunikov@gmail.com",
"password" : "123456",
"roles" : [ "USER", "ADMIN" ],
"_links" : {
"self" : {
"href" : "http://127.0.0.1:8080/users/5812193156aee116256a33d4"
},
"user" : {
"href" : "http://127.0.0.1:8080/users/5812193156aee116256a33d4{?projection}",
"templated" : true
}
}
}
您可能会看到,密码字段正在返回并且未应用投影.我知道有@JsonIgnore
批注,可用于隐藏资源的敏感数据.但是,我的User
对象位于不知道API或JSON表示形式的其他应用程序模块中,因此在其中用@JsonIgnore
批注标记字段是没有意义的.
As you may see, the password field is getting returned and projection is not applied. I know there is @JsonIgnore
annotation which can be used to hide sensitive data of resource. However, my User
object is located in different application module which does not know about API or JSON representation, so it does not make sense to mark fields with @JsonIgnore
annotation there.
我已经看过@Oliver Gierke的帖子此处,其中说明了为什么摘录投影不会自动应用于单个资源.但是,在我的情况下仍然很不方便,当我获得单个资源时,我想返回相同的UserProjection
.无需创建自定义控制器或使用@JsonIgnore
标记字段,是否可以通过某种方式做到这一点?
I've seen a post by @Oliver Gierke here about why excerpt projections are not applied to single resource automatically. However, it's still very inconvenient in my case and I would like to return the same UserProjection
when I get a single resource. Is it somehow possible to do it without creating a custom controller or marking fields with @JsonIgnore
?
推荐答案
我能够创建一个ResourceProcessor
类,该类将投影应用于
I was able to create a ResourceProcessor
class which applies projections on any resource as suggested in DATAREST-428. It works the following way: if projection parameter is specified in URL - the specified projection will be applied, if not - projection with name default will be returned, applied first found projection will be applied. Also, I had to add custom ProjectingResource
which ignores the links, otherwise there are two _links
keys in the returning JSON.
/**
* Projecting resource used for {@link ProjectingProcessor}. Does not include empty links in JSON, otherwise two
* _links keys are present in returning JSON.
*
* @param <T>
*/
@JsonInclude(JsonInclude.Include.NON_EMPTY)
class ProjectingResource<T> extends Resource<T> {
ProjectingResource(final T content) {
super(content);
}
}
/**
* Resource processor for all resources which applies projection for single resource. By default, projections
* are not
* applied when working with single resource, e.g. http://127.0.0.1:8080/users/580793f642d54436e921f6ca. See
* related issue <a href="https://jira.spring.io/browse/DATAREST-428">DATAREST-428</a>
*/
@Component
public class ProjectingProcessor implements ResourceProcessor<Resource<Object>> {
private static final String PROJECTION_PARAMETER = "projection";
private final ProjectionFactory projectionFactory;
private final RepositoryRestConfiguration repositoryRestConfiguration;
private final HttpServletRequest request;
public ProjectingProcessor(@Autowired final RepositoryRestConfiguration repositoryRestConfiguration,
@Autowired final ProjectionFactory projectionFactory,
@Autowired final HttpServletRequest request) {
this.repositoryRestConfiguration = repositoryRestConfiguration;
this.projectionFactory = projectionFactory;
this.request = request;
}
@Override
public Resource<Object> process(final Resource<Object> resource) {
if (AopUtils.isAopProxy(resource.getContent())) {
return resource;
}
final Optional<Class<?>> projectionType = findProjectionType(resource.getContent());
if (projectionType.isPresent()) {
final Object projection = projectionFactory.createProjection(projectionType.get(), resource
.getContent());
return new ProjectingResource<>(projection);
}
return resource;
}
private Optional<Class<?>> findProjectionType(final Object content) {
final String projectionParameter = request.getParameter(PROJECTION_PARAMETER);
final Map<String, Class<?>> projectionsForType = repositoryRestConfiguration.getProjectionConfiguration()
.getProjectionsFor(content.getClass());
if (!projectionsForType.isEmpty()) {
if (!StringUtils.isEmpty(projectionParameter)) {
// projection parameter specified
final Class<?> projectionClass = projectionsForType.get(projectionParameter);
if (projectionClass != null) {
return Optional.of(projectionClass);
}
} else if (projectionsForType.containsKey(ProjectionName.DEFAULT)) {
// default projection exists
return Optional.of(projectionsForType.get(ProjectionName.DEFAULT));
}
// no projection parameter specified
return Optional.of(projectionsForType.values().iterator().next());
}
return Optional.empty();
}
}
这篇关于Spring Data REST:单个资源的投影表示的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!