Как настроить Swagger UI, Джерси и загрузку файлов?

у меня есть сервис Джерси с методом загрузки файлов, который выглядит так (упрощенно):

@POST
@Path("/{observationId : [a-zA-Z0-9_]+}/files")
@Produces({ MediaType.APPLICATION_JSON})
@Consumes(MediaType.MULTIPART_FORM_DATA)
@ApiOperation(
    value = "Add a file to an observation",
    notes = "Adds a file to an observation and returns a JSON representation of the uploaded file.",
    response = ObservationMediaFile.class
)
@ApiResponses({
    @ApiResponse(code = 404, message = "Observation not found. Invalid observation ID."),
    @ApiResponse(code = 406, message= "The media type of the uploaded file is not supported. Currently supported types are 'images/*' where '*' can be 'jpeg', 'gif', 'png' or 'tiff',")
})
public RestResponse<ObservationMediaFile> addFileToObservation(
    @PathParam("observationId") Long observationId,
    @FormDataParam("file") InputStream is,
    @FormDataParam("file") FormDataContentDisposition fileDetail,
    @FormDataParam("fileBodyPart") FormDataBodyPart body
){

    MediaType type = body.getMediaType();

    //Validate the media type of the uploaded file...
    if( /* validate it is an image */    ){
        throw new NotAcceptableException("Not an image. Get out.");
    }

    //do something with the content of the file
    try{
        byte[] bytes = IOUtils.toByteArray(is);
    }catch(IOException e){}

    //return response...
}

он работает, и я могу проверить его успешно с помощью расширения Postman в Chrome.

однако Swagger видит 2 параметра с именем "файл". Почему-то кажется, что он понимает, что и FormDataContentDisposition параметр на самом деле 2 части одного и того же file параметр, но он не видит, что для

2 ответов


создайте фильтр swagger для Джерси, а затем отметьте параметр как внутреннюю или другую строку, на которой вы фильтруете. Это также показано в этом примере:

https://github.com/wordnik/swagger-core/blob/master/samples/java-jaxrs/src/main/java/com/wordnik/swagger/sample/util/ApiAuthorizationFilterImpl.java

ваш метод обслуживания будет иметь эту аннотацию параметра

@ApiParam(access = "internal") @FormDataParam("file") FormDataBodyPart body,

ваш фильтр будет выглядеть, как это:

public boolean isParamAllowed(Parameter parameter, Operation operation, ApiDescription api,
        Map<String, List<String>> params, Map<String, String> cookies, Map<String, List<String>> headers) {
    if ((parameter.paramAccess().isDefined() && parameter.paramAccess().get().equals("internal")))
        return false;
    else
        return true;
}

зарегистрируйте свой фильтр swagger для Джерси, а затем он не вернет это поле, и swagger-ui не покажет его, что исправит вашу проблему с загрузкой.

<init-param>
      <param-name>swagger.filter</param-name>
      <param-value>your.company.package.ApiAuthorizationFilterImpl</param-value>
    </init-param>

неясно, когда это было добавлено в Джерси, но примечание в самом конце раздела Multipart говорит:"@FormDataParam аннотация также может быть использована на полях". Конечно, вы можете сделать это:

@FormDataParam(value="file") FormDataContentDisposition fileDisposition;
@FormDataParam("fileBodyPart") FormDataBodyPart body;

@Path("/v1/source")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces({ MediaType.APPLICATION_JSON})
@ApiOperation(
        value = "Create a new Source from an uploaded file.",
        response = Source.class
        )
public Response makeSource(
        @FormDataParam(value="file") InputStream inputStream
        )
{
    logger.info(fileDisposition.toString());
    return makeSourceRaw(inputStream, fileDisposition.getFileName());
}

Это обеспечивает FormDataContentDisposition но делает его "невидимым" для чванства.

обновление: это работает, но не в том случае, если определены другие ресурсы (аннотации@Path), которые не принимают FormDataContentDisposition. Если есть затем Джерси терпит неудачу во время выполнения, потому что он не может заполнить поле fileDisposition.

лучшее решение, если вы используете последнюю версию Swagger, чтобы просто отметить параметр как скрытый.

@FormDataParam("fileBodyPart") FormDataBodyPart body;

@Path("/v1/source")
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces({ MediaType.APPLICATION_JSON})
@ApiOperation(
        value = "Create a new Source from an uploaded file.",
        response = Source.class
        )
public Response makeSource(
        @FormDataParam(value="file") InputStream inputStream,
        @ApiParam(hidden=true) @FormDataParam(value="file") FormDataContentDisposition fileDisposition;

        )
{
    logger.info(fileDisposition.toString());
    return makeSourceRaw(inputStream, fileDisposition.getFileName());
}