spring - 覆盖 Spring Data Rest 自动创建的存储库端点
问题描述
我有一个 Spring 项目spring-data-rest
作为依赖项。我的项目中有很多存储库,它们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);
}
}
如果我替换@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 Data Rest 提供的默认行为RepositoryRestMvcConfiguration
。
RepositoryRestMvcConfiguration
有一个DelegatingHandlerMapping
bean,其中包含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
是默认的,您可以在编写逻辑时检查它。这可能会有所帮助。
推荐阅读
- mysql - 如何将查询从 sql 转换为 codeigniter
- excel - 创建 Range 表达式以在 Union() 方法中使用
- vtk - 为什么 VTK 会为气球小部件示例代码给出错误“无法找到 vtkTextRenderer 对象”?
- python - OpenCV 捕获多个 RTSP 流 - Python
- facebook - 本机脚本 facebook//google sso 服务器端
- php - 从动态图片 url 获取图片扩展
- html - 为什么刷新浏览器时无法显示pdf文件?
- android - 使用 MainActivity.java 文件和 Window.java 文件创建一个窗口 HelloWorld 应用程序
- jwt - 基于令牌的身份验证:将路由限制为特定用户
- node.js - Puppeteer chrome 允许多个文件下载