目录
- 主要流程
- 编写接受文件上传的Controller
- 编写文件操作结果类
- 编写文件操作类
- 知识总结
- 参考
主要流程
- 在配置文件中添加文件操作的配置,示例:
storage:image:#保存位置save-path: D:\classdesign-photo\images\#允许上传的类型allow-type:- jpg- png
- 编写文件操作配置类,示例:
/*** 图片操作配置类*/
@Configuration
//用于自动获取配置文件中storage.image中的字段
@ConfigurationProperties("storage.image")
@Data
public class ImageConfig {private String savePath;private List<String> allowType;
}
- 编写接受文件上传的Controller方法,并带上参数
MultipartFile file
,如:
public T upload(MultipartFile file) throws IOException {...}
- 计算文件的字节数组的MD5的值,查找数据库中是否有重复的MD5值,防止重复上传相同文件(可以使用Hutool计算MD5),后面有具体实现
- 保存文件到对应文件夹,并往数据库中添加一条记录,数据库只存储文件的路径、MD5值、上传用户等信息
编写接受文件上传的Controller
在SpringBoot接受文件比较简单,只需要在Controller方法上加上参数MultipartFile file
即可获取前端上传的文件
@PostMapping("/upload")public Response<FileHandlerResult> upload(MultipartFile image) throws IOException {//自定义的通用回复类Response<FileHandlerResult> res = new Response<>();//自定义文件保存结果通用类FileHandlerResult saveRes = fileManager.saveImage(image);if(saveRes.getCode()==-1){//保存失败res.fail(saveRes.getDesc());return res;}else if(saveRes.getCode() == 0){//图片已存在res.setDesc(saveRes.getDesc());res.setData(saveRes);}res.success(saveRes);return res;}
编写文件操作结果类
因为保存文件的过程中可能出现成功、失败、异常三种情况,因此编写一个通用的文件操作结果类来返回信息
/*** 文件操作结果*/
@Data
public class FileHandlerResult{/*** 状态码,成功:1,失败:-1,其他:0(如:图片已存在)*/private int code;private String md5;//文件字节数组的md5,用于防止重复上传private String path;//文件存储路径private String desc;//结果状态描述public void success(String md5, String path){this.code = 1;this.md5 = md5;this.path = path;this.desc = "保存文件成功";}public void alreadyExisted(String md5, String path){this.code = 0;this.md5 = md5;this.path =path;this.desc = "文件已存在,请勿重复保存";}public void fail(String desc){this.code = -1;this.desc = desc;}}
编写文件操作类
此类中通过文件后缀来判断文件类型的方式并不安全(文件后缀可以伪造),应通过魔数判断,可参考:Java 通过魔数判断上传文件的类型
/*** 文件操作类* 用于文件的基本*/
@Component
public class FileManager<T extends BaseEntity> {@AutowiredBaseFileDao<T> dao;@AutowiredImageConfig imageConfig;//一开始编写的文件配置类/**** @param uploadFile 从控制器接收到的文件* @return*/public FileHandlerResult saveImage(MultipartFile uploadFile) {//获取文件类型,根据文件后缀判断文件类型的方式不安全!String contentType = uploadFile.getContentType();String type = contentType.substring(contentType.indexOf("/")+1);//文件操作返回结果FileHandlerResult handlerResult = new FileHandlerResult();if(!imageConfig.getAllowType().contains(type)){//判断是否为允许的文件类型handlerResult.fail("保存失败,仅支持:"+imageConfig.getAllowType());return handlerResult;}try{File file = new File(imageConfig.getSavePath());if(!file.exists()){//创建文件夹,会自动创建父文件夹file.mkdirs();//创建目录说明文件String descFilePath = new File(imageConfig.getSavePath()).getParentFile().toString()+"\\目录说明.txt";try(BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(descFilePath)))){writer.write("此目录为保存 xxx 项目文件的目录");}}byte[] bytes = uploadFile.getBytes();//图片字节数组的md5String md5 = SecureUtil.md5(uploadFile.getInputStream());List<T> list = dao.getByMd5(md5);//图片保存路径String path = imageConfig.getSavePath() + md5+"."+type;if(list.size() != 0){//图片已存在handlerResult.alreadyExisted(md5, path);return handlerResult;}try(BufferedOutputStream os = new BufferedOutputStream(new FileOutputStream(path))){os.write(bytes);}handlerResult.success(md5, path);return handlerResult;}catch(FileNotFoundException e){e.printStackTrace();handlerResult.fail(e.getMessage());return handlerResult;}catch (IOException e){e.printStackTrace();handlerResult.fail(e.getMessage());return handlerResult;}}
}
知识总结
- SpringBoot 使用
MultipartFile
类型的参数接受前端上传的文件 - 通过计算文件字节数组的MD5值,可用于防止文件重复上传
- 通过
File
类的创建目录时:
mkdir()
创建目录必须确保路径的父目录已存在
mkdirs()
如果父文件夹不存在时并且最后一级子文件夹不存在,它就自动新建所有路经里写的文件夹;如果父文件夹存在,它就直接在已经存在的父文件夹下新建子文件夹。
参考
- MultipartFile 类
- Java 通过魔数判断上传文件的类型
- SpringBoot实现多文件上传
- java File类mkdir()与mkdirs()方法的区别