引入包:
<!--swagger--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> <exclusions> <exclusion> <groupId>io.swagger</groupId> <artifactId>swagger-annotations</artifactId> </exclusion> <exclusion> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> </exclusion> </exclusions> </dependency> <!--解決進入swagger頁面報類型轉換錯誤,排除2.9.2中的引用,手動增加1.5.21版本--> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-annotations</artifactId> <version>1.5.21</version> </dependency> <dependency> <groupId>io.swagger</groupId> <artifactId>swagger-models</artifactId> <version>1.5.21</version> </dependency> <!-- swagger2 增強UI ,擁有好看的界面, 和接口分組,排序等功能,如不引用可自行刪除--> <!-- https://mvnrepository.com/artifact/com.github.xiaoymin/knife4j-spring-boot-starter --> <!-- https://doc.xiaominfo.com/--> <dependency> <groupId>com.github.xiaoymin</groupId> <artifactId>knife4j-spring-boot-starter</artifactId> <version>2.0.4</version> </dependency>
swagger配置並啟用:
import com.culturalCenter.placeManage.globalConfig.Interface.ApiVersion; import com.culturalCenter.placeManage.globalConfig.Interface.CustomVersion; import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Profile; import org.springframework.web.bind.annotation.RequestMethod; import springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.builders.ResponseMessageBuilder; import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spi.service.contexts.SecurityContext; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; /** * 解釋接口信息的一些注解 * * @author wu * @Api:修飾整個類,描述Controller的作用 * @ApiOperation:描述一個類的一個方法,或者說一個接口 * @ApiParam:單個參數描述 * @ApiModel:用對象來接收參數 * @ApiProperty:用對象接收參數時,描述對象的一個字段 * @ApiResponse:HTTP響應其中1個描述 * @ApiResponses:HTTP響應整體描述 * @ApiIgnore:使用該注解忽略這個API * @ApiError :發生錯誤返回的信息 * @ApiParamImplicitL:一個請求參數 * @ApiParamsImplicit 多個請求參數 * @Profile 注解 標識加載在dev和test文件使用 */ @Configuration @EnableSwagger2 @EnableKnife4j @Import(BeanValidatorPluginsConfiguration.class) @Profile("dev") public class SwaggerConfig implements InitializingBean { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private ApplicationContext applicationContext; /** * 獲取swagger創建初始化信息 * * @return */ @SuppressWarnings("deprecation") public ApiInfo apiInfo() { return new ApiInfoBuilder().title("接口文檔"). description("服務端通用接口").version("1.0").build(); } /** * 安全認證參數 * * @return */ private List<ApiKey> securitySchemes() { List<ApiKey> apiKeyList = new ArrayList<ApiKey>(); apiKeyList.add(new ApiKey("Authorization", "Authorization", "header")); return apiKeyList; } private List<SecurityContext> securityContexts() { List<SecurityContext> securityContexts = new ArrayList<>(); securityContexts.add( SecurityContext.builder() .securityReferences(defaultAuth()) .forPaths(PathSelectors.regex("^(?!auth).*$")) .build()); return securityContexts; } private List<SecurityReference> defaultAuth() { AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything"); AuthorizationScope[] authorizationScopes = new AuthorizationScope[1]; authorizationScopes[0] = authorizationScope; List<SecurityReference> securityReferences = new ArrayList<>(); securityReferences.add(new SecurityReference("Authorization", authorizationScopes)); return securityReferences; } /** * 創建全局響應值 * * @return */ private List<ResponseMessage> responseBuilder() { List<ResponseMessage> responseMessageList = new ArrayList<>(); // List<Map<String, Object>> resultCode = getAllEnum("com.culturalCenter.placeManage.Utils.ResultCode"); // for (Map<String,Object> item :resultCode) { // responseMessageList.add(new ResponseMessageBuilder().code(Integer.valueOf(item.get("code").toString())).message(item.get("message").toString()).build()); // } responseMessageList.add(new ResponseMessageBuilder().code(200).message("響應成功").build()); responseMessageList.add(new ResponseMessageBuilder().code(500).message("服務器內部錯誤").build()); return responseMessageList; } /** * 根據枚舉的字符串獲取枚舉的值 * * @param className 包名+類名 * @return * @throws Exception */ public List<Map<String, Object>> getAllEnum(String className) { try { // 得到枚舉類對象 Class<Enum> clazz = (Class<Enum>) Class.forName(className); List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); //獲取所有枚舉實例 Enum[] enumConstants = clazz.getEnumConstants(); //根據方法名獲取方法 Method getCode = clazz.getMethod("getCode"); Method getMessage = clazz.getMethod("getMessage"); Map<String, Object> map = null; for (Enum enum1 : enumConstants) { map = new HashMap<String, Object>(); //執行枚舉方法獲得枚舉實例對應的值 map.put("code", getCode.invoke(enum1)); map.put("message", getMessage.invoke(enum1)); list.add(map); } return list; } catch (Exception e) { log.error(e.getMessage()); return null; } } private Docket buildDocket(String groupName) { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .groupName(groupName) .select() .apis(method -> { // 每個方法會進入這里進行判斷並歸類到不同分組,**請不要調換下面兩段代碼的順序,在方法上的注解有優先級** // 該方法上標注了版本 if (method.isAnnotatedWith(ApiVersion.class)) { ApiVersion apiVersion = method.getHandlerMethod().getMethodAnnotation(ApiVersion.class); if (apiVersion.value() != null) { if (Arrays.asList(apiVersion.value()).contains(groupName)) { return true; } } } // 方法所在的類是否標注了? ApiVersion annotationOnClass = method.getHandlerMethod().getBeanType().getAnnotation(ApiVersion.class); if (annotationOnClass != null) { if (annotationOnClass.value() != null) { if (Arrays.asList(annotationOnClass.value()).contains(groupName)) { return true; } } }
//此處可以增加一下沒有版本控制的顯示
if (method.groupName().equals("token-controller")) return true;
return false; }) .paths(PathSelectors.any()) .build().securitySchemes(securitySchemes()).securityContexts(securityContexts());
} /** * 動態得創建Docket bean * * @throws Exception */ @Override public void afterPropertiesSet() throws Exception { // ApiConstantVersion 里面定義的每個變量會成為一個docket Class<CustomVersion> clazz = CustomVersion.class; Field[] declaredFields = clazz.getDeclaredFields(); // 動態注入bean AutowireCapableBeanFactory autowireCapableBeanFactory = applicationContext.getAutowireCapableBeanFactory(); if (autowireCapableBeanFactory instanceof DefaultListableBeanFactory) { DefaultListableBeanFactory capableBeanFactory = (DefaultListableBeanFactory) autowireCapableBeanFactory; for (Field declaredField : declaredFields) { // 要注意 "工廠名和方法名",意思是用這個bean的指定方法創建docket AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder .genericBeanDefinition()
//此處的swaggerConfig首字母要小寫否則報找不到bean的方法 .setFactoryMethodOnBean("buildDocket", "swaggerConfig") .addConstructorArgValue(declaredField.get(CustomVersion.class)).getBeanDefinition(); capableBeanFactory.registerBeanDefinition(declaredField.getName(), beanDefinition); } } } }
自定義注解實API版本控制:
ApiVersion.class
/** * API版本控制注解 * Created on 2019/4/18 11:17. * * @author caogu */ @Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Mapping public @interface ApiVersion { // //標識版本號 // int value() default 1; /** * 分組名(即版本號),可以傳入多個 * * @return */ String value() default "v1"; }
自定義一個API版本號控制類
/** * 版本管理接口 */ public interface CustomVersion { String VERSION_1 = "v1"; String VERSION_2 = "v2"; }
補個美美的效果圖