我正在尝试使用Spring MVC构建RESTful API。我正在拍摄干净且易于管理的代码,其中包结构遵循url结构。
所以这就是我所拥有的:
// com.test.api.library
@RequestMapping("/library/{libraryId}")
public Library getLibrary(@PathVariable long libraryId) {
return service.getLibraryById(libraryId);
}
// com.test.api.library.book
@RequestMapping("/library/{libraryId}/book/{bookId}")
public Book getBook(@PathVariable long libraryId, @PathVariable long bookId) {
Library library service.getLibraryById(libraryId);
return library.getBookById(bookId);
}
虽然这很有效,但我觉得它在所有继承的@RequestMappings中都要重复“/ library / {libraryId}”而且很容易出错,而且库很可能是API的一大部分根源应该写一次并重复使用,而不是写在任何地方。
我想把书类改写成这样的东西:
// com.test.api.library.book
@RequestMapping("/book/{bookId}")
public Book getBook(@PathVariable long bookId) {
// long libraryId magically given to me from the library-class's getLibrary()
Library library service.getLibraryById(libraryId);
return library.getBookById(bookId);
}
Spring有什么方法可以帮助我吗?我可以使用普通的java继承,spring注释或任何其他帮助我不写“/ library / {libraryId}”作为我写过的每个url的一部分。
答案 0 :(得分:4)
我相信这个问题已经被问到了&之前回答:Spring MVC @RequestMapping Inheritance
也就是说,这是减少重复信息量的一种方法。我实际上并没有在我自己的代码中执行此操作,因为我认为在代码旁边的URI更易于维护,即使它意味着一点点重复。
@RequestMapping(URI_LIBRARY)
public interface LibraryNamespace {
public static String URI_LIBRARY = "/library/{libraryId}";
}
@RequestMapping(URI_BOOK)
public interface BookNamespace {
public static String URI_BOOK = LibraryNamespace.URI_LIBRARY + "/book/{bookId}";
}
@Controller
public class LibraryController implements LibraryNamespace {
@RequestMapping("")
public Library get(@PathVariable long libraryId) {
return service.getLibraryById(libraryId);
}
}
@Controller
public class BookController implements BookNamespace {
@RequestMapping("")
public Book get(@PathVariable long libraryId, @PathVariable long bookId) {
Library library service.getLibraryById(libraryId);
return library.getBookById(bookId);
}
}
由于我自己不采用这种方法,我实际上没有尝试过这个解决方案!基于我对Spring的理解,我认为它应该可以工作......
答案 1 :(得分:3)
使用多态父方法。
@Controller
public class CommentsController {
@RequestMapping(value="/comments", method = RequestMethod.GET)
public @ResponseBody String index() {
/* kludge to allow optional path parameters */
return index(null, null);
}
@RequestMapping(value="/{parent_collection}/{parent_id}/comments", method = RequestMethod.GET)
public @ResponseBody String index(@PathVariable("parent_collection") String parentCollection, @PathVariable("parent_id") String parentId) {
if (parentCollection == null) {
return "all comments";
}
else if ((parentCollection != null) && (parentCollection.equals("posts"))) {
/* get parent, then get comments for parent */
return "comments for single post";
}
else if ((parentCollection != null) && (parentCollection.equals("customers"))) {
/* get parent, then get comments for parent */
return "comments for single customer";
}
else if ((parentCollection != null) && (parentCollection.equals("movies"))) {
/* get parent, then get comments for parent */
return "comments for single movie";
}
}
@RequestMapping(value = "/comments/{id}", method = RequestMethod.GET)
public @ResponseBody String show(@PathVariable Integer id) {
/* kludge to allow optional path parameters */
return show(null, null, id);
}
@RequestMapping(value = "/{parent_collection}/{parent_id}/comments/{id}", method = RequestMethod.GET)
public @ResponseBody String show(@PathVariable("parent_collection") String parentCollection, @PathVariable("parent_id") String parentId, @PathVariable Integer id) {
/* get comment, then get parent from foreign key */
if (parentCollection == null) {
return "single comment";
}
else if ((parentCollection != null) && (parentCollection.equals("posts"))) {
return "single comment for single post";
}
else if ((parentCollection != null) && (parentCollection.equals("customers"))) {
return "single comment for single customer";
}
else if ((parentCollection != null) && (parentCollection.equals("movies"))) {
return "single comment for single movie";
}
}
}
此外,您可以使用基本控制器将URI前缀路由到父资源(/libraries/{library_id}/../..
),将父模型添加到请求范围,然后让常规请求映射处理URI的其余部分子资源(/../../books/1
)。我没有这个副手的例子。
旁注。奇异嵌套资源通常被视为URI设计的反模式。控制器应该处理自己的资源。最常见的实现使得单数嵌套资源的密钥唯一,即不依赖于其父资源。例如,数据库记录主键。但是,在某些情况下,密钥可能不是唯一的,例如序数或位置值(例如,书1,第1章,第2章),或者甚至是自然键(例如,书籍ISBN,人SSN,电子邮件地址) ,用户名,文件名)。
嵌套资源的规范URI示例:
/articles
=> ArticlesController#索引/articles/1
=> ArticlesController#展示/articles/1/comments
=> CommentsController#索引/articles/1/comments/2
=> CommentsController #show(好的,但不是首选)/comments/2
=> CommentsController #show(首选)答案 2 :(得分:1)
我不认为这是可能的。但是您可以在类本身上使用@RequestMapping
注释,这样可以为您节省至少一些输入。
答案 3 :(得分:-1)
@Controller
@RequestMapping("/library/{libraryId}")
public class HelloWorldController {
@RequestMapping(value="/book/{bookId}")
public ModelAndView helloWorld() {
....
}
}