我有一个以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)
。这引发了映射冲突错误。
所以我完全不知道接下来要做什么。
您可以通过扩展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
是您在编写逻辑时可以检查的默认值。它可能会有所帮助。