Spring RESTful uygulamaları için ResponseEntity <T> ve @RestController kullanıldığında


163

MVC ve Rest ile birlikte Spring Framework 4.0.7 ile çalışıyorum

Huzur içinde çalışabilirim:

  • @Controller
  • ResponseEntity<T>

Örneğin:

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

Yöntemle (sadece oluşturmak için)

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

bir şeyi iade etmek

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

İyi çalışıyor

Ben de yapabilirim :

  • @RestController( @Controller+ İle aynı olduğunu biliyorum @ResponseBody)
  • @ResponseStatus

Örneğin:

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

Yöntemle (sadece oluşturmak için)

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

bir şeyi iade etmek

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

Sorularım:

  1. zaman katı bir nedenden dolayı veya belli bir senaryo bir seçenek diğeri üzerinde zorunlu olarak kullanılması gereken
  2. (1) önemli değilse, hangi yaklaşım önerilir ve neden.

Yanıtlar:


213

ResponseEntityHTTP yanıtının tamamını temsil eder. İçine giren her şeyi kontrol edebilirsiniz: durum kodu, başlıklar ve gövde.

@ResponseBodyHTTP yanıt gövdesi için bir işaretleyicidir ve HTTP yanıtının @ResponseStatusdurum kodunu bildirir.

@ResponseStatusçok esnek değil. Tüm yöntemi işaretler, böylece işleyici yönteminizin her zaman aynı şekilde davranacağından emin olmanız gerekir. Üstbilgileri hala ayarlayamazsınız. HttpServletResponseVeya bir HttpHeadersparametreye ihtiyacınız olacaktır .

Temel olarak, ResponseEntitydaha fazlasını yapmanıza izin verir.


6
Üçüncü gözlem hakkında iyi bir nokta. Teşekkür ederim… ve ben de aynı şeyi düşündüm ResponseEntity, daha esnek. Sadece şüphe ile @RestController. Teşekkür ederim
Manuel Jordan

55

Cevabı Sotorios Delimanolis'ten tamamlamak.

ResponseEntitySize daha fazla esneklik sağlayan doğrudur, ancak çoğu durumda buna ihtiyacınız olmaz ve ResponseEntitykontrol cihazınızın her yerinde bunlarla sonuçlanırsınız, böylece okumayı ve anlamayı zorlaştırırsınız.

Hatalar (Bulunamadı, Çatışma vb.) Gibi özel durumları ele almak istiyorsanız HandlerExceptionResolver, Bahar yapılandırmanıza bir ekleyebilirsiniz . Kodunuzda belirli bir istisna ( NotFoundExceptionörneğin) atarsınız ve İşleyici'nizde ne yapılacağına (HTTP durumunu 404 olarak ayarlayarak) karar verirsiniz, bu da Denetleyici kodunu daha net hale getirir.


5
Bakış açınız (@) ExceptionHandler ile çalışmak için geçerlidir. Buradaki nokta şudur: Tümünün tek bir yöntemle işlenmesini istiyorsanız (Try / Catch) HttpEntity iyi uyuyor, istisna işleme (@) ExceptionHandler için birçok (@) RequestMapping iyi uyuyor. HttpEntity'yi seviyorum çünkü HttpHeaders ile de çalışabiliyorum.
Manuel Ürdün

46

Resmi belgelere göre: @RestController ek açıklaması ile REST Denetleyicileri Oluşturma

@RestController, @ResponseBody ve @Controller'ı birleştiren klişeleştirilmiş bir ek açıklamadır. Dahası, Kontrolörünüze daha fazla anlam kazandırır ve çerçevenin gelecekteki sürümlerinde ek anlamlar taşıyabilir.

O kullanmak en iyisidir görünüyor @RestControllernetlik için, ama aynı zamanda edebilirsiniz birleştirmek ile ResponseEntitygerektiğinde esneklik ( resmi öğretici göre ve burada kod ve onaylayın buna soruma ).

Örneğin:

@RestController
public class MyController {

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

        return user;
    }

}

aynıdır:

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

}

Bu şekilde, ResponseEntityyalnızca gerektiğinde tanımlayabilirsiniz .

Güncelleme

Bunu kullanabilirsiniz:

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

Yönteme @ResponseStatus (HttpStatus.OK) eklediysek, ancak yöntem döndürürse yeni ResponseEntity <> (user, responseHeaders, HttpStatus.NOT_FOUND) döndürürse; Sadece @ResponseStatus'un yanıt kodunu daha fazla değiştirip değiştirmeyeceğini düşünüyorum.
Pratapi Hemant Patel

4
@Hemant @ResponseStatus(HttpStatus.OK), geri döndüğünüzde yok sayılıyor gibi görünüyor ResponseEntity<>(user, responseHeaders, HttpStatus.NOT_FOUND). HTTP yanıtı404
Danail

ResponseStatus'un JavaDoc'larından. Durum kodu HTTP yanıtına işleyici yöntemi çağrıldığında uygulanır ve {@code ResponseEntity} veya {@code "yönlendirme:"} gibi başka yollarla ayarlanan durum bilgilerini geçersiz kılar.
vzhemevko

14

Uygun bir REST API'si yanıt olarak aşağıdaki bileşenlere sahip olmalıdır

  1. Durum kodu
  2. Müdahale Organı
  3. Değiştirilen kaynağın konumu (örneğin, bir kaynak oluşturulduysa, istemci o konumun URL'sini bilmek ister)

ResponseEntity'nin temel amacı seçenek 3'ü sağlamaktı, ResponseEntity olmadan dinlenme seçenekleri elde edilebilir.

Eğer kaynağın konumunu sağlamak istiyorsanız ResponseEntity kullanmak daha iyi olurdu başka önlenebilir.

Bahsedilen tüm seçenekleri sağlamak için bir API'nın değiştirildiği bir örneği ele alalım

// Step 1 - Without any options provided
@RequestMapping(value="/{id}", method=RequestMethod.GET)
public @ResponseBody Spittle spittleById(@PathVariable long id) {
  return spittleRepository.findOne(id);
}

// Step 2- We need to handle exception scenarios, as step 1 only caters happy path.
@ExceptionHandler(SpittleNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public Error spittleNotFound(SpittleNotFoundException e) {
  long spittleId = e.getSpittleId();
  return new Error(4, "Spittle [" + spittleId + "] not found");
}

// Step 3 - Now we will alter the service method, **if you want to provide location**
@RequestMapping(
    method=RequestMethod.POST
    consumes="application/json")
public ResponseEntity<Spittle> saveSpittle(
    @RequestBody Spittle spittle,
    UriComponentsBuilder ucb) {

  Spittle spittle = spittleRepository.save(spittle);
  HttpHeaders headers = new HttpHeaders();
  URI locationUri =
  ucb.path("/spittles/")
      .path(String.valueOf(spittle.getId()))
      .build()
      .toUri();
  headers.setLocation(locationUri);
  ResponseEntity<Spittle> responseEntity =
      new ResponseEntity<Spittle>(
          spittle, headers, HttpStatus.CREATED)
  return responseEntity;
}

// Step4 - If you are not interested to provide the url location, you can omit ResponseEntity and go with
@RequestMapping(
    method=RequestMethod.POST
    consumes="application/json")
@ResponseStatus(HttpStatus.CREATED)
public Spittle saveSpittle(@RequestBody Spittle spittle) {
  return spittleRepository.save(spittle);
}

Kaynak - Spring in Action

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.