1. บทนำสู่ Swagger
ในบทความก่อนหน้านี้เราแนะนำการสนับสนุนของ Spring Boot สำหรับ Restful ในบทความนี้เรายังคงหารือเกี่ยวกับหัวข้อนี้ต่อไป อย่างไรก็ตามเราจะไม่หารือกันอีกต่อไปว่า API RESTFUL ถูกนำไปใช้ แต่จะหารือเกี่ยวกับการบำรุงรักษาเอกสาร API RESTFUL
ในการทำงานประจำวันเรามักจะต้องให้อินเทอร์เฟซกับส่วนหน้า (เว็บปลาย, iOS, Android) หรือบุคคลที่สาม ในเวลานี้เราจำเป็นต้องจัดทำเอกสาร API โดยละเอียด แต่การบำรุงรักษาเอกสารโดยละเอียดไม่ใช่เรื่องง่าย ก่อนอื่นการเขียนเอกสารโดยละเอียดเป็นงานที่ใช้เวลานานและลำบาก ในทางกลับกันเนื่องจากรหัสและเอกสารถูกคั่นด้วยมันเป็นเรื่องง่ายที่จะทำให้เกิดความไม่สอดคล้องกันระหว่างเอกสารและรหัส ในบทความนี้เราจะแบ่งปันวิธีในการรักษาเอกสาร API นั่นคือเพื่อสร้างเอกสาร API ที่มีความสุขโดยอัตโนมัติผ่าน Swagger
Swagger คืออะไร? เราสามารถอ่านคำอธิบายอย่างเป็นทางการได้โดยตรง:
เครื่องมือ API ที่ได้รับความนิยมมากที่สุดในโลกเป็นกรอบการทำงานที่ใหญ่ที่สุดในโลกของเครื่องมือนักพัฒนา API สำหรับ Specification OpenAPI (OAS) ช่วยให้การพัฒนาทั่ววงจรชีวิต API ทั้งหมดตั้งแต่การออกแบบและเอกสารประกอบไปสู่การทดสอบและการปรับใช้
ข้อความนี้เป็นครั้งแรกที่บอกคุณว่า Swagger เป็นเครื่องมือ API ที่ได้รับความนิยมมากที่สุดในโลกและจุดประสงค์ของ Swagger คือการสนับสนุนการพัฒนาวงจรชีวิต API ทั้งหมดรวมถึงการออกแบบเอกสารการทดสอบและการปรับใช้ ในบทความนี้เราจะใช้การจัดการเอกสารและฟังก์ชั่นการทดสอบของ Swagger
หลังจากได้รับความเข้าใจพื้นฐานเกี่ยวกับบทบาทของ Swagger ลองมาดูวิธีการใช้งาน
2. การรวมกลุ่ม swagger และ Spring Boot
ขั้นตอนที่ 1: แนะนำแพ็คเกจ JAR ที่เกี่ยวข้อง:
<Ependency> <sderctId> io.springfox </groupId> <ratifactid> SpringFox-Swagger2 </artifactid> <sersion> 2.6.0 </version> </การพึ่งพา> <predency> <roupid> io.springfox </groupid> <ratifactid>
ขั้นตอนที่ 2: การกำหนดค่าข้อมูลพื้นฐาน:
@Configuration @enablewagger2public คลาส swagger2config {@bean public docket createrestapi () {ส่งคืนใบปะหน้าใหม่ (DocumentationType.swagger_2) .apiinfo (apiinfo ()). select () .paths (pathselectors.regex ("/rest /.*")). build (); } ส่วนตัว apiinfo apiinfo () {ส่งคืน apiinfobuilder ใหม่ () .title ("ระบบบล็อก restful api") .description ("ระบบบล็อก restful api"). termsofserviceurl ("http://127.0.0.0.1:8080/") .สร้าง(); -การกำหนดค่าพื้นฐานคือคำอธิบายของเอกสาร API ทั้งหมดและการกำหนดค่าส่วนกลางบางอย่างซึ่งทำงานสำหรับอินเทอร์เฟซทั้งหมด มีสองคำอธิบายประกอบที่เกี่ยวข้องที่นี่:
@Configuration หมายความว่านี่คือคลาสการกำหนดค่าคำอธิบายประกอบที่จัดทำโดย JDK และได้รับการอธิบายในบทความก่อนหน้า
@ฟังก์ชั่นของ ENABSEWagger2 คือการเปิดใช้งานฟังก์ชั่นที่เกี่ยวข้องกับ Swagger2
ในคลาสการกำหนดค่านี้ฉันอินสแตนซ์วัตถุใบปะหน้าซึ่งส่วนใหญ่มีข้อมูลสามด้าน:
(1) ข้อมูลคำอธิบายของ API ทั้งหมดนั่นคือข้อมูลที่รวมอยู่ในวัตถุ APIINFO ส่วนนี้จะแสดงบนหน้า
(2) ระบุชื่อแพ็คเกจเพื่อสร้างเอกสาร API
(3) ระบุเส้นทางที่จะสร้าง API API ที่ใช้พา ธ สามารถรองรับสี่โหมดซึ่งสามารถใช้เพื่ออ้างถึงซอร์สโค้ดของมัน:
pathselectors ชั้นเรียนสาธารณะ {Private PathSelectors () {โยน unsupportedOperationException ใหม่ (); } Public Static Predicate <String> ใด ๆ () {return predicates.alwayStrue (); } Public Static Predicate <String> ไม่มี () {return predicates.alwaysFalse (); } สาธารณะคงที่ predicate <String> regex (สตริงสุดท้าย pathregex) {ส่งคืนเพรดิเคตใหม่ <string> () {บูลีนสาธารณะใช้ (อินพุตสตริง) {return input.matches (pathregex); - } Public Static Predicate <String> ANT (antpattern สตริงสุดท้าย) {ส่งคืนเพรดิเคตใหม่ <String> () {บูลีนสาธารณะใช้ (อินพุตสตริง) {AntPathMatcher matcher = new AntpathMatcher (); return matcher.match (antpattern, input); - -ดังที่เห็นได้จากซอร์สโค้ด Swagger รองรับสี่วิธี: การสร้างเส้นทางใด ๆ การไม่สร้างเส้นทางใด ๆ และการจับคู่รูปแบบการจับคู่และมดปกติ คุณอาจคุ้นเคยกับสามประเภทแรกซึ่งเป็นการจับคู่มดสุดท้าย หากคุณไม่คุ้นเคยกับ Ant เพียงเพิกเฉยต่อมัน สามประเภทแรกควรเพียงพอสำหรับทุกคนที่จะใช้ในการทำงานประจำวัน
ด้วยการกำหนดค่าข้างต้นเราสามารถเห็นผลกระทบ ฉันมีคลาส ArticlerestController ภายใต้แพ็คเกจ com.pandy.blog.rest ซอร์สโค้ดมีดังนี้:
เริ่มต้นสปริงบูตแล้วเยี่ยมชม: http://127.0.0.1:8080/swagger-ui.html เพื่อดูผลลัพธ์ต่อไปนี้:
คุณสามารถดูได้ในหน้านี้ว่ายกเว้นอินเทอร์เฟซ /ทดสอบ /{id} สุดท้ายอินเตอร์เฟสอื่น ๆ จะสร้างเอกสารที่เกี่ยวข้อง เนื่องจากอินเทอร์เฟซสุดท้ายไม่ตรงกับเส้นทางที่เรากำหนดค่า - "/rest/.*" จึงไม่มีการสร้างเอกสาร
นอกจากนี้เรายังสามารถคลิกเพื่อดูแต่ละอินเทอร์เฟซเฉพาะ ลองใช้อินเทอร์เฟซ“ โพสต์ /พักผ่อน /บทความ” เป็นตัวอย่าง:
อย่างที่คุณเห็น Swagger สร้างตัวอย่างของผลลัพธ์การส่งคืนและพารามิเตอร์ขอพารามิเตอร์สำหรับแต่ละอินเตอร์เฟสและสามารถเข้าถึงอินเทอร์เฟซโดยตรงผ่าน "ลองใช้" ด้านล่าง ในแง่ของอินเทอร์เฟซทุกคนทดสอบอินเทอร์เฟซ โดยรวมแล้ว Swagger ยังคงทรงพลังมากและการกำหนดค่าค่อนข้างง่าย
@RestControllerPublic Class ArticlerestController {@AutoWired Articlementservice ArticleService; @RequestMapping (value = "/rest/article", method = post, produces = "application/json") webresponse สาธารณะ <แผนที่ <String, Object >> SaveArticle (@requestbody บทความบทความ) articleservice.savearticle (บทความ); แผนที่ <สตริงวัตถุ> ret = ใหม่ hashmap <> (); ret.put ("id", article.getId ()); WebResponse <MAP <String, Object >> Response = WebResponse.getSuccessResponse (ret); การตอบกลับกลับ; } @RequestMapping (value = "/rest/บทความ/{id}", method = delete, produces = "application/json") webresponse สาธารณะ <?> deletearticle (@PathVariable Long ID) {บทความบทความ = บทความ บทความ SetStatus (-1); ArticleService.UpDateArticle (บทความ); WebResponse <Object> Response = WebResponse.getSuccessResponse (NULL); การตอบกลับกลับ; } @RequestMapping (value = "/ret/article/{id}", method = put, produces = "application/json") webresponse สาธารณะ <Public> updateArticle (@PathVariable Long ID, บทความบทความ @requestbody บทความ) ArticleService.UpDateArticle (บทความ); WebResponse <Object> Response = WebResponse.getSuccessResponse (NULL); การตอบกลับกลับ; } @RequestMapping (value = "/ret/startion/{id}", method = get, produces = "application/json") webresponse สาธารณะ <บทความ> getarticle (@PathVariable Long ID) {บทความบทความ = บทความ WebResponse <sarticle> Response = WebResponse.getSuccessResponse (บทความ); การตอบกลับกลับ; } @RequestMapping (value = "/test/{id}", method = get, produces = "application/json") webresponse สาธารณะ <?> getNoapi () {webresponse <?> response = webresponse.getSuccessResponse การตอบกลับกลับ; -3. การกำหนดค่าโดยละเอียดของ Swagger API
แต่คุณจะมีคำถามบางอย่างเมื่อเห็นสิ่งนี้:
คำถามแรก: ไม่มีคำอธิบายที่แท้จริงของผลการส่งคืนและพารามิเตอร์คำขอ สามารถกำหนดค่าได้หรือไม่?
คำถามที่สอง: พารามิเตอร์คำขอนี้ควรสะท้อนโดยตรงตามวัตถุ แต่ไม่ใช่ทุกคุณสมบัติของวัตถุที่จำเป็นและค่าของพารามิเตอร์อาจไม่ตรงกับความต้องการของเรา สามารถกำหนดค่าได้หรือไม่?
คำตอบก็โอเคอย่างแน่นอน ตอนนี้มาแก้ปัญหาทั้งสองนี้และดูรหัสการกำหนดค่าโดยตรง:
แพ็คเกจ com.pandy.blog.rest; นำเข้า com.pandy.blog.dto.webresponse; นำเข้า com.pandy.blog.po.article; นำเข้า com.pandy.blog.service.articleservice; นำเข้า io.swagger.annotations.apiimplicatparam; io.swagger.annotations.apioperation; นำเข้า io.swagger.annotations.apiresponse; นำเข้า io.swagger.annotations.apiresponse; นำเข้า io.swagger.annotations.apiresponse; นำเข้า io.swagger.Annotations.Apiresponse; org.springframework.context.annotation.profile; นำเข้า org.springframework.web.bind.annotation.pathvariable; นำเข้า org.springframework.web.bind.annotation.requestbody; org.springframework.web.bind.annotation.restcontroller; นำเข้า java.util.hashmap; นำเข้า java.util.list; นำเข้า java.util.map นำเข้า org.springframework.web.bind.annotation.requestmethod.delete; org.springframework.web.bind.annotation.requestmethod.get; นำเข้า org.springframework.web.bind.annotation.requestmethod.post; นำเข้า org.springframework.web.bind.annotation. ArticlerestController {@AutoWired Articlementservice ArticleService; @RequestMapping (value = "/บทความ", method = post, produces = "application/json") @apioperation (value = "เพิ่มบทความ", notes = "เพิ่มบทความใหม่", tags = "บทความ", httpmethod = "โพสต์") @apiimplicitparam (name = "summary", value = "บทความสรุป", จำเป็น = true, datatype = "string"), @apiimplicitparam (name = "status", value = "เผยแพร่สถานะ", จำเป็น = true, datatype = "integer")}) WebResponse <แผนที่ <String, Object >> SaveArticle (บทความ @requestbody บทความบทความ) {articleservice.savearticle (บทความ); แผนที่ <สตริงวัตถุ> ret = ใหม่ hashmap <> (); ret.put ("id", article.getId ()); WebResponse <MAP <String, Object >> Response = WebResponse.getSuccessResponse (ret); การตอบกลับกลับ; } @apioperation (value = "ลบบทความ", notes = "ลบบทความด้วย id", tags = "บทความ", httpmethod = "ลบ") @apiimplicitparams ({@apiimplicitparam (name = "id", value = "id idated ลบ, ผลิต = "แอปพลิเคชัน/json") webresponse สาธารณะ <?> deletearticle (@PathVariable Long ID) {บทความบทความ = articleService.getById (id); บทความ SetStatus (-1); articleservice.savearticle (บทความ); ส่งคืน webresponse.getSuccessResponse (ใหม่ hashmap <> ()); } @apioperation (value = "รับรายการบทความ", notes = "แบบสอบถามเต็มตามชื่อ", tags = "บทความ", httpmethod = "get") @apiimplicitparams ({@apiimplicitparam (name = "title", value = "ชื่อบทความ" หน้า ", จำเป็น = false, dataType =" Integer "), @apiimplicitparam (name =" pagenum ", value =" หมายเลข pagePage ", จำเป็น = false, datatype =" integer ")}) @requestmapping (value ="/article/listing " จำนวนเต็ม pagenum) {if (pagesize == null) {pagesize = 10; } if (pagenum == null) {pagenum = 1; } int offset = (pagenum - 1) * pagesize; รายการ <sarticle> articles = articleservice.getarticles (ชื่อ, 1L, ชดเชย, หน้า); กลับ webresponse.getSuccessResponse (บทความ); } @apioperation (value = "Update article", notes = "อัปเดตเนื้อหาบทความ", แท็ก = "บทความ", httpmethod = "ใส่") @apiimplicitparams ({@apiimplicitparam (name = "id", value = "id pratticle" "String"), @apiimplicitparam (name = "summary", value = "บทความสรุป", จำเป็น = false, datatype = "string"), @apiimplicitparam (name = "status", value = "publish status", neve = false, datatype = "Integer") WebResponse <?> updateArticle (@PathVariable Long ID,@requestbody บทความบทความ) {article.setId (id); ArticleService.UpDateArticle (บทความ); ส่งคืน webresponse.getSuccessResponse (ใหม่ hashmap <> ()); -เรามาอธิบายฟังก์ชั่นเฉพาะของคำอธิบายประกอบและแอตทริบิวต์ที่เกี่ยวข้องในรหัส:
@apioperation, การกำหนดค่าแอตทริบิวต์อินเตอร์เฟสทั้งหมด:
ค่า: คำอธิบายอินเตอร์เฟสแสดงในรายการอินเตอร์เฟส
หมายเหตุ: คำอธิบายโดยละเอียดของอินเทอร์เฟซที่แสดงในหน้ารายละเอียดอินเตอร์เฟส
Tags: แท็กของอินเทอร์เฟซ อินเทอร์เฟซที่มีแท็กเดียวกันจะปรากฏขึ้นภายใต้หน้าแท็บ
httpmethod: วิธีการ HTTP ที่รองรับ
@apiimplicitparams, คอนเทนเนอร์สำหรับ @apiimplicitparam สามารถมีคำอธิบายประกอบ @apiimplication priplicat หลายรายการหลายรายการ
@ApiimplicitParam, คำขอพารามิเตอร์การกำหนดค่าแอตทริบิวต์:
ชื่อ: ชื่อพารามิเตอร์
ค่า: คำอธิบายพารามิเตอร์
จำเป็น: จำเป็นหรือไม่
ประเภทข้อมูล: ประเภทข้อมูล
@apiresponses, @apiresponse container สามารถมีคำอธิบายประกอบ @apiresponse หลายรายการ
@apiresponse, ส่งคืนการกำหนดค่าแอตทริบิวต์ผลลัพธ์:
รหัส: ส่งคืนการเข้ารหัสผลลัพธ์
ข้อความ: ส่งคืนคำอธิบายของผลลัพธ์
การตอบสนอง: ส่งคืนคลาสที่สอดคล้องกันของผลลัพธ์
หลังจากเสร็จสิ้นการกำหนดค่าด้านบนให้ดูที่เอฟเฟกต์หน้า:
หน้ารายการ:
อย่างที่คุณเห็นตอนนี้อินเทอร์เฟซอยู่ภายใต้แท็กบทความและยังมีคำแนะนำสำหรับการกำหนดค่าของเราที่อยู่เบื้องหลังอินเทอร์เฟซ มาดูหน้ารายละเอียดของอินเทอร์เฟซ "โพสต์ /ส่วนที่เหลือ /บทความ":
รูปภาพมีขนาดใหญ่เกินไปและมีเพียงการแสดงแอตทริบิวต์ชื่อเรื่องเท่านั้นและพารามิเตอร์อื่น ๆ จะคล้ายกัน เราสามารถเห็นได้จากหน้าเว็บว่ามีคำแนะนำสำหรับพารามิเตอร์การร้องขอ แต่นี่ไม่ใช่เอฟเฟกต์ที่เราคาดหวัง หากพารามิเตอร์ของเราเป็นเพียงประเภทง่าย ๆ วิธีนี้ควรจะดี แต่ปัญหาตอนนี้คือพารามิเตอร์คำขอของเราเป็นวัตถุดังนั้นจะกำหนดค่าได้อย่างไร สิ่งนี้เกี่ยวข้องกับคำอธิบายประกอบอีกสองข้อ: @apimodel และ @apimodelproperty มาดูรหัสก่อนแล้วจึงอธิบายซึ่งเข้าใจได้ง่ายกว่า:
@apiModel (value = "บทความบทความ", คำอธิบาย = "เพิ่ม & อัปเดตบทความคำอธิบายวัตถุ") บทความคลาสสาธารณะ {@id @GeneratedValue @ApimodelProperty (name = "id", value = "id pricture id" @apiModelProperty (name = "title", value = "ชื่อบทความ", จำเป็น = true, example = "Test Title Title") ชื่อสตริงส่วนตัว; @apiModelProperty (name = "summary", value = "บทความสรุป", จำเป็น = true, example = "บทสรุปบทความสรุป") สรุปสตริงส่วนตัว; @ApimodelProperty (ซ่อน = จริง) วันที่ส่วนตัว createTime; @ApimodelProperty (ซ่อน = จริง) วันที่ส่วนตัวเผยแพร่; @ApimodelProperty (ซ่อน = จริง) วันที่ส่วนตัวอัปเดต; @apiModelProperty (ซ่อน = จริง) ผู้ใช้ยาวส่วนตัว; @apiModelProperty (name = "สถานะ", value = "สถานะการวางจำหน่ายบทความ", จำเป็น = true, example = "1") สถานะจำนวนเต็มส่วนตัว; @apiModelProperty (name = "type", value = "หมวดหมู่บทความ", จำเป็น = true, example = "1") ประเภทจำนวนเต็มส่วนตัว;}@Apimodel คือการกำหนดค่าคุณสมบัติของทั้งคลาส:
ค่า: คำอธิบายของชั้นเรียน
คำอธิบาย: รายละเอียดคำอธิบาย
@ApimodelProperty คือการกำหนดค่าของคุณสมบัติของแต่ละฟิลด์โดยละเอียด:
ชื่อ: ชื่อฟิลด์
ค่า: คำอธิบายฟิลด์
จำเป็น: จำเป็นหรือไม่
ตัวอย่าง: ค่าตัวอย่าง
ซ่อน: ไม่ว่าจะแสดง
หลังจากเสร็จสิ้นการกำหนดค่าข้างต้นลองดูที่เอฟเฟกต์:
ตอนนี้เราจะเห็นว่าคำอธิบายฟิลด์ได้รับการแสดงและค่าของฟิลด์ในตัวอย่างก็กลายเป็นค่าที่สอดคล้องกันของคุณสมบัติตัวอย่างที่เรากำหนดค่า ด้วยวิธีนี้เอกสาร API ที่สมบูรณ์จะถูกสร้างขึ้นและเอกสารเชื่อมโยงอย่างใกล้ชิดกับรหัสแทนที่จะเป็นชิ้นส่วนที่แยกได้สองชิ้น นอกจากนี้เรายังสามารถทดสอบได้อย่างง่ายดายผ่านเอกสารนี้ เราเพียงแค่คลิกที่กล่องสีเหลืองภายใต้ค่าตัวอย่างและเนื้อหาภายในจะถูกคัดลอกโดยอัตโนมัติไปยังกล่องค่าที่สอดคล้องกันของบทความจากนั้นคลิก "ลองใช้" เพื่อเริ่มคำขอ HTTP
หลังจากคลิกลองใช้เราจะเห็นผลลัพธ์ที่ส่งคืน:
การดำเนินการยังคงสะดวกมาก เมื่อเทียบกับ Junit และ Postman การทดสอบผ่าน Swagger นั้นสะดวกกว่า แน่นอนการทดสอบของ Swagger ไม่สามารถแทนที่การทดสอบหน่วยได้ แต่ก็ยังมีผลกระทบที่สำคัญมากในการดีบักร่วม
4. สรุป
โดยรวมแล้วการกำหนดค่าของ Swagger นั้นค่อนข้างง่ายและความสามารถของ Swagger ในการสร้างเอกสารโดยอัตโนมัติได้ช่วยให้เราประหยัดงานได้มากและให้ความช่วยเหลือที่ดีในการบำรุงรักษาที่ตามมา นอกจากนี้ Swagger สามารถสร้างข้อมูลการทดสอบสำหรับเราโดยอัตโนมัติตามการกำหนดค่าและให้วิธี HTTP ที่สอดคล้องกันซึ่งเป็นประโยชน์สำหรับการทดสอบตนเองและการดีบักร่วมของเรา ดังนั้นฉันยังคงแนะนำให้คุณใช้ Swagger ในการพัฒนาทุกวันซึ่งจะช่วยให้คุณปรับปรุงประสิทธิภาพการทำงานของคุณในระดับหนึ่ง ในที่สุดขอให้ฉันทิ้งคำถามให้คุณคิดนั่นคือเอกสารสามารถเข้าถึงได้โดยตรงผ่านหน้าเว็บดังนั้นเราจึงไม่สามารถเปิดเผยอินเทอร์เฟซโดยตรงกับสภาพแวดล้อมการผลิตโดยเฉพาะอย่างยิ่งระบบที่จำเป็นต้องให้บริการภายนอก ดังนั้นเราจะปิดฟังก์ชั่นนี้ในกระบวนการผลิตได้อย่างไร มีหลายวิธีคุณสามารถลองด้วยตัวเอง
ข้างต้นคือการต่อสู้ที่แท้จริงของโครงการ Swagger2 Integrated Spring Boot ที่แนะนำโดยบรรณาธิการ ฉันหวังว่ามันจะเป็นประโยชน์กับคุณ หากคุณมีคำถามใด ๆ โปรดฝากข้อความถึงฉันและบรรณาธิการจะตอบกลับคุณทันเวลา ขอบคุณมากสำหรับการสนับสนุนเว็บไซต์ Wulin.com!