Khi sử dụng FeedbackEntity <T> và @RestControll cho các ứng dụng Spring RESTful


163

Tôi đang làm việc với Spring Framework 4.0.7, cùng với MVC và Rest

Tôi có thể làm việc trong hòa bình với:

  • @Controller
  • ResponseEntity<T>

Ví dụ:

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

Với phương thức (chỉ để tạo)

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

trả lại một cái gì đó

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

Hoạt động tốt

Tôi có thể làm tương tự với :

  • @RestController(Tôi biết nó giống với @Controller+ @ResponseBody)
  • @ResponseStatus

Ví dụ:

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

Với phương thức (chỉ để tạo)

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

trả lại một cái gì đó

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

Câu hỏi của tôi là:

  1. khi vì một lý do chắc chắn hoặc kịch bản cụ thể, một tùy chọn phải được sử dụng bắt buộc so với tùy chọn khác
  2. Nếu (1) không quan trọng, phương pháp nào được đề xuất và tại sao.

Câu trả lời:


213

ResponseEntitycó nghĩa là đại diện cho toàn bộ phản hồi HTTP. Bạn có thể kiểm soát mọi thứ đi vào nó: mã trạng thái, tiêu đề và nội dung.

@ResponseBodylà một điểm đánh dấu cho phần phản hồi HTTP và @ResponseStatuskhai báo mã trạng thái của phản hồi HTTP.

@ResponseStatuskhông linh hoạt. Nó đánh dấu toàn bộ phương thức, do đó bạn phải chắc chắn rằng phương thức xử lý của bạn sẽ luôn hành xử theo cùng một cách. Và bạn vẫn không thể đặt tiêu đề. Bạn sẽ cần HttpServletResponsehoặc một HttpHeaderstham số.

Về cơ bản, ResponseEntitycho phép bạn làm nhiều hơn.


6
Điểm tốt về quan sát thứ ba. Cảm ơn bạn và tôi cũng nghĩ như vậy ResponseEntity, nó linh hoạt hơn. Chỉ là tôi đã nghi ngờ về @RestController. Cảm ơn bạn
Manuel Jordan

55

Để hoàn thành câu trả lời từ Sotorios Delimanolis.

Đúng là nó ResponseEntitymang lại cho bạn sự linh hoạt hơn nhưng trong hầu hết các trường hợp, bạn sẽ không cần đến nó và bạn sẽ kết thúc với những thứ này ResponseEntityở mọi nơi trong bộ điều khiển của mình, do đó gây khó khăn cho việc đọc và hiểu.

Nếu bạn muốn xử lý các trường hợp đặc biệt như lỗi (Không tìm thấy, Xung đột, v.v.), bạn có thể thêm HandlerExceptionResolvercấu hình vào Spring. Vì vậy, trong mã của bạn, bạn chỉ cần đưa ra một ngoại lệ cụ thể ( NotFoundExceptionví dụ) và quyết định những việc cần làm trong Trình xử lý của mình (đặt trạng thái HTTP thành 404), làm cho mã Trình điều khiển rõ ràng hơn.


5
Quan điểm của bạn là hợp lệ khi làm việc với (@) ExceptionHandler. Vấn đề là: nếu bạn muốn tất cả được xử lý theo một phương thức (Thử / Bắt) thì httpEntity rất phù hợp, nếu bạn muốn sử dụng lại xử lý ngoại lệ (@) ExceptionHandler cho nhiều (@) RequestMapping phù hợp. Tôi thích httpEntity vì tôi cũng có thể làm việc với HttpHeaders.
Manuel Jordan

46

Theo tài liệu chính thức: Tạo Bộ điều khiển REST với chú thích @RestControll

@RestControll là một chú thích rập khuôn kết hợp @ResponseBody và @Controll. Hơn thế nữa, nó mang lại nhiều ý nghĩa hơn cho Bộ điều khiển của bạn và cũng có thể mang thêm ngữ nghĩa trong các phiên bản tương lai của khung.

Có vẻ như tốt nhất là sử dụng @RestControllercho rõ ràng, nhưng bạn cũng có thể kết hợp nó với ResponseEntitysự linh hoạt khi cần thiết ( Theo hướng dẫn chính thứcmã ở đâycâu hỏi của tôi để xác nhận điều đó ).

Ví dụ:

@RestController
public class MyController {

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

        return user;
    }

}

giống như:

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

}

Bằng cách này, bạn chỉ có thể xác định ResponseEntitykhi cần thiết.

Cập nhật

Bạn có thể sử dụng điều này:

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

Điều gì sẽ xảy ra nếu chúng tôi đã thêm @ResponseStatus (HttpStatus.OK) trên phương thức, nhưng phương thức trả về trả về Phản hồi mới <> (người dùng, answerHeaders, HttpStatus.NOT_FOUND); Tôi chỉ nghĩ rằng liệu @ResponseStatus sẽ sửa đổi mã phản hồi hơn nữa.
Patapi Hemant Patel

4
@Hemant dường như @ResponseStatus(HttpStatus.OK)bị bỏ qua khi bạn trở lại ResponseEntity<>(user, responseHeaders, HttpStatus.NOT_FOUND). Phản hồi HTTP là404
Danail

Từ JavaDocs của FeedbackStatus. Mã trạng thái được áp dụng cho phản hồi HTTP khi phương thức xử lý được gọi và ghi đè thông tin trạng thái được đặt bằng các phương tiện khác, như {@code FeedbackEntity} hoặc {@code "redirect:"}.
vzhemevko

14

Một API REST thích hợp nên có các thành phần bên dưới để phản hồi

  1. Mã trạng thái
  2. Cơ quan đáp ứng
  3. Vị trí của tài nguyên đã bị thay đổi (ví dụ: nếu tài nguyên được tạo, khách hàng sẽ quan tâm để biết url của vị trí đó)

Mục đích chính của FeedbackEntity là cung cấp tùy chọn 3, các tùy chọn còn lại có thể đạt được mà không cần FeedbackEntity.

Vì vậy, nếu bạn muốn cung cấp vị trí của tài nguyên thì sử dụng FeedbackEntity sẽ tốt hơn nếu không thì có thể tránh được.

Xem xét một ví dụ trong đó API được sửa đổi để cung cấp tất cả các tùy chọn được đề cập

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

Nguồn - Mùa xuân trong hành động

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.