Chú thích Spring @ResponseBody hoạt động như thế nào?


89

Tôi có một phương thức được chú thích theo cách sau:

/**
* Provide a list of all accounts.
*/
//  TODO 02: Complete this method.  Add annotations to respond
//  to GET /accounts and return a List<Account> to be converted.
//  Save your work and restart the server.  You should get JSON results when accessing 
//  http://localhost:8080/rest-ws/app/accounts
@RequestMapping(value="/orders", method=RequestMethod.GET)
public @ResponseBody List<Account> accountSummary() {
    return accountManager.getAllAccounts();
}

Vì vậy, tôi biết điều đó bằng chú thích này:

@RequestMapping(value="/orders", method=RequestMethod.GET)

phương thức này xử lý các yêu cầu GET HTTP được thực hiện cho tài nguyên được đại diện bởi URL / đơn đặt hàng .

Phương thức này gọi một đối tượng DAO trả về một Danh sách .

trong đó Tài khoản đại diện cho người dùng trên hệ thống và có một số trường đại diện cho người dùng này, chẳng hạn như:

public class Account {

    @Id
    @Column(name = "ID")
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Long entityId;

    @Column(name = "NUMBER")
    private String number;

    @Column(name = "NAME")
    private String name;

    @OneToMany(cascade=CascadeType.ALL)
    @JoinColumn(name = "ACCOUNT_ID")
    private Set<Beneficiary> beneficiaries = new HashSet<Beneficiary>();

    ...............................
    ...............................
    ...............................
}

Câu hỏi của tôi là: Chính xác thì @ResponseBodychú thích hoạt động như thế nào?

Nó nằm trước List<Account>đối tượng trả về nên tôi nghĩ rằng nó đề cập đến Danh sách này. Tài liệu khóa học nói rằng chú thích này phục vụ chức năng:

đảm bảo rằng kết quả sẽ được ghi vào phản hồi HTTP bằng Trình chuyển đổi thông báo HTTP (thay vì Chế độ xem MVC).

Và cũng có thể đọc trên tài liệu chính thức của Mùa xuân: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html

có vẻ như nó lấy List<Account>đối tượng và đặt nó vào Http Response. Điều này là chính xác hay tôi đang hiểu sai?

Được viết vào bình luận của accountSummary()phương pháp trước đó có:

Bạn sẽ nhận được kết quả JSON khi truy cập http: // localhost: 8080 / rest-ws / app / account

Vậy chính xác thì điều này có nghĩa là gì? Nó có nghĩa là List<Account>đối tượng được trả về bởi accountSummary()phương thức được tự động chuyển đổi thành JSONđịnh dạng và sau đó được đưa vào Http Response? Hay cái gì?

Nếu khẳng định này là đúng, nó được chỉ định ở đâu rằng đối tượng sẽ được tự động chuyển đổi thành JSONđịnh dạng? Định dạng tiêu chuẩn có được chấp nhận khi @ResponseBodychú thích được sử dụng hay nó được chỉ định ở nơi khác không?

Câu trả lời:


160

Trước hết, chú thích không chú thích List. Nó chú thích phương pháp, cũng giống như RequestMappingvậy. Mã của bạn tương đương với

@RequestMapping(value="/orders", method=RequestMethod.GET)
@ResponseBody
public List<Account> accountSummary() {
    return accountManager.getAllAccounts();
}

Bây giờ, ý nghĩa của chú thích là giá trị trả về của phương thức sẽ tạo thành phần thân của phản hồi HTTP. Tất nhiên, một phản hồi HTTP không thể chứa các đối tượng Java. Vì vậy, danh sách tài khoản này được chuyển sang định dạng phù hợp với các ứng dụng REST, thường là JSON hoặc XML.

Việc lựa chọn định dạng phụ thuộc vào trình chuyển đổi thông báo đã cài đặt, vào các giá trị của producesthuộc tính của @RequestMappingchú thích và vào loại nội dung mà ứng dụng khách chấp nhận (có sẵn trong tiêu đề yêu cầu HTTP). Ví dụ: nếu yêu cầu cho biết nó chấp nhận XML, nhưng không chấp nhận JSON và có một trình chuyển đổi thông báo được cài đặt có thể chuyển đổi danh sách sang XML, thì XML sẽ được trả về.


3
xin chào, làm cách nào để thiết lập "bộ chuyển đổi tin nhắn đã cài đặt"? Tôi muốn mặc định luôn chuyển đổi thành Json. Tôi có thể làm điều đó?
GMsoF

@JB Nizet, bạn có thể vui lòng giải thích tại sao phản hồi http không thể chứa các đối tượng java. Tôi là người mới sử dụng java.
Naved Ali

3
@ Er.NavedAli đọc đặc tả http, loại nội dung phản hồi http xác định nội dung pháp lý mà phản hồi http có thể chứa. giá trị pháp lý cho điều đó có thể là "application / octet-stream", "image / jpeg", "text / HTML", nhưng đối tượng java không phải là giá trị pháp lý cho nó.
ZhaoGang

@ZhaoGang, Loại nội dung 'ứng dụng / json' đã được thay thế bằng 'ứng dụng / xml' trong trường hợp thử nghiệm của tôi, nhưng phần nội dung phản hồi dường như không thay đổi, vẫn có định dạng json.
LeafiWan

1
chính xác, ý tôi là ở lớp mùa xuân nào, quyết định xác định cách trả về phản hồi được thực hiện như thế nào? Bạn có thể chỉ cho tôi nguồn trên github, nơi quyết định này được thực hiện hoặc tên lớp? Ngoài ra, điều gì sẽ xảy ra nếu máy khách chấp nhận XML, nhưng không có trình chuyển đổi XML nào được cài đặt?
anir

63

Điều cơ bản đầu tiên cần hiểu là sự khác biệt về kiến ​​trúc.

Một đầu bạn có kiến ​​trúc MVC, dựa trên ứng dụng web bình thường của bạn, sử dụng các trang web và trình duyệt đưa ra yêu cầu cho một trang:

Browser <---> Controller <---> Model
               |      |
               +-View-+

Trình duyệt đưa ra yêu cầu, bộ điều khiển (@Controller) nhận mô hình (@Entity) và tạo chế độ xem (JSP) từ mô hình và chế độ xem được trả lại cho máy khách. Đây là kiến ​​trúc ứng dụng web cơ bản.

Mặt khác, bạn có một kiến ​​trúc RESTful. Trong trường hợp này, không có Chế độ xem. Bộ điều khiển chỉ gửi lại mô hình (hoặc biểu diễn tài nguyên, theo các thuật ngữ RESTful hơn). Máy khách có thể là một ứng dụng JavaScript, một ứng dụng máy chủ Java, bất kỳ ứng dụng nào mà chúng tôi sử dụng REST API của mình. Với kiến ​​trúc này, khách hàng quyết định phải làm gì với mô hình này. Lấy ví dụ Twitter. Twitter dưới dạng API Web (REST), cho phép các ứng dụng của chúng tôi sử dụng API của nó để nhận những thứ như cập nhật trạng thái, để chúng tôi có thể sử dụng nó để đưa dữ liệu đó vào ứng dụng của mình. Dữ liệu đó sẽ có một số định dạng như JSON.

Nói như vậy, khi làm việc với Spring MVC, lần đầu tiên nó được xây dựng để xử lý kiến ​​trúc ứng dụng web cơ bản. Có thể có các hương vị chữ ký phương pháp khác nhau cho phép tạo ra một khung nhìn từ các phương pháp của chúng tôi. Phương thức có thể trả về một ModelAndViewnơi chúng ta tạo nó một cách rõ ràng hoặc có những cách ngầm định mà chúng ta có thể trả về một số đối tượng tùy ý được đặt thành các thuộc tính của mô hình. Nhưng theo cách nào đó, ở đâu đó dọc theo chu kỳ yêu cầu-phản hồi, sẽ có một chế độ xem được tạo ra.

Nhưng khi chúng tôi sử dụng @ResponseBody, chúng tôi đang nói rằng chúng tôi không muốn một chế độ xem được tạo ra. Chúng tôi chỉ muốn gửi đối tượng trả về dưới dạng phần thân, ở bất kỳ định dạng nào chúng tôi chỉ định. Chúng tôi sẽ không muốn nó là một đối tượng Java được tuần tự hóa (mặc dù có thể). Vì vậy, có, nó cần được chuyển đổi sang một số loại phổ biến khác (loại này thường được xử lý thông qua thương lượng nội dung - xem liên kết bên dưới). Thành thật mà nói, tôi không làm việc nhiều với Spring, mặc dù tôi đã vọc nó chỗ này chỗ kia. Thông thường, tôi sử dụng

@RequestMapping(..., produces = MediaType.APPLICATION_JSON_VALUE)

để đặt loại nội dung, nhưng có thể JSON là mặc định. Đừng trích dẫn tôi, nhưng nếu bạn đang nhận JSON và bạn chưa chỉ định produces, thì có thể nó là mặc định. JSON không phải là định dạng duy nhất. Ví dụ, ở trên có thể dễ dàng được gửi trong XML, nhưng bạn sẽ cần phải có producesđể MediaType.APPLICATION_XML_VALUEvà tôi tin rằng bạn cần phải cấu hình HttpMessageConvertercho JAXB. Đối với JSON được MappingJacksonHttpMessageConvertercấu hình, khi chúng ta có Jackson trên classpath.

Tôi sẽ dành một chút thời gian để tìm hiểu về Thương lượng nội dung . Đó là một phần rất quan trọng của REST. Nó sẽ giúp bạn tìm hiểu về các định dạng phản hồi khác nhau và cách ánh xạ chúng với các phương pháp của bạn.


Nếu tìm thấy câu trả lời của bạn trong khi điều tra về cách tạo bộ điều khiển REST chung / động mà không cần sử dụng @Controller/@RestController. Tôi đã phát hiện ra rằng tôi cần phải bỏ qua bằng cách nào đó lớp trình phân giải chế độ xem. Nó không đơn giản như vậy vì lớp AbstractController cung cấp một phương thức phải trả về tên khung nhìn. Tôi đã hỏi một câu hỏi về vấn đề đó: stackoverflow.com/questions/41016018/… , nếu bạn có một số ý tưởng về cách giải quyết vấn đề của mình, vui lòng đăng nhận xét.
nowszy94

1

Hơn nữa, kiểu trả về được xác định bởi

  1. Yêu cầu HTTP cho biết nó muốn gì - trong tiêu đề Chấp nhận của nó. Hãy thử xem xét yêu cầu ban đầu như xem Chấp nhận được đặt thành gì.

  2. Những gì HttpMessageConverters Spring thiết lập. Spring MVC sẽ thiết lập các bộ chuyển đổi cho XML (sử dụng JAXB) và JSON nếu các thư viện của Jackson có trên classpath.

Nếu có lựa chọn, nó sẽ chọn một - trong ví dụ này, nó sẽ là JSON.

Điều này được đề cập trong các ghi chú của khóa học. Tìm các ghi chú về Trình chuyển đổi Thư và Đàm phán Nội dung.

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.