引入包:
<!--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"; }
补个美美的效果图