覆盖由SpringDataREST自动创建的存储库端点

覆盖由SpringDataREST自动创建的存储库端点,spring,spring-data-rest,Spring,Spring Data Rest,我有一个Spring项目,它依赖于Spring数据rest。我的项目中有相当多的存储库,它们spring-data-rest自动为创建restapi端点。到目前为止,这很适合我的需要。现在,我需要更改我所有存储库的一个端点的默认功能,特别是/BASE\u PATH/REPOSITORY。此路径以my db的所有记录的分页列表进行响应 现在我想为我所有的存储库重新实现这个端点。这就是我遇到的路障。我试过了 @RestController public class MyTableResource {

我有一个Spring项目,它依赖于
Spring数据rest
。我的项目中有相当多的存储库,它们
spring-data-rest
自动为创建restapi端点。到目前为止,这很适合我的需要。现在,我需要更改我所有存储库的一个端点的默认功能,特别是
/BASE\u PATH/REPOSITORY
。此路径以my db的所有记录的分页列表进行响应

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

@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}”,products=MediaTypes.HAL_JSON_value)
,但这也与我单独实现的
/api/v1/notarepository
相匹配

此外,即使我使用
@GetMapping(value=“/api/v1/{repository}”,products=MediaTypes.HAL_JSON_value)
我也希望使用
{repository}
路径变量获得存储库对象(
MyTable
)的句柄,在本例中,该变量将是
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);
    }
}
这与中的报告不一样

如果我将
@RestController
替换为
RepositoryRestController
,但
Predicate
会停止工作,如中所述

因此,我尝试使用
@querydsldpredicate-RootResourceInformation-resourceInformation
而不是
@querydspredicate(root=MyTable.class)谓词。这也不起作用,因为我的控制器端点中没有
/{repository}

然后我尝试设置
@GetMapping(value=“/{repository}”products=MediaTypes.HAL\u JSON\u value)
。这引发了映射冲突错误


因此,我完全无法确定下一步要做什么。

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

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

您可以使用任何逻辑来查找请求的处理程序。在您的情况下,如果path变量是存储库名称,则会出现这种情况

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

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);
    }
}
import org.springframework.beans.factory.ObjectFactory;
导入org.springframework.context.ApplicationContext;
导入org.springframework.context.annotation.Configuration;
导入org.springframework.core.convert.ConversionService;
导入org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
导入org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping;
导入org.springframework.web.servlet.HandlerExecutionChain;
导入org.springframework.web.servlet.HandlerMapping;
导入javax.servlet.http.HttpServletRequest;
导入java.util.List;
@配置
公共类CustomRestMvcConfiguration扩展了RepositoryRestMvcConfiguration{
公共CustomRestMVC配置(ApplicationContext上下文,
ObjectFactory转换服务){
超级(上下文、转换服务);
}
@重写公共DelegatingHandlerMapping restHandlerMapping(){
DelegatingHandlerMapping DelegatingHandlerMapping=super.restHandlerMapping();
List delegates=delegatingHandlerMapping.getDelegates();
添加(0,新HandlerMapping(){
@Override public HandlerExecutionChain getHandler(HttpServletRequest请求)引发异常{
//您可以使用自定义逻辑来决定是否应处理请求
//如果不想处理请求,则返回null
返回null;
}
});
返回新的DelegatingHandlerMapping(委托);
}
}
希望这有帮助

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

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