1. Pengantar Swagger
Di artikel sebelumnya, kami memperkenalkan dukungan Spring Boot untuk Restful. Dalam artikel ini, kami terus membahas topik ini. Namun, kami tidak akan lagi membahas bagaimana API yang tenang diimplementasikan, tetapi lebih membahas pemeliharaan dokumentasi API yang tenang.
Dalam pekerjaan sehari-hari, kita sering perlu menyediakan antarmuka ke front-end (Web End, iOS, Android) atau pihak ketiga. Pada saat ini, kita perlu memberi mereka dokumentasi API terperinci. Tetapi mempertahankan dokumen terperinci bukanlah tugas yang mudah. Pertama-tama, menulis dokumen terperinci adalah tugas yang memakan waktu dan melelahkan. Di sisi lain, karena kode dan dokumen dipisahkan, mudah untuk menyebabkan ketidakkonsistenan antara dokumen dan kode. Dalam artikel ini, kami akan berbagi cara untuk memelihara dokumen API, yaitu secara otomatis menghasilkan dokumen API yang restuful melalui kesombongan.
Jadi apa itu kesombongan? Kami dapat langsung membaca deskripsi resmi:
API Toolingswagger paling populer di dunia adalah kerangka alat pengembang API terbesar di dunia untuk spesifikasi OpenAPI (OAS), memungkinkan pengembangan di seluruh siklus hidup API, dari desain dan dokumentasi, hingga pengujian dan penyebaran.
Perikop ini pertama kali memberi tahu Anda bahwa Swagger adalah alat API paling populer di dunia, dan tujuan kesombongan adalah untuk mendukung pengembangan seluruh siklus hidup API, termasuk desain, dokumentasi, pengujian, dan penyebaran. Dalam artikel ini, kami akan menggunakan fungsi manajemen dokumen dan pengujian Swagger.
Setelah mendapatkan pemahaman dasar tentang peran kesombongan, mari kita lihat bagaimana menggunakannya.
2. Integrasi Boot Kuda dan Pegas
Langkah 1: Perkenalkan paket JAR yang sesuai:
<dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.6.0</version></dependency><dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.6.0</version></dependency>
Langkah 2: Konfigurasi Informasi Dasar:
@Configuration @enableSwagger2public kelas swagger2config {@bean docket createrestapi () {return new docket (DocumentationType.swagger_2) .ApiInfo (ApiInfo ()) .select () .apis (requestHandlectors.baspackage ("com.pandy.pandy.apis.) .paths (pathselectors.regex ("/rest /.*")) .build (); } private apiInfo apiInfo () {return new ApiInfobuilder () .title ("Sistem Blog Restful API") .Description ("Blog Restful API") .TermSofServiceUrl ("http://127.0.0.1:8080/") .contp:/127.0.0.1:8080/ "). .membangun(); }}Konfigurasi dasar adalah deskripsi dari seluruh dokumen API dan beberapa konfigurasi global, yang berfungsi untuk semua antarmuka. Ada dua anotasi yang terlibat di sini:
@Configuration berarti bahwa ini adalah kelas konfigurasi, anotasi yang disediakan oleh JDK, dan telah dijelaskan dalam artikel sebelumnya.
@Fungsi EnableSwagger2 adalah untuk mengaktifkan fungsi yang berhubungan dengan Swagger2.
Di kelas konfigurasi ini, saya membuat objek map, yang terutama mencakup tiga aspek informasi:
(1) Informasi deskripsi dari seluruh API, yaitu informasi yang termasuk dalam objek APIInfo, bagian dari informasi ini akan ditampilkan pada halaman.
(2) Tentukan nama paket untuk menghasilkan dokumen API.
(3) Tentukan jalur untuk menghasilkan API. API berbasis jalur dapat mendukung empat mode, yang dapat digunakan untuk merujuk pada kode sumbernya:
kelas publik PathSelectors {Private PathSelectors () {Throw New UnsportedOperPerationException (); } predikat statis public <string> any () {return predicates.alwaystrue (); } predikat statis public <string> none () {return predicates.alwaysfalse (); } public static predicate <string> regex (final string pathRegEx) {return new predicate <string> () {public boolean apply (input string) {return input.matches (pathregex); }}; } predikat statis public <string> semut (string final antpattern) {return baru predikat <string> () {public boolean apply (input string) {antpathmatcher matcher = baru antpathmatcher (); return matcher.match (antpattern, input); }}; }}Seperti dapat dilihat dari kode sumber, Swagger mendukung empat cara: pembuatan jalur apa pun, tidak menghasilkan jalur apa pun, dan pencocokan reguler dan pencocokan pola semut. Anda mungkin lebih akrab dengan tiga tipe pertama, yang terakhir cocok dengan semut. Jika Anda tidak terbiasa dengan semut, abaikan saja. Tiga jenis pertama harus cukup bagi semua orang untuk digunakan dalam pekerjaan sehari -hari.
Dengan konfigurasi di atas, kita dapat melihat efeknya. Saya memiliki kelas ArticlerestController di bawah paket com.pandy.blog.rest. Kode sumber adalah sebagai berikut:
Mulai boot musim semi, lalu kunjungi: http://127.0.0.1:8080/swagger-ui.html untuk melihat hasil berikut:
Anda dapat melihat di halaman ini bahwa kecuali untuk antarmuka terakhir /tes /{id}, antarmuka lainnya menghasilkan dokumen yang sesuai. Karena antarmuka terakhir tidak memenuhi jalur yang kami konfigurasi - "/rest/.*", tidak ada dokumen yang dihasilkan.
Kami juga dapat mengklik untuk melihat setiap antarmuka tertentu. Mari kita ambil antarmuka "post /istirahat /artikel" sebagai contoh:
Seperti yang Anda lihat, Swagger menghasilkan contoh hasil pengembalian dan meminta parameter untuk setiap antarmuka, dan dapat secara langsung mengakses antarmuka melalui "Coba Keluar" di bawah ini. Dalam hal antarmuka, semua orang menguji antarmuka. Secara keseluruhan, kesombongan masih sangat kuat dan konfigurasinya relatif sederhana.
@RestControllerPublic Class ArticlerestController {@Autowired Private ARTICLEService ArtikelService; @RequestMapping (value = "/REST/artikel", Method = POST, menghasilkan = "Application/JSON") Public WebResponse <MAP <String, Object >> SaveArticle (artikel artikel @RequestBody) {artikel.setUserId (1L); ArtikelService.Savearticle (artikel); Peta <String, Object> ret = HashMap baru <> (); ret.put ("id", artikel.getId ()); WebResponse <peta <string, objek >> respons = webResponse.getSucCessResponse (ret); respons pengembalian; } @RequestMapping (value = "/REST/ARTICTION/{id}", Method = Delete, menghasilkan = "Application/JSON") Public WebResponse <?> DeleteArticle (@PathVariable Long ID) {Artikel Artikel = ArtikelService.getById (id); artikel.setstatus (-1); ArtikelService.updateArticle (artikel); WebResponse <BOMPERTIF> Respons = WebResponse.getSucCessResponse (null); respons pengembalian; } @RequestMapping (value = "/REST/artikel/{id}", method = put, menghasilkan = "Application/JSON") Public WebResponse <POMPERTS> UpdateArticle (@PathVariable Long ID, artikel @RequestBody artikel) {artikel.setid (id); ArtikelService.updateArticle (artikel); WebResponse <BOMPERTIF> Respons = WebResponse.getSucCessResponse (null); respons pengembalian; } @RequestMapping (value = "/REST/artikel/{id}", method = get, menghasilkan = "Application/JSON") Public WebResponse <TARTENTER> getarticle (@pathvariable Long ID) {artikel artikel = artikelService.getById (id); WebResponse <TARTICTER> Respons = WebResponse.getSucCessResponse (artikel); respons pengembalian; } @RequestMapping (value = "/test/{id}", method = get, menghasilkan = "Application/JSON") Public WebResponse <?> GetNoapi () {WebResponse <?> Response = WebResponse.getSucCessResponse (null); respons pengembalian; }}3. Konfigurasi Rinci API Swagger
Tetapi Anda pasti akan memiliki beberapa pertanyaan saat Anda melihat ini:
Pertanyaan pertama: Tidak ada deskripsi literal tentang hasil pengembalian dan parameter permintaan. Bisakah ini dikonfigurasi?
Pertanyaan kedua: Parameter permintaan ini harus secara langsung tercermin berdasarkan objek, tetapi tidak setiap properti dari objek diperlukan, dan nilai parameter mungkin tidak memenuhi kebutuhan kita. Bisakah ini dikonfigurasi?
Jawabannya tentu baik -baik saja. Sekarang mari kita selesaikan dua masalah ini dan melihat langsung pada kode konfigurasi:
Paket com.pandy.blog.rest; import com.pandy.blog.dto.webresponse; import com.pandy.blog.po.article; import com.pandy.blog.service.articleService; import io.swagger.annotations.apiImplicitparam; import io.swagger.annotations io.swagger.annotations.Apioperation; impor io.swagger.annotations.apiresponse; impor io.swagger.annotations.apiresponse; import io.swagger.annotations.apiresponse; import io.swagger.Annotations.apiresponse; import org.springframram.springer. org.springframework.context.annotation.profile; impor org.springframework.web.bind.annotation.pathvariable; impor org.springframework.web.bind.annotation.requestbody; impor org.springframework.web.notation.notation; org.springframework.web.bind.annotation.RestController; impor java.util.hashmap; impor java.util.list; Java.util.map; impor static org.springframework.web.bind.annotation.requestmeethod.delete; we org.springframework.web.bind.annotation.requestmethod.get; impor static org.springframework.web.bind.annotation.requestmethod.post; impor static org.springframework. ArticlerestController {@Autowired Private Articerservice ArtikelService; @RequestMapping(value = "/article", method = POST, produces = "application/json") @ApiOperation(value = "Add article", notes = "Add new article", tags = "Article",httpMethod = "POST") @ApiImplicitParams({ @ApiImplicitParam(name = "title", value = "Article title", required = true, dataType = "String"), @ApIImplicitParam (name = "ringkasan", value = "artikel ringkasan", wajib = true, datatype = "string"), @apiImplicitParam (name = "status", value = "Publish Status", wajib = true, dataType = "integer")} @Apiresponses ({@apiresponse), konfon ", konfon") @Apiresponses ({@apiresponse (code = 200, @apiresse = 200, @apirespons (@apirponse = 200 Public WebResponse <Map <String, Object >> SaveArticle (artikel @RequestBody artikel) {artikelService.SaveArticle (artikel); Peta <String, Object> ret = HashMap baru <> (); ret.put ("id", artikel.getId ()); WebResponse <peta <string, objek >> respons = webResponse.getSucCessResponse (ret); respons pengembalian; } @ApiOperation (value = "Delete Artikel", notes = "Hapus artikel dengan id", tag = "artikel", httpmethod = "delete") @apiImplicitParams ({@apiImplicitParam (name = "id", value = "artikel ID", wajib = true, datatipe = "long") @ @ @ @long " @ @long") (name ") (value" @long ") @ @long") @ @long ") @ @long") (name "), Hapus, menghasilkan = "Application/JSON") Public WebResponse <?> DeleteArticle (@PathVariable Long ID) {Artikel Artikel = ArtikelService.getById (id); artikel.setstatus (-1); ArtikelService.Savearticle (artikel); return webResponse.getSucCessResponse (hashmap baru <> ()); } @ApiOperation (value = "Dapatkan daftar artikel", notes = "kueri lengkap sesuai dengan judul", tag = "artikel", httpmethod = "get") @apiImplicitParams ({@apiImplicitparam (name = "judul", nilai = "Artikel judul", wajib = false, DATATYPE = "NOMING" (NAME = "NOMEICEK (NOVEICEK =" NOMEICEK = "NOMEICEK (NOMEICEK =" NOMEICEK = "NOVICET" NOVICET "NOVICET" NOVAL "NOVEICION" NOVING = "NOVEICION", NOVEICION "NOVEICION" NOVEICION "NOVESICEK =" Artikel per halaman ", wajib = false, dataType =" integer "), @ApiImplicitParam (name =" pagenum ", value =" nomor pagepage ", wajib = false, dataType =" integer ")}) @requestmapping (value ="/artikel/daftar ", metode = get, produses =" application/json "publing (value ="/artikel/list ", Method = get, produces =" Application/Jon "publing (value ="/artikel/list ", Method = get, produces =" application/json "publing) we publy halamanzeze, integer pagenum) {if (pagesize == null) {pagesize = 10; } if (pagenum == null) {pagenum = 1; } int offset = (pagenum - 1) * halaman; Daftar <Artikel> Artikel = ArtikelService.Getarticles (Judul, 1L, Offset, PageSize); return webResponse.getSucCessResponse (artikel); } @Apioperation (value = "Update artikel", notes = "Perbarui konten artikel", tag = "artikel", httpmethod = "put") @ApiImplicitParams ({@apiImplicitParam (name = "id", value = "artikel", wajib = true, dataType = "long"), @apiim, "name", name, "name," name, "name," name, "name," name "name (name" name (name "name. = "String"), @ApIImplicitParam (name = "ringkasan", value = "Ringkasan artikel", wajib = false, datatype = "string"), @ApiImplicitParam (name = "status", value = "publish status", wajib = false, datatype = "integer")}) @requestmapping (value = "/false, DATATYPE =" integer ")}) @requestmapping (value ="/false/dATatype = "integer")} @reviestmapping (value = "/{iD (value (value/{iD (value") {nilai ") {nilai" " WebResponse <?> UpdateArticle (@PathVariable Long ID,@Requestbody Artikel artikel) {artikel.setId (id); ArtikelService.updateArticle (artikel); return webResponse.getSucCessResponse (hashmap baru <> ()); }}Mari kita jelaskan fungsi spesifik dari beberapa anotasi dan atribut terkait dalam kode:
@Apioperation, seluruh konfigurasi atribut antarmuka:
Nilai: Deskripsi Antarmuka, ditampilkan dalam Daftar Antarmuka.
Catatan: Deskripsi terperinci dari antarmuka, ditampilkan pada halaman Detail Antarmuka.
Tag: Tag antarmuka. Antarmuka dengan tag yang sama akan ditampilkan di bawah halaman tab.
HTTPMethod: Metode HTTP yang didukung.
@ApIImplicitParams, wadah untuk @ApIImplicitParam, dapat berisi beberapa anotasi @ApIImplicitParam
@ApIImplicitParam, permintaan Atribut Parameter Konfigurasi:
Nama: Nama parameter
Nilai: Deskripsi Parameter
Diperlukan: apakah perlu
DataType: Tipe Data
@Apirespons, wadah @apiresponse, dapat berisi beberapa anotasi @apiresponse
@Apiresponse, kembalikan konfigurasi atribut hasil:
Kode: Mengembalikan pengkodean hasil.
Pesan: Mengembalikan deskripsi hasilnya.
Tanggapan: Mengembalikan kelas hasil yang sesuai.
Setelah menyelesaikan konfigurasi di atas, mari kita lihat efek halaman:
Halaman daftar:
Seperti yang Anda lihat, antarmuka sekarang terletak di bawah tag artikel, dan ada juga instruksi untuk konfigurasi kami di balik antarmuka. Mari kita lihat halaman detail antarmuka "post /istirahat /artikel":
Gambarnya terlalu besar, dan hanya tampilan atribut judul yang dicegat, dan parameter lainnya serupa. Kita dapat melihat dari halaman bahwa ada instruksi untuk parameter permintaan, tetapi ini bukan efek yang kami harapkan. Jika parameter kami hanyalah tipe sederhana, metode ini seharusnya baik -baik saja, tetapi masalahnya sekarang adalah bahwa parameter permintaan kami adalah objek, jadi bagaimana cara mengkonfigurasinya? Ini melibatkan dua anotasi lainnya: @apimodel dan @apimodelproperty. Mari kita lihat kode terlebih dahulu dan kemudian jelaskan, mana yang lebih mudah dipahami:
@Apimodel (value = "objek artikel", description = "Tambah & perbarui objek Artikel Deskripsi") Artikel kelas publik {@id @generatedValue @ApImodelProperty (name = "id", value = "ID artikel", wajib = false, example = "1") Private Long ID; @Apimodelproperty (name = "title", value = "artikel judul", wajib = true, example = "test artikel judul") judul string pribadi; @ApimodelProperty (name = "ringkasan", value = "Ringkasan artikel", wajib = true, example = "Test artikel ringkasan") ringkasan string pribadi; @Apimodelproperty (tersembunyi = true) private Date createTime; @Apimodelproperty (tersembunyi = true) publictime tanggal pribadi; @Apimodelproperty (tersembunyi = true) private Date updateTime; @Apimodelproperty (tersembunyi = true) private long userid; @ApimodelProperty (name = "status", value = "Status rilis artikel", wajib = true, example = "1") Status integer pribadi; @ApImoDelProperty (name = "type", value = "artikel kategori", diperlukan = true, example = "1") tipe integer pribadi;}@Apimodel adalah konfigurasi properti dari seluruh kelas:
Nilai: Deskripsi kelas
Deskripsi: Deskripsi terperinci
@Apimodelproperty adalah konfigurasi properti masing -masing bidang secara rinci:
Nama: Nama Lapangan
Nilai: Deskripsi Bidang
Diperlukan: apakah perlu
Contoh: Nilai contoh
Tersembunyi: Apakah akan menampilkan
Setelah menyelesaikan konfigurasi di atas, mari kita lihat efeknya:
Sekarang kita dapat melihat bahwa deskripsi bidang telah ditampilkan, dan nilai bidang dalam contoh juga telah menjadi nilai yang sesuai dari contoh properti yang kami konfigurasi. Dengan cara ini, dokumen API lengkap dihasilkan dan dokumen tersebut terkait erat dengan kode, daripada dua bagian yang terisolasi. Selain itu, kami juga dapat mengujinya dengan mudah melalui dokumen ini. Kami hanya perlu mengklik kotak kuning di bawah nilai contoh, dan konten di dalamnya akan secara otomatis disalin ke kotak nilai yang sesuai dari artikel tersebut, dan kemudian klik "Cobalah" untuk memulai permintaan HTTP.
Setelah mengklik Cobalah, kita dapat melihat hasil yang dikembalikan:
Operasi masih sangat nyaman. Dibandingkan dengan Junit dan Postman, pengujian melalui kesombongan lebih nyaman. Tentu saja, pengujian Swagger tidak dapat menggantikan pengujian unit, tetapi masih memiliki efek yang sangat penting dalam debugging bersama.
4. Ringkasan
Secara keseluruhan, konfigurasi Swagger relatif sederhana, dan kemampuan Swagger untuk secara otomatis menghasilkan dokumen memang telah menyelamatkan kami banyak pekerjaan dan memberikan bantuan besar untuk pemeliharaan selanjutnya. Selain itu, Swagger dapat secara otomatis menghasilkan data uji untuk kami sesuai dengan konfigurasi dan menyediakan metode HTTP yang sesuai, yang juga bermanfaat untuk uji diri dan pekerjaan debugging bersama kami. Karena itu, saya masih menyarankan agar Anda menggunakan kesombongan dalam pengembangan harian, yang akan membantu Anda meningkatkan efisiensi kerja Anda sampai batas tertentu. Akhirnya, izinkan saya meninggalkan pertanyaan untuk Anda pikirkan, yaitu, dokumen dapat diakses langsung melalui halaman, jadi kami tidak dapat mengekspos antarmuka langsung ke lingkungan produksi, terutama sistem yang perlu menyediakan layanan eksternal. Jadi bagaimana kita bisa mematikan fungsi ini dalam proses produksi? Ada banyak metode, Anda dapat mencobanya sendiri.
Di atas adalah pertempuran aktual dari Proyek Spring Boot Integrated Swagger2 yang diperkenalkan kepada Anda oleh editor. Saya harap ini akan membantu Anda. Jika Anda memiliki pertanyaan, silakan tinggalkan saya pesan dan editor akan membalas Anda tepat waktu. Terima kasih banyak atas dukungan Anda ke situs web Wulin.com!