import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.catalina.connector.ClientAbortException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * @Title: IndexController.java * @Package com.fhhr.controller * @Description: * @author ybwei * @date 2018年9月10日 下午12:11:04 * @version V1.0 */ @RestController public class IndexController { private final Logger logger = LoggerFactory.getLogger(getClass()); @Value("${file.download.path}") private String filePathName; /** * 斷點下載 * @param request * @param response * @param range * @author ybwei */ @RequestMapping("/downloadFile") public void home(HttpServletRequest request, HttpServletResponse response, @RequestHeader(required = false) String range) { // 文件目錄 File file = new File(filePathName); // 開始下載位置 long startByte = 0; // 結束下載位置 long endByte = file.length() - 1; // 有range的話 if (range != null && range.contains("bytes=") && range.contains("-")) { range = range.substring(range.lastIndexOf("=") + 1).trim(); String ranges[] = range.split("-"); try { // 判斷range的類型 if (ranges.length == 1) { // 類型一:bytes=-2343 if (range.startsWith("-")) { endByte = Long.parseLong(ranges[0]); } // 類型二:bytes=2343- else if (range.endsWith("-")) { startByte = Long.parseLong(ranges[0]); } } // 類型三:bytes=22-2343 else if (ranges.length == 2) { startByte = Long.parseLong(ranges[0]); endByte = Long.parseLong(ranges[1]); } } catch (NumberFormatException e) { startByte = 0; endByte = file.length() - 1; } } // 要下載的長度(爲啥要加一問小學數學老師去) long contentLength = endByte - startByte + 1; // 文件名 String fileName = file.getName(); // 文件類型 String contentType = request.getServletContext().getMimeType(fileName); // 解析斷點續傳相關信息 response.setHeader("Accept-Ranges", "bytes"); // 若客戶端傳來Range,說明以前下載了一部分,設置206狀態(SC_PARTIAL_CONTENT) response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); response.setContentType(contentType); response.setHeader("Content-Type", contentType); // 這裏文件名換你想要的,inline表示瀏覽器直接實用(我方便測試用的) // 參考資料:http://hw1287789687.iteye.com/blog/2188500 response.setHeader("Content-Disposition", "attachment;filename=" + file.getName()); response.setHeader("Content-Length", String.valueOf(contentLength)); // [要下載的開始位置]-[結束位置]/[文件總大小] response.setHeader("Content-Range", "bytes " + startByte + "-" + endByte + "/" + file.length()); BufferedOutputStream outputStream = null; RandomAccessFile randomAccessFile = null; // 已傳送數據大小 long transmitted = 0; try { randomAccessFile = new RandomAccessFile(file, "r"); outputStream = new BufferedOutputStream(response.getOutputStream()); byte[] buff = new byte[4096]; int len = 0; randomAccessFile.seek(startByte); // contentLength)要放前面!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // 否則會會先讀取randomAccessFile,形成後面讀取位置出錯,找了一天才發現問題所在 while ((transmitted + len) <= contentLength && (len = randomAccessFile.read(buff)) != -1) { outputStream.write(buff, 0, len); transmitted += len; } // 處理不足buff.length部分 if (transmitted < contentLength) { len = randomAccessFile.read(buff, 0, (int) (contentLength - transmitted)); outputStream.write(buff, 0, len); transmitted += len; } outputStream.flush(); response.flushBuffer(); randomAccessFile.close(); logger.info("下載完畢:" + startByte + "-" + endByte + ":" + transmitted); } catch (ClientAbortException e) { logger.info("用戶中止下載:" + startByte + "-" + endByte + ":" + transmitted); // 捕獲此異常表示擁護中止下載 } catch (IOException e) { logger.info("下載異常:", e); } finally { try { if (randomAccessFile != null) { randomAccessFile.close(); } } catch (IOException e) { logger.info("下載異常:", e); } } } }