當(dāng)前位置:
首頁 >
前端技术
> javascript
>内容正文
javascript
【SpringBoot新手篇】SpringBoot优雅文件上传方式
生活随笔
收集整理的這篇文章主要介紹了
【SpringBoot新手篇】SpringBoot优雅文件上传方式
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
SpringBoot文件上傳
- Pom
- yml
- controller
- UploadController
- FileController
- 文件上傳
- 多文件上傳
- 文件下載
- 頁面
- BUG
- 封裝版
- 工具類
- StringUtil
- MimeTypeUtils
- FileUploadUtils
- 異常類
- FileNameLengthLimitExceededException
- FileSizeLimitExceededException
- InvalidExtensionException
- Controller層
工作中上傳文件是常見的場景之一,最典型的情況就是上傳頭像等,上傳文檔。自己上傳文件中遇到的坑,自己已經(jīng)填了,現(xiàn)在把它寫下來,方便提醒自己,我使用的是Spring Boot 上傳文件
Pom
主要引入了web和thymeleaf啟動器
<!-- 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 #默認(rèn)支持文件上傳.# 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("/");//文件絕對路徑,項(xiàng)目中一般使用相對類路徑,即使文件變更路徑也會跟著變String filePath = request.getServletContext().getRealPath("G:\\dev_workspace\\springboot-learning-examples\\springboot-13-fileupload\\src\\main\\resources\\static");System.out.println("path = " + filePath);//構(gòu)造一個路徑String newImg = UUID.randomUUID()+suffixName;String path = filePath + newImg;log.info("構(gòu)造路徑"+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);//文件絕對路徑,項(xiàng)目中一般使用相對類路徑,即使文件變更路徑也會跟著變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())));//設(shè)置文件路徑及名字stream.write(bytes);// 寫入stream.close();} catch (Exception e) {stream = null;model.addAttribute("msg", "第 " + i + " 個文件上傳失敗 ==> "+ e.getMessage());return "upload";}} else {model.addAttribute("msg","第 " + i+ " 個文件上傳失敗因?yàn)槲募榭?#34;);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) {//設(shè)置文件路徑 真實(shí)環(huán)境是存放在數(shù)據(jù)庫中的// String filePath = request.getServletContext().getRealPath("/");//文件絕對路徑,項(xiàng)目中一般使用相對類路徑,即使文件變更路徑也會跟著變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");// 設(shè)置強(qiáng)制下載不打開response.addHeader("Content-Disposition", "attachment;fileName=" + fileName);// 設(shè)置文件名byte[] buffer = new byte[1024];FileInputStream fis = null;BufferedInputStream bis = null;try {fis = new FileInputStream(file);bis = new BufferedInputStream(fis);// 創(chuàng)建輸出對象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
解決:
封裝版
工具類
StringUtil
/*** 字符串工具類,抽取一些常用操作*/ public class StringUtil {/*** 判斷val是否不為空(null/"")* @param val* @return*/public static boolean isNotEmpty(String val){return val != null && !"".equals(val);}/*** 將給定的駝峰命名值轉(zhuǎn)換為下劃線命名* @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 {/*** 默認(rèn)大小 50M*/public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;/*** 默認(rèn)的文件名最大長度 100*/public static final int DEFAULT_FILE_NAME_LENGTH = 100;/*** 默認(rèn)存儲圖片目錄*/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";/*** 默認(rèn)上傳的地址*/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;}/*** 以默認(rèn)配置進(jìn)行文件上傳** @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 相對應(yīng)用的基目錄* @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);}//文件大小校驗(yàn)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;}/*** 文件大小校驗(yàn)** @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
/*** 文件名字長度超過限制異常,用于文件校驗(yàn)*/ public class FileNameLengthLimitExceededException extends RuntimeException{private static final long serialVersionUID = 1L;public FileNameLengthLimitExceededException(){}public FileNameLengthLimitExceededException(String message){super(message);}}FileSizeLimitExceededException
/*** 文件大小超過限制異常,用于文件校驗(yàn)*/ public class FileSizeLimitExceededException extends RuntimeException{private static final long serialVersionUID = 1L;public FileSizeLimitExceededException(){}public FileSizeLimitExceededException(String message){super(message);}}InvalidExtensionException
/*** 文件后綴無效異常,用于文件校驗(yàn)*/ 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>總結(jié)
以上是生活随笔為你收集整理的【SpringBoot新手篇】SpringBoot优雅文件上传方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Q12矩阵中的路径 回溯法
- 下一篇: JavaScript之document对