Spring Boot 是一個非常好的Java Web框架,它作為一個微服務的框架,提供了很多基本工具和服務支持,而文件下載是其中一個相對簡單的功能。下面我們將從多個方面詳細闡述Spring Boot文件下載的實現。
一、下載方式
通常有兩種主要的文件下載方式:使用HTTP協議下載和使用FTP協議下載。
HTTP協議下載:
@RequestMapping(value = "/download", method = RequestMethod.GET)
public ResponseEntity fileDownload(HttpServletRequest request, String fileName) throws IOException {
// 加載文件資源
File file = new File(fileName);
InputStream in = new FileInputStream(file);
byte[] body = new byte[in.available()];
in.read(body);
// 設置響應頭
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=" + new String(file.getName().getBytes("UTF-8"), "iso-8859-1"));
HttpStatus statusCode = HttpStatus.OK;
// 構造請求實體對象
ResponseEntity entity = new ResponseEntity(body, headers, statusCode);
return entity;
}FTP協議下載:
@RequestMapping(value = "/download", method = RequestMethod.GET)
public void ftpDownload(HttpServletResponse response, String server, int port, String username, String password, String path, String fileName) throws IOException {
FTPClient ftpClient = new FTPClient();
ftpClient.connect(server, port);
ftpClient.login(username, password);
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
InputStream in = ftpClient.retrieveFileStream(path + "/" + fileName);
OutputStream out = response.getOutputStream();
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString()));
response.setContentType("application/octet-stream");
byte[] buffer = new byte[1024 * 1024];
int len;
while ((len = in.read(buffer)) > 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
ftpClient.logout();
ftpClient.disconnect();
}二、文件安全
文件下載涉及到的安全問題很重要,我們需要確保下載的文件是用戶有權限獲取的。文件安全應該在文件上傳時進行驗證,例如使用MD5或SHA256作為文件唯一標識,以便確保文件上傳的時候是完整無損的。
例如使用MD5:
public String getFileMD5(File file) throws FileNotFoundException {
FileInputStream fis = new FileInputStream(file);
byte[] buffer = new byte[1024];
MessageDigest md5;
try {
md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException e) {
return null;
}
int numRead;
do {
numRead = fis.read(buffer);
if (numRead > 0) {
md5.update(buffer, 0, numRead);
}
} while (numRead != -1);
fis.close();
return toHexString(md5.digest());
}
public String toHexString(byte[] b) {
StringBuilder sb = new StringBuilder(b.length * 2);
for (byte value : b) {
sb.append(toHexString(value));
}
return sb.toString();
}
private static String toHexString(byte b) {
int value = b & 0xFF;
String hexString = Integer.toHexString(value);
if (hexString.length() < 2) {
hexString = "0" + hexString;
}
return hexString;
}三、大文件下載
如果文件比較大,會對網絡和系統性能有很大的影響。一些方案可以被使用來緩解這個問題,如:
- 使用多個線程來下載文件;
- 使用流來減少內存使用;
- 使用壓縮文件包來減少文件大小。
例如使用多個線程:
@RequestMapping("/download/bigfile")
public void download(HttpServletResponse response) throws IOException {
response.setContentType("application/vnd.ms-excel");
response.setHeader("content-disposition", "attachment;filename=test.xls");
InputStream inputStream = this.getClass().getResourceAsStream("/static/test.xls");
OutputStream os = response.getOutputStream();
byte[] b = new byte[1024];
int length;
while ((length = inputStream.read(b)) != -1) {
os.write(b, 0, length);
}
os.close();
inputStream.close();
}四、斷點續傳
如果下載的文件比較大,有可能中途會出現網絡斷開或其他問題導致下載中斷,斷點續傳是一個很有用的功能,可以在之前中斷的位置重新開始下載。
使用 Range Header 實現斷點續傳:
@RequestMapping("/download")
public ResponseEntity download(HttpServletRequest request) throws IOException {
// ...
String range = request.getHeader("Range");
Long start = 0L;
Long end = file.length() - 1;
if (range != null && range.contains("bytes=") && range.contains("-")) {
String[] parts = range.split("=")[1].split("-");
start = Long.parseLong(parts[0]);
end = parts.length > 1 ? Long.parseLong(parts[1]) : end;
}
Long contentLength = end - start + 1;
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(file.getName(), "UTF-8"));
headers.add("Accept-Ranges", "bytes");
headers.add("Content-Length", String.valueOf(contentLength));
headers.add("Content-Range", "bytes " + start + "-" + end + "/" + file.length());
headers.add("Content-Type", "application/octet-stream");
RandomAccessFile randomAccessFile = new RandomAccessFile(file, "r");
randomAccessFile.seek(start);
InputStream inputStream = new FileInputStream(file);
byte[] data = new byte[inputStream.available()];
randomAccessFile.read(data);
ResponseEntity.BodyBuilder builder = ResponseEntity
.status(HttpStatus.PARTIAL_CONTENT)
.headers(headers);
builder = builder.body(data);
return builder.build();
}五、Spring Security 限制文件下載
對於需要限制用戶權限才能下載的文件,Spring Security框架是一個非常好的選擇。
例如使用Spring Security:
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/**").hasRole("USER")
.and()
.formLogin()
.and()
.logout()
.and()
.csrf().disable()
}
}其中, “secure” 路徑可以通過用戶角色進行訪問控制。
總結
以上是對Spring Boot文件下載的詳細分析,包括下載方式、文件安全、大文件下載、斷點續傳、Spring Security文件下載限制等多個方面進行了講述。通過這些方式,我們可以實現各種場景下的文件下載功能。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/287075.html
微信掃一掃
支付寶掃一掃