maven+springMVC整合swagger,带注解扫描,非springBoot
背景
是在一个在用的项目中进行整合swagger,使用maven+springMVC,springMVC使用web.xml和spring-mvc.xml文件进行配置,带注解扫描,非springBoot项目
基本整合过程
1.pom.xml中加入相应的依赖
<!--swagger-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger.version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger.version}</version>
</dependency>
<!--如果项目没有guava,则需要加上.swagger至少选择19.0以上的guava-->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
2.编写swagger配置类
@Configuration //声明该类为配置类
@EnableSwagger2 //声明启动Swagger2
//@EnableWebMvc //这里我注释掉了也能正常使用,后面会讨论这个注解
public class SwaggerConfig {
/**
* controller接口所在的包
*/
@Value("${swagger.basePackage}")
private String basePackage;
/**
* 当前文档的标题
*/
@Value("${swagger.title}")
private String title;
/**
* 当前文档的详细描述
*/
@Value("${swagger.description}")
private String description;
/**
* 当前文档的版本
*/
@Value("${swagger.version}")
private String version;
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage(basePackage))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))//只扫描有swagger注解的方法
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title(title)
.description(description)
.version(version)
.build();
}
}
3.properties文件增加相应内容
#swagger
swagger.basePackage=com.demo
swagger.title=swagger文档的标题
swagger.description=swagger文档的描述
swagger.version=0.0.1
4.编写spring和springMVC配置文件
留意Spring的配置文件和Spring-MVC的配置文件是否启用了注解扫描,如果没有是需要手动注册的
我这里已经开启了注解扫描,但Controller是在MVC加载的,所以swagger也要在MVC中加载才能发现Controller
Spring配置文件
<context:component-scan base-package="com.demo">
<!-- 将Controller的注解排除掉,在spring-mvc.xml单独扫描Controller注解 -->
<context:exclude-filter expression="org.springframework.stereotype.Controller" type="annotation" />
<!--由于controller在spring-mvc中加载,swagger也要在mvc中加载才能扫描到controller,那在spring加载就没必要了-->
<context:exclude-filter type="regex" expression="com.demo.config.SwaggerConfig"/>
</context:component-scan>
SpringMVC配置文件
<!--仅扫描Controller注解和SwaggerConfig类-->
<context:component-scan base-package="com.demo" use-default-filters="false">
<context:include-filter expression="org.springframework.stereotype.Controller" type="annotation" />
<context:include-filter type="regex" expression="com.demo.config.SwaggerConfig"/>
</context:component-scan>
<!--启用注解扫描-->
<mvc:annotation-driven />
<!--加载properties到MVC-->
<context:property-placeholder file-encoding="UTF-8" location="classpath:*.properties"
ignore-unresolvable="true" />
6.拦截器/过滤器开放swagger页面的路径
包括
页面: /swagger-ui.html
api信息: /v2/*
配置信息: /swagger-resources/*
js和CSS: /webjars/*
5.Controller和DTO增加注解
Controller
@ApiOperation(value = "接口名称", notes = "接口提示信息", httpMethod = "POST", response = StudentDTO.class)
@RequestMapping(value = "postSutdent",method = RequestMethod.POST)
public void postSutdent(@RequestBody StudentDTO studentDTO){
System.out.println(studentDTO);
}
DTO
@ApiModel(value = "StudentDTO",description = "学生信息")
class StudentDTO{
@ApiModelProperty(value = "学生姓名",required = true)
private String name;
@ApiModelProperty(value = "学生年龄",required = true)
private Integer age;
@ApiModelProperty(value = "考试情况",required = true)
private List<ExamDTO> exams;
//get set 方法略
}
@ApiModel(value = "ExamDTO",description = "考试情况")
class ExamDTO{
@ApiModelProperty(value = "科目名称",required = true)
private String name;
@ApiModelProperty(value = "分数",required = true)
private Double grade;
//get set 方法略
}
6.启动并访问localhost:8080/demo/swagger-ui.html
常见问题
1.swagger出现无限递归
原因:通常是由于swagger解析时遇到循环引用,例如树形结构
方法1:在swaggerConfig中添加自定义的TypeResolver
,当成Object类型处理
private TypeResolver typeResolver = new TypeResolver();
private AlternateTypeRule alternateTypeRule = new AlternateTypeRule(typeResolver.resolve(TreeNode.class),typeResolver.resolve(Object.class));
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.alternateTypeRules(alternateTypeRule)//将TreeNode当Object处理
.select()
.apis(RequestHandlerSelectors.basePackage(basePackage))
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}
方法2:使用注解属性hidden隐藏循环引用的字段,缺点是文档会缺失这个字段
@ApiModelProperty(hidden = true)
2.swagger提示缺少 com.google.common.base.MoreObjects
原因:缺少guava依赖或者guava版本太低
方法:maven添加或者升级guava
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
3.swagger读取properties失败,显示${swagger.title}等
原因:springMVC没有读取到properties
方法:springMVC配置文件增加读取properties文件
<context:property-placeholder file-encoding="UTF-8" location="classpath:*.properties"
ignore-unresolvable="true" />
4.swagger的properties中文乱码
原因:springMVC读取properties的编码不对
方法:增加file-encoding="UTF-8"
<context:property-placeholder file-encoding="UTF-8" location="classpath:*.properties"
ignore-unresolvable="true" />
5.无法访问swagger-ui.html,但idea的Spring->bean工具中能看到swaggerConfig加载了
进行如下检查:
拦截器或过滤器没有拦截/swagger-ui.html
?
spring-MVC正确处理了静态资源?
6.能访问swagger-ui.html但没有api列表
进行如下检查:
swaggerConfig能正常读取properties?
swaggerConfig的basePackage路径覆盖到Controller所在包?
swaggerConfig只扫描swagger注解,且Controller已有对应注解?
swaggerComfig加载时能发现Controller?(Controller一般由SpringMVC加载.如果swaggerConfig在String加载,但MVC中没有加载,那么swaggerConfig无法发现Controller)
idea的Spring->MVC工具中能看到/v2/api-docs路径?(说明swagger组件启动成功)
/v2/*
路径被拦截?
web.xml配置springMVC时访问路径包含了/v2/*
?
7.能访问swagger-ui.html但样式丢失
进行如下检查:
/webjars/*
被拦截?
/swagger-resources/*
被拦截?
8.能访问swagger-ui.html但一直弹窗提示Unable to infer base url
进行如下检查:
swaggerConfig已配置@EnableSwagger2
注解?
/swagger-resources/*
被拦截?
9.swagger把许多不需要的Controller都扫描出来了
方法1:缩小basePackage范围
方法2:扫描特定的类注解
方法3:扫描特定的方法注解
1.apis(RequestHandlerSelectors.basePackage("com.xx.xx.controller"))
2.apis(RequestHandlerSelectors.withClassAnnotation(Api.class))
3.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
关于@EnableWebMvc
网上一些教程认为swaggerConfig
必须增加@EnableWebMvc
@EnableWebMvc
的作用是引入配置类DelegatingWebMvcConfiguration.class
进行自动装配
由于我的项目已经使用xml文件配置好了SpringMVC,是否使用``@EnableWebMvc`都没有影响,估计是被xml覆盖了,没有深究下去
网上也有关于SpringBoot和@EnableWebMvc
的讨论
不使用@EnableWebMvc
时SpringBoot使用WebMvcAutoConfiguration.class
对SpringMVC进行配置
使用@EnableWebMvc
时SpringBoot使用DelegatingWebMvcConfiguration.class
对SpringMVC进行配置
这是两条不一样的配置路线,后者通常配合自定义的MVCConfig使用