Several Implementations of Uploading Files to go-fastdfs by Obtaining File Input Stream in Spring MVC/SpringBook Controller

Keywords: Java OkHttp JSON Apache

This is a reprinted article, the reason for reprinting is that the original author missed an import of hutool, resulting in a waste of 5 hours, and the original author's article can not comment, hereby reprint + explanation.

It's this line of code that pitted me for five hours:
import cn.hutool.core.io.resource.InputStreamResource;

Recently, many friends in the go-fast DFS micro-group asked, when do go-fast DFS support stream upload? Actually, it has always been supported! Why do you say that? Because go-fastdfs itself is based on http protocol for transmission, if readers have studied the source code of http URLConnection in Java, they will find that their internal input and output streams can also be obtained through conn.getInputStream() and conn.getOutputStream(), which can usually be written directly into the output Stream in line with ht. TP protocol data. According to this feature, in Java, it is no problem to upload InputStream directly through stream (usually from MultipartFile) to go-fast dfs. Knowledge points related to http protocol include http protocol message format and uploading binary data. If you don't know, you can Baidu first. I won't go into details here.

Reasons for thinking that go-fast DFS cannot be uploaded directly
After my analysis, I think that the reason why most readers can not use stream upload directly is that the github code example of go-fastdfs causes some misunderstandings. However, the official code example is not wrong, just read the file system directly from the local file system to form File object for upload. For users who use Spring and other frameworks to receive files uploaded from the front end and then forward them to go-fast dfs, there may be doubts. Because you get MultipartFile, not java.io.File.

Hutool-http, HttpClient, OkHttp3 streaming file upload
Because many people have asked the above questions, now I summarize several commonly used methods of http client file streaming upload, which is equivalent to making records for myself, but also give a reference to friends who have doubts in this regard. No more nonsense, just code it. The code is based on springboot's maven project.

Hutool-http approach
First add hutool dependencies to the pom

<dependency>

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

</dependency>
Then the code example in 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 approach
pom dependence

<dependency>

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

</dependency>
<dependency>

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

</dependency>
Then the code example in 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 upload example
pom file dependency

<dependency>

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

</dependency>
Then the code example in 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;
}

summary
Some examples are given above. Are they all quite simple? In this way, you can do transit in Controller, which is quite convenient. By the way, I personally think Hutool is the simplest and most convenient of the above ways. For HttpClient, there are many concepts, which are relatively complex. OkHttp is the same, but it is more elegant than HttpClient. For general concurrent quantities, I feel that Hutool's Http is enough. The bottom layer is based on jdk's Http UrlConnection. If there are special requirements for performance, you can consider httpclient or OKHttp, the latter two are relatively recommended to use OkHttp.

Posted by Loafin on Thu, 22 Aug 2019 08:09:54 -0700