如何在不复制 ResourceAssembler 的情况下在 spring 数据中创建自定义本机查询?

How to create custom native query in spring data rest without duplicating their ResourceAssembler?

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

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

如您所见return 位置列表。

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

问题是我想 return 这个列表的格式 spring data rest 用于包含所有 hateoas 字段和内容的位置资源。更具体地说,我想在输出中有一个 link 到元定位。

我读过 spring-hateoas 和 ResourceAssembler 以及 @RepositoryRestController,我想我可以通过编写自定义 ResourceAssembler 来复制 spring-data-rest 正在做的事情,但我没有想要,因为你知道,为什么我要编写已经由 spring-data-rest 编写的代码,对吗?

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

您可以尝试以下方法。

首先用 @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 数据剩余生成的内容。在这里您还必须使用 PagedResourcesAssembler 来生成页面链接。

这是您要搜索的内容吗?

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