当前位置: 首页 > 知识库问答 >
问题:

Spring Data REST:单个资源的投影表示

万乐逸
2023-03-14

我有一个简单的UserRepository,它使用Spring Data REST公开。下面是user实体类:

@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类,它的外观如下:

@JsonInclude(JsonInclude.Include.NON_NULL)
@Projection(types = User.class)
public interface UserProjection {

    String getId();

    String getName();

    String getEmail();

    Set<UserRole> getRoles();
}

下面是repository类:

@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);
}

我还在配置中指定了用户投影,以确保它将被使用。

config.getProjectionConfiguration().addProjection(UserProjection.class, User.class);

因此,当我进入/users路径时,我得到以下响应(应用了投影):

{
  "_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
  }
}
{
  "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
    }
  }
}

共有1个答案

东郭瀚玥
2023-03-14

我能够创建一个ResourceProcessor类,它按照DataRest-428中的建议对任何资源应用投影。它的工作方式如下:如果在URL中指定了projection参数--将应用指定的投影,如果不--将返回名称为default的projection,将应用appliced first found投影。另外,我必须添加自定义的projectingresource,它忽略链接,否则返回的JSON中有两个_links键。

/**
 * 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();
    }
}
 类似资料:
  • 我有一个关于嵌套列表投影界面用法的问题。我有两个实体(父和子)(它们有单向关联) 父级=> 子=> 我有两个选择特定列投影界面。 这个查询可以工作,但是它选择ChildEntity的所有列,并且只将id、name propeties映射到ChildProjection。(生成的查询选择所有列,但我想只选择id和name列) 我如何只选择id和name列(为嵌套列表投影界面选择特定列)并映射到Chi

  • 问题内容: 因此,我使用RequireJS和Socket.io编写了一个应用程序,该应用程序检查socket.io资源是否可用,然后在连接时引导该应用程序。万一socket.io暂时关闭,我想对资源进行几次requireJS轮询,直到可用为止,然后继续初始化应用程序。 不幸的是(或者幸运的是?)似乎有某种缓存机制要求require为未加载的脚本注册脚本错误,因此,如果您在错误回调中执行setTim

  • Cesium中的视频投影是指将视频作为一种物体材质,实现在物体上播放视频的效果。这个功能在Cesium早期版本中就支持了,在Code Example中有一个示例。今天就来分析一下其内部实现原理。 1. 添加视频投影及效果 示例中添加视频投影的代码分为两部分,第一步是添加div控件,控件负责视频播放、暂停等任务,代码如下: <video id="trailer" muted autoplay loo

  • MongoDB 中的投影即查询指定的字段,而不是直接查询文档的全部字段。比如说某个文档中有 5 个字段,而我们只需要其中的 3 个字段,那么就可以使用 MongoDB 中的投影来指定需要查询的 3 个字段。 在《 MongoDB查询文档》一节中我们介绍的 find() 方法,在使用 find() 方法时,如果不设置其中的第二个参数,那么在查询时将返回文档中的所有字段,想要限制要查询的字段,您就需要

  • 举个简单的例子来说明正交投影与透视投影照相机的区别。使用透视投影照相机获得的结果是类似人眼在真实世界中看到的有“近大远小”的效果(如下图中的(a));而使用正交投影照相机获得的结果就像我们在数学几何学课上老师教我们画的效果,对于在三维空间内平行的线,投影到二维空间中也一定是平行的(如下图中的(b))。 (a)透视投影,(b)正交投影 那么,你的程序需要正交投影还是透视投影的照相机呢? 一般说来,对

  • 当我尝试这个函数时,我得到一个错误。 CRSError:无效的投影: epsg: 4326:(内部程序错误:proj_create: SQLite错误对SELECT名称,类型,coordinate_system_auth_name,coordinate_system_code,datum_auth_name,datum_code,area_of_use_auth_name,area_of_use_