我面临 Jersey 2 文件上传问题。服务器端的输入流为空。使用 jersey 2.21、jackson 2.5.4、spring 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)。
Jersey 配置:
@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 文件上传代码运行良好,InputStream 即将推出。但 Jersey 代码不起作用。使用相同的客户端代码来测试 API。
工作 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);
}
我想将 Jersey 用于 api,但不想使用 Spring REST。
有人可以帮忙解决这个问题吗?
最佳答案
我发现当您使用 @FormDataParam("file") InputStream 文件方法时,在幕后参数永远不会被处理,因为 jersey 实际上是在寻找文件。发生的情况(至少从我到目前为止读到的内容来看)是,当请求传入 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;
}
}
这将允许 jersey 检测 InputStream。
您还必须更改 createValueFactory 方法以反射(reflect)新的 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 提取模块源代码并进行更改编译...您必须基本上重新创建以下类才能引用新类通过引用链。
类(class):
- FormDataParamValueFactoryProvider
- FormDataParamInjectionFeature(引用:FormDataParamValueFactoryProvider)
- MultiPartFeature(引用:FormDataParamInjectionFeature)
完成此操作后,您可以使用@FormDataParam("file") InputStream,它将按预期工作。
关于java - Jersey 2 多部分/表单数据问题。输入流为空(可用=0),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32426291/