2011-08-23 16 views
22

Mam problemy z prawidłowym sposobem wdrożenia usług RESTful Spring MVC 3.x z HATEOAS. Rozważ następujące ograniczenia:Spring MVC, REST i HATEOAS

  • Nie chcę, aby moje encje domeny były zanieczyszczone konstrukcjami web/rest.
  • Nie chcę, aby moje kontrolery były zanieczyszczone przez konstrukcje widokowe.
  • Chcę obsługiwać wiele widoków.

Obecnie mam ładnie złożoną aplikację MVC bez HATEOAS. Jednostki domeny są czystymi obiektami POJO bez żadnego widoku lub osadzonych koncepcji web/rest. Na przykład:

class User { 
    public String getName() {...} 
    public String setName(String name) {...} 
    ... 
} 

Moje sterowniki są również proste. Zapewniają routing i status oraz delegują do Spring's resolution framework. Uwaga mojej aplikacji obsługuje JSON, XML i HTML, jeszcze nie podmioty lub kontrolery domen zostały osadzone wyświetlić informacje:

@Controller 
@RequestMapping("/users") 
class UserController { 

    @RequestMapping 
    public ModelAndView getAllUsers() { 
    List<User> users = userRepository.findAll(); 
    return new ModelAndView("users/index", "users", users); 
    } 

    @RequestMapping("/{id}") 
    public ModelAndView getUser(@PathVariable Long id) { 
    User user = userRepository.findById(id); 
    return new ModelAndView("users/show", "user", user); 
    } 
} 

Więc teraz mój problem - nie jestem pewien czystym sposób wspierania hateoas. Oto przykład. Powiedzmy, gdy klient prosi o użytkownika w formacie JSON, to wychodzi tak:

{ 
    firstName: "John", 
    lastName: "Smith" 
} 

Załóżmy też, że kiedy Popieram hateoas, chcę JSON zawierają prostą „ja” link, który klient może następnie użyć do odświeżenia obiektu, usunięcia go lub czegoś innego. To może również mieć „przyjaciół” odnośnik wskazujący, jak uzyskać listę użytkownika przyjaciół:

{ 
    firstName: "John", 
    lastName: "Smith", 
    links: [ 
    { 
     rel: "self", 
     ref: "http://myserver/users/1" 
    }, 
    { 
     rel: "friends", 
     ref: "http://myserver/users/1/friends" 
    } 
    ] 
} 

Jakoś chcesz dołączyć linki do mojego obiektu. Uważam, że właściwym miejscem do tego jest warstwa kontrolera, ponieważ wszystkie kontrolery znają poprawne adresy URL. Dodatkowo, ponieważ obsługuję wiele widoków, uważam, że właściwą rzeczą jest udekorowanie moich jednostek domeny w kontrolerze, zanim zostaną one przekonwertowane do JSON/XML/cokolwiek w ramach wglądu w Spring. Jednym ze sposobów na zrobienie tego może być owinięcie danego POJO ogólną klasą zasobów zawierającą listę łączy. Konieczne będzie dostosowanie niektórych widoków, aby dopasować go do formatu, który chcę, ale jest to wykonalne. Niestety zagnieżdżone zasoby nie mogą być opakowane w ten sposób. Inne rzeczy, które przychodzą na myśl, to dodawanie linków do ModelAndView, a następnie dostosowywanie każdego z wyskakujących widoków Springa do wstawiania linków do wygenerowanego JSON/XML/etc. To, czego nie chcę, to ciągłe ręczne tworzenie JSON/XML/etc. w celu dostosowania różnych połączeń, gdy przychodzą i odchodzą w trakcie rozwoju.

Myśli?

+2

Istnieje teraz projekt danych Spring zwany [Spring Data - Rest] (http://www.springsource.org/spring-data/rest), który obsługuje HATEOAS w jakiejś formie. – SingleShot

+1

lub możesz bezpośrednio użyć modułu autonomicznego [spring-hateoas] (https://github.com/SpringSource/spring-hateoas). – Mariusz

Odpowiedz

10

Jest użyteczny projekt o nazwie Spring HATEOAS na GitHub który ma następujący opis:

„Ten projekt zawiera kilka interfejsów API w celu ułatwienia tworzenia REST reprezentacji dla że zgodne z zasadą hateoas podczas pracy z wiosny i zwłaszcza wiosną MVC”

Jeśli klasa zasób wracasz rozciąga«ResourceSupport»można łatwo dodawać linki do niego i można zbudować przy użyciu łącza«ControllerLinkBuilder», na przykład dodać link samodzielne:

import static org.sfw.hateoas.mvc.ControllerLinkBuilder.*; 

Link link = linkTo(YourController.class).slash(resource.getName()).withSelfRel(); 
resource.add(link); 

To zupełnie nowy projekt, ale jest ona dostępna z publicznego Maven repo jeśli wymagane:

<dependency> 
    <groupId>org.springframework.hateoas</groupId> 
    <artifactId>spring-hateoas</artifactId> 
    <version>0.3.0.RELEASE</version> 
</dependency> 

Jeśli używasz artefaktu maven:

org.sfw.hateoas.mvc.ControllerLinkBuilder 

staje:

org.springframework.hateoas.mvc.ControllerLinkBuilder 
+0

Interesujące. Wolę import Springa i innych kodów infrastrukturalnych znajdujących się na obrzeżach mojej aplikacji, ale w tym przypadku wszystkie klasy zasobów rozszerzające 'ResourceSupport' wydają się przyzwoitym kompromisem. Dzięki! – SingleShot

+2

Aha, i to od Olivera Gierke, który jest głównym facetem w Spring Data. Chłodny. – SingleShot

+0

Napisałem posty na blogu związane z [HATEOAS używając Spring Framework] (http://azagorneanu.blogspot.com/2013/06/hateoas-using-spring-framework.html) –

1

myśli moje

  • wykorzystujące jakieś nazewnictwo tak, że na przykład na własny Przekierowanie może być zbudowana z nazwą klasy obiektu.
  • Nie sądzę, że dodanie elementów linków powinno zostać dodane przez kontroler (przy okazji napisałeś: "Nie chcę, aby moje kontrolery były zanieczyszczone przez konstrukcje widoku".) Próbowałbym znaleźć sposób na rozszerzenie serializacji JSON. aby automatycznie dodawać dodatkowe elementy. Możesz dodać kilka adnotacji do swoich jednostek, nawet jeśli trochę ich to zanieczyści.
+1

Dzięki. Konwencja nazewnictwa mogłaby zadziałać, gdyby wszystko, co chciałem, było łączem "ja", jednak w prawdziwej aplikacji istniałyby liczne łącza specyficzne dla przepływu pracy na obiektach (podobne do nieco słynnego ["jak zdobyć filiżankę kawy"] (http://www.infoq.com/articles/webber-rest-workflow)), które nie mogły zostać stworzone zgodnie z konwencją. – SingleShot

+0

Odnośnie generowania linków - muszę wymyślić coś nieco ogólnego, więc kiedy dodaję nowy link, nie muszę edytować 3 różnych rozpoznawania widoku (JSON/XML/HTML). Hmmm.Być może natura architektury RESTful z tym stosem technologii wymaga, aby domeny były "zanieczyszczone" linkami, a może to nie jest złe ... – SingleShot

+2

"Konwencja nazewnictwa" jest złym pomysłem. W szczególności wydaje się całkowicie anty-HATEOAS. Celem HATEOAS jest to, że klient nie musi "znać" twojego API, ale może po prostu podążać za odnośnikami, aby uzyskać przejście do innego podmiotu lub stanu. – HDave

0

Aby utworzyć łącze w Twój aplet REST można użyć projektu HAETOAS struktury Spring.

org.springframework.hateoas.mvc.ControllerLinkBuilder klasa ustawieniu metody, które można wykorzystać do budowania link jak -

Link link=linkTo(PersonControllerImpl.class).slash(null).withSelfRel(); 

Także jeśli masz metoda kontroler posiadający @RequestMapping adnotacji z jakąś wartość URI -

@RequestMapping(value = "/customer", method = RequestMethod.GET, produces = {MediaType.APPLICATION_JSON_VALUE}) 
    public ResponseEntity<?> getCustomer() { 

//... 
} 

następnie możesz utworzyć łącze przy użyciu wartości URI metody jako -

linkTo(methodOn(PersonControllerImpl.class).getCustomer()).toUri().toString() 

to zwróci wartość String (http://www.urhost.com/customer), którą można ustawić w swoim entityObject.