目錄
3,@ApiImplicitParam和@ApiImplicitParams
一,原始項目說明
首先,我找了一個Springboot+SpringCloud的項目,裏面沒什麼東西,是個最簡單的服務,比如這樣:
啓動類:
@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
public class ConsumerRibbonApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerRibbonApplication.class, args);
}
@Bean
@LoadBalanced
RestTemplate restTemplate() {
return new RestTemplate();
}
}
一個Controller:
@RestController
public class HiController {
@Autowired
RibbonService ribbonService;
@RequestMapping(value = "/hi")
public String hi(@RequestParam String name) {
return ribbonService.hiService(name);
}
}
一個Service:
@Service
public class RibbonService {
@Autowired
RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "hiServiceError")
public String hiService(String name) {
return restTemplate.getForObject("http://provider-a/hi?name=" + name, String.class);
}
public String hiServiceError(String name) {
return "hi," + name + ",斷路機制啓動,hiServiceError";
}
}
application.properties文件裏寫的是:
server.port: 8764
spring.application.name: consumer-ribbon
eureka.client.service-url.defaultZone: http://localhost:8761/eureka/
以上代碼,和Swagger有關的也只有端口配置8764了。
二,引入Swagger
如果要在項目中加入Swagger,首先要在pom文件中加入:
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
然後我們需要一個Swagger的配置類:
package consumer.ribbon;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;
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;
@EnableSwagger2
@ComponentScan(basePackages = {"consumer.ribbon"})
@Configuration
public class SwaggerConfig extends WebMvcConfigurationSupport {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("這裏填title")//標題
.description("這裏填description")//描述
.termsOfServiceUrl("http://www.google.com.hk")//(不可見)條款地址,公司內部使用的話不需要配
.contact(new Contact("這裏填作者姓名", "這裏填作者url", "這裏填作者email"))//作者信息
.version("這裏填version")//版本號
.build();
}
// @Override
// public void addInterceptors(InterceptorRegistry registry) {
// registry.addInterceptor(new LoginInterceptor())
// .addPathPatterns("/**")
// .excludePathPatterns("/user/login")
// .excludePathPatterns("/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**");
// }
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
// registry.addResourceHandler("/templates/**")
// .addResourceLocations("classpath:/META-INF/resources/templates/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
}
}
注:
1,註解別寫少了,另外@ComponentScan註解中的basePackages參數別寫錯了,這是需要掃描Swagger註解的文件路徑。
2,createRestApi()方法裏的內容基本照抄,不用改。
3,addResourceHandlers()方法是爲了避免Swagger首頁進不去而添加的路徑關聯,這個方法不寫的話進首頁會404。
其中:
registry.addResourceHandler("swagger-ui.html")
是爲了訪問首頁。
registry.addResourceHandler("/webjars/**")
是首頁用到的一些靜態資源。
中間註釋的一段貌似不寫也沒什麼影響。
4,被註釋的addInterceptors()方法網上很多文章說需要加,否則首頁404,不過我試了一下好像也可以不寫。方法中用到的LoginInterceptor類實際上是自定義的一個Interceptor,沒什麼內容:
package consumer.ribbon;
import org.springframework.web.servlet.HandlerInterceptor;
public class LoginInterceptor implements HandlerInterceptor {
}
三,Swagger首頁
做完這些後,啓動SpringBoot服務,在地址欄輸入:
可以進入Swagger首頁:
可以看到,首頁中已經展示了兩個Controller。
其中BasicErrorController不是自己定義的,點開之後裏面展示的是/error接口的配置,看起來像是請求錯誤地址後的跳轉接口:
另外首頁還展示了hi-controller,這個controller沒有使用任何Swagger專用的註解,但是Swagger依然掃描到了他,可能是用@RestController和@RequestMapping兩種註解掃描的。另外/hi接口沒有配置請求方式,所以Swagger列出了所有格式的/hi接口:
打開某個接口會有參數的說明,返回值說明等:
另外,點擊右上角的Try it out按鈕,還可以實際調用一下該接口,輸入參數值,點擊Execut按鈕調用,就像PostMan一樣:
四,Swagger註解使用
1,@Api
@Api註解用在Controller上,說明該類的作用。
注意:使用該註解必須與Controller註解一起使用,比如@RestController或@Controller。
部分參數:
value:網上說是url路徑值,但是我填了貌似沒啥用,沒見在哪能展示。
tags:應該理解爲Controller的名字,可以選擇填Controller類名,或者Controller的Url路徑。網上說此參數會覆蓋value,但是即使沒有此參數value也顯示不出來。
description:描述信息。
position:在Swagger上的排序位置,有多個@Api的時候可以配。
hidden:爲true時隱藏該文檔,但是我設置了沒啥用。
寫個代碼:
@Api(tags = "SwaggerController", description = "Swagger測試Controller", position = 0)
@RestController
@RequestMapping(value = "/swagger", method = RequestMethod.POST)
public class SwaggerController {
@RequestMapping(value = "/hi")
public String hi(@RequestParam String name) {
return "name=" + name;
}
}
Swagger裏顯示的是這樣的:
2,@ApiOperation
@ApiOperation註解用在Controller中的方法上,用於說明方法的作用。
部分參數:
tags:方法名。可以選擇寫方法名或url路徑。
notes:描述信息。
寫個代碼:
@ApiOperation(value = "getUser", notes = "獲取用戶接口", response = java.lang.String.class)
@RequestMapping(value = "/hi")
public String getUser(@RequestParam String name) {
return "name=" + name;
}
Swagger裏顯示的是這樣的:
3,@ApiImplicitParam和@ApiImplicitParams
@ApiImplicitParam註解用在單參數方法上,或者多參數方法的 @ApiImplicitParams註解中。
部分參數:
paramType:參數類型,可選項有:
- path:以地址的形式提交數據。此類型的參數必須由@PathVariable註解來獲取。
- query:直接跟參數完成自動映射賦值。此類型的參數必須由@RequestParam註解來獲取。
- body:以流的形式提交,僅支持POST。
- header:參數在request headers裏提交。此類型的參數必須由@RequestHeader註解來獲取。
- form:以form表單的形式提交,僅支持POST
dataType:參數數據類型:可選值有Integer和String。
name:參數名,最好寫成和Java方法中實際的參數名一致。
value:參數描述。
required:參數是否必填,可選值有true和false。
defaultValue:默認值,這個默認值是使用Swagger發起調用時用的,和SpringMVC提供的參數默認值不是一個概念。
Swagger和Spring對參數的控制方式完全不同
Swagger對參數的控制是文檔層面的,並不能真正控制接口本身,而Spring可以真正控制接口的定義,二者各管一邊互不干擾。
以required爲例,在Swagger中是這麼用的:
@ApiImplicitParam(name = "userName", value = "用戶名", required = true)
該配置代表Swagger認爲userName參數必填,這一點將體現在Swagger生成的文檔上,另外,如果在Swagger首頁上使用Try it out發起調用,這個配置也會生效,如果不填userName的話請求就發不出去。然而,以上這些和接口的實際要求並沒有什麼關係,從配置上來說二者完全可以對不上。
相比之下,Spring提供restful接口時是這樣使用required的:
@RequestParam(required = true) String userName
該配置代表Spring認爲接口的userName參數是必填項,那麼這個參數就真的是必填的,如果沒填那麼請求將被返回400的錯誤。
同理,Swagger和Spring對默認值的使用也有同樣的情況,Swagger的默認值就是能在文檔上看看。
@ApiImplicitParam中的name,最好寫成和Java方法中實際的參數名一致,否則在Swagger上會分別展示,比如:
@ApiOperation(value = "getUser", notes = "獲取用戶接口", response = java.lang.String.class)
@ApiImplicitParam(name = "name", value = "用戶名value", required = true, defaultValue = "abcde", paramType = "form", dataType = "String")
@RequestMapping(value = "/getUser", method = RequestMethod.POST)
public String getUser(@RequestParam String userName) {
return "userName=" + userName;
}
在Swagger上的效果是:
圖8
上面的name參數就是我們用@ApiImplicitParam註解定義的,下面的userName是在Java方法中定義的參數,而且和@RequestParam註解無關。使用Try it out來發起調用的時候,我們自定義的name和方法的真實參數userName都可以使用輸入值,但是隻有真實參數纔是有效的:
@ApiImplicitParam註解的另一個用法,是用在@ApiImplicitParams註解中,比如:
@ApiOperation(value = "getUser2", notes = "獲取用戶接口", response = java.lang.String.class)
@ApiImplicitParams({
@ApiImplicitParam(name = "userName", value = "用戶名", required = true, defaultValue = "abcde", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "age", value = "用戶年齡", required = false, defaultValue = "12", paramType = "query", dataType = "Integer")
})
@RequestMapping(value = "/getUser2", method = RequestMethod.POST)
public String getUser2(@RequestParam String userName,
Integer age) {
return "userName=" + userName + " age=" + age;
}
在Swagger上的效果是:
依然需要注意參數名和java方法實際的參數名要一致。
4,@ApiResponse和@ApiResponses
@ApiResponse註解用在方法上,並且用在@ApiResponses註解中,是對返回信息的說明。
@ApiResponse註解直接用在方法上時貌似不會起作用。
部分參數:
code:http響應狀態碼
message:描述信息
response:響應類,默認void
注:關於response參數,可能本身設計的初衷是爲了維護某些錯誤的http請求時的響應類,不過實際上此參數也可以用來描述正常http請求(code=200)的響應類。另外,響應類的參數可以設置爲public,或者設置爲private並且寫好get/set方法。
比如:
@ApiOperation(value = "getUser3", notes = "獲取用戶接口", response = java.lang.String.class)
@ApiResponses({
@ApiResponse(code = 200, message = "請求正常", response = ErrorResponse.class),
@ApiResponse(code = 400, message = "參數錯誤", response = ErrorResponse.class)
})
@RequestMapping(value = "/getUser3", method = RequestMethod.POST)
public String getUser3(@RequestParam String userName,
Integer age) {
return "userName=" + userName + " age=" + age;
}
其中ErrorResponse類是這樣的:
public class ErrorResponse {
private int code;
private String message;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
在Swagger裏效果是這樣的:
5,@ApiModel和@ApiModelProperty
@ApiModel用於響應類上,是返回響應類的說明。
@ApiModelProperty用於響應類的屬性上,是對響應類屬性的描述。
@ApiModel註解的部分參數:
value:名稱
description:描述
parent:父類class,爲了可以描述從父類繼承來的屬性。
@ApiModelProperty註解的部分參數:
value:參數名
舉個例子:
@ApiOperation(value = "getUser4", notes = "獲取用戶接口", response = consumer.swagger.UserResponse.class)
@RequestMapping(value = "/getUser4", method = RequestMethod.POST)
public UserResponse getUser4(@RequestParam String userName,
Integer age) {
UserResponse userResponse = new UserResponse();
userResponse.setId(123);
userResponse.setAge(age);
userResponse.setName(userName);
return userResponse;
}
其中的響應類UserResponse是這樣的:
package consumer.swagger;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
@ApiModel(value = "UserResponse",description = "用戶信息",parent = consumer.swagger.UserResponseParent.class)
public class UserResponse extends UserResponseParent{
@ApiModelProperty(value = "用戶id")
private int id;
@ApiModelProperty(value = "用戶名")
private String name;
@ApiModelProperty(value = "年齡")
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
有父類UserResponseParent,此類定義如下:
package consumer.swagger;
import io.swagger.annotations.ApiModelProperty;
public class UserResponseParent {
@ApiModelProperty(value = "父級姓名")
private String parentName;
public String getParentName() {
return parentName;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
}
父類可以不用@ApiModel註解,只需要在屬性上添加@ApiModelProperty註解。
於是在Swagger上是這樣的效果:
注意,在code=200的那一欄裏,此時默認選中的是Example Value這一項,所以顯示了UserResponse類的一個例子,如果我們選擇Model這一項,就會顯示UserResponse類的說明:
可見,父類的屬性也被列出來了,如果父類屬性添加了@ApiModelProperty註解,註解就會生效,否則就只有屬性名。
6,@ResponseHeader
@ResponseHeader註解用於設置響應頭,可以用在@ApiResponse註解中。
部分參數:
name:響應頭名稱
description:描述
response:響應類,默認Void。
比如:
@ApiOperation(value = "getUser5", notes = "獲取用戶接口", response = java.lang.String.class)
@ApiResponses({
@ApiResponse(code = 400, message = "參數錯誤", response = ErrorResponse.class,responseHeaders = {
@ResponseHeader(name = "Location", description = "The URL to retrieve created resource", response = String.class)
})
})
@RequestMapping(value = "/getUser5", method = RequestMethod.POST)
public String getUser5(@RequestParam String userName,
Integer age) {
return "userName=" + userName + " age=" + age;
}
在Swagger中的效果是這樣的:
其實Swagger的功能還是蠻強大的,不只是生成文檔這麼簡單,上面提到的註解和參數也只是冰山一角,待後面慢慢學習。
完