文件下载与上传
文件上传与下载
工具:hutool
springboot 文件上传与下载,hutool目录操作、文件解压、yaml文件操作。此例子展示了一个文件压缩包上传到服务器,解压放到某个特定目录的,并且校验md5值
html
<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>
springboot
上传
/**
* 规定,一个归档文件比如叫 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();
}