首先在yml配置文件路径:
files: upload: path: D:/spring+vue项目练习/File
//获得yml配置文件中的文件上传路径
@Value("${files.upload.path}")
private String fileUploadPath;
@Autowired
IFileService fileService;
//上传文件
@PostMapping
public String upload(@RequestParam MultipartFile file) throws IOException {
//获得文件原始名称
String originName=file.getOriginalFilename();
//获得文件后缀
String type= FileUtil.extName(originName);
long size=file.getSize();
//先存储到磁盘
//父文件夹
File uploadParentFile=new File(fileUploadPath);
//不存在就先创建
if(!uploadParentFile.exists()){
uploadParentFile.mkdirs();
}
//定义文件唯一标识码
String uuid= IdUtil.fastSimpleUUID();
String fileUUID=uuid+ StrUtil.DOT +type;
//父文件夹下面的文件
File uploadFile =new File(fileUploadPath+fileUUID);
//为了防止出现一个图片多次出现的问题,使用md5给文件赋予唯一标识
String md5= SecureUtil.md5(file.getInputStream());
//查数据库看是否有md5相同的文件,如果有,证明文件夹已经有相同图片,就不再储存进入磁盘,达到节约内存的作用
//文件路径
String url="";
//查到url就用之前的,否则再赋值
Files Files=getFileByMd5(md5);
if(Files!=null)
{
url=Files.getUrl();
}
else
{
//把获取到的文件存储到磁盘目录
file.transferTo(uploadFile);
url="http://localhost:8080/file/"+fileUUID;
}
//写入数据库
Files files=new Files();
files.setName(originName);
files.setType(type);
files.setSize(size/1024);
files.setMd5(md5);
files.setUrl(url);
fileService.save(files);
return url;
}
通过上面方法接收到上传的文件后,返回一个url表示当前文件的路径(不包括前面的local.../file/,这一段只是为了可以访问到下面的方法,所以下面接受到的uuid实际上只有上面的fileUUID)
然后下面通过get接受后,可以获得文件的uuid,通过文件uuid可以获得上传文件在磁盘的路径
//下载文件
@GetMapping("/{fileUUID}")
public void download(@PathVariable String fileUUID, HttpServletResponse response) throws IOException {
//根据唯一标识获得文件
File uploadFile=new File(fileUploadPath+fileUUID);
//设置输出流的格式
ServletOutputStream os=response.getOutputStream();
/*
在 HTTP 场景中,第一个参数或者是 inline(默认值,表示回复中的消息体会以页面的一部分或者整个页面的形式展示),
或者是 attachment(意味着消息体应该被下载到本地;大多数浏览器会呈现一个“保存为”的对话框,
attachment后接 filename 的值预填为下载后的文件名,假如它存在的话)。
*/
response.addHeader("Content-Disposition","attachment;filename="+ URLEncoder.encode(fileUUID,"UTF-8"));
//告知浏览器这是一个字节流,浏览器处理默认字节流的方式是下载
response.setContentType("application/octet-stream");
//以上2行个人测试:同时注释2行那浏览器或者注释第二行把第一行的attachment和后面的filename=...换成inline不会下载图片,变成在浏览器直接展示图片,注释其中一个都会变成下载
//读取文件的字节流
os.write(FileUtil.readBytes(uploadFile));
os.flush();
os.close();
}
//通过md5查文件
private Files getFileByMd5(String md5){
LambdaQueryWrapper<Files>lambdaQueryWrapper=new LambdaQueryWrapper<>();
lambdaQueryWrapper.eq(Files::getMd5,md5);
List<Files> filesList=fileService.list(lambdaQueryWrapper);
if(filesList.size()==0)return null;
return filesList.get(0);
}