目录
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的功能还是蛮强大的,不只是生成文档这么简单,上面提到的注解和参数也只是冰山一角,待后面慢慢学习。
完