您当前的位置:首页 > 计算机 > 编程开发 > Java

跨项目文件流转发功能实现

时间:02-01来源:作者:点击数:

需求:文件流从当前项目转发到另外一个项目。

思路:需要拦截请求中的文件流,组装之后转发到另外一个项目中。

效果:

具体步骤如下

1.首先读取文件的接口

api接口,接收文件:

package com.zxy.demo.api;

import com.zxy.demo.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

/**
 * FileUpload
 *
 * @author zhouxy@133.cn
 * @date 2022/3/1
 **/
@RestController
@RequestMapping("/file")
@Slf4j
public class FileUploadController {
    @Autowired
    private FileService fileService;

    @PostMapping("/upload")
    public String test(@RequestParam("file") MultipartFile file) {
        fileService.uploadFile(file);
        return "成功";
    }
}

文件处理逻辑,读取文件内容:

package com.zxy.demo.service.impl;

import com.zxy.demo.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * FileServiceImpl
 *
 * @author zhouxy@133.cn
 * @date 2022/3/1
 **/
@Slf4j
@Service
public class FileServiceImpl implements FileService {
    @Override
    public void uploadFile(MultipartFile file) {
        try (InputStream is = file.getInputStream();
             InputStreamReader isReader = new InputStreamReader(is);
             BufferedReader br = new BufferedReader(isReader);) {
            log.info("文件打印:");
            while (br.ready()) {
                log.info("{}", br.readLine());
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}

2.调用方代码,拦截器处理文件流

package com.zxy.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.protocol.HttpDateGenerator;
import org.apache.http.util.EntityUtils;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.List;

/**
 * InterceptorConfig
 *
 * @author zhouxy@133.cn
 * @date 2022/3/3
 **/
@Slf4j
public class InterceptorConfig implements HandlerInterceptor {

    private static final CloseableHttpClient httpclient;

    static {
        //创建http客户端
        httpclient = HttpClients.custom()
                .useSystemProperties()
                .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true))
                .build();
    }


    /**
     * 进入controller层之前拦截请求
     *
     * @param request
     * @param httpServletResponse
     * @param o
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse httpServletResponse, Object o) throws Exception {
        log.info("");
        String url = request.getRequestURI();
        String newUrl = "http://localhost:8081/file/upload";
        if (url.contains("/file/upload")) {
            String result = null;
            /*1.第一种读取流方式*/
            MultipartEntityBuilder builder = readFile(request);
            result = postResultMultipartFile(newUrl, builder, "文件上传");

            /*2.第二种读取流方式*/
            /*InputStreamEntity inputStreamEntity = new InputStreamEntity(request.getInputStream(), request.getContentLength(), ContentType.parse(request.getContentType()));
            result = postResultMultipartFile(newUrl, inputStreamEntity, "文件上传");*/
            log.info("result====>{}", result);
            return false;
        }
        return true;
    }

    /**
     * post请求接口
     *
     * @Author zhouxy
     */
    public String postResultMultipartFile(String url, HttpEntity httpEntity, String actionDesc) {
        HttpEntity responseEntity;
        try {
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(httpEntity);
            RequestConfig config = RequestConfig.custom().setConnectTimeout(3000).build();
            httpPost.setConfig(config);
            log.info("lenght:{}", httpEntity.getContentLength());
            HttpResponse response = httpclient.execute(httpPost);// 执行提交
            responseEntity = response.getEntity();
            if (responseEntity != null) {
                log.info("responseEntity:{}", responseEntity);
                // 将响应内容转换为字符串
                return EntityUtils.toString(responseEntity, Charset.forName("UTF-8"));
            }
        } catch (IOException e) {
            log.error(actionDesc + ":IOException:", e.getMessage());
        } catch (Exception e) {
            log.error(actionDesc + ":Exception:", e.getMessage());
        }
        return null;
    }

    /**
     * 读取文件
     *
     * @param request
     * @return
     */
    private MultipartEntityBuilder readFile(HttpServletRequest request) {
        MultipartEntityBuilder builder = MultipartEntityBuilder.create();
        builder.setCharset(Charset.forName("utf-8"));
        builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);//加上此行代码解决返回中文乱码问题

        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
        upload.setHeaderEncoding("UTF-8");
        List<FileItem> list = null;
        try {

            list = upload.parseRequest(request);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        log.info("list:{}", list.size());
        for (FileItem file : list) {
            //获取文件名(带后缀名)
            String fileName = file.getName();
            //获取文件输入流
            try (InputStream input = file.getInputStream()) {
                builder.addBinaryBody("file", input, ContentType.MULTIPART_FORM_DATA, fileName);// 文件流
            } catch (IOException e) {
                log.error("文件流读取失败:", e);
            }
        }
        return builder;
    }

    /**
     * post请求接口
     *
     * @Author zhouxy
     */
    public String postResultMultipartFile(String url, MultipartEntityBuilder builder, String actionDesc) {
        HttpEntity httpEntity;
        HttpEntity responseEntity;
        try {
            HttpPost httpPost = new HttpPost(url);
            // 添加分销接口默认header,分销新网关凭证
            httpEntity = builder.build();
            httpPost.setEntity(httpEntity);

            HttpResponse response = httpclient.execute(httpPost);// 执行提交
            log.info("转发成功:");
            responseEntity = response.getEntity();
            if (responseEntity != null) {
                // 将响应内容转换为字符串
                return EntityUtils.toString(responseEntity, Charset.forName("UTF-8"));
            }
        } catch (IOException e) {
            log.error(actionDesc + ":IOException:", e.getMessage());
        } catch (Exception e) {
            log.error(actionDesc + ":Exception:", e.getMessage());
        }
        return null;
    }
}

调用方文件上传接口:

package com.zxy.demo.api;

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

/**
 * FileUpload
 *
 * @author zhouxy@133.cn
 * @date 2022/3/1
 **/
@RestController
@RequestMapping("/file")
@Slf4j
public class FileUploadController {

    @PostMapping("/upload")
    public void test(@RequestParam("file") MultipartFile file) {
        log.info("1111111");
    }
}

完成上述代码之后,测试了一下,不行。发现调用upload.parseRequest(request),返回的list的size为0,不能从request中读取文件流。该问题需要修改一下配置文件application.yml(Springboot项目):

spring:
  servlet:
    multipart:
  # 禁用multipart读取文件
      enabled: false

遇到的问题:

1.读取upload.parseRequest(request)返回size为0的问题,上面已经说了解决办法。

2.刚开始采用的是aop方式,但是获取不到文件。在解决1的问题之后,继续获取,仍然不行。

问题点在于两点:

(1)没分清aop和拦截器的区别(链接: https://www.cdsy.xyz/computer/programme/suggest/230201/cd39995.html),区别如下:

过滤器
过滤器可以拦截到方法的请求和响应(ServletRequest request, SetvletResponse response),并对请求响应做出响应的过滤操作,比如设置字符编码、鉴权操作。
 
拦截器
拦截器可以在方法之前(preHandle)和方法执行之后(afterCompletion)进行操作,回调操作(postHandle),可以获取执行的方法的名称,请求(HttpServletRequest)。
 
AOP切片
AOP操作可以对操作进行横向的拦截,最大的优势在于可以获取执行方法的参数,对方法进行统一的处理,常见使用日志,事务,请求参数安全验证等

(2)MultipartFile的读取流程

MultipartFile读取文件流,是从HttpServletRequest中读取文件流,而request中的流只能读取一次。因此aop做切片,无法从中读取文件流。

使用aop读取文件流会报以下错误。

严重: Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is org.springframework.web.multipart.MultipartException: Failed to parse multipart servlet request; nested exception is java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided] with root cause
java.lang.IllegalStateException: Unable to process parts as no multi-part configuration has been provided
方便获取更多学习、工作、生活信息请关注本站微信公众号城东书院 微信服务号城东书院 微信订阅号
推荐内容
相关内容
栏目更新
栏目热门