คำอธิบายประกอบ Spring @ResponseBody ทำงานอย่างไร


91

ฉันมีวิธีการที่มีคำอธิบายประกอบดังต่อไปนี้:

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

ดังนั้นฉันจึงรู้ว่าโดยคำอธิบายประกอบนี้:

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

วิธีการจับนี้GETร้องขอ HTTP ที่เกิดขึ้นกับทรัพยากรที่แสดงโดยที่ URL / สั่งซื้อ

วิธีการนี้เรียกว่าวัตถุ DAO ที่ส่งกลับรายการ

โดยที่บัญชีเป็นตัวแทนของผู้ใช้ในระบบและมีบางฟิลด์ที่แสดงถึงผู้ใช้รายนี้เช่น:

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

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

คำถามของฉันคือวิธีตรงไม่@ResponseBodyทำงานคำอธิบายประกอบ?

มันตั้งอยู่ก่อนList<Account>วัตถุที่ส่งคืนดังนั้นฉันคิดว่ามันหมายถึงรายการนี้ เอกสารประกอบหลักสูตรระบุว่าคำอธิบายประกอบนี้ทำหน้าที่เพื่อ:

ตรวจสอบให้แน่ใจว่าผลลัพธ์จะถูกเขียนไปยังการตอบสนอง HTTP โดย HTTP Message Converter (แทนที่จะเป็น MVC View)

และอ่านเอกสารอย่างเป็นทางการของ Spring: http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/bind/annotation/ResponseBody.html

ดูเหมือนว่าจะใช้List<Account>วัตถุและใส่ลงในไฟล์Http Response . ถูกต้องหรือฉันเข้าใจผิด?

เขียนไว้ในความคิดเห็นของaccountSummary()วิธีการก่อนหน้านี้มี:

คุณควรได้รับผลลัพธ์ JSON เมื่อเข้าถึง http: // localhost: 8080 / rest-ws / app / accounts

แล้วนี่หมายความว่าอย่างไร? หมายความว่าList<Account>วัตถุที่ส่งคืนโดยaccountSummary()วิธีนี้จะถูกแปลงเป็นJSONรูปแบบโดยอัตโนมัติจากนั้นใส่ลงในไฟล์Http Response ? หรืออะไร?

ถ้าการยืนยันนี้เป็นจริงจะมีการระบุไว้ที่ใดว่าวัตถุจะถูกแปลงเป็นJSONรูปแบบโดยอัตโนมัติ รูปแบบมาตรฐานถูกนำมาใช้เมื่อใช้@ResponseBodyคำอธิบายประกอบหรือมีการระบุไว้ที่อื่นหรือไม่

คำตอบ:


162

Listแรกของทุกคำอธิบายประกอบไม่ได้คำอธิบายประกอบ มันใส่คำอธิบายประกอบวิธีการเช่นเดียวกับที่RequestMappingทำ รหัสของคุณเทียบเท่ากับ

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

ตอนนี้ความหมายของคำอธิบายประกอบก็คือค่าที่ส่งคืนของวิธีการจะประกอบเป็นเนื้อความของการตอบสนอง HTTP แน่นอนการตอบสนอง HTTP ต้องไม่มีวัตถุ Java ดังนั้นรายการบัญชีนี้จึงเปลี่ยนเป็นรูปแบบที่เหมาะสมกับแอปพลิเคชัน REST โดยทั่วไปคือ JSON หรือ XML

การเลือกรูปแบบขึ้นอยู่กับตัวแปลงข้อความที่ติดตั้งค่าของproducesแอตทริบิวต์ของ@RequestMappingคำอธิบายประกอบและประเภทเนื้อหาที่ไคลเอ็นต์ยอมรับ (ซึ่งมีอยู่ในส่วนหัวของคำขอ HTTP) ตัวอย่างเช่นหากคำขอระบุว่ายอมรับ XML แต่ไม่ใช่ JSON และมีการติดตั้งตัวแปลงข้อความที่สามารถแปลงรายการเป็น XML ได้ก็จะส่งคืน XML


3
สวัสดีเราจะตั้งค่า "ตัวแปลงข้อความที่ติดตั้ง" ได้อย่างไร ฉันต้องการให้ค่าเริ่มต้นแปลงเป็น Json เสมอ ฉันสามารถทำได้หรือไม่?
Sam YC

@JB Nizet คุณช่วยอธิบายได้ไหมว่าเหตุใดการตอบกลับ http จึงไม่มีวัตถุ java ฉันเป็น newbee กับ java
Naved Ali

3
@ Er.NavedAli อ่านข้อกำหนด http ประเภทเนื้อหาตอบกลับ http กำหนดเนื้อหาทางกฎหมายที่การตอบกลับ http สามารถมีได้ ค่าทางกฎหมายสำหรับสิ่งนั้นอาจเป็น "application / octet-stream", "image / jpeg", "text / HTML" แต่วัตถุ java ไม่ใช่ค่าทางกฎหมายสำหรับมัน
ZhaoGang

@ZhaoGang 'application / json' ประเภทเนื้อหาถูกแทนที่ด้วย 'application / xml' ในกรณีทดสอบของฉัน แต่เนื้อหาตอบกลับดูเหมือนจะไม่มีการเปลี่ยนแปลง แต่ยังคงมีรูปแบบ json อยู่
LeafiWan

1
ฉันหมายถึงชั้นเรียนฤดูใบไม้ผลิใดกันแน่การตัดสินใจว่าจะตอบสนองกลับเป็นอย่างไร คุณช่วยชี้แหล่งที่มาใน github ได้ไหมว่าการตัดสินใจนี้เสร็จสิ้นแล้วหรือชื่อคลาส? จะเกิดอะไรขึ้นหากไคลเอนต์ยอมรับ XML แต่ไม่มีการติดตั้งตัวแปลง XML
anir

69

สิ่งพื้นฐานแรกที่ต้องเข้าใจคือความแตกต่างในสถาปัตยกรรม

ปลายด้านหนึ่งคุณมีสถาปัตยกรรม MVC ซึ่งขึ้นอยู่กับเว็บแอปปกติของคุณโดยใช้หน้าเว็บและเบราว์เซอร์จะร้องขอหน้า:

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

เบราว์เซอร์ทำการร้องขอคอนโทรลเลอร์ (@Controller) รับโมเดล (@Entity) และสร้างมุมมอง (JSP) จากโมเดลและมุมมองจะถูกส่งกลับไปยังไคลเอนต์ นี่คือสถาปัตยกรรมเว็บแอปพื้นฐาน

ในอีกด้านหนึ่งคุณมีสถาปัตยกรรมที่เหลืออยู่ ในกรณีนี้ไม่มี View คอนโทรลเลอร์จะส่งโมเดลกลับไปเท่านั้น (หรือการแสดงทรัพยากรในเงื่อนไขที่น่าสนใจมากขึ้น) ไคลเอนต์สามารถเป็นแอปพลิเคชัน JavaScript แอปพลิเคชันเซิร์ฟเวอร์ Java แอปพลิเคชันใด ๆ ที่เราเปิดเผย REST API ของเรา ด้วยสถาปัตยกรรมนี้ลูกค้าจะตัดสินใจว่าจะทำอย่างไรกับโมเดลนี้ ยกตัวอย่างเช่น Twitter Twitter เป็น API ของเว็บ (REST) ​​ที่อนุญาตให้แอปพลิเคชันของเราใช้ API เพื่อรับสิ่งต่างๆเช่นการอัปเดตสถานะเพื่อให้เราสามารถใช้เพื่อใส่ข้อมูลนั้นในแอปพลิเคชันของเรา ข้อมูลนั้นจะอยู่ในรูปแบบบางอย่างเช่น JSON

ดังที่กล่าวไว้เมื่อทำงานกับ Spring MVC มันถูกสร้างขึ้นครั้งแรกเพื่อจัดการกับสถาปัตยกรรมเว็บแอปพลิเคชันพื้นฐาน อาจมีรสชาติอันเป็นเอกลักษณ์ของวิธีการที่แตกต่างกันซึ่งช่วยให้สามารถผลิตมุมมองจากวิธีการของเราได้ วิธีนี้สามารถส่งคืนModelAndViewตำแหน่งที่เราสร้างขึ้นอย่างชัดเจนหรือมีวิธีการโดยปริยายที่เราสามารถส่งคืนอ็อบเจ็กต์ที่กำหนดเองบางอย่างที่ได้รับการตั้งค่าเป็นคุณลักษณะของโมเดล แต่ไม่ว่าจะด้วยวิธีใดก็ตามในรอบการตอบสนองคำขอจะมีการสร้างมุมมอง

แต่เมื่อเราใช้@ResponseBodyเรากำลังบอกว่าเราไม่ต้องการมุมมองที่เกิดขึ้น เราแค่ต้องการส่งวัตถุส่งคืนเป็นร่างกายในรูปแบบใดก็ตามที่เราระบุ เราไม่ต้องการให้มันเป็นวัตถุ Java แบบอนุกรม (แม้ว่าจะเป็นไปได้) ใช่จำเป็นต้องแปลงเป็นประเภททั่วไปอื่น ๆ (โดยปกติแล้วประเภทนี้จะจัดการผ่านการเจรจาต่อรองเนื้อหา - ดูลิงก์ด้านล่าง) บอกตามตรงว่าฉันไม่ค่อยได้ทำงานกับ Spring มากนักแม้ว่าฉันจะตะลุยกับมันที่นี่และที่นั่น ปกติฉันใช้

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

เพื่อตั้งค่าประเภทเนื้อหา แต่ JSON อาจเป็นค่าเริ่มต้น อย่าอ้างฉัน แต่ถ้าคุณได้รับ JSON และคุณไม่ได้ระบุproducesอาจเป็นค่าเริ่มต้น JSON ไม่ใช่รูปแบบเดียว ตัวอย่างเช่นข้างต้นสามารถส่งใน XML ได้อย่างง่ายดาย แต่คุณจะต้องมีสิ่งที่producesต้องทำMediaType.APPLICATION_XML_VALUEและฉันเชื่อว่าคุณต้องกำหนดค่าHttpMessageConverterสำหรับ JAXB สำหรับการMappingJacksonHttpMessageConverterกำหนดค่าJSON เมื่อเรามี Jackson บน classpath

ฉันจะใช้เวลาในการเรียนรู้เกี่ยวกับการเจรจาต่อรองเนื้อหา เป็นส่วนที่สำคัญมากของ REST ซึ่งจะช่วยให้คุณเรียนรู้เกี่ยวกับรูปแบบการตอบกลับต่างๆและวิธีการจับคู่กับวิธีการของคุณ


หากพบคำตอบของคุณขณะตรวจสอบวิธีสร้างคอนโทรลเลอร์ REST ทั่วไป / ไดนามิกโดยไม่ต้องใช้@Controller/@RestController. ฉันค้นพบว่าฉันจำเป็นต้องละเว้นเลเยอร์ตัวแก้ไขมุมมอง ไม่ใช่เรื่องง่ายเพราะคลาส AbstractController มีเมธอดที่ต้องส่งคืนชื่อมุมมอง ฉันถามคำถามเกี่ยวกับเรื่องนี้: stackoverflow.com/questions/41016018/…หากคุณมีความคิดเกี่ยวกับวิธีแก้ปัญหาของฉันโปรดโพสต์ความคิดเห็น
nowszy94

2

นอกจากนี้ประเภทผลตอบแทนจะถูกกำหนดโดย

  1. สิ่งที่คำขอ HTTP บอกว่าต้องการ - ในส่วนหัวยอมรับ ลองดูคำขอเริ่มต้นดูว่า Accept ถูกตั้งค่าเป็นอะไร

  2. สิ่งที่ HttpMessageConverters Spring กำหนดขึ้น Spring MVC จะตั้งค่าตัวแปลงสำหรับ XML (โดยใช้ JAXB) และ JSON หากไลบรารี Jackson อยู่ใน classpath ของเขา

หากมีตัวเลือกก็เลือกอย่างใดอย่างหนึ่ง - ในตัวอย่างนี้จะเป็น JSON

นี้จะครอบคลุมในบันทึกการเรียนการสอน มองหาหมายเหตุเกี่ยวกับตัวแปลงข้อความและการเจรจาต่อรองเนื้อหา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.