先说坑,遇到个无法解决的问题
在2.0.6等后面的高版本中,由于升级了Springfox基础组件,如果开发者使用类似JRebel这类热加载插件的时候,会出现类字段没有的情况,目前没有办法解决springfox项目与JRebel插件的冲突,建议是不用JRebel
恰巧我用了JRebel,所以.使用老版本的Knife4j!!!
引入依赖
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
编写返回实体对象
注意此处的静态方法传入实体对象操作,需要在Rest
public class Rest<T> {
@ApiModelProperty(value = "返回对象")
private T data;
@ApiModelProperty(value = "响应码,正常为0")
private Integer errCode;
@ApiModelProperty(value = "响应信息")
private String msg;
public static Rest ok() {
return new Rest();
}
public static <T> Rest<T> ok(T data) {
Rest rest = new Rest();
rest.setData(data);
return rest;
}
public static Rest error() {
return error(500, "未知异常,请联系管理员");
}
public static Rest error(String msg) {
return error(500, msg);
}
public static Rest error(int code, String msg) {
Rest r = new Rest();
r.msg = msg;
r.errCode = code;
return r;
}
public Rest() {
this.msg = "success";
this.errCode = 0;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Integer getErrCode() {
return errCode;
}
public void setErrCode(Integer errCode) {
this.errCode = errCode;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
编写配置
@Configuration
@EnableSwagger2 //开启功能
@EnableKnife4j //开启功能
@Profile("test") //指定环境
public static class WfDocConfig {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2) //此处选择版本
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))//筛选注解,也可选择包路径
.paths(PathSelectors.any()) //匹配所有
.build()
.globalRequestParameters(getGlobalRequestParameters())//添加默认参数
.globalResponses(HttpMethod.GET, getGlobalResponseMessage())//添加响应状态码
.globalResponses(HttpMethod.POST, getGlobalResponseMessage())//添加响应状态码
;
}
//配置首页介绍
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.description("")
.contact(new Contact("爱看爱秀技术", "", ""))
.version("v1.0")
.title("好芳法API")
.build();
}
//配置默认的头信息,调试会自动带上
private List<RequestParameter> getGlobalRequestParameters() {
List<RequestParameter> parameters = new ArrayList<>();
parameters.add(new RequestParameterBuilder()
.name("sign")
.description("**签名,调试用含默认值**")
.required(true)
.in(ParameterType.HEADER)
.query(q -> q.model(m -> m.scalarModel(ScalarType.STRING)))
.required(false).example(new Example("xxx"))
.build());
return parameters;
}
//显示自定义状态码
private List<Response> getGlobalResponseMessage() {
List<Response> responseList = new ArrayList<>();
responseList.add(new ResponseBuilder().code("errCode : 200").description("前端重复提交").build());
responseList.add(new ResponseBuilder().code("errCode : 0").description("请求成功").build());
return responseList;
}
}
效果
注意
有时候配置了拦截器,需要排除swagger的请求地址,如:
excludePath.add("/doc.html");
excludePath.add("/swagger-resources");
excludePath.add("/favicon.ico");
excludePath.add("/v3/api-docs");
excludePath.add("/v2/api-docs");
excludePath.add("/webjars/**");
排除不想展示的接口(比如不想展示DELETE,HEAD等http动词接口)
如果我们的接口使用的@RequestMapping,并且没有指定方法,则默认会展示所有请求方法;当接口很多的时候,返回的数据量很大,响应慢,并且会造成浏览器卡顿;
(1)配置方式:
@Bean
public Docket createRestApi2() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("好芳法接口")
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.wfcm.controller"))
.paths(PathSelectors.any())
.build()
.globalResponseMessage(RequestMethod.GET, getGlobalResponseMessage())//添加响应状态码
.globalResponseMessage(RequestMethod.POST, getGlobalResponseMessage())//添加响应状态码
;
}
@Bean
public Docket createRestApi2() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("好芳法接口")
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.wfcm.controller"))
.apis(customRequestHandlers())
.paths(PathSelectors.any())
.build()
.globalResponseMessage(RequestMethod.GET, getGlobalResponseMessage())//添加响应状态码
.globalResponseMessage(RequestMethod.POST, getGlobalResponseMessage())//添加响应状态码
;
}
但是这种方式有个缺点,会把没指定方法的@RequestMapping排除;
(2)使用@ControllerAdvice增强器
@Profile("test")
@ControllerAdvice
public class ResponseAdviceController implements ResponseBodyAdvice {
TimedCache<String, Object> swaggerMap = CacheUtil.newTimedCache(1000 * 10);
@Override
public boolean supports(MethodParameter returnType, Class converterType) {
return true;
}
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
if ("/wfcm_api/v2/api-docs".equals(request.getURI().getPath())) {
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest();
if (body == null) {
return body;
}
JSONObject bodyJson = JSON.parseObject(JSON.toJSONString(body));
JSONObject paths = bodyJson.getJSONObject("paths");
if (paths == null) {
return body;
}
Object result = swaggerMap.get(servletRequest.getParameter("group"));
if (result != null) {
return result;
}
paths.entrySet().parallelStream().forEach(stringObjectEntry -> {
Object value = stringObjectEntry.getValue();
if (value == null) {
return;
}
JSONObject methods = JSON.parseObject(value.toString());
methods.remove("put");
methods.remove("delete");
methods.remove("patch");
methods.remove("options");
methods.remove("head");
stringObjectEntry.setValue(methods);
});
String resultJson = bodyJson.toJSONString();
swaggerMap.put(servletRequest.getParameter("group"), resultJson);
return resultJson;
}
return body;
}
}
这里我使用了个定时缓存,其实不用也行;由于我使用了jrebel热更新,所以如果不定时过期会出现数据无法更新问题;
本文由 GY 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:
2021/12/29 16:26