SpringBoot文件上传

  • Pom
  • yml
  • controller
    • UploadController
    • FileController
      • 文件上传
      • 多文件上传
      • 文件下载
  • 页面
  • BUG
  • 封装版
    • 工具类
      • StringUtil
      • MimeTypeUtils
      • FileUploadUtils
    • 异常类
      • FileNameLengthLimitExceededException
      • FileSizeLimitExceededException
      • InvalidExtensionException
    • Controller层

工作中上传文件是常见的场景之一,最典型的情况就是上传头像等,上传文档。自己上传文件中遇到的坑,自己已经填了,现在把它写下来,方便提醒自己,我使用的是Spring Boot 上传文件

Pom

主要引入了webthymeleaf启动器

<!-- web start-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- web end-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency><!-- io常用工具类 -->
<dependency><groupId>commons-io</groupId><artifactId>commons-io</artifactId><version>2.5</version>
</dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId>
</dependency>

yml

spring:servlet:multipart:max-file-size: 10MB  # 最大支持文件大小max-request-size: 10MB  # 最大支持请求大小#enabled: true  #默认支持文件上传.# file-size-threshold: #支持文件写入磁盘.#location: #上传文件的临时目录

controller

UploadController

UploadController首页的显示

@Controller
public class UploadController {@GetMapping("/")public String index() {return "upload";}}

FileController

FileController文件上传,下载请求

文件上传

/*** @author: 三月三* @description:  单个文件上传* @param: [file]* @return: java.lang.String*/@RequestMapping(value = "/upload")public String upload(HttpServletRequest request, @RequestParam("file") MultipartFile file, Model model) {// 测试MultipartFile接口的各个方法System.out.println("文件类型ContentType=" + file.getContentType());System.out.println("文件组件名称Name=" + file.getName());System.out.println("文件原名称OriginalFileName=" + file.getOriginalFilename());System.out.println("文件大小Size=" + file.getSize()/1024 + "KB");try {if (file.isEmpty()) {return "文件为空";}// 获取文件名String fileName = file.getOriginalFilename();log.info("上传的文件名为:" + fileName);// 获取文件的后缀名String suffixName = fileName.substring(fileName.lastIndexOf("."));log.info("文件的后缀名为:" + suffixName);// 获取文件相对类路径//String filePath = request.getServletContext().getRealPath("/");//文件绝对路径,项目中一般使用相对类路径,即使文件变更路径也会跟着变String filePath = request.getServletContext().getRealPath("G:\\dev_workspace\\springboot-learning-examples\\springboot-13-fileupload\\src\\main\\resources\\static");System.out.println("path = " + filePath);//构造一个路径String newImg = UUID.randomUUID()+suffixName;String path = filePath + newImg;log.info("构造路径"+path);File dest = new File(path);// 检测是否存在目录if (!dest.getParentFile().exists()) {dest.getParentFile().mkdirs();// 新建文件夹}file.transferTo(dest);// 文件写入model.addAttribute("msg","<font color=\"green\">上传成功</font>");model.addAttribute("img",newImg);return "upload";} catch (IllegalStateException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}model.addAttribute("msg","<font color=\"green\">上传失败</font>");return "upload";}

多文件上传

 /*** @author: 三月三* @description: 多个文件上传* @param: [request]* @return: java.lang.String*/@PostMapping("/batch")public String handleFileUpload(Model model,HttpServletRequest request) {List<MultipartFile> files = ((MultipartHttpServletRequest) request).getFiles("file");MultipartFile file = null;BufferedOutputStream stream = null;for (int i = 0; i < files.size(); ++i) {file = files.get(i);//文件绝对路径,项目中一般使用相对类路径,即使文件变更路径也会跟着变String filePath = request.getServletContext().getRealPath("G:\\dev_workspace\\springboot-learning-examples\\springboot-13-fileupload\\src\\main\\resources\\static");if (!file.isEmpty()) {try {byte[] bytes = file.getBytes();stream = new BufferedOutputStream(new FileOutputStream(new File(filePath + file.getOriginalFilename())));//设置文件路径及名字stream.write(bytes);// 写入stream.close();} catch (Exception e) {stream = null;model.addAttribute("msg", "第 " + i + " 个文件上传失败 ==> "+ e.getMessage());return "upload";}} else {model.addAttribute("msg","第 " + i+ " 个文件上传失败因为文件为空");return "upload";}}model.addAttribute("msg","上传成功");return "upload";}

文件下载

/*** @author: 三月三* @description:  文件下载* @param: [model, request, response, fileName]* @return: java.lang.String*/@PostMapping("/download")public String downloadFile(Model model,HttpServletRequest request, HttpServletResponse response,String fileName) {if (fileName != null) {//设置文件路径   真实环境是存放在数据库中的// String filePath = request.getServletContext().getRealPath("/");//文件绝对路径,项目中一般使用相对类路径,即使文件变更路径也会跟着变String filePath = request.getServletContext().getRealPath("G:\\dev_workspace\\springboot-learning-examples\\springboot-13-fileupload\\src\\main\\resources\\static");File file = new File(filePath);if (file.exists()) {response.setContentType("application/force-download");// 设置强制下载不打开response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 设置文件名byte[] buffer = new byte[1024];FileInputStream fis = null;BufferedInputStream bis = null;try {fis = new FileInputStream(file);bis = new BufferedInputStream(fis);// 创建输出对象OutputStream os = response.getOutputStream();int i = bis.read(buffer);while (i != -1) {os.write(buffer, 0, i);i = bis.read(buffer);}model.addAttribute("msg","<font color=\"green\">下载成功</font>");return "upload";} catch (Exception e) {e.printStackTrace();} finally {if (bis != null) {try {bis.close();} catch (IOException e) {e.printStackTrace();}}if (fis != null) {try {fis.close();} catch (IOException e) {e.printStackTrace();}}}}}model.addAttribute("msg","<font color=\"red\">下载失败</font>");return "upload";}

页面

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body><h1>Spring Boot file upload example</h1><p>单文件上传</p>
<form action="upload" method="POST" enctype="multipart/form-data">文件:<input type="file" name="file"/><input type="submit"/>
</form><span  th:if="${msg!=null}" th:utext="${msg}"></span><div th:if="${img!=null}"><img th:src="${img}"><p>文件下载</p><form action="download" method="post"><input type="hidden" th:value="${img}" name="fileName"/><input type="submit" value="下载文件"/></form>
</div><p>多文件上传</p>
<form method="POST" enctype="multipart/form-data" action="batch"><p>文件1:<input type="file" name="file"/></p><p>文件2:<input type="file" name="file"/></p><p><input type="submit" value="上传"/></p>
</form>
</body>
</html>

BUG

  1. 文件上传路径问题
  2. 文件下载的路径问题

解决:

  1. String filePath = request.getServletContext().getRealPath("/");获取的是tomcat目录下webapps下的目录及类路径(class文件存放的路径),因为我使用的是SpringBoot项目,而SringBoot项目内嵌了tomcat,路径为C:\Users\L15096000421\AppData\Local\Temp\tomcat-docbase.2191751665660359817.8080\的一个临时目录,重启项目,文件就丢失了
  2. 还有使用String filePath = request.getServletContext().getRealPath("/")做为下载的路径去下载文件,后台报错没有权限,使用绝对路径下载,及使用绝对路径上传
  3. 可以使用 private static final String parentPath = ClassUtils.getDefaultClassLoader().getResource("static/images").getPath();获取springboot项目static/images的目录

封装版

工具类

StringUtil

/*** 字符串工具类,抽取一些常用操作*/
public class StringUtil {/*** 判断val是否不为空(null/"")* @param val* @return*/public static boolean isNotEmpty(String val){return val != null && !"".equals(val);}/*** 将给定的驼峰命名值转换为下划线命名* @param val* @return*/public static String toUnderScoreCase(String val){if(!isNotEmpty(val)){return val;}StringBuilder sb = new StringBuilder(val);for(int i = 0; i < sb.length(); i++){if(sb.charAt(i) >= 'A' && sb.charAt(i) <= 'Z'){//将大写字母 "A" 替换为 "_a"sb.replace(i, i + 1, "_" + (char)(sb.charAt(i) + 32));}}return sb.toString();}}

MimeTypeUtils

/*** 媒体类型工具类**/
public class MimeTypeUtils
{public static final String IMAGE_PNG = "image/png";public static final String IMAGE_JPG = "image/jpg";public static final String IMAGE_JPEG = "image/jpeg";public static final String IMAGE_BMP = "image/bmp";public static final String IMAGE_GIF = "image/gif";public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };public static final String[] DEFAULT_ALLOWED_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};public static String getExtension(String prefix){switch (prefix){case IMAGE_PNG:return "png";case IMAGE_JPG:return "jpg";case IMAGE_JPEG:return "jpeg";case IMAGE_BMP:return "bmp";case IMAGE_GIF:return "gif";default:return "";}}
}

FileUploadUtils

/*** 文件上传工具类*/
public class FileUploadUtils
{/*** 默认大小 50M*/public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;/*** 默认的文件名最大长度 100*/public static final int DEFAULT_FILE_NAME_LENGTH = 100;/*** 默认存储图片目录*/private static final String parentPath = ClassUtils.getDefaultClassLoader().getResource("static/images").getPath();public static final String actorPath = "/actor";public static final String cinemaPath = "/cinema";public static final String moviePath = "/movie";public static final String userPath = "/user";/*** 默认上传的地址*/private static String defaultBaseDir = userPath;public static void setDefaultBaseDir(String defaultBaseDir){FileUploadUtils.defaultBaseDir = defaultBaseDir;}public static String getDefaultBaseDir(){return defaultBaseDir;}public static String getParentPath() {return parentPath;}/*** 以默认配置进行文件上传** @param file 上传的文件* @return 文件名称* @throws Exception*/public static final String upload(MultipartFile file) throws IOException{try{return upload(getParentPath() + getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);}catch (Exception e){throw new IOException(e.getMessage(), e);}}/*** 文件上传** @param baseDir 相对应用的基目录* @param file 上传的文件* @param allowedExtension 上传文件类型* @return 返回上传成功的文件名*/public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,InvalidExtensionException{int fileNamelength = file.getOriginalFilename().length();if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH){throw new FileNameLengthLimitExceededException("文件名称长度不能超过" + FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);}//文件大小校验assertAllowed(file, allowedExtension);//编码文件名String fileName = extractFilename(file);//File desc = getAbsoluteFile(baseDir, fileName);file.transferTo(desc);String pathFileName = getPathFileName(baseDir, fileName);return pathFileName;}/*** 编码文件名 如 : images/user/2020/12/4/***.png*/public static final String extractFilename(MultipartFile file){String fileName = file.getOriginalFilename();String extension = getExtension(file);fileName = DateFormatUtils.format(new Date(), "yyyy/MM/dd") + "/" + UUID.randomUUID().toString().replaceAll("-","") + "." + extension;return fileName;}private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException{File desc = new File(uploadDir + File.separator + fileName);if (!desc.getParentFile().exists()){desc.getParentFile().mkdirs();}if (!desc.exists()){desc.createNewFile();}return desc;}private static final String getPathFileName(String uploadDir, String fileName) throws IOException{int dirLastIndex = parentPath.length() + 1;String currentDir = StringUtils.substring(uploadDir, dirLastIndex);String pathFileName = "/images/" + currentDir + "/" + fileName;return pathFileName;}/*** 文件大小校验** @param file 上传的文件* @return* @throws FileSizeLimitExceededException 如果超出最大大小* @throws InvalidExtensionException*/public static final void assertAllowed(MultipartFile file, String[] allowedExtension)throws FileSizeLimitExceededException, InvalidExtensionException{long size = file.getSize();if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE){throw new FileSizeLimitExceededException("文件大小不能超过" + DEFAULT_MAX_SIZE / 1024 / 1024 + "MB");}String fileName = file.getOriginalFilename();String extension = getExtension(file);if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)){// if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)throw new InvalidExtensionException("图片格式不支持" + extension + "格式");}}/*** 判断MIME类型是否是允许的MIME类型** @param extension* @param allowedExtension* @return*/public static final boolean isAllowedExtension(String extension, String[] allowedExtension){for (String str : allowedExtension){if (str.equalsIgnoreCase(extension)){return true;}}return false;}/*** 获取文件名的后缀** @param file 表单文件* @return 后缀名*/public static final String getExtension(MultipartFile file){String extension = FilenameUtils.getExtension(file.getOriginalFilename());if (!StringUtil.isNotEmpty(extension)){extension = MimeTypeUtils.getExtension(file.getContentType());}return extension;}}

异常类

FileNameLengthLimitExceededException

/*** 文件名字长度超过限制异常,用于文件校验*/
public class FileNameLengthLimitExceededException extends RuntimeException{private static final long serialVersionUID = 1L;public FileNameLengthLimitExceededException(){}public FileNameLengthLimitExceededException(String message){super(message);}}

FileSizeLimitExceededException

/*** 文件大小超过限制异常,用于文件校验*/
public class FileSizeLimitExceededException extends RuntimeException{private static final long serialVersionUID = 1L;public FileSizeLimitExceededException(){}public FileSizeLimitExceededException(String message){super(message);}}

InvalidExtensionException

/*** 文件后缀无效异常,用于文件校验*/
public class InvalidExtensionException extends RuntimeException{private static final long serialVersionUID = 1L;public InvalidExtensionException(){}public InvalidExtensionException(String message){super(message);}}

Controller层

multifile.html页面

    <form action="/uploadFile" method="post" enctype="multipart/form-data"><p align="center">选择文件1:<input type="file" name="file"/></p><p align="center"><input type="submit" value="提交"/></p></form>

Controller

    @PostMapping("/uploadFile")public String uploadFile(@RequestPart("file") MultipartFile file,Model model) throws IOException {String upload = FileUploadUtils.upload(file);log.info("上传路径:{}",upload);model.addAttribute("uploadUrl",upload);return "img";}

img.html页面

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"><head><meta charset="UTF-8"><title>Title</title>
</head>
<body>
<img th:src="@{http://localhost:8080{uploadUrl}(uploadUrl=${uploadUrl})}"/>
</body>
</html>

【SpringBoot新手篇】SpringBoot优雅文件上传方式相关推荐

  1. SpringBoot整合阿里云OSS文件上传、下载、查看、删除

    SpringBoot整合阿里云OSS文件上传.下载.查看.删除 该项目源码地址:https://github.com/ggb2312/springboot-integration-examples ( ...

  2. MinIO入门-02 SpringBoot 整合MinIO并实现文件上传

    SpringBoot 整合MinIO并实现文件上传 1.依赖 <!-- https://mvnrepository.com/artifact/io.minio/minio --> < ...

  3. [网络安全学习篇60]:文件上传

    引言:我的系列博客[网络安全学习篇]上线了,小编也是初次创作博客,经验不足:对千峰网络信息安全开源的视频公开课程的学习整理的笔记整理的也比较粗糙,其实看到目录有300多集的时候,讲道理,有点怂了,所以 ...

  4. 【《编辑器篇》kindeditor 文件上传漏洞利用】

    <编辑器篇>kindeditor 文件上传漏洞利用             一.漏洞描述 KindEditor是一套开源的HTML可视化编辑器,其采用的开发语言支持asp.aspx.php ...

  5. Spring Boot + Vue 前后端分离,两种文件上传方式总结

    在Vue.js 中,如果网络请求使用 axios ,并且使用了 ElementUI 库,那么一般来说,文件上传有两种不同的实现方案: 通过 Ajax 实现文件上传 通过 ElementUI 里边的 U ...

  6. .vue文件_Spring Boot + Vue 前后端分离,两种文件上传方式总结!

    在Vue.js 中,如果网络请求使用 axios ,并且使用了 ElementUI 库,那么一般来说,文件上传有两种不同的实现方案: 通过 Ajax 实现文件上传 通过 ElementUI 里边的 U ...

  7. 二阶段补充:文件上传服务端处理,后端文件上传、前端两种文件上传方式

    1.文件上传 2.后端文件上传 两种方案: 兼容性较好的commons-fileupload,支持所有版本的Servlet,即所有版本的Tomcat 优点: 兼容性 缺点 需要外部jar,比较麻烦.代 ...

  8. SpringBoot整合Jersey2.x实现文件上传API

    前言 SpringBoot的官方文档中关于Jersey的介绍并不是很全面: 27.3 JAX-RS and Jersey,SpringBoot-Sample项目里面也只有非常基础的代码,对于一些复杂的 ...

  9. 【前端】wangeditor源码修改,打包发布到npm,实现上传视频功能,得到视频的第一帧保存为封面,spring-boot+vue,axios实现文件上传,视频图片浏览

    一.实现 1.创建git分支,clone下源码 git地址 创建分支 2.图片上传具有文件选择的功能,所以我完全模仿(抄袭)图片上传 报错不慌,全部改完就不报错了 1)在src/config/inde ...

  10. 【一文学会文件上传】SpringBoot+form表单实现文件上传

    唠嗑部分 平时我们在项目过程中,往往会遇到这种情况,比如:我的用户应该有一个头像,那就涉及到文件上传,那么文件应该如何存储呢? 这就会有很多方式 1.最简单的就是存在服务器上,这就要考虑到服务器的磁盘 ...

最新文章

  1. 定制你的敏捷方法:以结果为导向
  2. python经典100例答案pdf-Python3基础训练经典100题(带答案)下载
  3. docker入门与实践之【04-使用dockerfile定制镜像】
  4. 剑指offer03-数组中重复的数字(java)|leetcode刷题
  5. 万字长文剖析清楚 Go 语言 defer 原理
  6. asp当中的DateDiff的用法
  7. onnx格式转tensorRT
  8. Android虚拟键盘上下左右键按下和弹起的响应事件
  9. java mysql数据库操作_java 操作mysql数据库
  10. mysql数据库表格导出为excel表格
  11. 淘宝的npaliedit在mb下会崩溃的问题解决了
  12. 100%概率与任意好友获取QQ幸运字符的方法
  13. 一篇读懂深度学习中「训练」和「推断」的区别
  14. 论文笔记:主干网络——DenseNet
  15. 网站使用国外服务器越来越卡、越来越慢的原因
  16. 让Crystal Report【水晶报表】助你编程马到成功!
  17. tesseract安装及配置
  18. VSCode中安装Live Server插件实现Html网页代码的实时预览
  19. 查找技术:有序表的对分查找(折半查找)类
  20. RCNN SPPNet Fast R-CNN Faster R-CNN Cascade R-CNN

热门文章

  1. [经验教程]谷歌浏览器google chrome如何设置默认百度搜索引擎?
  2. sa-admin 一个简单又强大的后台管理模板
  3. 戴尔R720服务器U盘安装Windows
  4. 我们是选择开源CRM,还是选择商业CRM?
  5. C++十一月月末总结
  6. 2012年8月编程语言就业趋势
  7. 2020秋招 携程算法岗笔试编程题解答
  8. 为什么华为a1路由器网速变慢_华为路由器上网速度慢怎么办?
  9. 宝塔面板配置服务器代理
  10. Word怎么填服务器草稿位置,Word步骤制作目录的索引符号的操作