我有一个带有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);
}
}
如果我将@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)
。这引发了映射冲突错误。
所以我完全不知道下一步该怎么做。
答案 0 :(得分:0)
您可以通过扩展RepositoryRestMvcConfiguration
来扩展Spring Data Rest提供的默认行为。
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
是默认的,您可以在编写逻辑时检查它。可能会有帮助。