当前位置 博文首页 > CHQIUU的专栏:Spring Boot项目中集成Swagger knife4j并自定义访
我们在项目开发中,往往期望做到前后端分离,也就是后端开发人员需要输出大量的服务接口,在没有Swagger之前需要我们话费大量的精力去编写接口文档。包含如接口的地址、需要传递参数情况、返回值的JSON数据格式以及每一个字段说明、当然还要考虑HTTP请求头、请求内容等信息。而随着项目的开发进度和后期进行迭代,后端输出的接口往往会面临修改、修复等问题,那也意味着接口文档又要进行相应的调整。接口文档的维护度以及可读性就大大下降。既然接口文档需要花费精力去维护,还要适当的进行面对面交流沟通。
Swagger为我们解决的问题:
这里我推荐使用knife4j(当前最新版3.0.2),相比springfox-swagger-ui界面要美观,同时功能更完善。
在项目pom.xml文件中增加如下依赖项:
<properties>
<knife4j-spring-boot-starter.version>3.0.2</knife4j-spring-boot-starter.version>
<!--其他配置代码-->
</properties>
<dependencies>
<!--swagger2 begin-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>${knife4j-spring-boot-starter.version}</version>
</dependency>
<!--swagger2 end-->
</dependencies>
?
这里我推荐使用knife4j,相比springfox-swagger-ui界面要美观点。
?
package com.chqiuu.config;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.http.ResponseEntity;
import org.springframework.plugin.core.PluginRegistry;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.resource.PathResourceResolver;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import org.springframework.web.util.UrlPathHelper;
import springfox.documentation.annotations.ApiIgnore;
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.DocumentationCache;
import springfox.documentation.spring.web.json.Json;
import springfox.documentation.spring.web.json.JsonSerializer;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger.web.ApiResourceController;
import springfox.documentation.swagger.web.SecurityConfiguration;
import springfox.documentation.swagger.web.SwaggerResource;
import springfox.documentation.swagger.web.UiConfiguration;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper;
import springfox.documentation.swagger2.web.Swagger2ControllerWebMvc;
import springfox.documentation.swagger2.web.WebMvcSwaggerTransformationFilter;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.springframework.util.MimeTypeUtils.APPLICATION_JSON_VALUE;
/**
* Swagger2 前端API配置
*
* @author chqiu
*/
@Configuration
@EnableSwagger2
@AutoConfigureAfter({WebMvcConfig.class})
@AllArgsConstructor
public class Swagger2Config {
private final VrihProperties properties;
private static final String DEFAULT_PATH = "/swagger";
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(properties.isSwaggerEnable())
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.chquu.xxx"))
.paths(PathSelectors.any())
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("XX项目API接口管理")
.description("XX项目API接口管理")
.termsOfServiceUrl("127.0.0.1")
.contact(new Contact("xxx", "http://www.apache.org", "xxx@qq.com"))
.version("1.0.0").license("Apache 2.0").licenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html")
.build();
}
/**
* SwaggerUI资源访问
*
* @param servletContext
* @param order
* @return
* @throws Exception
*/
@Bean
public SimpleUrlHandlerMapping swaggerUrlHandlerMapping(ServletContext servletContext,
@Value("${swagger.mapping.order:10}") int order) throws Exception {
SimpleUrlHandlerMapping urlHandlerMapping = new SimpleUrlHandlerMapping();
Map<String, ResourceHttpRequestHandler> urlMap = new HashMap<>();
{
PathResourceResolver pathResourceResolver = new PathResourceResolver();
pathResourceResolver.setAllowedLocations(new ClassPathResource("META-INF/resources/webjars/"));
pathResourceResolver.setUrlPathHelper(new UrlPathHelper());
ResourceHttpRequestHandler resourceHttpRequestHandler = new ResourceHttpRequestHandler();
resourceHttpRequestHandler.setLocations(Arrays.asList(new ClassPathResource("META-INF/resources/webjars/")));
resourceHttpRequestHandler.setResourceResolvers(Arrays.asList(pathResourceResolver));
resourceHttpRequestHandler.setServletContext(servletContext);
resourceHttpRequestHandler.afterPropertiesSet();
//设置新的路径
urlMap.put(DEFAULT_PATH + "/webjars/**", resourceHttpRequestHandler);
}
{
PathResourceResolver pathResourceResolver = new PathResourceResolver();
pathResourceResolver.setAllowedLocations(new ClassPathResource("META-INF/resources/"));
pathResourceResolver.setUrlPathHelper(new UrlPathHelper());
ResourceHttpRequestHandler resourceHttpRequestHandler = new ResourceHttpRequestHandler();
resourceHttpRequestHandler.setLocations(Arrays.asList(new ClassPathResource("META-INF/resources/")));
resourceHttpRequestHandler.setResourceResolvers(Arrays.asList(pathResourceResolver));
resourceHttpRequestHandler.setServletContext(servletContext);
resourceHttpRequestHandler.afterPropertiesSet();
//设置新的路径
urlMap.put(DEFAULT_PATH + "/**", resourceHttpRequestHandler);
}
urlHandlerMapping.setUrlMap(urlMap);
//调整DispatcherServlet关于SimpleUrlHandlerMapping的排序
urlHandlerMapping.setOrder(order);
return urlHandlerMapping;
}
/**
* SwaggerUI接口访问
*/
@Controller
@ApiIgnore
@RequestMapping(DEFAULT_PATH)
public static class SwaggerResourceController implements InitializingBean {
private final ApiResourceController apiResourceController;
private final DocumentationCache documentationCache;
private final ServiceModelToSwagger2Mapper mapper;
private final JsonSerializer jsonSerializer;
private final PluginRegistry<WebMvcSwaggerTransformationFilter, DocumentationType> transformations;
private static final String HAL_MEDIA_TYPE = "application/hal+json";
private Swagger2ControllerWebMvc swagger2ControllerWebMvc;
public SwaggerResourceController(ApiResourceController apiResourceController, DocumentationCache documentationCache, ServiceModelToSwagger2Mapper mapper, JsonSerializer jsonSerializer, PluginRegistry<WebMvcSwaggerTransformationFilter, DocumentationType> transformations) {
this.apiResourceController = apiResourceController;
this.documentationCache = documentationCache;
this.mapper = mapper;
this.jsonSerializer = jsonSerializer;
this.transformations = transformations;
}
@Override
public void afterPropertiesSet() throws Exception {
swagger2ControllerWebMvc = new Swagger2ControllerWebMvc(documentationCache, mapper, jsonSerializer, transformations);
}
/**
* Swagger API首页地址
*
* @return 首页地址
*/
@RequestMapping
public ModelAndView index() {
return new ModelAndView("redirect:" + DEFAULT_PATH + "/doc.html");
}
@RequestMapping("/swagger-resources/configuration/security")
@ResponseBody
public ResponseEntity<SecurityConfiguration> securityConfiguration() {
return apiResourceController.securityConfiguration();
}
@RequestMapping("/swagger-resources/configuration/ui")
@ResponseBody
public ResponseEntity<UiConfiguration> uiConfiguration() {
return apiResourceController.uiConfiguration();
}
@RequestMapping("/swagger-resources")
@ResponseBody
public ResponseEntity<List<SwaggerResource>> swaggerResources() {
return apiResourceController.swaggerResources();
}
@RequestMapping(value = "/v2/api-docs", method = RequestMethod.GET, produces = {APPLICATION_JSON_VALUE, HAL_MEDIA_TYPE})
@ResponseBody
public ResponseEntity<Json> getDocumentation(
@RequestParam(value = "group", required = false) String swaggerGroup,
HttpServletRequest servletRequest) {
return swagger2ControllerWebMvc.getDocumentation(swaggerGroup, servletRequest);
}
}
}
@Api(tags = "接口服务", value = "/api/v1/swagger/**")
@RestController
@RequestMapping("/api/v1/swagger")
public class ApiController {
@ApiOperation("保存用户信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "名字", required = true, paramType = "path"),
@ApiImplicitParam(name = "age", dataType = "int", value = "年龄", required = true, paramType = "query")
})
@PostMapping("/{name}")
@ResponseBody
public Boolean save(
@PathVariable("name") String name,
@RequestParam("age") Integer age
) {
userInfo.put(name, new User(name, age));
return true;
}
}
启动项目访问Swagger页面 http://localhost+端口名+项目名+/swagger/doc.html 呈现效果如下:
@Api:用在请求的类上,表示对类的说明
tags="说明该类的作用,可以在UI界面上看到的注解"
value="该参数没什么意义,在UI界面上也看到,所以不需要配置"
@ApiOperation:用在请求的方法上,说明方法的用途、作用
value="说明方法的用途、作用"
notes="方法的备注说明"
@ApiImplicitParams:用在请求的方法上,表示一组参数说明
@ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方
· header --> 请求参数的获取:@RequestHeader
· query --> 请求参数的获取:@RequestParam
· path(用于restful接口)--> 请求参数的获取:@PathVariable
· body(不常用)
· form(不常用)
dataType:参数类型,默认String,其它值dataType="Integer"
defaultValue:参数的默认值
@ApiResponses:用在请求的方法上,表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
code:数字,例如400
message:信息,例如"请求参数没填好"
response:抛出异常的类
@ApiModel:用于响应类上,表示一个返回响应数据的信息
(这种一般用在post创建的时候,使用@RequestBody这样的场景,
请求参数无法使用@ApiImplicitParam注解进行描述的时候)
@ApiModelProperty:用在属性上,描述响应类的属性