【问题标题】:How to create custom native query in spring data rest without duplicating their ResourceAssembler?如何在 Spring Data Rest 中创建自定义本机查询而不复制其 ResourceAssembler?
【发布时间】:2015-11-20 16:39:41
【问题描述】:

我有一个看起来像这样的控制器

@RestController
public class LocationsController {

    @Autowired
    private EntityManager manager;

    private String withinQuery =
            "WITH L as\n" +
            "\n" +
            "(SELECT *\n" +
            "FROM location\n" +
            "\n" +
            "WHERE ST_Distance(ST_FlipCoordinates(location.shape), ST_FlipCoordinates(ST_GeomFromGeoJSON('%s'\n" +
            "        )))=0)\n" +
            "\n" +
            "SELECT *\n" +
            "FROM L\n" +
            "WHERE id NOT IN (\n" +
            "SELECT metalocation_id FROM location\n" +
            "WHERE metalocation_id IS NOT NULL\n" +
            ")";

    private String nearestQuery =
            "select * from location order by ST_Distance(ST_FlipCoordinates(location.shape), ST_FlipCoordinates(St_GeomFromGeoJSON('%s'))) limit 1";

    @RequestMapping(value="near", method = RequestMethod.GET)
    public List<Location> getNearestLocations(@RequestParam(value = "point") String pointAsString) throws IOException {
        List<Location> locationCloseToPoint = manager.createNativeQuery(String.format(withinQuery, pointAsString), Location.class).getResultList();
        if (locationCloseToPoint.size() == 0) {
            List<Location> closesLocation = manager.createNativeQuery(String.format(nearestQuery, pointAsString), Location.class)
                    .getResultList();
            locationCloseToPoint.addAll(closesLocation);
        }
        return locationCloseToPoint;
    }
}

如您所见,它返回位置列表。

@Entity
public class Location {

    public Geometry getShape() {
        return shape;
    }

    public void setShape(Geometry shape) {
        this.shape = shape;
    }

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @NotNull
    private Geometry shape;

    @ManyToOne(cascade = CascadeType.ALL)
    private Location metalocation;

问题是我想以 spring data rest 用于位置资源的格式返回此列表,其中包含所有 hateoas 字段和内容。更具体地说,我想在输出中有一个指向元定位的链接。

我读过关于 spring-hateoas 和 ResourceAssembler 和 @RepositoryRestController 的内容,我认为我可以通过编写自定义 ResourceAssembler 来复制 spring-data-rest 正在做的事情,但我不想这样做,因为你知道,我为什么要想写spring-data-rest已经写好的代码吧?

他们自动完成所有这些组装工作,对吧?因为我在 http 输出中看到了它。所以我觉得应该有办法使用它。

【问题讨论】:

    标签: spring rest spring-data-rest spring-hateoas


    【解决方案1】:

    您可以尝试以下方法。

    首先使用@RepositoryRestController 而不是@RestController 注释您的控制器。

    然后您可以使用 spring data rest 内部使用的资源组装器 - PersistentEntityResourceAssembler

    下面的例子对我有用。

    @RepositoryRestController
    public class DemoController {
    
        private final ProductRepository productRepository;
        private final PagedResourcesAssembler<Object> pagedResourcesAssembler;
    
        @Autowired
        public DemoController(ProductRepository productRepository,
                              PagedResourcesAssembler<Object> pagedResourcesAssembler) {
            this.productRepository = productRepository;
            this.pagedResourcesAssembler = pagedResourcesAssembler;
        }
    
        //use PersistentEntityResourceAssembler and PagedResourcesAssembler to return a resource with paging links
        @RequestMapping(method = GET, path="/products/search/listProductsPage", produces = HAL_JSON_VALUE)
        public ResponseEntity<PagedResources<PersistentEntityResource>> getAllPage(Pageable pageable, PersistentEntityResourceAssembler persistentEntityResourceAssembler) {
            Iterable<?> all = productRepository.findAll(pageable);
    
            return ResponseEntity.ok(pagedResourcesAssembler.toResource((Page<Object>) all, persistentEntityResourceAssembler));
        }
    
        //return Resources of entity resources
        @RequestMapping(method = GET, path="/products/search/listProducts", produces = HAL_JSON_VALUE)
        public ResponseEntity<Resources<PersistentEntityResource>> getAll(Pageable pageable, PersistentEntityResourceAssembler persistentEntityResourceAssembler) {
    
            return ResponseEntity.ok(new Resources<PersistentEntityResource>(productRepository.findAll().stream()
                    .map(persistentEntityResourceAssembler::toResource)
                    .collect(Collectors.toList())));
        }
    }
    

    getAll 方法可能就是你想要的。

    我还添加了 getAllPage 变体,它将 Page 转换为 PagedResource - 如果您获得集合资源,这就是 spring data rest 生成的内容。这里还得使用PagedResourcesAssembler来生成页面链接。

    这是您要搜索的内容吗?

    在您的情况下,我也会尝试避免使用自定义控制器 - 如果您可以将本机查询表达为存储库查找器,那么 spring data rest 将自动公开查找器。 Spring data jpa 似乎通过注解支持原生查询 - http://docs.spring.io/spring-data/jpa/docs/1.9.1.RELEASE/reference/html/#jpa.query-methods.at-query

    【讨论】:

    • 刚刚看到您根本没有使用该页面。所以在你的情况下,检查你的列表并使用 PersistentEntityResourceAssembler 来转换列表中的每个项目就足够了。
    • 谢谢,我发现我可以使用 PersistentEntityResourceAssembler 并尝试返回 List 但这给了我未找到的错误,尽管持久实体列表是正确的。因此,如果您也能提供一些指向文档的链接,我将不胜感激,我可以在其中阅读它为什么实际工作的原因。谢谢!
    • 我试图在我的示例代码中显示的是,您不应该返回实体列表。您需要返回一个资源 - Resources&lt;PersistentEntityResource&gt;。据我所知,PersistentEntityResourceAssembler 的使用没有记录。
    • 刚刚编辑了我的答案 - 请参阅最后一段以获取有关如何更改解决方案想法的建议。
    • 虽然我可以为这两个查询使用@Query 注释,但正如您所见,我仍然需要一个控制器,因为那里有一个逻辑。如果第一个查询返回空,那么只有这样我才需要第二个查询。我可以用 postgres 存储过程来表达,但我不认为这是要走的路。
    猜你喜欢
    • 2015-03-25
    • 2014-11-16
    • 1970-01-01
    • 2017-08-15
    • 1970-01-01
    • 2019-03-08
    • 2020-04-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多