做文件上传功能时,dubbo对MultipartFile文件传输时,一个bug:Fail to decode request due to: RpcInvocation

三月 22, 2019 2:37:27 下午 org.apache.catalina.core.StandardWrapperValve invoke
严重: Servlet.service() for servlet [taotao-manager-web] in context with path [] threw exception [Request processing failed; nested exception is com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method uploadPicture in the service com.taotao.manager.service.PictureService. Tried 3 times of the providers [192.168.138.1:20880] (1/1) from the registry 192.168.138.128:2181 on the consumer 192.168.138.1 using the dubbo version 2.5.3. Last error is: Failed to invoke remote method: uploadPicture, provider: dubbo://192.168.138.1:20880/com.taotao.manager.service.PictureService?anyhost=true&application=taotao-manager-web&check=false&dubbo=2.5.3&interface=com.taotao.manager.service.PictureService&methods=uploadPicture&pid=20660&revision=1.0-SNAPSHOT&side=consumer&timeout=1000000&timestamp=1553236601190, cause: Fail to decode request due to: RpcInvocation [methodName=uploadPicture, parameterTypes=null, arguments=null, attachments={path=com.taotao.manager.service.PictureService, input=883, dubbo=2.5.3, version=0.0.0}]] with root cause
com.alibaba.dubbo.remoting.RemotingException: Fail to decode request due to: RpcInvocation [methodName=uploadPicture, parameterTypes=null, arguments=null, attachments={path=com.taotao.manager.service.PictureService, input=883, dubbo=2.5.3, version=0.0.0}]
    at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.returnFromResponse(DefaultFuture.java:190)
    at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:110)
    at com.alibaba.dubbo.remoting.exchange.support.DefaultFuture.get(DefaultFuture.java:84)
    at com.alibaba.dubbo.rpc.protocol.dubbo.DubboInvoker.doInvoke(DubboInvoker.java:96)
    at com.alibaba.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:144)
    at com.alibaba.dubbo.rpc.listener.ListenerInvokerWrapper.invoke(ListenerInvokerWrapper.java:74)
    at com.alibaba.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:75)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.invoke(FutureFilter.java:53)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.filter.ConsumerContextFilter.invoke(ConsumerContextFilter.java:48)
    at com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:91)
    at com.alibaba.dubbo.rpc.protocol.InvokerWrapper.invoke(InvokerWrapper.java:53)
    at com.alibaba.dubbo.rpc.cluster.support.FailoverClusterInvoker.doInvoke(FailoverClusterInvoker.java:77)
    at com.alibaba.dubbo.rpc.cluster.support.AbstractClusterInvoker.invoke(AbstractClusterInvoker.java:227)
    at com.alibaba.dubbo.rpc.cluster.support.wrapper.MockClusterInvoker.invoke(MockClusterInvoker.java:72)
    at com.alibaba.dubbo.rpc.proxy.InvokerInvocationHandler.invoke(InvokerInvocationHandler.java:52)
    at com.alibaba.dubbo.common.bytecode.proxy2.uploadPicture(proxy2.java)
    at com.taotao.manager.controller.PictureController.uploadPicture(PictureController.java:25)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:222)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:814)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:737)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:969)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:871)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:845)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
View Code

 

问题解决:

1、通过删代码试验得出的结论是:采用dubbo对MultipartFile文件进行传输时,会报invoke method 错误,是因为dubbo并不能跨系统传递这个对象,可以采用Hessian

 <dependency>
            <groupId>com.caucho</groupId>
            <artifactId>hessian</artifactId>
            <version>4.0.7</version>
        </dependency>
        <dependency>
            <groupId>org.mortbay.jetty</groupId>
            <artifactId>jetty</artifactId>
            <version>6.1.26</version>
            <exclusions>
                 <exclusion>
                     <groupId>org.mortbay.jetty</groupId>
                    <artifactId>servlet-api</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

要注意,jetty包中要排除servlet-api包的依赖,否则会报错,Tomcat不能正常启动。

 

2、在spring配置文件里面配置文件上传

<!-- 多部分文件上传 文件上传解析器 -->
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize" value="104857600" />
        <property name="maxInMemorySize" value="4096" />
        <property name="defaultEncoding" value="UTF-8"></property>
    </bean>

 

3、在service层就是我们的provider里面将需要的服务注册成Hessian协议的就可以了。 
我的spring-service.xml

<!-- 配置dubbo -->
    <!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="taotao-manager-service" />

    <!-- 使用multicast广播注册中心暴露服务地址 -->
    <dubbo:registry protocol="zookeeper" address="192.168.138.128:2181" />

    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880"/>
    <dubbo:protocol name="hessian" port="20887"/>

    <!-- 声明需要暴露的服务接口 -->
     <dubbo:service interface="com.taotao.manager.service.TestService" ref="testServiceImpl" />
     <dubbo:service interface="com.taotao.manager.service.ItemService" ref="itemServiceImpl" />
     <dubbo:service interface="com.taotao.manager.service.ItemCatService" ref="itemCatServiceImpl" />
     <dubbo:service protocol="hessian" interface="com.taotao.manager.service.PictureService" ref="pictureServiceImpl" />

 

4、consumer消费者那儿注册一下 
我的spring-mvc.xml

<!-- 配置dubbo服务 -->
    <dubbo:application name="taotao-manager-web" />

    <!-- 使用广播 -->
    <dubbo:registry protocol="zookeeper" address="192.168.138.128:2181" />

    <!-- 声明要调用的服务,timeout是设置连接超时最长时间,如果不设置,超时时间默认是3秒 -->
     <dubbo:reference interface="com.taotao.manager.service.TestService" id="testService" timeout="1000000" />
     <dubbo:reference interface="com.taotao.manager.service.ItemService" id="itemService" timeout="1000000" />
     <dubbo:reference interface="com.taotao.manager.service.ItemCatService" id="itemCatService" timeout="1000000" />
     <dubbo:reference protocol="hessian" interface="com.taotao.manager.service.PictureService" id="pictureService" timeout="1000000" />

 

5、发现能传递这个对象了,但是最后发现MultipartFile.getInputStream() 拿不到InputStream了,没办法只能用byte数组来传递这个InputStream了。

  1.   先把上传的文件转换成二进制数组,并传递到service层
    @RequestMapping(value = "/pic/upload")
        @ResponseBody
        public String uploadPicture(MultipartFile uploadFile) throws IOException {
            byte[] pic = uploadFile.getBytes();
            PictureResult pictureResult = pictureService.uploadPicture(pic, uploadFile);
            String result = JsonUtils.objectToJson(pictureResult);
            return result;
        }

  2.   

 @Override
    public PictureResult uploadPicture(byte[] pic, MultipartFile uploadFile) {
        PictureResult pictureResult = new PictureResult();
        if (pic == null || pic.length == 0) {
            pictureResult.setError(1);
            pictureResult.setMessage("空文件");
            return pictureResult;
        }
        //拿到上传文件的二进制数组inputStream
        InputStream inputStream = new ByteArrayInputStream(pic);

        //上传文件的名称
        String oldName = uploadFile.getOriginalFilename();
        //使用IDUtils工具类生成新名称
        String newName = IDUtils.genImageName();
        //新名称加上旧名称扩展名
        newName = newName + oldName.substring(oldName.lastIndexOf("."));
        //创建一个以日期命名的文件目录"/2019/3/21"
        String imagePath = new DateTime().toString("/yyyy/mm/dd");
        //上传文件到图片服务器
        boolean result = FtpUtil.uploadFile(FTP_ADRESS, FTP_PORT, FTP_USERNAME, FTP_PASSWORD, FTP_BASE_PATH,
                imagePath, newName, inputStream);
        //返回格式参考KindEditor
        String url = IMAGE_BASE_PATH + imagePath + "/" + newName;
        if (!result) {
            pictureResult.setError(1);
            pictureResult.setMessage("文件上传失败");
            return pictureResult;
        } else {
            pictureResult.setError(0);
            pictureResult.setUrl(url);
            return pictureResult;
        }
    }

 

 

 

posted on 2019-03-22 14:39  yadDRL  阅读(7578)  评论(0编辑  收藏  举报

导航