2011-08-29 19 views
13

Tôi đang cố gắng xây dựng một API RESTful bằng cách sử dụng Spring MVC. Tôi đang chụp mã sạch và dễ quản lý nơi cấu trúc gói theo cấu trúc url.Cách kế thừa RequestMappings trong API REST MVC của mùa xuân 3

Vì vậy, đây là những gì tôi đã có:

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

Trong khi làm việc này, tôi thấy nó lộn xộn và dễ bị lỗi để phải lặp lại "/ thư viện/{} libraryId "trong tất cả các @RequestMappings được thừa hưởng,/thư viện có khả năng là gốc của một phần lớn của API và nó phải được viết một lần và được tái sử dụng thay vì được viết ở khắp mọi nơi.

Tôi muốn viết lại sách lớp để một cái gì đó như thế này:

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

Có cách nào mùa xuân có thể giúp tôi ở đây? Có thể chấp nhận cho tôi sử dụng thừa kế java bình thường, chú thích mùa xuân hoặc bất kỳ thứ gì khác giúp tôi không viết "/ library/{libraryId}" như một phần của mỗi url mà tôi từng viết.

Trả lời

1

Tôi không nghĩ điều đó là có thể. Nhưng bạn có thể có chú thích @RequestMapping trên chính lớp đó, vì vậy nó sẽ giúp bạn tiết kiệm ít nhất một số thao tác gõ.

+0

Vâng, tôi biết khả năng đó và nó tốt hơn là chỉ chú thích các phương pháp nhưng vẫn còn một chặng đường dài từ hoàn hảo. –

+0

Dựa trên câu trả lời của bạn rằng nó là một chặng đường dài từ hoàn hảo, không rõ ràng với tôi những gì bạn muốn. Bạn có thể hiển thị các url đầy đủ của một vài tài nguyên và mô tả (các) trình điều khiển nào bạn muốn chúng xử lý không? – SingleShot

+0

Phải, đây có thể là ví dụ lạ nhưng ... '/ quốc gia/{countryCode}/bang/{stateCode}/city/{cityCode}/street/{streetCode}/number/{streetNumber}' mỗi các bước này (ví dụ, quốc gia, tiểu bang, thành phố, đường phố và số) nên đi vào Bộ điều khiển riêng của nó và mỗi bộ có một tập hợp các động từ trên chúng. Câu hỏi chính là khi tôi làm các numberController mà tôi sẽ không lặp lại url tất cả các cách từ quốc gia và tôi không wan't để "biết" rằng countryCode là chìa khóa để tài nguyên này. Tôi chỉ muốn "có" nó. –

-1
@Controller 
@RequestMapping("/library/{libraryId}") 
public class HelloWorldController { 

    @RequestMapping(value="/book/{bookId}") 
    public ModelAndView helloWorld() { 
     .... 
    } 

} 
+0

Điều đó không trả lời được câu hỏi của tôi. Tôi cũng nhận thức được khả năng này (nếu không có gì khác nó đã được chỉ ra trong câu trả lời được đưa ra bởi Bozho). Làm như thế có nghĩa là tôi phải đặt tất cả các thư viện con vào Thư viện trong cùng một Bộ điều khiển. Đó là có thể ofcourse nhưng không phải những gì tôi yêu cầu. Cảm ơn mọi người. –

4

Tôi tin rằng câu hỏi này đã được hỏi & trả lời trước: Spring MVC @RequestMapping Inheritance

Điều đó nói rằng, đây là một cách để giảm bớt số lượng thông tin trùng lặp. Tôi không thực sự làm điều này trong mã của riêng tôi bởi vì tôi nghĩ rằng có URI ngay bên cạnh mã là duy trì hơn, ngay cả khi nó có nghĩa là một chút trùng lặp.

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

Vì tôi sẽ không tự mình thực hiện phương pháp này, tôi chưa thực sự thử giải pháp này! Dựa trên sự hiểu biết của tôi về mùa xuân, tôi nghĩ rằng nó sẽ làm việc mặc dù ...

+0

Tôi bắt đầu nghĩ rằng câu trả lời là "không, điều đó là không thể". Ý tưởng của bạn thêm một mức trừu tượng nhưng vẫn không giải quyết được vấn đề chính đang xử lý "@PathVariable long libraryId" ở đâu đó gần với lớp thư viện. Xuất phát từ java "bình thường", tôi được sử dụng để kế thừa và cho phép lớp cha xử lý các biến riêng của nó và chỉ cho phép các lớp con xử lý những gì cụ thể cho chúng. Cảm ơn mọi người. –

+0

Không thể thực hiện được. Xin lỗi tôi đã không làm cho điều này rõ ràng hơn ở đây. Tôi nghĩ câu hỏi/câu trả lời mà tôi liên kết là đủ rõ ràng. – jtoberon

+0

Tôi đã làm điều này. Nếu bạn kết hợp phương pháp này với cách tiếp cận cha mẹ đa hình, thì bạn có thể nhận được đường dẫn DRY và các đối số phân tách mối quan tâm. Tôi sẽ đào mã của tôi và đăng câu trả lời. – Alex

3

Sử dụng phương pháp tiếp cận cha mẹ đa hình.

@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"; 
     } 
    } 
} 

Ngoài ra, bạn có thể sử dụng một bộ điều khiển cơ sở để định tuyến tiền tố URI để nguồn cha mẹ (/libraries/{library_id}/../..), thêm các mô hình mẹ đến phạm vi yêu cầu, và sau đó để yêu cầu ánh xạ thường xuyên xử lý phần còn lại của URI để nguồn lực trẻ em (/../../books/1). Tôi không có một ví dụ về điều này off-hand.

Lưu ý phụ. Các tài nguyên lồng nhau từng được coi là một mô hình antipattern cho thiết kế URI. Một bộ điều khiển nên xử lý tài nguyên của chính nó. Các cách triển khai phổ biến nhất tạo khóa cho tài nguyên lồng nhau duy nhất, tức là, không phụ thuộc vào tài nguyên gốc của nó. Ví dụ, một khóa cơ sở dữ liệu bản ghi chính. Tuy nhiên, có những tình huống mà khóa có thể không phải là duy nhất, chẳng hạn như giá trị thứ tự hoặc vị trí (ví dụ: sách 1, chương 1, chương 2) hoặc thậm chí là khóa tự nhiên (ví dụ: ISBN sách, SSN người, địa chỉ email , tên người dùng, tên tệp).

Ví dụ về URI kinh điển cho các nguồn lực lồng nhau:

  • /articles => ArticlesController # index
  • /articles/1 => ArticlesController # show
  • /articles/1/comments => CommentsController # index
  • /articles/1/comments/2 => CommentsController # hiển thị (được, nhưng không được ưa thích)
  • /comments/2 => CommentsController # show (ưa thích)
Các vấn đề liên quan