1. مقدمة إلى Swagger
في المقالة السابقة ، قدمنا دعم Spring Boot لـ Restful. في هذه المقالة ، نواصل مناقشة هذا الموضوع. ومع ذلك ، لن نناقش بعد الآن كيف يتم تنفيذ واجهة برمجة التطبيقات المريحة ، بل نناقش صيانة وثائق API المريحة.
في العمل اليومي ، غالبًا ما نحتاج إلى توفير واجهات للواجهة الأمامية (نهاية الويب ، iOS ، Android) أو أطراف ثالثة. في هذا الوقت ، نحتاج إلى تزويدهم بوثائق API مفصلة. لكن الحفاظ على وثيقة مفصلة ليس مهمة سهلة. بادئ ذي بدء ، فإن كتابة وثيقة مفصلة هي مهمة تستغرق وقتًا طويلاً وشاقة. من ناحية أخرى ، نظرًا لأن الكود والوثيقة يتم فصلهم ، فمن السهل التسبب في تناقضات بين المستند والرمز. في هذه المقالة ، سوف نشارك طريقة للحفاظ على مستندات API ، أي لإنشاء مستندات API المريضة تلقائيًا من خلال Swagger.
إذن ما هو التباهي؟ يمكننا قراءة الوصف الرسمي مباشرة:
تعد Toolingswagger الأكثر شعبية في العالم أدوات API في العالم أكبر إطار في العالم لأدوات مطوري API لمواصفات OpenAPI (OAS) ، وتمكين التطوير عبر دورة حياة API بأكملها ، من التصميم والوثائق ، إلى اختبار ونشر.
يخبرك هذا المقطع أولاً أن Swagger هو أداة API الأكثر شعبية في العالم ، والغرض من Swagger هو دعم تطوير دورة حياة API بأكملها ، بما في ذلك التصميم والتوثيق والاختبار والنشر. في هذه المقالة ، سوف نستخدم وظائف Swagger لإدارة المستندات واختبارها.
بعد الحصول على فهم أساسي لدور Swagger ، دعونا نلقي نظرة على كيفية استخدامه.
2. تكامل Swagger و Spring Boot
الخطوة 1: تقديم حزمة الجرة المقابلة:
<Rependency> <roupEd> io.springfox </rougiD> <StifactId> Springfox-Swagger2 </shintifactid> <splection> 2.6.0 </version> </sependency>
الخطوة 2: تكوين المعلومات الأساسية:
@configuration @enlobeswagger2public class Swagger2Config {bean public docket createrestapi () {return new docket (documentationType.swagger_2) .ApiInfo (apiinfo ()) .Select () .Apis (requestHandlersElectors.BasePackage ("com.pandy.rest")). .Paths (pathselectors.regex ("/rest/.")) .build () ؛ } apiinfo apiinfo () {إرجاع apiinfobuilder () .يبني()؛ }}التكوين الأساسي هو وصف لمستند API بأكمله وبعض التكوينات العالمية ، والتي تعمل لجميع الواجهات. هناك نوعان من التعليقات التوضيحية هنا:
configuration يعني أن هذا فئة التكوين ، والشرح المقدمة من JDK ، وتم شرحها في المقالة السابقة.
@enborleswagger2 وظيفة تمكين الوظائف المتعلقة Swagger2.
في فئة التكوين هذه ، قمت بتثبيت كائن Docket ، والذي يتضمن بشكل أساسي ثلاثة جوانب من المعلومات:
(1) معلومات الوصف الخاصة بآبار واجهة برمجة التطبيقات بأكملها ، أي المعلومات المدرجة في كائن Apiinfo ، وسيتم عرض هذا الجزء من المعلومات على الصفحة.
(2) حدد اسم الحزمة لإنشاء مستند API.
(3) حدد المسار لإنشاء واجهة برمجة التطبيقات. يمكن أن تدعم واجهة برمجة التطبيقات المستندة إلى المسار أربعة أوضاع ، والتي يمكن استخدامها للإشارة إلى رمز المصدر الخاص بها:
Public Class PathSelectors {private pathselectors () {رمي جديد غير مدعوم جديد () ؛ } protect static static <string> any () {return predicates.alwaystrue () ؛ } protect static predicate <string> none () {return predicates.alwaysfalse () ؛ } procedicate static predicate <string> regex (Final String PathRegex) {return new predicate <string> () {public boolean application (string input) {return input.matches (pathregex) ؛ }} ؛ } proced static static prose <string> ant (سلسلة نهائية antpattern) {إرجاع مسند جديد <string> () {public boolean تطبيق (إدخال سلسلة) {antathmatcher matcher = new Antpathmatcher () ؛ إرجاع matcher.match (antpattern ، الإدخال) ؛ }} ؛ }}كما يتضح من الكود المصدري ، يدعم Swagger أربع طرق: توليد أي مسار ، وعدم توليد أي مسار ، ومطابقة نمط النمل بشكل منتظم. قد تكون أكثر دراية بالأنواع الثلاثة الأولى ، وهو الأخير من مطابقة النمل. إذا لم تكن على دراية بـ Ant ، فما عليك سوى تجاهله. يجب أن تكون الأنواع الثلاثة الأولى كافية للجميع لاستخدامها في العمل اليومي.
مع التكوين أعلاه ، يمكننا أن نرى التأثير. لدي فئة ArticLerestController ضمن حزمة com.pandy.blog.rest. رمز المصدر كما يلي:
ابدأ SPRING BOOT ، ثم تفضل بزيارة: http://127.0.0.1:8080/swagger-ui.html لمعرفة النتائج التالية:
يمكنك أن ترى في هذه الصفحة باستثناء الواجهة الأخيرة /الاختبار /{id} ، وتنشئ الواجهات الأخرى مستندات مقابلة. نظرًا لأن الواجهة الأخيرة لا تفي بالمسار الذي قمنا بتكوينه - "/rest/.*" ، لا يتم إنشاء مستند.
يمكننا أيضًا النقر في رؤية كل واجهة محددة. دعنا نأخذ واجهة "post /rest /article" كمثال:
كما ترون ، يقوم Swagger بإنشاء أمثلة لنتائج الإرجاع وطلب معلمات كل واجهة ، ويمكنه الوصول مباشرة إلى الواجهة من خلال "Try It Out" أدناه. من حيث الواجهة ، يختبر الجميع الواجهة. بشكل عام ، لا يزال Swagger قويًا للغاية والتكوين بسيط نسبيًا.
RestControllerPublic Class ArticLerestController {Autowired Private articleservice ؛ requestmapping (value = "/rest/article" ، method = post ، reduces = "application/json") public webresponse <map <string ، object >> savearticle (requestbody article) {article.setuserid (1L) ؛ entlicservice.savealicle (مقال) ؛ الخريطة <string ، object> ret = new hashmap <> () ؛ ret.put ("id" ، article.getId ()) ؛ WebResponse <map <string ، object >> reponse = webresponse.getSuccessResponse (ret) ؛ استجابة العودة ؛ } requestmapping (value = "/rest/article/{id}" ، method = delete ، reductes = "application/json") public webresponse <؟> deletearticle ( @pathvariable id) article.setStatus (-1) ؛ Enticleservice.updatearticle (مقال) ؛ WebResponse <Object> response = webresponse.getSuccessResponse (null) ؛ استجابة العودة ؛ } @requestmapping (value = "/rest/article/{id}" ، method = put ، store = "application/json") public webresponse <Object> updatearticle (pathvariable ong id ، requestbody article) {article.setid (id) ؛ Enticleservice.updatearticle (مقال) ؛ WebResponse <Object> response = webresponse.getSuccessResponse (null) ؛ استجابة العودة ؛ } @requestmapping (value = "/rest/article/{id}" ، method = get ، store = "application/json") public webresponse <article> getArticle ( @pathvarable long id) {article article = articlevice.getById (id) ؛ webresponse <article> repressing = webresponse.getSuccessResponse (article) ؛ استجابة العودة ؛ } @requestmapping (value = "/test/{id}" ، method = get ، reduces = "application/json") public webresponse <؟> getNoapi () {webresponse <؟ استجابة العودة ؛ }}3. التكوين التفصيلي ل Swagger API
ولكن سيكون لديك بالتأكيد بعض الأسئلة عندما ترى هذا:
السؤال الأول: لا يوجد وصف حرفي لنتيجة الإرجاع ومعلمات الطلب. هل يمكن تكوين هذا؟
السؤال الثاني: يجب أن تنعكس معلمة الطلب هذه مباشرة بناءً على الكائن ، ولكن ليس كل خاصية للكائن مطلوبة ، وقد لا تلبي قيمة المعلمة احتياجاتنا. هل يمكن تكوين هذا؟
الجواب بالتأكيد على ما يرام. الآن دعنا نحل هاتين المشكلتين وننظر مباشرة إلى رمز التكوين:
package com.pandy.blog.rest ؛ import com.pandy.blog.dto.webResponse ؛ import com.pandy.blog.po io.swagger.annotations.apioperation ؛ import io.swagger.annotations.apiresponse ؛ import io.swagger.ants.apirespons 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.get ؛ استيراد org.springframework.web.bind.annotation.requestmethod.post ArticlerestController {Autowired Private Articleservice ؛ requestmapping (value = "/article" ، method = post ، reduces = "application/json") apiOperation (value = "add article" ، notes = "add article" ، tags = "article" ، httpmethod = "post" ، appiiMplicitparams ({{{ardipplicitparam apiImplicitParam (name = "summary" ، value = "ملخص المقالة" ، مطلوب = true ، datatype = "string") ، apiImplicitParam (name = "status" ، value = "publish status" ، required = true ، your type = "integer") @apiResponses ({apapons public webresponse <map <string ، object >> savearticle (requestbody article article) {ettionservice.savearticle (article) ؛ الخريطة <string ، object> ret = new hashmap <> () ؛ ret.put ("id" ، article.getId ()) ؛ WebResponse <map <string ، object >> reponse = webresponse.getSuccessResponse (ret) ؛ استجابة العودة ؛ } apiOperation (value = "delete article" ، notes = "delete article by id" ، tags = "article" ، httpmethod = "delete") apiImplicitParams ({apiImplicitParam (name = "id" ، value = "article id" ، regined = datatype = "long" delete ، reduces = "application/json") public webresponse <؟> deletearticle (@pathvariable id) article.setStatus (-1) ؛ entlicservice.savealicle (مقال) ؛ return webresponse.getSuccessResponse (new hashmap <> ()) ؛ } apiOperation (value = "get the article list" ، notes = "query full requary" ، tags = "article" ، httpmethod = "get"). المقالات لكل صفحة "، مطلوب = false ، datatype =" integer ") ، apiImplicitParam (name =" pagenum "، value =" pagepage number "، required = false ، datatype =" integer ")}) requestmapping (value ="/article ، method = get ، produces = "jonse) pagesize ، integer pagenum) {if (pagesize == null) {pagesize = 10 ؛ } if (pagenum == null) {pagenum = 1 ؛ } int offset = (pagenum - 1) * pagesize ؛ قائمة <Contract> المقالات = entlicservice.getArticles (العنوان ، 1L ، الإزاحة ، pagesize) ؛ إرجاع webresponse.getSuccessResponse (المقالات) ؛ } apiOperation (value = "update article" ، notes = "update article content" ، tags = "article" ، httpmethod = "put") apiImplicitParams ({apiimplicitparam (name = "id" ، value = "article id" ، regale = true ، datatype = "long"). dataType = "string") ، apiImplicitParam (name = "summary" ، value = "article summary" ، required = false ، datatype = "string") ، apiImplicitparam (name = "status" ، value = "publish status" ، quient = dataType = "integer"}) @requestmapp "application/json") public webresponse <؟> updatearticle (@pathvariable long id ،@requestbody article) {article.setId (id) ؛ Enticleservice.updatearticle (مقال) ؛ return webresponse.getSuccessResponse (new hashmap <> ()) ؛ }}دعونا نوضح الوظائف المحددة للعديد من التعليقات التوضيحية والسمات ذات الصلة في الكود:
apiOperation ، تكوين سمة الواجهة بأكملها:
القيمة: وصف الواجهة ، معروض في قائمة الواجهة.
ملاحظات: وصف مفصل للواجهة ، معروضة على صفحة تفاصيل الواجهة.
العلامات: علامة الواجهة. سيتم عرض الواجهة مع نفس العلامة ضمن صفحة علامة تبويب.
httpmethod: طريقة HTTP المدعومة.
يمكن أن تحتوي apiImplicitparams ، وهي حاوية لـ apiimplicitparam ،
apiImplicitparam ، تكوين سمة المعلمة:
الاسم: اسم المعلمة
القيمة: وصف المعلمة
مطلوب: هل هو ضروري
نوع البيانات: نوع البيانات
يمكن أن تحتوي apiResponses ، apiresponse على التعليقات التوضيحية apiresponse متعددة
apiresponse ، إرجاع تكوين سمة النتيجة:
الكود: إرجاع ترميز النتيجة.
الرسالة: إرجاع وصف النتيجة.
الاستجابة: إرجاع الفئة المقابلة للنتيجة.
بعد الانتهاء من التكوين أعلاه ، دعونا نلقي نظرة على تأثير الصفحة:
صفحة القائمة:
كما ترون ، توجد الواجهات الآن ضمن علامة المقالة ، وهناك أيضًا تعليمات لتكويننا خلف الواجهة. دعونا نلقي نظرة على صفحة التفاصيل لواجهة "post /rest /article":
الصورة كبيرة جدًا ، ولا يتم اعتراض سوى عرض سمة العنوان ، والمعلمات الأخرى متشابهة. يمكننا أن نرى من الصفحة أن هناك تعليمات لمعلمات الطلب ، ولكن هذا ليس التأثير الذي توقعناه. إذا كانت معلماتنا مجرد أنواع بسيطة ، فيجب أن تكون هذه الطريقة جيدة ، ولكن المشكلة الآن هي أن معلمات طلبنا هي كائن ، فكيف تكوينها؟ يتضمن ذلك اثنين من التعليقات التوضيحية الأخرى: apimodel و apiModelProperty. دعونا نلقي نظرة على الكود أولاً ثم شرحه ، وهو أمر أسهل في فهمه:
apImodel (value = "article object" ، description = "add & update article about description") article class public article {idgeneratedValue apImodElProperty (name = "id" ، value = "article id" ، required = false ، example = "1") private id ؛ apImodElProperty (name = "title" ، value = "title article" ، required = true ، example = "test article title") title private string ؛ apImodElProperty (name = "summary" ، value = "ملخص المقالة" ، مطلوب = true ، مثال = "اختبار ملخص المقالة") ملخص السلسلة الخاصة ؛ apImodElProperty (Hidden = true) التاريخ الخاص الإبداعي ؛ apimodelProperty (Hidden = true) تاريخ النشر الخاص ؛ apImodElProperty (Hidden = true) تاريخ خاص updateTime ؛ apImodElProperty (Hidden = true) userId private long ؛ apImodElProperty (name = "الحالة" ، value = "حالة إصدار المقالة" ، مطلوب = true ، example = "1") حالة عدد صحيح خاص ؛ apImodElProperty (name = "type" ، value = "article stistrapimodel هو تكوين خصائص الفئة بأكملها:
القيمة: وصف الفصل
الوصف: وصف مفصل
apimodelproperty هو تكوين خصائص كل حقل بالتفصيل:
الاسم: اسم الحقل
القيمة: وصف الحقل
مطلوب: هل هو ضروري
مثال: قيمة مثال
مخفي: سواء كنت ستعرض
بعد الانتهاء من التكوين أعلاه ، دعونا نلقي نظرة على التأثير:
الآن يمكننا أن نرى أن وصف الحقل قد تم عرضه ، وأصبحت قيمة الحقل في المثال أيضًا القيمة المقابلة لخاصية المثال التي قمنا بتكوينها. وبهذه الطريقة ، يتم إنشاء مستند API كامل ويترتبط المستند ارتباطًا وثيقًا بالرمز ، بدلاً من الجزأين المعزولين. بالإضافة إلى ذلك ، يمكننا أيضًا اختباره بسهولة من خلال هذا المستند. نحتاج فقط إلى النقر على المربع الأصفر ضمن قيمة المثال ، وسيتم نسخ المحتويات الموجودة في الداخل تلقائيًا إلى مربع القيمة المقابل للمقالة ، ثم انقر فوق "Try It Out" لبدء طلب HTTP.
بعد النقر فوق تجربته ، يمكننا أن نرى النتيجة التي تم إرجاعها:
العملية لا تزال مريحة للغاية. مقارنة مع Junit و Postman ، فإن الاختبار من خلال Swagger أكثر ملاءمة. بالطبع ، لا يمكن أن يحل اختبار Swagger محل اختبار الوحدة ، لكن لا يزال له تأثير مهم للغاية في تصحيح الأخطاء المشتركة.
4. ملخص
بشكل عام ، يكون تكوين Swagger بسيطًا نسبيًا ، وقدرة Swagger على توليد المستندات تلقائيًا قد أنقذنا بالفعل الكثير من العمل وقدمت مساعدة كبيرة للصيانة اللاحقة. بالإضافة إلى ذلك ، يمكن أن يقوم Swagger تلقائيًا بإنشاء بيانات الاختبار لنا وفقًا للتكوين وتوفير طرق HTTP المقابلة ، وهو أمر مفيد أيضًا لأعمالنا الذاتية وتصحيح الأخطاء المشتركة. لذلك ، ما زلت أوصي بأن تستخدم Swagger في التطوير اليومي ، والذي من شأنه أن يساعدك على تحسين كفاءة عملك إلى حد ما. أخيرًا ، اسمحوا لي أن أترك سؤالًا لكي تفكر فيه ، أي يمكن الوصول إلى المستند مباشرة من خلال الصفحة ، لذلك لا يمكننا فضح الواجهة مباشرة إلى بيئة الإنتاج ، وخاصة الأنظمة التي تحتاج إلى تقديم خدمات خارجية. فكيف يمكننا إيقاف تشغيل هذه الوظيفة في عملية الإنتاج؟ هناك العديد من الطرق ، يمكنك تجربتها بنفسك.
ما سبق هو القتال الفعلي لمشروع Swagger2 المدمج في SPRING BOOT الذي قدمه لك المحرر. آمل أن يكون ذلك مفيدًا لك. إذا كان لديك أي أسئلة ، فيرجى ترك رسالة لي وسوف يرد المحرر إليك في الوقت المناسب. شكرا جزيلا لدعمكم لموقع wulin.com!