使用RestTemplate上傳文件到遠程接口


有一個業務需求。需要將一個在線文件,在不經過本地存儲轉換的方式下同步到現有服務中。最終采納的解決方案是使用Spring提供的RestTemplate來遠程操作http服務,實現在線的文件同步上傳。

以下是文件上傳的核心代碼

錯誤演示


    try{
            MultiValueMap<String, Object> postParameters = new LinkedMultiValueMap<>();
            postParameters.add("type",type);
            postParameters.add("subType",subType);
		 
            //獲取文件名稱
            URL openUrl = new URL(chenvaFilePath+fileUrl);
            URLConnection urlConnection = openUrl.openConnection();
            int fileLength = urlConnection.getContentLength();
            byte[]bytes = new byte[fileLength];
            // 讀取流信息,一次性寫入字節數組(與下面正確示例中不同之處)
            InputStream inputStream = urlConnection.getInputStream();
            inputStream.read(bytes);
            inputStream.close();

            HttpHeaders fileHeader = new HttpHeaders();
            fileHeader.setContentType(MediaType.parseMediaType(urlConnection.getContentType()));
            fileHeader.setContentDispositionFormData("upload", fileName);
            HttpEntity<ByteArrayResource> filePart = new HttpEntity<>(new
                    ByteArrayResource(bytes),fileHeader);
            postParameters.add("upload",filePart);
        } catch (Exception e) {
            updateSyncStatus(projectId,dictId,"4");
            throw new RuntimeException("文件上傳錯誤");
        }


        HttpHeaders headers = new HttpHeaders();

        // 使用客戶端的請求頭,發起請求
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        headers.add("Cookie", newCookie);
        headers.add("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36");
        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity(postParameters, headers);
        restTemplate.setRequestFactory(new NoRedirectClientHttpRequestFactory());

        restTemplate.postForObject(UPLOAD_PATH, request, String.class) ;

問題描述

      在使用上方代碼實現文件上傳時,是能夠上傳成功的。在進行文件下載時,出現錯誤。本業務程序中上傳的是pdf文檔,下載時文件大小都正確,內容是空白的。最后使用了ByteOutputStream進行緩存字節來實現的。可以正確下載。

正確示例


     try{
            MultiValueMap<String, Object> postParameters = new LinkedMultiValueMap<>();
            postParameters.add("type",type);
            postParameters.add("subType",subType);
            //獲取文件名稱
            URL openUrl = new URL(chenvaFilePath+fileUrl);
            URLConnection urlConnection = openUrl.openConnection();
            InputStream inputStream = openUrl.openStream();
                
            // 將讀取到的字節緩存到此處,用到的使用直接一次性獲取
            ByteOutputStream byteOutputStream = new ByteOutputStream();

            int index = -1;
            byte[] bytes = new byte[1024];
            while ((index = inputStream.read(bytes)) != -1) {
                byteOutputStream.write(bytes,0,index);
            }
            inputStream.close();

            HttpHeaders fileHeader = new HttpHeaders();
            fileHeader.setContentType(MediaType.parseMediaType(urlConnection.getContentType()));
            fileHeader.setContentDispositionFormData("upload", fileName);
            HttpEntity<ByteArrayResource> filePart = new HttpEntity<>(new
                    ByteArrayResource(byteOutputStream.getBytes()),fileHeader);
            postParameters.add("upload",filePart);
        } catch (Exception e) {
            throw new RuntimeException("文件上傳錯誤");
        }

        HttpHeaders headers = new HttpHeaders();

        // 使用客戶端的請求頭,發起請求
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
        headers.add("Cookie", newCookie);
        headers.add("User-Agent","Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36");
        HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity(postParameters, headers);
        restTemplate.setRequestFactory(new NoRedirectClientHttpRequestFactory());

        restTemplate.postForObject(UPLOAD_PATH, request, String.class) ;

實現SimpleClientHttpRequestFactory類

public class NoRedirectClientHttpRequestFactory extends SimpleClientHttpRequestFactory {

    @Override
    protected void prepareConnection(HttpURLConnection connection, String httpMethod) throws IOException {
        // TODO Auto-generated method stub
        super.prepareConnection(connection, httpMethod);
        // 禁止自動重定向
        connection.setFollowRedirects(false);
    }
}

    至此文件可以正常上傳

問題復現

    在使用maven進行打包編譯時,提示錯誤,錯誤信息如下:

com.sun.xml.internal.messaging.saaj.util程序包不存在

    於是乎開始了網上沖浪,在上線的緊要關頭怎么能出現問題呢是吧。
    原因是在上面示例程序中使用了ByteOutputStream類,導致maven進行compiler的時候找不到該類信息,在maven編譯打包時指定該類位置信息即可。

          <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-compiler-plugin.version}</version>
                <configuration>
                   <!--重要部分-->
                    <compilerArguments>
                        <bootclasspath>${env.JAVA_HOME}\jre\lib\rt.jar;${env.JAVA_HOME}\jre\lib\jce.jar</bootclasspath>
                    </compilerArguments>
                    <source>${java.version}</source>
                    <target>${java.version}</target>
                    <encoding>${maven.compiler.encoding}</encoding>
                    <verbose/>
                </configuration>
            </plugin>

    其中${env.JAVA_HOME}是java的系統變量,在maven中可以直接使用。使用mvn help:system可以系統的查看內置信息。

    還有一些maven的常用內置變量如下:

${basedir} 項目根目錄
${project.build.directory} 構建目錄,缺省為target
${project.build.outputDirectory} 構建過程輸出目錄,缺省為target/classes
${project.build.finalName} 產出物名稱,缺省為${project.artifactId}-${project.version} 當前版本
${project.packaging} 打包類型,缺省為jar


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM