Jersey 2 multipart / form-data问题。 InputStream为空(可用= 0)

时间:2015-09-06 17:27:15

标签: java spring jersey jackson tomcat8

我正面临着球衣2文件上传的问题。输入流对服务器端是空的。使用jersey 2.21,jackson 2.5.4,弹簧4.1.6.RELEASE(仅适用于DI)& spring security 4.0.2.RELEASE用于安全性。使用JDK 1.8.0_25和Tomcat 8.0.26。

代码:

@POST
@Path("/upload")
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.MULTIPART_FORM_DATA)
public SimpleResult categoryImageUpload(
        @FormDataParam("file") InputStream file,
        @FormDataParam("file") FormDataBodyPart bodyPart) {
        return SimpleResult.success("File Uploaded successfully!!!");
}

文件详细信息将在FormDataBodyPart中出现,但InputStream将变为空(可用= 0)。

泽西岛配置:

@ApplicationPath("api-business")
public class BusinessApplicationConfig extends ResourceConfig {
    public BusinessApplicationConfig() {
        register(RequestContextFilter.class);
        register(MultiPartFeature.class);
        packages("com.smx.biz.api");
    }
}

pom.xml中的依赖项:

    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.5.4</version>
    </dependency>

    <!--Jersey-->
    <dependency>
        <groupId>org.glassfish.jersey.core</groupId>
        <artifactId>jersey-server</artifactId>
        <version>2.21</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.containers</groupId>
        <artifactId>jersey-container-servlet</artifactId>
        <version>2.21</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-json-jackson</artifactId>
        <version>2.21</version>
    </dependency>

    <dependency>
        <groupId>org.glassfish.jersey.media</groupId>
        <artifactId>jersey-media-multipart</artifactId>
        <version>2.21</version>
    </dependency>

    <!-- Jersey + Spring -->
    <dependency>
        <groupId>org.glassfish.jersey.ext</groupId>
        <artifactId>jersey-spring3</artifactId>
        <version>2.21</version>
    </dependency>

有人可以帮忙解决这个问题吗?我错过了什么吗?

PS:Spring REST文件上传代码运行良好&amp; InputStream即将到来。但泽西岛代码不起作用。使用相同的客户端代码来测试apis。

使用Spring REST api代码:

@ResponseStatus(HttpStatus.OK)
@RequestMapping(value = "/business/upload", method = RequestMethod.POST, consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
ImageItem categoryPhotoUpload(@RequestBody MultipartFile file) {
    return uploadService.uploadFile(file);
}

我想将泽西用于apis&amp;我不想使用Spring REST。

有人可以帮忙解决这个问题吗?

3 个答案:

答案 0 :(得分:1)

我发现当你使用@FormDataParam(&#34; file&#34;)InputStream文件方法时,参数永远不会被处理,因为jersey实际上正在寻找文件。会发生什么(至少从我到目前为止所读到的)是当请求进入泽西时,使用mimepull库进行一些mime检查,然后将传入的文件保存为临时文件。问题是,如果您的参数类型是InputStream,则jersey不会处理它,因为没有为InputStream注册ValueFactory。因此,为了实现这一点,您必须执行以下操作。

FormDataParamValueFactoryProvider内部

添加以下实现:

private final class InputStreamFactory extends ValueFactory<InputStream> {

    private final String name;

    public InputStreamFactory(final String name) {
        this.name = name;
    }

    @Override
    public InputStream provide() {
        LOG.info("Processing paramaeter [" + name + "]");
        final FormDataBodyPart part = getEntity().getField(name);
        final BodyPartEntity entity = part != null ? part.getEntityAs(BodyPartEntity.class) : null;

        if (entity != null) {
            try {
                // Create a temporary file.
                final File file = Utils.createTempFile();

                // Move the part (represented either via stream or file) to the specific temporary file.
                entity.moveTo(file);

                //Retreive file via a FileInputStream
                return new FileInputStream(file);
            } catch (final Exception ex) {
                // Unable to create a temporary file or move the file.
                LOG.warn("Error while processing InputStream. " + ex);
            }
        }

        return null;
    }

}

这将允许运动衫检测InputStream。

您还必须更改createValueFactory方法以反映新的ValueFactoryProvider。

@Override
protected Factory<?> createValueFactory(final Parameter parameter) {
    final Class<?> rawType = parameter.getRawType();
    if (Parameter.Source.ENTITY == parameter.getSource()) {
        if (FormDataMultiPart.class.isAssignableFrom(rawType)) {
            return new FormDataMultiPartFactory();
        } else {
            return null;
        }
    } else if (parameter.getSourceAnnotation().annotationType() == FormDataParam.class) {
        final String paramName = parameter.getSourceName();
        if (paramName == null || paramName.isEmpty()) {
            // Invalid query parameter name
            return null;
        }

        if (Collection.class == rawType || List.class == rawType) {
            final Class clazz = ReflectionHelper.getGenericTypeArgumentClasses(parameter.getType()).get(0);

            if (FormDataBodyPart.class == clazz) {
                // Return a collection of form data body part.
                return new ListFormDataBodyPartValueFactory(paramName);
            } else if (FormDataContentDisposition.class == clazz) {
                // Return a collection of form data content disposition.
                return new ListFormDataContentDispositionFactory(paramName);
            } else {
                // Return a collection of specific type.
                return new FormDataParamValueFactory(parameter, get(parameter));
            }
        } else if (FormDataBodyPart.class == rawType) {
            return new FormDataBodyPartFactory(paramName);
        } else if (FormDataContentDisposition.class == rawType) {
            return new FormDataContentDispositionFactory(paramName);
        } else if (File.class == rawType) {
            return new FileFactory(paramName);
        } else if (InputStream.class == rawType) {
            return new InputStreamFactory(paramName);
        } else {
            return new FormDataParamValueFactory(parameter, get(parameter));
        }
    }

    return null;
}

现在......在这里它变得很痛苦...如果你不从github拉出模块源并且用变化编译....你必须基本上重新创建以下类以便通过参考链引用新类。

类:

  • FormDataParamValueFactoryProvider
  • FormDataParamInjectionFeature(参考文献:FormDataParamValueFactoryProvider)
  • MultiPartFeature(引用:FormDataParamInjectionFeature)

完成后,您可以使用@FormDataParam(&#34; file&#34;)InputStream,它将按预期工作。

答案 1 :(得分:0)

确保注释中的字符串

@FormDataParam("theSameStringUsedInAnnotation") InputStream file

与您要发布的资源的名称完全匹配。

在我的情况下,我使用的是ExtJs fileupload,当你定义一个文件上传时,如:

xtype: 'filefield', name: 'theSameStringUsedInAnnotation',

你必须定义相同的字符串

答案 2 :(得分:-1)

在我的情况下,我将@FormDataParam("file") InputStream file替换为@FormDataParam("file") File file,然后它开始正常工作。