首先明确思路:
swagger扫描的是controller包或者说是@Controller或者@RestController的类,本人的遇到的问题是controller是封装好的,service层是重写controller层下的方法,
比如controller里面的方法是需要传递参数的,{name}需要替换为service雷明如果想实现展示service下的方法,做法如下
1.pom导入依赖包
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2
org.codehaus.jackson
jackson-core-asl
1.9.13
myswagger.swagger-ui-layer-master
swagger-ui-layer
1.0
2.开启swagger
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.bind.annotation.RequestMethod; import springfox.documentation.RequestHandler; import springfox.documentation.builders.*; import springfox.documentation.schema.ModelRef; import springfox.documentation.service.*; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; import java.util.ArrayList; import java.util.List; import com.google.common.base.Function; import com.google.common.base.Optional; import com.google.common.base.Predicate; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.service.ApiInfo; /** * Swagger2配置类 * 在与spring boot集成时,放在与Application.java同级的目录下。 * 通过@Configuration注解,让Spring来加载该类配置。 * 再通过@EnableSwagger2注解来启用Swagger2。 * Author: zyg * Date: 2020-03-26 10:49 * http://localhost:8080/swagger-ui.html */ @Configuration @EnableSwagger2 //@Profile({"dev", "test"})// @Profile({"dev", "test"})注解是在开发环境和测试环境的时候加载该类,线上生产环境为安全不建议创建swagger的bean public class Swagger2Config{ // 定义分隔符 private static final String splitor = ";"; @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2).groupName("spring-test-interface") //加载配置信息 .apiInfo(apiInfo()) //设置全局参数 .globalOperationParameters(globalParamBuilder()) //设置全局响应参数 .globalResponseMessage(RequestMethod.GET,responseBuilder()) .globalResponseMessage(RequestMethod.POST,responseBuilder()) .globalResponseMessage(RequestMethod.PUT,responseBuilder()) .globalResponseMessage(RequestMethod.DELETE,responseBuilder()) .select() /** * 加载swagger 扫描包 */ // .apis(RequestHandlerSelectors.any())//加载所有的controller .apis(basePackage("com.mes7801.server.controller"+splitor+"com.evjrsf.server.controller")) // .apis(basePackage("com.mes7801.server.controller"))//加载单个controller .paths(PathSelectors.any()) .build() //设置安全认证 .securitySchemes(security()); } /** * 获取swagger创建初始化信息 * @return */ private ApiInfo apiInfo() { Contact contact = new Contact("慧都科技", "", "[email protected]"); return new ApiInfoBuilder().title("MES7801 测试文档").description("dev by 慧都科技").contact(contact) .version("1.1.0").build(); } /** * 安全认证参数 * @return */ private Listsecurity() { List list=new ArrayList<>(); list.add(new ApiKey("token", "token", "header")); return list; } /** * 构建全局参数列表 * @return */ private List globalParamBuilder(){ List pars = new ArrayList<>(); pars.add(parameterBuilder("token","令牌","string","header",false).build()); return pars; } /** * 创建参数 * @return */ private ParameterBuilder parameterBuilder(String name,String desc,String type ,String parameterType,boolean required) { ParameterBuilder tokenPar = new ParameterBuilder(); tokenPar.name(name).description(desc).modelRef(new ModelRef(type)).parameterType(parameterType).required(required).build(); return tokenPar; } /** * 创建全局响应值 * @return */ private List responseBuilder() { List responseMessageList = new ArrayList<>(); responseMessageList.add(new ResponseMessageBuilder().code(200).message("响应成功").build()); responseMessageList.add(new ResponseMessageBuilder().code(500).message("服务器内部错误").build()); return responseMessageList; } public static Predicate basePackage(final String basePackage) { return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true); } private static Function , Boolean> handlerPackage(final String basePackage) { return input -> { // 循环判断匹配 for (String strPackage : basePackage.split(splitor)) { boolean isMatch = input.getPackage().getName().startsWith(strPackage); if (isMatch) { return true; } } return false; }; } private static Optional extends Class>> declaringClass(RequestHandler input) { return Optional.fromNullable(input.declaringClass()); } }
3.建立监听器和拦截器(将返回的日期格式数据由时间戳重新转换为日期格式)
//授权检测的创建继承HandlerInterceptorAdapter import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.CrossOrigin; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Description:授权检测的创建继承HandlerInterceptorAdapter 方法 * Author: zyg * Date: 2020-03-27 13:45 */ @Component @CrossOrigin(origins = "*", maxAge = 3600) //实现跨域注解 //origin="*"代表所有域名都可访问 //maxAge飞行前响应的缓存持续时间的最大年龄,简单来说就是Cookie的有效期 单位为秒 //若maxAge是负数,则代表为临时Cookie,不会被持久化,Cookie信息保存在浏览器内存中,浏览器关闭Cookie就消失 public class LoginInterceptor extends HandlerInterceptorAdapter { /** * preHandle在业务处理器处理请求之前被调用。预处理,可以进行编码、安全控制等处理; */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { //未开启权限检测 跳过 // String url = request.getRequestURI();//这里打端点,页面访问swagger页面看看请求的什么路径 // System.out.println("访问接口地址为"+url); return true; } /** * postHandle在业务处理器处理请求执行完成后,生成视图之前执行。后处理(调用了Service并返回ModelAndView,但未进行页面渲染), * 有机会修改ModelAndView; */ @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } /** * afterCompletion在DispatcherServlet完全处理完请求后被调用,可用于清理资源等。返回处理(已经渲染了页面), * 可以根据ex是否为null判断是否发生了异常,进行日志记录; */ @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { } }
//拦截器用来放行swagger和自定义的docs页面 import com.alibaba.fastjson.serializer.SerializerFeature; import com.alibaba.fastjson.support.config.FastJsonConfig; import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter; import com.mes7801.server.config.interceptor.LoginInterceptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import org.springframework.web.servlet.config.annotation.*; import java.util.ArrayList; import java.util.List; /** * Description:放开swagger访问 * Author: zyg * Date: 2020-03-27 13:32 */ @Configuration public class WebMvcConfigurerAdapter extends WebMvcConfigurationSupport { @Autowired private LoginInterceptor loginInterceptor; /** * WebMvcConfigurationSupport将返回值json中的日期格式转换为时间戳,这里转换成日期格式 */ @Override public void configureMessageConverters(List> converters) { //1.需要定义一个convert转换消息的对象; FastJsonHttpMessageConverter fastJsonHttpMessageConverter = new FastJsonHttpMessageConverter(); //2.添加fastJson的配置信息,比如:是否要格式化返回的json数据; FastJsonConfig fastJsonConfig = new FastJsonConfig(); fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat, SerializerFeature.WriteMapNullValue, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteNullListAsEmpty, SerializerFeature.WriteDateUseDateFormat); //3处理中文乱码问题 List fastMediaTypes = new ArrayList<>(); fastMediaTypes.add(MediaType.APPLICATION_JSON_UTF8); //4.在convert中添加配置信息. fastJsonHttpMessageConverter.setSupportedMediaTypes(fastMediaTypes); fastJsonHttpMessageConverter.setFastJsonConfig(fastJsonConfig); //5.将convert添加到converters当中. converters.add(fastJsonHttpMessageConverter); } /** * addInterceptor:需要一个实现HandlerInterceptor接口的拦截器实例 * addPathPatterns:用于设置拦截器的过滤路径规则 * excludePathPatterns:用于设置不需要拦截的过滤规则 */ @Override public void addInterceptors(InterceptorRegistry registry) { // 添加拦截接口请求处理, /** *此处拦截路径(/**) * 注意两个**。一个*号只拦截一级路径下,两个*号拦截所有 * 添加拦截的路径 * /为根路径 * /*为一级路径HandlerInterceptor * /** 为所有路径包括多级 */ registry.addInterceptor(loginInterceptor) .addPathPatterns("/**") .excludePathPatterns("/docs.html/**") .excludePathPatterns("/v2/**") .excludePathPatterns("/swagger-ui.html") .excludePathPatterns("/swagger-resources/**") .excludePathPatterns("/error") .excludePathPatterns("/webjars/**"); } @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //定向swagger 位置 String RESOURCE_LOCATION = "classpath:/META-INF/resources/"; registry.addResourceHandler("/**").addResourceLocations("classpath:/static/"); registry.addResourceHandler("swagger-ui.html").addResourceLocations(RESOURCE_LOCATION); registry.addResourceHandler("swagger-resources.html").addResourceLocations(RESOURCE_LOCATION); registry.addResourceHandler("docs.html").addResourceLocations(RESOURCE_LOCATION); registry.addResourceHandler("/webjars/**").addResourceLocations(RESOURCE_LOCATION+"webjars/"); } /** * 拦截后的跨域解决 * * @param registry */ @Override public void addCorsMappings(CorsRegistry registry) { /* * .addMapping("/cors/**") */ registry.addMapping("/cors/**") .allowedHeaders("*") .allowCredentials(true) .allowedMethods("GET","POST", "PUT", "OPTIONS") .allowedOrigins("*"); } /** * 处理拦截前处理检测 授权跨域问题 * */ @Bean public CorsFilter corsFilter() { UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfig()); return new CorsFilter(source); } /** * @return */ private CorsConfiguration corsConfig() { CorsConfiguration corsConfiguration = new CorsConfiguration(); // 请求常用的三种配置,*代表允许所有,当时你也可以自定义属性(比如header只能带什么,只能是post方式等等) corsConfiguration.addAllowedOrigin("*"); corsConfiguration.addAllowedHeader("*"); corsConfiguration.addAllowedMethod("*"); corsConfiguration.setAllowCredentials(true); corsConfiguration.setMaxAge(3600L); return corsConfiguration; } }
4.swagger接口复制过来添加你需要修改补充的内容
import com.google.common.base.Optional; import com.google.common.base.Strings; import com.mes7801.service.utils.ClassUint; import io.swagger.models.Path; import io.swagger.models.Swagger; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.core.env.Environment; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import org.springframework.web.util.UriComponents; import springfox.documentation.service.Documentation; import springfox.documentation.spring.web.DocumentationCache; import springfox.documentation.spring.web.json.Json; import springfox.documentation.spring.web.json.JsonSerializer; import springfox.documentation.swagger.common.HostNameProvider; import springfox.documentation.swagger2.mappers.ServiceModelToSwagger2Mapper; import springfox.documentation.swagger2.web.Swagger2Controller; import javax.servlet.http.HttpServletRequest; import java.util.*; /** * Description:获取swagger的接口文档并添加需要加入的接口 * Author: zyg * Date: 2020-03-30 15:07 */ @RestController @RequestMapping("/api") @Scope("request") public class GetSwaggerApiDocController { public static final String DEFAULT_URL = "/v2/api-docs"; private static final Logger LOGGER = LoggerFactory.getLogger(Swagger2Controller.class); private static final String HAL_MEDIA_TYPE = "application/hal+json"; private final String hostNameOverride; private final DocumentationCache documentationCache; private final ServiceModelToSwagger2Mapper mapper; private final JsonSerializer jsonSerializer; @Autowired public GetSwaggerApiDocController(Environment environment, DocumentationCache documentationCache, ServiceModelToSwagger2Mapper mapper, JsonSerializer jsonSerializer) { this.hostNameOverride = environment.getProperty("springfox.documentation.swagger.v2.host", "DEFAULT"); this.documentationCache = documentationCache; this.mapper = mapper; this.jsonSerializer = jsonSerializer; } /** * 获取swagger返回的 json * //@RequestParam(value = "condition") String condition, */ @RequestMapping(value = "/swagger2", method = RequestMethod.GET) public ResponseEntitygetDocumentation(@RequestParam(value = "group", required = false) String swaggerGroup, HttpServletRequest servletRequest) { String groupName = (String) Optional.fromNullable(swaggerGroup).or("spring-test-interface"); Documentation documentation = this.documentationCache.documentationByGroup(groupName); if (documentation == null) { LOGGER.warn("Unable to find specification for group {}", groupName); return new ResponseEntity(HttpStatus.NOT_FOUND); } else { //获取swagger返回的json Swagger swagger = this.mapper.mapDocumentation(documentation); UriComponents uriComponents = HostNameProvider.componentsFrom(servletRequest, swagger.getBasePath()); swagger.basePath(Strings.isNullOrEmpty(uriComponents.getPath()) ? "/" : uriComponents.getPath()); if (Strings.isNullOrEmpty(swagger.getHost())) { swagger.host(this.hostName(uriComponents)); } /************************这里加入你想加入的代码****************************/ /************************因为这里还没有生成转换后的swagger的json****************************/ swagger.setPaths(pathTmp); return new ResponseEntity(this.jsonSerializer.toJson(swagger), HttpStatus.OK); } } private String hostName(UriComponents uriComponents) { if ("DEFAULT".equals(this.hostNameOverride)) { String host = uriComponents.getHost(); int port = uriComponents.getPort(); return port > -1 ? String.format("%s:%d", host, port) : host; } else { return this.hostNameOverride; } }
5. 自定义页面的引入
5.1.可以在项目的基础上新增一个servlet ,指向对应的html文件
html文件里再去解析json,并渲染UI
5.2.新建一个项目,用webjars将前端资源打成jar包,再供其他项目使用
项目结构如图
这里自己就可以改造docs.js 把访问路径改为 GetSwaggerApiDocController的访问路径swagger2,现在返回的swagger文档是自己改造过的,docs.html也可以自己改造
感谢 https://blog.csdn.net/tuposky/article/details/77965139