java maven,SpringMvc集成Springfox使用Swagger寫文檔和測試

 2023-10-06 阅读 31 评论 0

摘要:SpringMvc集成Springfox使用Swagger寫文檔和測試 前言 swagger簡介 swagger確實是個好東西,可以跟據業務代碼自動生成相關的api接口文檔,尤其用于restful風格中的>>項目,開發人員幾乎可以不用專門去維護rest >api,這個框架可以自動為你的

SpringMvc集成Springfox使用Swagger寫文檔和測試

前言

swagger簡介

swagger確實是個好東西,可以跟據業務代碼自動生成相關的api接口文檔,尤其用于restful風格中的>>項目,開發人員幾乎可以不用專門去維護rest >api,這個框架可以自動為你的業務代碼生成restfut風格的api,而且還提供相應的測試界面,自動顯>>示json格式的響應。大大方便了后臺開發人員與前端的溝通與聯調成本。

springfox-swagger簡介

java maven,Swagger 是一系列對 RESTful 接口進行規范描述和頁面展示的工具. 通過 springfox-swagger 將
Swagger 與 Spring-MVC 整合, 可從代碼中的注解獲取信息,
并生成相應的文檔。springfox本身只是利用自身的aop的特點,通過plug的方式把swagger集成了進來>>,它本身對業務api的生成,還是依靠swagger來實現。

springfox大致原理

springfox的大致原理就是,在項目啟動的過種中,spring上下文在初始化的過程,框架自動跟據配置>加載一些swagger相關的bean到當前的上下文中,并自動掃描系統中可能需要生成api文檔那些類,并
生成相應的信息緩存起來。如果項目MVC控制層用的是springMvc那么會自動掃描所有Controller類,跟>據這些Controller類中的方法生成相應的api文檔。

注意要點

一:SpringMVC與Spring分別是兩個容器,把Swagger注入到根容器(Spring)中,可能會導致異常

Springboot框架。Spring是根容器,SpringMvc是子容器,為了能自動掃描出所有Controller類,以制定數據緩存供頁>> 面api使用,有些bean需要依賴于SpringMvc中的一些bean,但這時候如果把這個注入到spring容器>>中了,因為rootcontext中沒有spring mvc的context中的那些配置類時就會報錯。

所以,我們解決方案是,1:保證這個類所在的路徑剛好在springmvc的component-scan的配置的b ase-package范圍內, 2:直接在Spring-mvc.xml配置文件中使用標簽,把這個類直接進行注入,所以我們可以不使用@Configuration注解讓Spring進行注入,而采用SpringMVC的配置文件的方式注入,當我們在上正式的時候,不進行注入就可以了。也不用在編輯代碼去掉配置@Configuration,而重新編譯一下了。


二:api分組相關,Docket實例不能延遲加載

springfox默認會把所有api分成一組,這樣通過類似于http://127.0.0.1:8080/jadDemo/swagger-ui.html這樣的地址訪問時,會在同一個頁面里加載所有api列表。這樣,如果系統稍大一點,api稍微多一點,頁面就會出現假死的情況,所以很有必要對api進行分組。api分組,是通過在ApiConf這個配置文件中,通過@Bean注解定義一些Docket實例

集成測試的策略有哪些。然而,同使用@Configuration一樣,我并不贊成使用@Bean來配置Docket實例給api分組。因為這樣,同樣會把代碼寫死。所以,我推薦在xml文件中自己配置Docket實例實現這些類似的功能。當然,考慮到Docket中的眾多屬性,直接配置bean比較麻煩,可以自己為Docket寫一個FactoryBean,然后在xml文件中配置FactoryBean就行了。然而將Docket配置到xml中時。又會遇到一個大坑,就那是,spring對bean的加載方式默認是延遲加載的,在xml中直接配置這些Docket實例Bean后。你會發現,沒有一點效果,頁面左上角的下拉列表中跟本沒有你的分組項。
這個問題曾困擾過我好幾個小時,后來憑經驗推測出可能是因為sping bean默認延遲加載,這個Docket實例還沒加載到spring context中。實事證明,我的猜測是對的。我不知道這算是springfox的一個bug,還是因為我跟本不該把對Docket的配置從原來的java代碼中搬到xml配置文件中來。


三:Controller類的參數,注意防止出現無限遞歸的情況

Spring mvc有強大的參數綁定機制,可以自動把請求參數綁定為一個自定義的命令對像。所以,很多開發人員在寫Controller時,為了偷懶,直接把一個實體對像作為Controller方法的一個參數。@RequestMapping(value = “update”)
public String update(MenuVomenuVo, Model model){}
這是大部分程序員喜歡在Controller中寫的修改某個實體的代碼。在跟swagger集成的時候,這里有一個大坑。如果MenuVo這個類中所有的屬性都是基本類型,那還好,不會出什么問題。但如果這個類里面有一些其它的自定義類型的屬性,而且這個屬性又直接或間接的存在它自身類型的屬性,那就會出問題。例如:假如MenuVo這個類是菜單類,在這個類時又含有MenuVo類型的一個屬性parent代表它的父級菜單。這樣的話,系統啟動時swagger模塊就因無法加載這個api而直接報錯。報錯的原因就是,在加載這個方法的過程中會解析這個update方法的參數,發現參數MenuVo不是簡單類型,則會自動以遞歸的方式解釋它所有的類屬性。這樣就很容易陷入無限遞歸的死循環。

為了解決這個問題,我目前只是自己寫了一個OperationParameterReader插件實現類以及它依賴的ModelAttributeParameterExpander工具類,通過配置的方式替換掉到srpingfox原來的那兩個類,偷梁換柱般的把參數解析這個邏輯替換掉,并避開無限遞歸。當然,這相當于是一種修改源碼級別的方式。我目前還沒有找到解決這個問題的更完美的方法,所以,只能建議大家在用spring-fox Swagger的時候盡量避免這種無限遞歸的情況。畢竟,這不符合springmvc命令對像的規范,springmvc參數的命令對像中最好只含有簡單的基本類型屬性。

SpringMVC+SpringFox的集成

Spring boot?1. 增加依賴

<!--springfox-swagger需要的最小依賴 start--><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger2</artifactId><version>2.5.0</version></dependency><dependency><groupId>io.springfox</groupId><artifactId>springfox-swagger-ui</artifactId><version>2.5.0</version></dependency><!--jackson用于將springfox返回的文檔對象轉換成JSON字符串--><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId><version>${version.jackson}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>${version.jackson}</version></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-core</artifactId><version>${version.jackson}</version></dependency><!--petStore是官方提供的一個代碼參考, 可用于后期寫文檔時進行參考, 可不加--><dependency><groupId>io.springfox</groupId><artifactId>springfox-petstore</artifactId><version>2.5.0</version></dependency>
<!--最小依賴 end-->

2. spring-fox 提供了配置信息

說明:下面例子是配置里兩個分組,分組是什么呢?
分組其實就是按照一定的規則顯示接口的文檔,相當于文檔的指定文檔的目錄。
- 通過.paths(PathSelectors.ant(“/user/**”)).build()配置匹配請求地址進行分組。
- 下面是定義了兩個分組,userDocket,shopDocket,注意分組名稱不可相同。
- 當分組沒有效果時,可以參考此配置,還可以檢查配置的順序有可能導致分組的配置失效。

package com.pkk.ssms1.config;import org.springframework.context.annotation.Bean;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;/*** @author peikunkun* @version V1.0* @Title: mybatisproject* @Package com.pkk.ssms1.config* @Description: <Swagger配置類>* @date 2018/4/12 20:02*//*spring框架中本身就有的
* 有了這個注解后,spring會自動把這個類實例化成一個bean注冊到spring上下文中
* 但是Spring和SpringMVC是倆個不同的容器,在使用的時候我們需要把其注入到SpringMVC容器器中,而此配置在上正式的時候,
* 需要取消掉,因為一般此api只是用于測試的時候用,我們可以采用xml配置的方式注冊此bean*/
/*@Configuration*/
/*用來集成swagger 2的*/
@EnableSwagger2
/*啟用srpingmvc了*/
@EnableWebMvc
public class MySwaggerConfig {private static final String INDEX_PAGE   = "http://localhost:8099/index.jsp";private static final String BASE_PACKAGE = "com.pkk.ssms1";@Beanpublic Docket userDocket() {ApiInfo apiInfo = new ApiInfoBuilder().title("用戶信息操作").description("用于操作用戶相關接口的文檔").contact(new Contact("kunzai", INDEX_PAGE, "youmail")).version("1.0").build();return new Docket(DocumentationType.SWAGGER_2).groupName("userDocket")//配置pathMapping之后,會顯示為/useruser/**/user/getInfo/*docket.pathMapping("/user*//**");*/.pathMapping("/")//設置只生成被Api這個注解注解過的Ctrl類中有ApiOperation注解的api接口的文檔/*docket.select().apis(RequestHandlerSelectors.withClassAnnotation(Api.class)).apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();*///指定要掃描的包.select().apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE))/*設置此組只匹配user/**的請求*/.paths(PathSelectors.ant("/user/**")).build().apiInfo(apiInfo);}@Beanpublic Docket shopDocket() {ApiInfo apiInfo = new ApiInfoBuilder().title("商品信息操作").description("用于操作商品相關接口的文檔").contact(new Contact("kunzai", INDEX_PAGE, "youmail")).version("1.0").build();return new Docket(DocumentationType.SWAGGER_2).groupName("shopDocket")//配置pathMapping之后,會顯示為/shop/**/shop/getInfo/*docket.pathMapping("/shop*//**");*/.pathMapping("/")//設置只生成被Api這個注解注解過的Ctrl類中有ApiOperation注解的api接口的文檔/*docket.select().apis(RequestHandlerSelectors.withClassAnnotation(Api.class)).apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class)).build();*///指定要掃描的包.select().apis(RequestHandlerSelectors.basePackage(BASE_PACKAGE))/*設置此組只匹配user/**的請求,需要放到最后否則無效*/.paths(PathSelectors.ant("/shop/*")).build()/*最后設置并返回Docket*/.apiInfo(apiInfo);}
}

3:接口定義Controller

集成測試的測試點有哪些,userController接口定義(屬于userDocket)

package com.pkk.ssms1.controller;import javax.servlet.http.HttpServletRequest;import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.pkk.ssms1.entity.User;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;/*** @author peikunkun* @version V1.0* @Title: mybatisproject* @Package com.pkk.ssms1.controller* @Description: <>* @date 2018/4/12 20:13*/
@RequestMapping("/user")
@RestController
@Api(tags = "UserController", description = "用戶信息相關")
public class UserController {/*https://github.com/catinred2/swagger_test/blob/master/src*/@RequestMapping("/getInfo")@ApiOperation(value = "獲取用戶信息", httpMethod = "GET", notes = "顯示用戶信息,不顯示密碼")public Object getInfo() {return "哈哈,我是信息";}@RequestMapping("/login")@ApiOperation(value = "登錄", httpMethod = "POST", notes = "用戶登錄文檔說明", consumes = "application/x-www-form-urlencoded")/*@ApiImplicitParams({@ApiImplicitParam(name = "username", value = "用戶名", required = true, defaultValue = "kunzai", paramType = "query", dataType = "String"),@ApiImplicitParam(name = "password", value = "密碼(MD5)", required = true, defaultValue = "admin", paramType = "query", dataType = "String"),@ApiImplicitParam(name = "deptid", value = "部門id", required = true, defaultValue = "1", paramType = "query", dataType = "Long"),@ApiImplicitParam(name = "cardid", value = "卡號", required = true, defaultValue = "1", paramType = "query", dataType = "Long"),})*/public Object login(@ApiParam User user, HttpServletRequest request) throws Exception {return "哈哈可以啊";}
}

shopController接口定義(屬于shopDocket)

package com.pkk.ssms1.controller;import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;import com.pkk.ssms1.entity.User;import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;/*** @author peikunkun* @version V1.0* @Title: mybatisproject* @Package com.pkk.ssms1.controller* @Description: <>* @date 2018/4/12 20:13*/
@RestController
@RequestMapping("/shop")
@Api(tags = "ShopController", description = "商戶信息相關")
public class ShopController {/*https://github.com/catinred2/swagger_test/blob/master/src*/@RequestMapping("/getInfo")@ApiOperation(value = "獲取商品信息", httpMethod = "GET", notes = "顯示商品信息")public Object getInfo() {return "哈哈,我是信息";}@RequestMapping("/login")@ApiOperation(value = "商品信息登錄", httpMethod = "POST", notes = "商品信息文檔說明", consumes = "application/x-www-form-urlencoded")@ApiImplicitParams({@ApiImplicitParam(name = "username", value = "用戶名", required = true, defaultValue = "kunzai", paramType = "query", dataType = "String"),@ApiImplicitParam(name = "password", value = "密碼(MD5)", required = true, defaultValue = "admin", paramType = "query", dataType = "String"),@ApiImplicitParam(name = "deptid", value = "部門id", required = true, defaultValue = "1", paramType = "query", dataType = "Long"),@ApiImplicitParam(name = "cardid", value = "卡號", required = true, defaultValue = "1", paramType = "query", dataType = "Long"),})public Object login(@Valid User user, BindingResult bindingResult, HttpServletRequest request) throws Exception {if (bindingResult.hasErrors()) {System.out.println("使用注解@Valid,檢驗參數時,出現以下錯誤:" + bindingResult.getFieldError().getDefaultMessage());return "使用注解@Valid,檢驗參數時,出現以下錯誤:" + bindingResult.getFieldError().getDefaultMessage();}return "哈哈可以啊";}
}

實體類

package com.pkk.ssms1.entity;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;/*** @param* @author peikunkun* @version V1.0* @return* @Description: <用戶實體類>* @date 2018/4/11 20:16*//*data相當于注解在類上,相當于同時使用了@ToString、@EqualsAndHashCode
、@Getter、@Setter和@RequiredArgsConstrutor這些注解,對于POJO類十分有用
@RequiredArgsConstructor: 會生成一個包含常量,和標識了NotNull的變量
的構造方法。生成的構造方法是private,如何想要對外提供使用可以使用staticName選項生成一個static方法。*/
@Data
@ApiModel(value = "User對象", description = "用戶對象信息")
public class User implements BaseEntity {@ApiModelProperty(required = false, dataType = "Long", hidden = true)private Long   id;@ApiModelProperty(name = "username", example = "昆仔", dataType = "String", value = "用戶名稱")private String username;@ApiModelProperty(name = "password", example = "admin", dataType = "String", value = "用戶密碼")private String password;@ApiModelProperty(required = false, name = "deptid", hidden = true, example = "1", dataType = "Long", value = "部門id")private Long   deptid;@ApiModelProperty(name = "cardid", hidden = true, example = "1", dataType = "Long", value = "身份id")private Long   cardid;
}

文檔常用的注解

- @Api 表示該類是一個 SwaggerResource, 是對 Controller 進行注解的,表示標識這個類是swagger的資源(tags–表示說明 value–也是說明,可以使用tags替代 )
- @ApiOperation 表示對應一個 RESTful 接口, 對方法進行注解,表示一個http請求的操作(value用于方法描述 notes用于提示內容,tags可以重新分組(視情況而用) )
- @ApiResponse 表示對不同 HTTP 狀態碼的意義進行描述 
- @ApiParam 表示對傳入參數進行注解用于方法,參數,字段說明;表示對參數的添加元數據(說明或是否必填等)(name–參數名 value–參數說明 required–是否必填)
- @ApiModel()用于類 表示對類進行說明,用于參數用實體類接收(value–表示對象名description–描述 )
- @ApiModelProperty()用于方法,字段 表示對model屬性的說明或者數據操作更改(value–字段說明 name–重寫屬性名字dataType–重寫屬性類型 required–是否必填 example–舉例說明 hidden–隱藏) 
- @ApiIgnore()用于類,方法,方法參數 表示這個方法或者類被忽略 
- @ApiImplicitParam() 用于方法 表示單獨的請求參數 
- @ApiImplicitParams() 用于方法,包含多個 @ApiImplicitParam(name–參數名 value–參數說明dataType–數據類型 paramType–參數類型 example–舉例說明)

傳送門

注解說明傳送門

SpringBoot項目、springfox-swagger原理解析與使用過程中遇到的坑(原理分析的還是不錯的)【精】

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://808629.com/129715.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 86后生记录生活 Inc. 保留所有权利。

底部版权信息