工具:hutool
springboot 檔案上傳與下載,hutool目錄操作、檔案解壓、yaml檔案操作。此例子展示了一個檔案壓縮包上傳到伺服器,解壓放到某個特定目錄的,並且校驗md5值
<html lang="en">
<head>
<meta charset="UTF-8">
<title>檔案上傳介面</title>
</head>
<body>
<div>
<form method="POST" enctype="multipart/form-data" action="/upload">
<table>
<tr>
<td><input type="file" name="file"/></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="上傳"/></td>
</tr>
</table>
</form>
<a href="http://localhost:8080/download" download> file_name </a>
</div>
</body>
</html>
/**
* 規定,一個歸檔檔案比如叫 1.1.1.2023.tar 這個歸檔檔案裡面有兩個檔案一個叫:upgrade-info.yml 一個叫:1.1.1.2023.tar.gz
* 這個歸檔檔案放到 /device-upgrade-pack-repo/1.1.1.2023 資料夾,然後將歸檔檔案在此目錄解壓,然後刪除歸檔檔案
* 最終目錄結構為:
* /device-upgrade-pack-repo/1.1.1.2023
* |--> 1.1.1.2023.tar.gz
* |--> upgrade-info.yml
* |--> 1.1.1.2023.tar
*
* @param file
* @return
*/
@PostMapping("/upload")
public AjaxResult upload(@RequestParam("file") MultipartFile file) {
if (file.isEmpty()) {
return error("檔案不能為空");
}
String filename = file.getOriginalFilename();
// 檔案大概名字為:1.1.1.2023.tar ,不要 .tar 字尾
String versionNum = filename.substring(0, filename.length() - 4);
// jar包的上一級目錄
String canonicalPath = FileUtil.getCanonicalPath(new File(".."));
// 建立目錄
String directory = canonicalPath + "/device-upgrade-pack-repo/" + versionNum;
FileUtil.mkdir(directory);
// 將檔案放到目錄
String filePath = directory + "/" + filename;
try {
// 此方法是,如果檔案已經存在,那麼會刪除老的,然後用新的檔案
file.transferTo(new File(filePath));
} catch (IOException e) {
throw new ServiceException("檔案上傳失敗");
}
// 解壓
Extractor extractor = CompressUtil.createExtractor(
CharsetUtil.defaultCharset(),
FileUtil.file(filePath));
extractor.extract(FileUtil.file(directory));
// 讀取upgrade-info.yml 檔案, 對比md5,如果不正確則返回錯誤,並刪除目錄
Yaml yaml = new Yaml();
BufferedInputStream inputStream = FileUtil.getInputStream(directory + "/upgrade-info.yml");
Map<String, Object> obj = yaml.load(inputStream);
try {
inputStream.close();
} catch (IOException e) {
throw new ServiceException("讀取upgrade-info.yml異常,檢視檔案是否存在");
}
String md5 = (String) obj.get("md5");
String version = (String) obj.get("versionNum");
String devType = (String) obj.get("devType");
// 校驗md5值
String digestHex = SecureUtil.md5().digestHex(FileUtil.file(filePath + ".gz"));
// 如果md5值不相等
if (!StringUtils.equals(md5, digestHex)) {
log.info("md5 {} digestHex {}", md5, digestHex);
// 刪除目錄,並且返回錯誤
boolean del = FileUtil.del(directory);
if (del) {
return error("壓縮包與yml檔案中校驗碼不一致,請確認升級包是否正確");
} else {
return error("壓縮包與yml檔案中校驗碼不一致,且上傳的檔案刪除失敗,請聯絡系統管理員");
}
}
// 返回upgrade-info.yml 中的資訊
JSONObject res = new JSONObject();
res.put("versionNum", version);
res.put("checkCode", md5);
res.put("devType", devType);
return success(res);
}
根據一定規則找到檔案目錄,然後進行下載
"Content-disposition: attachment;filename=" + versionNum + ".tar" 這個的作用是設定下載的檔案的名字,比如說versionNum的值為1.1.0,那麼下載檔案的名字為1.1.0.tar
@SneakyThrows
@GetMapping("/download")
public void download(HttpServletResponse response, @RequestParam String versionNum) {
if (StringUtils.isEmpty(versionNum)) {
throw new ServiceException("版本號不能為空");
}
// jar包的上一級目錄
String canonicalPath = FileUtil.getCanonicalPath(new File(".."));
String filePath = canonicalPath + "/device-upgrade-pack-repo/" + versionNum + "/" + versionNum + ".tar";
BufferedInputStream stream = FileUtil.getInputStream(filePath);
response.setContentType("application/octet-stream");
response.setHeader("Content-disposition",
"attachment;filename=" + versionNum + ".tar");
// Read the input stream and print to the console till EOF.
byte[] buf = new byte[16384];
int bytesRead;
while ((bytesRead = stream.read(buf, 0, buf.length)) >= 0) {
response.getOutputStream().write(buf, 0, bytesRead);
}
stream.close();
}