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-tw/n/287075.html