转载

在SpringMVC/SpringBoot控制器中通过获取文件输入流方式上传文件到go-fastdfs的几种实现

这是转载的文章,之所以转载,是因为原作者漏了一个hutool的import,导致我浪费了5个小时,而原作者的文章不能评论,特此转载+说明。

就是这行代码坑了我5个小时:

import cn.hutool.core.io.resource.InputStreamResource;

最近很多朋友在go-fastdfs的微信群里面问道,go-fastdfs什么时候支持流上传?其实一直都支持的!为什么这样子说呢?因为go-fastdfs本身就是基于http协议进行传输的,那么如果有读者对Java的HttpURLConnection的源码研究过的话,会发现其内部也是可以通过conn.getInputStream()和conn.getOutputStream()获取其输入输出流,通常可以直接往outputStream里面写入符合http协议的数据。那么根据这个特点,在Java里面,直接通过流的形式(通常是从MultipartFile里面获取InputStream)再上传到go-fastdfs是没问题的。跟http协议相关的知识点包括http协议报文格式和上传二进制数据等如果不了解可以先自行百度一下。这里不会细讲的哦。

引发认为go-fastdfs不能直接流上传的原因

经过本人的分析认为,让广大读者认为不能直接使用流上传的原因应该是go-fastdfs的github的代码示例造成一些误会。不过官方的代码示例并没有错误,只是直接从本地读取文件系统的文件,形成File对象进行上传。针对使用Spring等框架接收前端上传过来的文件再进行转发上传到go-fastdfs的用户,就可能会有疑惑。因为获取到的是MultipartFile,而非java.io.File。

在SpringMVC/SpringBoot控制器中通过获取文件输入流方式上传文件到go-fastdfs的几种实现

Hutool-http、HttpClient、OkHttp3多种方式流式文件上传

由于有不少人问到上面的问题,现在本人总结了一个常用的几种http客户端文件流式上传的方式,相当于给自己做下记录,同时也给有这方面疑问的朋友一个借鉴。废话不多说,直接上代码吧。代码是基于springboot的maven工程。

Hutool-http方式

先在pom中添加hutool的依赖

<dependency>

<groupId>cn.hutool</groupId>
 <artifactId>hutool-all</artifactId>
 <version>4.5.1</version>

</dependency>

接着在Controller中代码示例

import cn.hutool.core.io.resource.InputStreamResource;

@RequestMapping("/upload")
public String  upload(MultipartFile file) {
    String result = "";
    try {
        InputStreamResource isr = new InputStreamResource(file.getInputStream(),
                file.getOriginalFilename());

        Map<String, Object> params = new HashMap<>();
        params.put("file", isr);
        params.put("path", "86501729");
        params.put("output", "json");
        String resp = HttpUtil.post(UPLOAD_PATH, params);
        Console.log("resp: {}", resp);
        result = resp;
    } catch (IOException e) {
        e.printStackTrace();
    }
    
    return result;
}

HttpClient方式

pom依赖

<dependency>

<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>

</dependency>

<dependency>

<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>

</dependency>

接着在Controller中代码示例

@RequestMapping("/upload1")
public String upload1(MultipartFile file) {
    String result = "";
    try {
        CloseableHttpClient httpClient = HttpClientBuilder.create().build();
        CloseableHttpResponse httpResponse = null;
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(200000)
                .setSocketTimeout(2000000)
                .build();
        HttpPost httpPost = new HttpPost(UPLOAD_PATH);
        httpPost.setConfig(requestConfig);
        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create()
                .setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
                .setCharset(Charset.forName("UTF-8"))
                .addTextBody("output", "json")
                .addBinaryBody("file", file.getInputStream(),
                        ContentType.DEFAULT_BINARY, file.getOriginalFilename());
        httpPost.setEntity(multipartEntityBuilder.build());
        httpResponse = httpClient.execute(httpPost);

        if (httpResponse.getStatusLine().getStatusCode() == 200) {
            String respStr = EntityUtils.toString(httpResponse.getEntity());
            System.out.println(respStr);
            result = respStr;
        }

        httpClient.close();
        httpResponse.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return result;
}

OkHttp3上传示例

pom文件依赖

<dependency>

<groupId>com.squareup.okhttp3</groupId>
 <artifactId>okhttp</artifactId>
 <version>3.9.1</version>

</dependency>

接着在Controller中代码示例

@RequestMapping("/upload2")
public String upload2(MultipartFile file) {
    String result = "";
    try {
        OkHttpClient httpClient = new OkHttpClient();
        MultipartBody multipartBody = new MultipartBody.Builder().
                setType(MultipartBody.FORM)
                .addFormDataPart("file", file.getOriginalFilename(),
                        RequestBody.create(MediaType.parse("multipart/form-data;charset=utf-8"),
                                file.getBytes()))
                .addFormDataPart("output", "json")
                .build();

        Request request = new Request.Builder()
                .url(UPLOAD_PATH)
                .post(multipartBody)
                .build();

        Response response = httpClient.newCall(request).execute();
        if (response.isSuccessful()) {
            ResponseBody body = response.body();
            if (body != null) {
                result = body.string();
                System.out.println(result);
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
    }

    return result;
}

总结

上面给出了几个示例,是不是都挺简单的?通过这种方式,就可以在Controller中做中转了,还是挺方便的。顺便提一下,上面几种方式中,我个人觉得Hutool的是最简单的,最方便的,对于HttpClient而言,概念比较多,显得相对复杂,OkHttp也一样,不过比HttpClient显得优雅点。针对一般的并发量,个人觉得hutool的Http已经够用了,底层是基于jdk的HttpUrlConnection实现的。如果对性能有特殊要求的,可以考虑httpclient或者OKHttp,后两者相对而言,更推荐使用OkHttp。

原文  https://segmentfault.com/a/1190000020158062
正文到此结束
Loading...