2014-10-24 10 views
81

Pracuję z Spring Framework 4.0.7, wraz z MVC i resztaKiedy użycie ResponseEntity <T> i @RestController na wiosnę aplikacji REST

mogę pracować w spokoju z:

  • @Controller
  • ResponseEntity<T>

Na przykład:

@Controller 
@RequestMapping("/person") 
@Profile("responseentity") 
public class PersonRestResponseEntityController { 

Dzięki metodzie (tylko stworzyć)

@RequestMapping(value="/", method=RequestMethod.POST) 
public ResponseEntity<Void> createPerson(@RequestBody Person person, UriComponentsBuilder ucb){ 
    logger.info("PersonRestResponseEntityController - createPerson"); 
    if(person==null) 
     logger.error("person is null!!!"); 
    else 
     logger.info("{}", person.toString()); 

    personMapRepository.savePerson(person); 
    HttpHeaders headers = new HttpHeaders(); 
    headers.add("1", "uno"); 
    //http://localhost:8080/spring-utility/person/1 
    headers.setLocation(ucb.path("/person/{id}").buildAndExpand(person.getId()).toUri()); 

    return new ResponseEntity<>(headers, HttpStatus.CREATED); 
} 

powrócić coś

@RequestMapping(value="/{id}", method=RequestMethod.GET) 
public ResponseEntity<Person> getPerson(@PathVariable Integer id){ 
    logger.info("PersonRestResponseEntityController - getPerson - id: {}", id); 
    Person person = personMapRepository.findPerson(id); 
    return new ResponseEntity<>(person, HttpStatus.FOUND); 
} 

Works fine

mogę zrobić to samo z:

  • @RestController (wiem, że to jest to samo niż @Controller + @ResponseBody)
  • @ResponseStatus

Na przykład:

@RestController 
@RequestMapping("/person") 
@Profile("restcontroller") 
public class PersonRestController { 

Z metody (wystarczy stworzyć)

@RequestMapping(value="/", method=RequestMethod.POST) 
@ResponseStatus(HttpStatus.CREATED) 
public void createPerson(@RequestBody Person person, HttpServletRequest request, HttpServletResponse response){ 
    logger.info("PersonRestController - createPerson"); 
    if(person==null) 
     logger.error("person is null!!!"); 
    else 
     logger.info("{}", person.toString()); 

    personMapRepository.savePerson(person); 
    response.setHeader("1", "uno"); 

    //http://localhost:8080/spring-utility/person/1 
    response.setHeader("Location", request.getRequestURL().append(person.getId()).toString()); 
} 

do Zwróć coś

@RequestMapping(value="/{id}", method=RequestMethod.GET) 
@ResponseStatus(HttpStatus.FOUND) 
public Person getPerson(@PathVariable Integer id){ 
    logger.info("PersonRestController - getPerson - id: {}", id); 
    Person person = personMapRepository.findPerson(id); 
    return person; 
} 

Moje pytania są następujące:

  1. gdy solidnego powodu lub specyficzny scenariusz jedna opcja powinna być stosowana obowiązkowo nad drugą
  2. Jeśli (1) nie ma znaczenia, jakie podejście jest zasugerował i dlaczego.

Odpowiedz

117

ResponseEntity służy do reprezentowania całej odpowiedzi HTTP. Możesz kontrolować wszystko, co się w nim znajduje: kod statusu, nagłówki i treść.

@ResponseBody jest znacznikiem dla treści odpowiedzi HTTP, a @ResponseStatus deklaruje kod statusu odpowiedzi HTTP.

@ResponseStatus nie jest zbyt elastyczny. Oznacza całą metodę, więc musisz mieć pewność, że twoja metoda obsługi zawsze będzie zachowywać się w ten sam sposób. Nadal nie możesz ustawić nagłówków. Będziesz potrzebował parametru HttpServletResponse lub HttpHeaders.

Zasadniczo, ResponseEntity pozwala zrobić więcej.

+4

dobry punkt o trzeciej obserwacji. Dziękuję ... i pomyślałem to samo o "ResponseEntity", jest bardziej elastyczny. Właśnie miałem wątpliwości dotyczące '@ RestController'. Dziękujemy –

35

Aby ukończyć odpowiedź z Sotorios Delimanolis.

To prawda, że ​​ zapewnia większą elastyczność, ale w większości przypadków nie jest potrzebna, a skończysz z tymi ResponseEntity na całym kontrolerze, co utrudnia czytanie i zrozumienie.

Jeśli chcesz obsłużyć specjalne przypadki, takie jak błędy (Nie znaleziono, Konflikt itp.), Możesz dodać HandlerExceptionResolver do konfiguracji Spring. Tak więc w swoim kodzie, po prostu rzucasz konkretny wyjątek (na przykład NotFoundException) i decydujesz, co zrobić w swoim Handler'u (ustawiając status HTTP na 404), czyniąc Kod kontrolera bardziej przejrzystym.

+3

Twój punkt widzenia działa z (@) ExceptionHandler. Chodzi o to, że jeśli chcesz, aby wszystkie obsługiwane jedną metodą (Try/Catch) HttpEntity dobrze pasuje, jeśli chcesz ponownie użyć obsługi wyjątków (@) ExceptionHandler dla wielu (@) RequestMapping dobrze pasuje. Lubię HttpEntity, ponieważ jestem również w stanie pracować z HttpHeaders. –

19

Według oficjalnej dokumentacji: Creating REST Controllers with the @RestController annotation

@RestController jest adnotacja stereotyp, który łączy @ResponseBody i @Controller. Co więcej, nadaje to więcej znaczenia kontrolerowi i może zawierać dodatkowe semantyki w przyszłych wersjach architektury.

Wydaje się, że najlepiej użyć @RestController dla jasności, ale można również połączyć go ResponseEntity elastyczność w razie potrzeby (According to official tutorial i the code here i my question to confirm that).

Na przykład:

@RestController 
public class MyController { 

    @GetMapping(path = "/test") 
    @ResponseStatus(HttpStatus.OK) 
    public User test() { 
     User user = new User(); 
     user.setName("Name 1"); 

     return user; 
    } 

} 

jest taka sama, jak:

@RestController 
public class MyController { 

    @GetMapping(path = "/test") 
    public ResponseEntity<User> test() { 
     User user = new User(); 
     user.setName("Name 1"); 

     HttpHeaders responseHeaders = new HttpHeaders(); 
     // ... 
     return new ResponseEntity<>(user, responseHeaders, HttpStatus.OK); 
    } 

} 

ten sposób można zdefiniować ResponseEntity tylko w razie potrzeby.

Aktualizacja

Można to wykorzystać:

return ResponseEntity.ok().headers(responseHeaders).body(user); 
+0

Co jeśli dodaliśmy @ResponseStatus (HttpStatus.OK) do metody, ale metoda zwraca return new ResponseEntity <> (user, responseHeaders, HttpStatus.NOT_FOUND); Po prostu myślę, że czy @ResponseStatus będzie modyfikować kod odpowiedzi dalej. –

+2

@Hemant wydaje się, że '@ResponseStatus (HttpStatus.OK)' jest ignorowany po zwróceniu 'ResponseEntity <> (user, responseHeaders, HttpStatus.NOT_FOUND)'. Odpowiedź HTTP to '404' – Danail

Powiązane problemy