專案實戰 —— 端點上傳與極速秒傳功能實現案例程式碼
阿新 • • 發佈:2020-07-24
bigfile.vue 元件
檔案上傳,分片
import com.alibaba.fastjson.JSON; import com.aliyuncs.DefaultAcsClient; import com.aliyuncs.vod.model.v20170321.GetMezzanineInfoResponse; import com.course.server.dto.FileDto; import com.course.server.dto.ResponseDto; import com.course.server.enums.FileUseEnum; import com.course.server.service.FileService; import com.course.server.util.Base64ToMultipartFile; import com.course.server.util.VodUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; @RequestMapping("/admin") @RestController public class UploadController { private static final Logger LOG = LoggerFactory.getLogger(UploadController.class); public static final String BUSINESS_NAME = "檔案上傳"; @Value("${file.domain}") private String FILE_DOMAIN; @Value("${file.path}") private String FILE_PATH; @Value("${vod.accessKeyId}") private String accessKeyId; @Value("${vod.accessKeySecret}") private String accessKeySecret; @Resource private FileService fileService; @RequestMapping("/upload") public ResponseDto upload(@RequestBody FileDto fileDto) throws Exception { LOG.info("上傳檔案開始"); String use = fileDto.getUse(); String key = fileDto.getKey(); String suffix = fileDto.getSuffix(); String shardBase64 = fileDto.getShard(); MultipartFile shard = Base64ToMultipartFile.base64ToMultipart(shardBase64); // 儲存檔案到本地 FileUseEnum useEnum = FileUseEnum.getByCode(use); //如果資料夾不存在則建立 String dir = useEnum.name().toLowerCase(); File fullDir = new File(FILE_PATH + dir); if (!fullDir.exists()) { fullDir.mkdir(); } // String path = dir + File.separator + key + "." + suffix + "." + fileDto.getShardIndex(); String path = new StringBuffer(dir) .append(File.separator) .append(key) .append(".") .append(suffix) .toString(); // course\6sfSqfOwzmik4A4icMYuUe.mp4 String localPath = new StringBuffer(path) .append(".") .append(fileDto.getShardIndex()) .toString(); // course\6sfSqfOwzmik4A4icMYuUe.mp4.1 String fullPath = FILE_PATH + localPath; File dest = new File(fullPath); shard.transferTo(dest); LOG.info(dest.getAbsolutePath()); LOG.info("儲存檔案記錄開始"); fileDto.setPath(path); fileService.save(fileDto); ResponseDto responseDto = new ResponseDto(); fileDto.setPath(FILE_DOMAIN + path); responseDto.setContent(fileDto); if (fileDto.getShardIndex().equals(fileDto.getShardTotal())) { this.merge(fileDto); } return responseDto; } public void merge(FileDto fileDto) throws Exception { LOG.info("合併分片開始"); String path = fileDto.getPath(); //http://127.0.0.1:9000/file/f/course\6sfSqfOwzmik4A4icMYuUe.mp4 path = path.replace(FILE_DOMAIN, ""); //course\6sfSqfOwzmik4A4icMYuUe.mp4 Integer shardTotal = fileDto.getShardTotal(); File newFile = new File(FILE_PATH + path); FileOutputStream outputStream = new FileOutputStream(newFile, true);//檔案追加寫入 FileInputStream fileInputStream = null;//分片檔案 byte[] byt = new byte[10 * 1024 * 1024]; int len; try { for (int i = 0; i < shardTotal; i++) { // 讀取第i個分片 fileInputStream = new FileInputStream(new File(FILE_PATH + path + "." + (i + 1))); // course\6sfSqfOwzmik4A4icMYuUe.mp4.1 while ((len = fileInputStream.read(byt)) != -1) { outputStream.write(byt, 0, len); } } } catch (IOException e) { LOG.error("分片合併異常", e); } finally { try { if (fileInputStream != null) { fileInputStream.close(); } outputStream.close(); LOG.info("IO流關閉"); } catch (Exception e) { LOG.error("IO流關閉", e); } } LOG.info("合併分片結束"); System.gc(); Thread.sleep(100); // 刪除分片 LOG.info("刪除分片開始"); for (int i = 0; i < shardTotal; i++) { String filePath = FILE_PATH + path + "." + (i + 1); File file = new File(filePath); boolean result = file.delete(); LOG.info("刪除{},{}", filePath, result ? "成功" : "失敗"); } LOG.info("刪除分片結束"); } @GetMapping("/check/{key}") public ResponseDto check(@PathVariable String key) throws Exception { LOG.info("檢查上傳分片開始:{}", key); ResponseDto responseDto = new ResponseDto(); FileDto fileDto = fileService.findByKey(key); if (fileDto != null) { if (StringUtils.isEmpty(fileDto.getVod())) { fileDto.setPath(FILE_DOMAIN + fileDto.getPath()); } else { DefaultAcsClient vodClient = VodUtil.initVodClient(accessKeyId, accessKeySecret); GetMezzanineInfoResponse response = VodUtil.getMezzanineInfo(vodClient, fileDto.getVod()); System.out.println("獲取視訊資訊, response : " + JSON.toJSONString(response)); String fileUrl = response.getMezzanine().getFileURL(); fileDto.setPath(fileUrl); } } responseDto.setContent(fileDto); return responseDto; } }
logback.xml
<?xml version="1.0" encoding="UTF-8"?> <configuration> <!-- 修改一下路徑--> <property name="PATH" value="/log/imooc/course/file"></property> <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> <encoder> <!-- <Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %blue(%-50logger{50}:%-4line) %msg%n</Pattern>--> <Pattern>%d{ss.SSS} %highlight(%-5level) %blue(%-30logger{30}:%-4line) %msg%n</Pattern> </encoder> </appender> <appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${PATH}/trace.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>${PATH}/trace.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <layout> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-8X{UUID}) %msg%n</pattern> </layout> </appender> <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> <file>${PATH}/error.log</file> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <FileNamePattern>${PATH}/error.%d{yyyy-MM-dd}.%i.log</FileNamePattern> <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> <maxFileSize>10MB</maxFileSize> </timeBasedFileNamingAndTriggeringPolicy> </rollingPolicy> <layout> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level %-50logger{50}:%-4line %green(%-8X{UUID}) %msg%n</pattern> </layout> <filter class="ch.qos.logback.classic.filter.LevelFilter"> <level>ERROR</level> <onMatch>ACCEPT</onMatch> <onMismatch>DENY</onMismatch> </filter> </appender> <root level="ERROR"> <appender-ref ref="ERROR_FILE" /> </root> <root level="TRACE"> <appender-ref ref="TRACE_FILE" /> </root> <root level="INFO"> <appender-ref ref="STDOUT" /> </root> </configuration>