When calling Dubbo service for file upload, com.com appears alibaba. dubbo. rpc. RpcException: Failed to invoke the method

Error problem display

This problem bothered me all day. I don't know why. Fortunately, there are big guys on the Internet. The reference blog is at the bottom.

Problem solving

When dubbo is used to transfer MultipartFile files, an invoke method error will be reported because dubbo cannot transfer this object across the system. Hessian can be used

Add dependency

<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>

Note that the dependency of servlet API package should be excluded from the jetty package, otherwise an error will be reported and Tomcat cannot start normally.
In addition, I can't use MultipartFile in the interface layer anyway, but I found that it can be used in the Service layer. At this time, I found that the Service layer has more Spring related dependencies than the interface layer, so I thought for a day and finally solved it
Add dependency

<!-- 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>

Upload the configuration file in the spring configuration file

Modify spring MVC xml

<!-- Multi part file upload parser -->
    <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>

In the service layer, our provider registers the required services as Hessian protocol.

My ApplicationContext service xml

   <!-- use dubbo Publishing services -->
    <!-- Provider application information for calculating dependencies -->
    <dubbo:application name="taotao-manager" />
    <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181" />
    <!-- use dubbo The protocol exposes services on port 20880 -->
    <dubbo:protocol name="dubbo" port="20880" />
    <dubbo:protocol name="hessian" port="20887"/>
    <!-- Declare the service interfaces that need to be exposed -->
    <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" />

Register with the consumer

My springmvc xml

    <!-- quote dubbo service -->
    <dubbo:application name="taotao-manager-web"/>
    <dubbo:registry protocol="zookeeper" address="192.168.25.128:2181"/>

    <!--Timeout can be set in both service layer and presentation layer.-->
    <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" />

It was found that this object could be passed, but finally multipartfile There is no way to get the InputStream () array.

Modify code

It was found that this object could be passed, but finally multipartfile Getinputstream () can't get the InputStream. There's no way but to pass the InputStream with a byte array.
1. Modify PictureService

package com.taotao.service;


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

/**
 * @Author LH
 * @Description Interface for uploading pictures
 * @Date 13:27 2020/9/6
 * @Param
 * @return
 **/
public interface PictureService {
    PictureResult uploadPicture(byte[] pic,MultipartFile uploadFile);
}

2. Modify 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 : Image upload service implementation class
 * @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("Empty file");
            return pictureResult;
        }
        //Get the binary array inputStream of the uploaded file
        InputStream inputStream = new ByteArrayInputStream(pic);

        //Name of uploaded file
        String oldName = uploadFile.getOriginalFilename();
        //Use the IDUtils utility class to generate a new name
        String newName = IDUtils.genImageName();
        //New name plus old name extension
        newName = newName + oldName.substring(oldName.lastIndexOf("."));
        //Create a file directory named with date "/ 2019 / 3 / 21"
        String imagePath = new DateTime().toString("/yyyy/mm/dd");
        //Upload files to image server
        boolean result = FtpUtil.uploadFile(FTP_ADDRESS, FTP_PORT, FTP_USERNAME, FTP_PASSWORD, FTP_BASE_PATH,
                imagePath, newName, inputStream);
        //Return format reference KindEditor
        String url = IMAGE_BASE_URL + imagePath + "/" + newName;
        if (!result) {
            pictureResult.setError(1);
            pictureResult.setMessage("File upload failed");
            return pictureResult;
        } else {
            pictureResult.setError(0);
            pictureResult.setUrl(url);
            return pictureResult;
        }
    }

}


3. Modify the PictureController to convert the uploaded files into binary arrays,

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 : Upload picture 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;
    }
}

Reference blog

During the file upload function, when dubbo transfers MultipartFile files, there is a bug: Fail to decode request due to: RpcInvocation

Tags: Spring Distribution

Posted by willpower on Wed, 18 May 2022 11:38:29 +0300