解决Spring3.x版本中自定义控制器建议影响swagger的问题

  • 问题
    集成springdoc出现以下这个界面:


    image.png

    当前使用版本:

<dependency>
     <groupId>org.springdoc</groupId>
     <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
     <version>2.8.8</version>
 </dependency>

这是自动跳转到示例数据了:

<hgroup class="main" style="box-sizing: inherit; margin: 0px 0px 20px; color: rgb(59, 65, 81); font-family: sans-serif; font-size: medium; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; white-space: normal; background-color: rgb(250, 250, 250); text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;">

## Swagger Petstore <small style="box-sizing: inherit; font-size: 10px; background: rgb(125, 132, 146); border-radius: 57px; display: inline-block; margin: 0px 0px 0px 5px; padding: 2px 4px; position: relative; top: -5px; vertical-align: super;"><pre class="version" style="box-sizing: border-box; font-family: sans-serif; font-size: 14px; color: rgb(255, 255, 255); margin: 0px; padding: 0px;"> 1.0.7 </pre></small> <small class="version-stamp" style="box-sizing: inherit; font-size: 10px; background: rgb(137, 191, 4); border-radius: 57px; display: inline-block; margin: 0px 0px 0px 5px; padding: 2px 4px; position: relative; top: -5px; vertical-align: super;"><pre class="version" style="box-sizing: border-box; font-family: sans-serif; font-size: 14px; color: rgb(255, 255, 255); margin: 0px; padding: 0px;">OAS 2.0</pre></small> 

<pre class="base-url" style="box-sizing: border-box; font-family: monospace; font-size: 12px; color: rgb(59, 65, 81); margin: 0px; font-weight: 300 !important;">[ Base URL: petstore.swagger.io/v2 ]</pre>

[https://petstore.swagger.io/v2/swagger.json](https://petstore.swagger.io/v2/swagger.json)</hgroup>

This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io/) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters.

[Terms of service](http://swagger.io/terms/)

[Contact the developer](mailto:apiteam@swagger.io)

[Apache 2.0](http://www.apache.org/licenses/LICENSE-2.0.html)

[Find out more about Swagger](http://swagger.io/)

  • 自定义统一处理API返回格式注解
/*
 * Copyright [2025-present] [Liu Rongming]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.wewetea.open.weadmin.common.aspect.api;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface IgnoreRestFulAPI {

}
  • 自定义注解实现:
/*
 * Copyright [2025-present] [Liu Rongming]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.wewetea.open.weadmin.common.aspect.api;

import com.alibaba.fastjson.JSON;
import com.wewetea.open.weadmin.model.dto.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

 @Slf4j
@RestControllerAdvice
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public  class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
         log.debug("GlobalResponseAdvice supports: " +returnType.getDeclaringClass().getName());
        // 如果已经是 Result 包装过的就跳过
        // 如果标注有 @IgnoreResponseBody 注解的也跳过
        // 如果是springdoc的也跳过,目的为了去兼容swagger3
        return !(returnType.getParameterType().isAssignableFrom(Result.class)
                || returnType.hasMethodAnnotation(IgnoreRestFulAPI.class)
                || returnType.getDeclaringClass().getName().contains("springdoc")
        );
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        log.debug("GlobalResponseAdvice beforeBodyWrite: " +returnType.getDeclaringClass().getName());
        // String类型不能直接包装
        // warning: RestController方法上返回值类型为String时,默认响应的Content-Type是text/plain,
        // 需要手动指定为application/json 才能对结果进行包装成 json
        if (returnType.getParameterType().isAssignableFrom(String.class)) {// 将数据包装在Result里后转换为json串进行返回
            return JSON.toJSONString(Result.success(body));
        } else if (returnType.getParameterType().isAssignableFrom(Void.TYPE)) { // 如果返回值是void类型,直接返回200状态信息
            return Result.success();
        } else { // 其他情况也都返回一下信息
            return Result.success(body);
        }
    }
}
  • 解决问题
/*
 * Copyright [2025-present] [Liu Rongming]
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.wewetea.open.weadmin.common.aspect.api;

import com.alibaba.fastjson.JSON;
import com.wewetea.open.weadmin.model.dto.Result;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

 @Slf4j
@RestControllerAdvice
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
public  class GlobalResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
         log.debug("GlobalResponseAdvice supports: " +returnType.getDeclaringClass().getName());
        // 如果已经是 Result 包装过的就跳过
        // 如果标注有 @IgnoreResponseBody 注解的也跳过
        // 如果是springdoc的也跳过,目的为了去兼容swagger3
        return !(returnType.getParameterType().isAssignableFrom(Result.class)
                || returnType.hasMethodAnnotation(IgnoreRestFulAPI.class)
                || returnType.getDeclaringClass().getName().contains("springdoc")
        );
    }

    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
        log.debug("GlobalResponseAdvice beforeBodyWrite: " +returnType.getDeclaringClass().getName());
        // String类型不能直接包装
        // warning: RestController方法上返回值类型为String时,默认响应的Content-Type是text/plain,
        // 需要手动指定为application/json 才能对结果进行包装成 json
        if (returnType.getParameterType().isAssignableFrom(String.class)) {// 将数据包装在Result里后转换为json串进行返回
            return JSON.toJSONString(Result.success(body));
        } else if (returnType.getParameterType().isAssignableFrom(Void.TYPE)) { // 如果返回值是void类型,直接返回200状态信息
            return Result.success();
        } else { // 其他情况也都返回一下信息
            return Result.success(body);
        }
    }
}

处理很简单,就是把它跳过不处理:

  • 其中关键的代码:
||returnType.getDeclaringClass().getName().contains("springdoc")

这样,就可以兼容处理了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容