Swagger Springfox全局响应头

Swagger Springfox全局响应头,swagger,swagger-ui,springfox,Swagger,Swagger Ui,Springfox,在我的spring boot rest API中,我为每个端点的每个响应(不考虑方法)返回一个唯一的请求id头“x-request-id”。我可以用如下方式添加: @ApiResponses(value = { @ApiResponse( code = 200, message = "Successful status response", responseHeaders = {

在我的spring boot rest API中,我为每个端点的每个响应(不考虑方法)返回一个唯一的请求id头“x-request-id”。我可以用如下方式添加:

@ApiResponses(value = { 
    @ApiResponse(
            code = 200, 
            message = "Successful status response", 
            responseHeaders = {
                    @ResponseHeader(
                            name = "x-request-id", 
                            description = "auto generated unique request id", 
                            response = String.class)})
})

这工作得很好,我可以在大摇大摆的UI中看到它。然而,对每个端点执行此操作是一个乏味的+维护问题。我希望在全局范围内执行此操作,但仅使用.globalResponseMessage选项显示关于全局响应消息-我找不到全局响应标题的任何内容。

最终创建了一个注释来处理此问题:

package com.abc.xyz.api.docs.annotations;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import io.swagger.annotations.ResponseHeader;

import com.abc.xyz.api.constants.ApiConstants;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@ApiResponses(value = { 
    @ApiResponse(
            code = 200, 
            message = "Successful status response",
            responseHeaders = {
                    @ResponseHeader(
                            name = ApiConstants.REQUESTIDHEADER,
                            description = ApiConstants.REQUESTIDDESCRIPTION, 
                            response = String.class)}),
    @ApiResponse(
            code = 401, 
            message = "Successful status response",
            responseHeaders = {
                    @ResponseHeader(
                            name = ApiConstants.REQUESTIDHEADER,
                            description = ApiConstants.REQUESTIDDESCRIPTION, 
                            response = String.class)}),
    @ApiResponse(
            code = 403, 
            message = "Successful status response",
            responseHeaders = {
                    @ResponseHeader(
                            name = ApiConstants.REQUESTIDHEADER,
                            description = ApiConstants.REQUESTIDDESCRIPTION, 
                            response = String.class)}),
    @ApiResponse(
            code = 404, 
            message = "Successful status response",
            responseHeaders = {
                    @ResponseHeader(
                            name = ApiConstants.REQUESTIDHEADER,
                            description = ApiConstants.REQUESTIDDESCRIPTION, 
                            response = String.class)}),
    }
)
public @interface RequestIdMethod {};
有了它,我可以将其作为标记注释添加到我的方法前面:

@RequestMapping(value = "/heartbeat", method = RequestMethod.GET)
@RequestIdMethod
public Heartbeat checkHeartbeat() {
    return new Heartbeat(status);
}

这并不好,因为我需要为每个http返回代码重复整个@ApiResponse注释块(显然可能还有其他返回代码,但我只介绍了Springfox显示的默认代码)。如果有一种方法可以参数化整个@ApiResponse块,那就更好了。

我更新了我的Docket配置,在每个API上都包含全局头。希望这有帮助

返回新摘要(DocumentationType.SWAGGER_2)
.apiInfo(新的ApiInfoBuilder()
.contact(新联系人(“我的支持”,空,“我的电子邮件”))
.描述(“我的描述”)
.licenseUrl(“我的许可证”)
.头衔(“我的头衔”)
.termsOfServiceUrl(“我的条款和条件”)
.version(“我的版本”)
.build())
.globalOperationParameters(Collections.singletonList(新参数生成器()
.名称(“x-request-id”)
.modelRef(新modelRef(“字符串”))
.parameterType(“标题”)
。必填项(错误)
.build())
.选择()
.path(PathSelectors.regex(“/user*))
.build()
.directModelSubstitute(LocalDate.class、String.class)
.directModelSubstitute(LocalDateTime.class,String.class);

我知道我来晚了,但我确实找到了一种方法,使用反射在每个响应中全局添加一个标题(可能不是必需的,但事实证明这是我获取每个响应的最简单方法。您也可以检查所有
ApiResponses
注释,但有些注释是隐式添加的,因此没有使用该方法)

@组件
@订单(SwaggerPluginSupport.SWAGGER\u PLUGIN\u订单+10)
公共类RequestIdResponseHeaderPlugin实现OperationBuilderPlugin{
@凌驾
公共布尔支持(DocumentationType DocumentationType){
返回true;
}
@凌驾
公共无效应用(OperationContext OperationContext){
试一试{
//我们在这里使用反射,因为operationBuilder.build()方法会导致不同的操作ID
//我们只想访问私有字段“responseMessages”,将请求id头添加到其中
字段f=operationContext.operationBuilder().getClass().getDeclaredField(“responseMessages”);
f、 setAccessible(true);
Set responseMessages=(Set)f.get(operationContext.operationBuilder());
responseMessages.forEach(消息->{
int code=message.getCode();
Map Map=newhashmap();
put(“我的标题名”,新标题(null,null,newmodelref(“字符串”));
ResponseMessage ResponseMessage=新的ResponseMessageBuilder().code(code).headersWithDescription(map).build();
operationContext.operationBuilder().responseMessages(Collections.singleton(responseMessage));
});
}捕获(NoSuchFieldException | IllegalacessException e){
e、 printStackTrace();
}
}
}
在查看operation builder的方法
responseMessages()
后发现了这种方法。它根据状态代码在内部合并响应头,逻辑本身只会将头添加到现有响应头中


希望它能帮助某些人,因为它不需要您对每个端点都进行注释。

这会添加一个全局请求头,而不是响应头。您能添加一个全局响应头吗?嗨,Soumen,我为这个非常古老的线程添加了一个答案……希望它能帮助您
@Component
@Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 10)
public class RequestIdResponseHeaderPlugin implements OperationBuilderPlugin {

  @Override
  public boolean supports(DocumentationType documentationType) {
    return true;
  }

  @Override
  public void apply(OperationContext operationContext) {
    try {
      // we use reflection here since the operationBuilder.build() method would lead to different operation ids
      // and we only want to access the private field 'responseMessages' to add the request-id header to it
      Field f = operationContext.operationBuilder().getClass().getDeclaredField("responseMessages");
      f.setAccessible(true);
      Set<ResponseMessage> responseMessages = (Set<ResponseMessage>) f.get(operationContext.operationBuilder());
      responseMessages.forEach(message -> {
        int code = message.getCode();
        Map<String, Header> map = new HashMap<>();
        map.put("my-header-name", new Header(null, null, new ModelRef("string")));
        ResponseMessage responseMessage = new ResponseMessageBuilder().code(code).headersWithDescription(map).build();
        operationContext.operationBuilder().responseMessages(Collections.singleton(responseMessage));
      });
    } catch (NoSuchFieldException | IllegalAccessException e) {
      e.printStackTrace();
    }
  }
}