Spring Boot Swagger多部分包含JSON内容和附件

问题描述

我需要在单个请求中使用Swagger-3上传所有文件内容以及一些元数据信息作为JSON。因此,我对以下配置进行了调整:

"requestBody": {
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object","properties": {
                    "Metadata": {
                        "$ref": "#/components/schemas/Attachment"
                    },"file": {
                        "type": "string","format":"binary","description": "Actual File Attachment"
                    }
                }
              }
            }
          },"description": "The Attachment record / entry be created","required": true
 }

当我构建控制器对象时,它转换为以下内容

@ApiOperation(value = "Upload attachments to a existing Ticket",nickname = "uploadAttachment",notes = "",response = Attachment.class,responseContainer = "List",tags={ "changeRequest",})
@RequestMapping(value = "/changeRequest/attachment/{id}",produces = { "application/json" },consumes = { "multipart/form-data" },method = RequestMethod.POST)
public ResponseEntity<List<Attachment>> uploadAttachment(@ApiParam(value = "Identifier of the Change Request",required=true) @PathVariable("id") String id,@ApiParam(value = "Application ID invoking the call",required=true) @RequestHeader(value="X-app-id",required=true) String xAppId,@NotNull @ApiParam(value = "To track unique transaction across multiple systems for audit trail",required = true) @Valid @RequestParam(value = "X-Transaction-Id",required = true) String xTransactionId,@ApiParam(value = "Authorization header" ) @RequestHeader(value="authorization",required=false) String authorization,@ApiParam(value = "",defaultValue="null") @RequestParam(value="Metadata",required=false)  Attachment Metadata,@ApiParam(value = "file detail") @Valid @RequestPart("file") multipartfile file) {
    
    ResponseEntity<List<Attachment>> responseEntity = new ResponseEntity<>(HttpStatus.OK);
    responseEntity.getBody().add(Metadata);
    return responseEntity;

}

以下是附件架构定义:

"Attachment": {
            "type": "object","description": "Attachment Metadata deFinition","properties": {
                "description": {
                    "type": "string","description": "A narrative text describing the content of the attachment"
                },"href": {
                    "type": "string","description": "Reference of the attachment"
                },"id": {
                    "type": "string","description": "Unique identifier of the attachment"
                },"mimeType": {
                    "type": "string","description": "The mime type of the document as defined in RFC 2045 and RFC 2046 specifications."
                },"name": {
                    "type": "string","description": "The name of the file"
                },"path": {
                    "type": "string","description": "The path of the attached file"
                },"size": {
                    "type": "integer","description": "The size of the file (sizeUnit if present indicates the unit,otherwise kilobytes is the default)."
                },"sizeUnit": {
                    "type": "integer","description": "The unit size for expressing the size of the file (MB,kB...)"
                },"url": {
                    "type": "string","description": "Uniform Resource Locator,is a web page address (a subset of URI)"
                },"validFor": {
                    "$ref": "#/components/schemas/TimePeriod","description": "Period of validity of the attachment"
                },"@type": {
                    "type": "string","description": "The class type of the actual resource (for type extension)."
                },"@schemaLocation": {
                    "type": "string","description": "A link to the schema describing a resource (for type extension)."
                },"@baseType": {
                    "type": "string","description": "The base type for use in polymorphic collections"
                }
            }
}

在上面的示例中,附件元数据是我试图作为SOAP API测试的一部分传递的内容。但是我一直收到以下错误

Mon Oct 12 17:06:28 IST 2020:DEBUG:<< "{"timestamp":"2020-10-12T11:36:28.371Z","status":500,"error":"Internal Server Error","message":"Failed to convert value of type 'java.lang.String' to required type 'com.bell.na.nt.change.swagger.model.Attachment'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'com.bell.na.nt.change.swagger.model.Attachment': no matching editors or conversion strategy found","path":"/changeManagement/api/v1/changeRequest/attachment/1234"}"

为什么字符串没有被转换并映射到JSON对象。不知道我错过了什么。以下是我的json的样子。

{"@baseType": "string","@schemaLocation": "string","@type": "string","description": "string","href": "string","id": "string","mimeType": "string","name": "string","path": "string","size": 0,"sizeUnit": 0,"url": "string","validFor": {       "endDateTime": "2020-10-11T19:06:40.586Z","startDateTime": "2020-10-11T19:06:40.586Z"}}

Postman Request

解决方法

结果是我必须添加一个转换器,用于将JSON的字符串表示形式转换为所需的Swagger生成的Model对象,例如:

@Component
public class StringToAttachmentObjectConverter implements Converter<String,Attachment> {
    
    Logger logger = LoggerFactory.getLogger(StringToAttachmentObjectConverter.class);
    
    @Autowired
    private ObjectMapper objectMapper;
    
    DocumentContext docContext = null;

    @Override
    public Attachment convert(String source) {
        try {
            String sourceString = JsonPath.using(NetsUtilityJSONDatumUtils.jsonPathConfig).parse(source).jsonString();
            return objectMapper.readValue(sourceString,Attachment.class);
        } catch (JsonParseException e) {
            logger.error("Error While converting the String: \n" + source,e);
        } catch (JsonMappingException e) {
            logger.error("Error While converting the String: \n" + source,e);
        } catch (IOException e) {
            logger.error("Error While converting the String: \n" + source,e);
        }
        return null;
    }
}

不确定是否有更好的方法或我是否违反了最佳做法,但这对我来说是成功的秘诀。