首先是Controller层的入口方法
@ApiOperation注解是swagger接口文档的,没用这个可以直接删掉
@RequestParam注解是用来接收其它参数的,我这个是为了标记文件类型的,比如是临时文件还是其它文件
import org.springframework.web.multipart.MultipartFile;
@PostMapping("/upload")
@ApiOperation(value = "上传文件")
public Map upload(@RequestPart("file") MultipartFile file, @RequestParam(value = "mediaLibrary") Integer mediaLibrary) throws Exception {
Map map = fileService.upload(file, mediaLibrary);
return map;
}
这个接口在postman上传参是下面这样的:
注意里面的参数名称要和接口上的一致,不然会拿不到值
还有file那里key的类型要选file类型的,这样就可以在后面value里面选择文件
然后是Service方法
这里面LOCAL_HOST就是取配置文件里面的项目访问路径比如http://127.0.0.1:8080/,或者你的域名
上传的文件都保存在根目录./resources/files/下了,也就是跟部署的jar包同目录下
UploadFile 是用来记录上传文件的实体类,方便做文件列表管理的
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sakura.base.exception.BizException;
import com.sakura.base.utils.DateUtil;
import com.sakura.base.utils.FileTypeTool;
import com.sakura.entity.UploadFile;
import com.sakura.demo.mapper.UploadFileMapper;
import com.sakura.demo.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
@Override
@Transactional
public Map upload(MultipartFile multipartFile, Integer mediaLibrary) throws Exception {
if (multipartFile.isEmpty()) {
throw new BizException(500, "上传文件为空");
}
UploadFile uploadFile = new UploadFile();
// 保存原文件名称,文件列表展示需要用到
uploadFile.setFileName(multipartFile.getOriginalFilename());
// 生成系统文件名称,不可重复,防止同名文件上传覆盖问题
String name = RandomStringUtils.randomAlphanumeric(32) + multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".")).toLowerCase();
uploadFile.setName(name.substring(0, name.lastIndexOf(".")));
uploadFile.setFileSuffix(multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".")).toLowerCase());
// 判断文件类型
int fileType = FileTypeTool.fileType(name);
uploadFile.setType(fileType);
uploadFile.setDomain(LOCAL_HOST + "file/");
uploadFile.setPath(LOCAL_HOST + "file/" + name.substring(0, name.lastIndexOf(".")));
uploadFile.setPathExt(DateUtil.today());
// 获取文件大小
uploadFile.setSize((int)multipartFile.getSize());
uploadFile.setMediaLibrary(mediaLibrary);
uploadFile.setStatus(1);
uploadFileMapper.insert(uploadFile);
// 将文件保存到本目录/resources/files/下
// DateUtil.today()得到得是当天日期如:20230715,这个会在/resources/files/下再以日期生成一层目录
File newFile = new File("./resources/files/" + DateUtil.today() + "/" + name);
// 保证这个文件的父文件夹必须要存在
if (!newFile.getParentFile().exists()) {
newFile.getParentFile().mkdirs();
}
newFile.createNewFile();
// 将文件内容写入到这个文件中
InputStream is = multipartFile.getInputStream();
FileOutputStream fos = new FileOutputStream(newFile);
try {
int len;
byte[] buf = new byte[1024];
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
} finally {
// 关流顺序,先打开的后关闭
fos.close();
is.close();
}
// 返回文件信息给前端
Map resultMap = new HashMap();
resultMap.put("id", uploadFile.getId());
resultMap.put("path", uploadFile.getPath());
resultMap.put("code", 200);
resultMap.put("message", "请求成功!");
return resultMap;
}
刚才上传路径返回给前端的路径是这样的:http://127.0.0.1:8080/file/ojod5g3as12g3sd2g13g1a3g1g785ef9
所以要拿到这个文件还需要下面这个下载的接口
同样的Controller的入口方法
@GetMapping("/{name}")
@ApiOperation(value = "下载", response = ApiResult.class)
public void download(HttpServletResponse response, @PathVariable("name") String name) throws Exception {
fileService.download(response, name);
}
然后是Service方法
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sakura.base.exception.BizException;
import com.sakura.base.utils.DateUtil;
import com.sakura.base.utils.FileTypeTool;
import com.sakura.entity.UploadFile;
import com.sakura.demo.mapper.UploadFileMapper;
import com.sakura.demo.service.FileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
@Override
public void download(HttpServletResponse response, String name) throws Exception {
LambdaQueryWrapper<UploadFile> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(UploadFile::getName, name);
wrapper.eq(UploadFile::getStatus, 1);
UploadFile uploadFile = uploadFileMapper.selectOne(wrapper);
if (uploadFile == null) {
throw new BizException(500, "文件不存在");
}
// 去./resources/files/目录下取出文件
File downloadFile = File("./resources/files/" + uploadFile.getPathExt() + "/" + name + uploadFile.getFileSuffix());
if(!downloadFile.exists() || downloadFile.length() == 0) {
throw new BizException(500, "文件不存在");
}
InputStream is = null;
OutputStream os = null;
try {
// 判断是否是图片,如果是图片加上 response.setContentType("image/jpeg"),这样就可以直接在浏览器打开而不是下载
if (uploadFile.getType() == 1) {
response.setContentType("image/jpeg");
}
response.addHeader("Content-Length", "" + downloadFile.length());
is = new FileInputStream(downloadFile);
os = response.getOutputStream();
IOUtils.copy(is, os);
} catch (Exception e) {
log.error("下载图片发生异常", e);
} finally {
try {
if (os != null) {
os.flush();
os.close();
}
if (is != null) {
is.close();
}
} catch (IOException e) {
log.error("关闭流发生异常", e);
}
}
}
3.其它工具类,根据文件后缀判断文件类型的
package com.sakura.base.utils;
public class FileTypeTool {
public static int fileType(String fileName) {
if (fileName == null) {
return 0;
} else {
// 获取文件后缀名并转化为写,用于后续比较
String fileType = fileName.substring(fileName.lastIndexOf(".") + 1).toLowerCase();
// 创建图片类型数组
String img[] = {"bmp", "jpg", "jpeg", "png", "tiff", "gif", "pcx", "tga", "exif", "fpx", "svg", "psd",
"cdr", "pcd", "dxf", "ufo", "eps", "ai", "raw", "wmf"};
for (int i = 0; i < img.length; i++) {
if (img[i].equals(fileType)) {
return 1;
}
}
// 创建文档类型数组
String document[] = {"txt", "doc", "docx", "xls", "htm", "html", "jsp", "rtf", "wpd", "pdf", "ppt"};
for (int i = 0; i < document.length; i++) {
if (document[i].equals(fileType)) {
return 2;
}
}
// 创建视频类型数组
String video[] = {"mp4", "avi", "mov", "wmv", "asf", "navi", "3 gp", "mkv", "f4v", "rmvb", "webm"};
for (int i = 0; i < video.length; i++) {
if (video[i].equals(fileType)) {
return 3;
}
}
// 创建音乐类型数组
String music[] = {"mp3", "wma", "wav", "mod", "ra", "cd", "md", "asf", "aac", "vqf", "ape", "mid", "ogg",
"m4a", "vqf"};
for (int i = 0; i < music.length; i++) {
if (music[i].equals(fileType)) {
return 4;
}
}
}
return 0;
}
}