调用Dubbo服务做图片上传时,出现com.alibaba.dubbo.rpc.RpcException: Failed to invoke the method

错误问题显示

这个问题困扰了我一天,不知道是什么原因。还好网上有大佬解决了,参考博客在最下方。
在这里插入图片描述
在这里插入图片描述

问题解决

采用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不能正常启动。
另外,补充一下,我在interface层,无论如何也用不了MultipartFile这个类,但是发现在Service层可以用,这时候对比发现,Service层比Interface层多了Spring的相关依赖,所以想了一天,终于解决了
添加依赖

<!-- Spring -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jms</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>

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

修改springmvc.xml

<!-- 多部分文件上传 文件上传解析器 -->
    <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>

在service层就是我们的provider里面将需要的服务注册成Hessian协议。

我的applicationContext-service.xml

   <!-- 使用dubbo发布服务 -->
    <!-- 提供方应用信息,用于计算依赖关系 -->
    <dubbo:application name="taotao-manager" />
    <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181" />
    <!-- 用dubbo协议在20880端口暴露服务 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="hessian" port="20887"/>
    <!-- 声明需要暴露的服务接口 -->
    <dubbo:service interface="com.taotao.service.TestService" ref="testServiceImpl" />
    <dubbo:service interface="com.taotao.service.ItemService" ref="itemServiceImpl" />
    <dubbo:service interface="com.taotao.service.ItemCatService" ref="itemCatServiceImpl"/>
    <dubbo:service protocol="hessian" interface="com.taotao.service.PictureService" ref="pictureServiceImpl" />

consumer消费者那儿注册一下

我的springMvc.xml

    <!-- 引用dubbo服务 -->
    <dubbo:application name="taotao-manager-web"/>
    <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/>

    <!--在服务层和表现层都可以设置超时时间。-->
    <dubbo:reference interface="com.taotao.service.TestService" id="testService" timeout="300000" />
    <dubbo:reference interface="com.taotao.service.ItemService" id="itemService" timeout="300000"/>
    <dubbo:reference interface="com.taotao.service.ItemCatService" id="itemCatService" timeout="300000"/>
    <dubbo:reference protocol="hessian" interface="com.taotao.service.PictureService" id="pictureService" timeout="1000000" />

修改代码

发现能传递这个对象了,但是最后发现MultipartFile.getInputStream() 拿不到InputStream了,用byte数组来传递这个InputStream。
1.修改PictureService

package com.taotao.service;


import com.taotao.common.pojo.PictureResult;
import org.springframework.web.multipart.MultipartFile;

/**
 * @Author LH
 * @Description 上传图片的接口
 * @Date 13:27 2020/9/6
 * @Param
 * @return
 **/
public interface PictureService {
    PictureResult uploadPicture(byte[] pic,MultipartFile uploadFile);
}

2.修改PictureServiceImpl

package com.taotao.service.impl;

import com.taotao.common.pojo.PictureResult;
import com.taotao.common.util.FtpUtil;
import com.taotao.common.util.IDUtils;
import com.taotao.service.PictureService;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

/**
 * @ClassName : PictureServiceImpl
 * @Description : 图片上传服务实现类
 * @Author : LH
 * @Date: 2020-09-05 17:50
 * @Version: 1.0
 */
@Service
public class PictureServiceImpl implements PictureService {
    @Value("${FTP_ADDRESS}")
    private String FTP_ADDRESS;
    @Value("${FTP_PORT}")
    private Integer FTP_PORT;
    @Value("${FTP_USERNAME}")
    private String FTP_USERNAME;
    @Value("${FTP_PASSWORD}")
    private String FTP_PASSWORD;
    @Value("${FTP_BASE_PATH}")
    private String FTP_BASE_PATH;
    @Value("${IMAGE_BASE_URL}")
    private String IMAGE_BASE_URL;


    @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_ADDRESS, FTP_PORT, FTP_USERNAME, FTP_PASSWORD, FTP_BASE_PATH,
                imagePath, newName, inputStream);
        //返回格式参考KindEditor
        String url = IMAGE_BASE_URL + imagePath + "/" + newName;
        if (!result) {
            pictureResult.setError(1);
            pictureResult.setMessage("文件上传失败");
            return pictureResult;
        } else {
            pictureResult.setError(0);
            pictureResult.setUrl(url);
            return pictureResult;
        }
    }

}


3.修改PictureController,把上传的文件转换成二进制数组,

package com.taotao.controller;

import com.taotao.common.pojo.PictureResult;
import com.taotao.common.util.JsonUtils;
import com.taotao.service.PictureService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;

/**
 * @ClassName : PictureController
 * @Description : 上传图片Controller
 * @Author : LH
 * @Date: 2020-09-05 18:30
 * @Version: 1.0
 */
@Controller
public class PictureController {

    @Autowired
    private PictureService pictureService;

    @RequestMapping("/pic/upload")
    @ResponseBody
    public String upload(MultipartFile uploadFile) {
        byte[] pic = new byte[0];
        try {
            pic = uploadFile.getBytes();
        } catch (IOException e) {
            e.printStackTrace();
        }
        PictureResult pictureResult = pictureService.uploadPicture(pic, uploadFile);
        String result = JsonUtils.objectToJson(pictureResult);
        return result;
    }
}

参考博客

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值