覆盖Spring Data Rest自动创建的存储库端点

问题描述 投票:0回答:1

我有一个以spring-data-rest为依赖的Spring项目。我的项目中有很多存储库,spring-data-rest自动为其创建REST API端点。这非常适合我的需求,直到现在。现在我需要更改所有存储库的一个端点的默认功能,特别是/BASE_PATH/REPOSITORY。此路径以我的数据库的所有记录的分页列表进行响应。

现在我想为我的所有存储库重新实现此端点。这就是我遇到障碍的地方。我试过了

@RestController
public class MyTableResource {
    private MyTableService myTableService;

    @Autowired
    public MyTableResource(MyTableService myTableService) {
        this.myTableService = myTableService;
    }

    @GetMapping(value = "/api/v1/myTables", produces = MediaTypes.HAL_JSON_VALUE)
    public ResponseEntity getMyTables(@QuerydslPredicate(root = MyTable.class) Predicate predicate) throws NoSuchMethodException {
        // My custom implementation
    }
}

现在这有点工作,但问题是我需要为我的所有存储库编写几乎相同的代码。我尝试了@GetMapping(value = "/api/v1/{repository}", produces = MediaTypes.HAL_JSON_VALUE),但这也匹配/api/v1/notarepository,我已单独实施。

此外,即使我做@GetMapping(value = "/api/v1/{repository}", produces = MediaTypes.HAL_JSON_VALUE)我想使用MyTable路径变量来获取存储库对象({repository})的句柄,在这种情况下这将是myTables

简而言之,我想为我的所有存储库编写一个自定义控制器,因为每个存储库的逻辑都是相同的,同时确保根据调用的路径调用正确的存储库,同时确保我引入的任何路径变量不会隐藏我编写的其他控制器类。

我尝试过更多的事情

我试图从我的实体列表中自动获取分页的HATEOAS资源对象。为此,我发现我可以使用PagedResourceAssembler

@RestController
public class MyTableResource {
    private MyTableService myTableService;

    @Autowired
    public MyTableResource(MyTableService myTableService) {
        this.myTableService = myTableService;
    }

    @GetMapping(value = "/api/v1/myTables", produces = MediaTypes.HAL_JSON_VALUE)
    public ResponseEntity getMyTables(@QuerydslPredicate(root = MyTable.class) Predicate predicate, PagedResourcesAssembler<Object> pagedResourcesAssembler) throws NoSuchMethodException {
        // My custom implementation
        return ResponseEntity.ok(pagedResourcesAssembler.toResource(myTableList);
    }
}

这为我提供了对页面所需链接的良好响应,但没有为每个实体提供链接。然后我发现我可以连接PersistentEntityResourceAssembler并将其传递给上面的toResource所以我做了

@RestController
public class MyTableResource {
    private MyTableService myTableService;

    @Autowired
    public MyTableResource(MyTableService myTableService) {
        this.myTableService = myTableService;
    }

    @GetMapping(value = "/api/v1/myTables", produces = MediaTypes.HAL_JSON_VALUE)
    public ResponseEntity getMyTables(@QuerydslPredicate(root = MyTable.class) Predicate predicate, PagedResourcesAssembler<Object> pagedResourcesAssembler, PersistentEntityResourceAssembler assembler) throws NoSuchMethodException {
        // My custom implementation
        return ResponseEntity.ok(pagedResourcesAssembler.toResource(myTableList, assembler);
    }
}

这不像How to have PersistentEntityResourceAssembler injected into request methods of custom @RepositoryRestController in a @WebMvcTest unit test报道的那样有效。

如果我用@RestController替换RepositoryRestController然后Predicate停止工作,如https://jira.spring.io/browse/DATAREST-838中提到的那样有用。

所以,我尝试使用@QuerydslPredicate RootResourceInformation resourceInformation而不是@QuerydslPredicate(root = MyTable.class) Predicate predicate。这也没有用,因为我的控制器端点没有/{repository}

然后我尝试设置@GetMapping(value = "/{repository}" produces = MediaTypes.HAL_JSON_VALUE)。这引发了映射冲突错误。

所以我完全不知道接下来要做什么。

spring spring-data-rest
1个回答
0
投票

您可以通过扩展RepositoryRestMvcConfiguration来扩展Spring Data Rest提供的默认行为。

RepositoryRestMvcConfiguration有一个DelegatingHandlerMapping豆,其中包含HandlerMapping列表。 Spring迭代此列表并尝试查找请求的处理程序。此列表的顺序很重要。第一个被拿起来执行。因此,如果我们在已经拥有的处理器之前添加一个新的处理程序,那么将调用我们的HandlerMapping

您可以使用您想要的任何逻辑来查找请求的处理程序。在您的情况下,这将是路径变量是存储库名称。

以下代码添加了一个新的处理程序:

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

@Configuration
public class CustomRestMvcConfiguration extends RepositoryRestMvcConfiguration {
    public CustomRestMvcConfiguration(ApplicationContext context,
                                      ObjectFactory<ConversionService> conversionService) {
        super(context, conversionService);
    }

    @Override public DelegatingHandlerMapping restHandlerMapping() {
        DelegatingHandlerMapping delegatingHandlerMapping = super.restHandlerMapping();

        List<HandlerMapping> delegates = delegatingHandlerMapping.getDelegates();
        delegates.add(0, new HandlerMapping() {
            @Override public HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
                //Your custom logic to decide if you should handle the request
                //If you don't want to handle the request return null
                return null;
            }
        });

        return new DelegatingHandlerMapping(delegates);
    }
}

希望这可以帮助!

注意:RepositoryRestHandlerMapping是您在编写逻辑时可以检查的默认值。它可能会有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.