有一個業務需求。需要將一個在線文件,在不經過本地存儲轉換的方式下同步到現有服務中。最終采納的解決方案是使用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
