快速文件上传 java rest api mimepull 关闭多部分表单数据问题

quick file upload java rest api mimepull close issue with multi part form data

谁能帮我解决这个 mimepull 库问题?

我认为问题出在较新版本的库中已弃用的方法或依赖版本不匹配。或者球衣团队的某个人将一些未经测试的代码推送到生产环境。

我的问题与 org.glassfish.jersey.server.ContainerException: java.lang.NoSuchMethodError: org.jvnet.mimepull.MIMEMessage.close()V

我已经按照 File upload along with other object in Jersey restful web service

Glassfish 服务器:

java.lang.NoSuchMethodError: org.jvnet.mimepull.MIMEMessage.close()V
    at org.glassfish.jersey.media.multipart.internal.MultiPartReaderClientSide.getMimeParts(MultiPartReaderClientSide.java:276)
    at org.glassfish.jersey.media.multipart.internal.MultiPartReaderClientSide.readMultiPart(MultiPartReaderClientSide.java:231)
    at org.glassfish.jersey.media.multipart.internal.MultiPartReaderServerSide.readMultiPart(MultiPartReaderServerSide.java:91)
    at org.glassfish.jersey.media.multipart.internal.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:183)
    at org.glassfish.jersey.media.multipart.internal.MultiPartReaderClientSide.readFrom(MultiPartReaderClientSide.java:93)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.invokeReadFrom(ReaderInterceptorExecutor.java:256)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor$TerminalReaderInterceptor.aroundReadFrom(ReaderInterceptorExecutor.java:235)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
    at org.glassfish.jersey.server.internal.MappableExceptionWrapperInterceptor.aroundReadFrom(MappableExceptionWrapperInterceptor.java:74)
    at org.glassfish.jersey.message.internal.ReaderInterceptorExecutor.proceed(ReaderInterceptorExecutor.java:155)
    at org.glassfish.jersey.message.internal.MessageBodyFactory.readFrom(MessageBodyFactory.java:1085)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:852)
    at org.glassfish.jersey.message.internal.InboundMessageContext.readEntity(InboundMessageContext.java:786)
    at org.glassfish.jersey.server.ContainerRequest.readEntity(ContainerRequest.java:233)
    at org.glassfish.jersey.media.multipart.internal.FormDataParamValueFactoryProvider$ValueFactory.getEntity(FormDataParamValueFactoryProvider.java:132)
    at org.glassfish.jersey.media.multipart.internal.FormDataParamValueFactoryProvider$FormDataParamValueFactory.provide(FormDataParamValueFactoryProvider.java:282)
    at org.glassfish.jersey.server.spi.internal.ParamValueFactoryWithSource.provide(ParamValueFactoryWithSource.java:71)
    at org.glassfish.jersey.server.spi.internal.ParameterValueHelper.getParameterValues(ParameterValueHelper.java:89)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$AbstractMethodParamInvoker.getParamValues(JavaResourceMethodDispatcherProvider.java:127)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$VoidOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:143)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:99)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:389)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:347)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:102)
    at org.glassfish.jersey.server.ServerRuntime.run(ServerRuntime.java:309)
    at org.glassfish.jersey.internal.Errors.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:317)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:292)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1139)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:460)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:386)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:334)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1682)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:318)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:160)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:734)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:673)
    at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:99)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:174)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:416)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:283)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:459)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:167)
    at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206)
    at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180)
    at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:235)
    at org.glassfish.grizzly.filterchain.ExecutorResolver.execute(ExecutorResolver.java:119)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:283)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:200)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:132)
    at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:111)
    at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77)
    at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:536)
    at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access0(WorkerThreadIOStrategy.java:56)
    at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:591)
    at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:571)
    at java.lang.Thread.run(Thread.java:745)

控制器:

import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.core.MediaType;

import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
import org.glassfish.jersey.media.multipart.FormDataParam;

@Path("fu")
public class FUController {

    /** Logger */
    private static final BaseLogger LOGGER = BaseLogger.getLogger(FUController.class);

    /**
     * 
     * @param inputStream
     * @param fileDisposition
     * @param dpName
     * @return
     */
    @POST
    @Path("/")
    @Consumes(MediaType.MULTIPART_FORM_DATA)
    public void upload(@FormDataParam("fu") InputStream inputStream,
            @FormDataParam("fu") FormDataContentDisposition fileDisposition, @FormDataParam("msg") String dpName) {

        byte[] zipByte = null;
        String fileName = null;
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream();
                BufferedInputStream bis = new BufferedInputStream(inputStream)) {

            byte[] fbytes = new byte[1024];
            int length = 0;
            while ((length = bis.read(fbytes)) > 0) {
                bos.write(fbytes, 0, length);
            }
            zipByte = bos.toByteArray();
            fileName = fileDisposition.getFileName();
            System.out.println("filename = " + fileName + "\t zipByte = " + zipByte.length);
        } catch (IOException e) {
            LOGGER.error("Failure in file upload", e);
        }

        LOGGER.info("File {} is uploaded", fileName);
    }
}

应用程序配置:

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.core.Application;

import org.glassfish.jersey.media.multipart.MultiPartFeature;

public class ApplicationConfig extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> resources = new HashSet<>();
        // final Set<Class<?>> resources = new HashSet<Class<?>>();
        resources.add(MultiPartFeature.class);
        return resources;
    }

    @Override
    public Map<String, Object> getProperties() {
        Map<String, Object> props = new HashMap<>();
        props.put("jersey.config.server.provider.classnames", "org.glassfish.jersey.media.multipart.MultiPartFeature");
        return props;
    }
}

pom.xml:

<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-common</artifactId>
    <version>2.26</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-server</artifactId>
    <version>2.26</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.jvnet.mimepull/mimepull -->
<dependency>
    <groupId>org.jvnet.mimepull</groupId>
    <artifactId>mimepull</artifactId>
    <version>1.9.6</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-multipart</artifactId>
    <version>2.26</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
    <version>2.26</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.26</version>
</dependency>

怎么说"which version of jersey am i using?"

pom.xml

中缺少以下依赖项
<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet-core</artifactId>
    <version>2.26</version>
</dependency>

修复了问题。

我也添加了一些文件 I/O 控制和调试代码

@POST
@Path("/")
@Consumes(MediaType.MULTIPART_FORM_DATA)
public void upload(@FormDataParam("fu") InputStream inputStream,
        @FormDataParam("fu") FormDataContentDisposition formDataContentDisposition) {

    String zipByte = null;
    String fileName = null;
    String fileType = null;
    long fileSize = 0;
    OutputStream out = null;
    File target = null;
    try {

        fileName = formDataContentDisposition.getFileName();
        fileType = formDataContentDisposition.getType();
        fileSize = formDataContentDisposition.getSize();
        target = new File("/home/research/" + fileName);
        out = new FileOutputStream(target);
        LOGGER.info("filePath = " + target + " fileSize = " + fileSize + " fileType = " + fileType);
    } catch (FileNotFoundException e1) {
        LOGGER.error("Current Path not Found");
        e1.printStackTrace();
    }
    try (BufferedInputStream bis = new BufferedInputStream(inputStream)) {

        byte[] fbytes = new byte[1024];
        int length = 0;
        while ((length = bis.read(fbytes)) > 0) {
            out.write(fbytes, 0, length);
        }
        zipByte = out.toString();
        LOGGER.info("zipByte = " + zipByte.length());
    } catch (IOException e) {
        LOGGER.error("Failure in file upload", e);
    }
    LOGGER.info("File {} is uploaded at " + target.getAbsolutePath());
    try {
        LOGGER.info("File {} is uploaded at " + target.getCanonicalPath());
    } catch (IOException e) {
        LOGGER.error("Canonical Path not Found");
        e.printStackTrace();
    }
}

花了 5 天时间才找到这个!