SpringBoot實現文件上傳
1、創建一個Springboot工程
2、改pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.qbb</groupId>
<artifactId>file-upload</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>file-upload</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3、寫application.yml/properties文件
server:
port: 9001 # 配置端口號
spring:
freemarker:
suffix: .html # 設置視圖模板后綴
cache: false # 不開啟緩存
servlet:
multipart:
max-file-size: 10MB # 設置文件大小
enabled: true
4、主啟動類
package com.qbb.springboot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @author QiuQiu&LL
* @version 1.0
* @createTime 2021-12-15 20:50
* @Description:
*/
@SpringBootApplication
public class FileUploadMain9001 {
public static void main(String[] args) {
SpringApplication.run(FileUploadMain9001.class, args);
}
}
5、編寫一個HelloController測試
package com.qbb.springboot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author QiuQiu&LL
* @version 1.0
* @createTime 2021-12-15 20:52
* @Description:
*/
@Controller
public class HelloController {
@ResponseBody
@RequestMapping("/hello")
public String hello() {
return "Hello FileUpload";
}
}
6、業務代碼,處理文件上傳
-
1.在資源目錄resources目錄下創建一個templates目錄
-
2.創建一個文件上傳的簡單頁面upload.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>文件上傳</title>
</head>
<body>
<h1>Springboot整合文件上傳</h1>
</body>
</html>
-
- HelloController添加一下內容
@RequestMapping("/upload")
public String upload(){
return "upload";
}
-
- 測試
-
- 修改頁面代碼
<!--注意:
enctype="multipart/form-data"
method必須是post請求
input的type是file類型,需要給上name值,controller才能獲取
-->
<form action="/upload/file" enctype="multipart/form-data" method="post">
<input name="dir" value="bbs">
<input name="file" type="file">
<input type="submit" value="文件上傳">
</form>
-
- 修改controller層代碼
/**
* 文件上傳具體實現
* @param multipartFile
* @param request
* @return
*/
@PostMapping("/upload/file")
@ResponseBody
public String upload(@RequestParam("file") MultipartFile multipartFile, HttpServletRequest request){
if(multipartFile.isEmpty()){
return "文件有誤!!!";
}
long size = multipartFile.getSize();
String originalFilename = multipartFile.getOriginalFilename();
String contentType = multipartFile.getContentType();//imgae/png;image/jpg;image/gif
// if(!contentType.equals("png|jpg|gif")){ //偽代碼 ,不正確的代碼
// return "文件類型不正確";
// }
// 1: 獲取用戶指定的文件夾。問這個文件夾為什么要從頁面上傳遞過來呢?
// 原因是:做隔離,不同業務,不同文件放在不同的目錄中
String dir = request.getParameter("dir");
return uploadService.uploadImg(multipartFile,dir);
}
-
- 配置文件可以配置文件上傳相關信息
servlet:
multipart:
enabled: true
# 是單個文件大小 默認1M 10KB
max-file-size: 2MB
# 是設置總上傳的數據大小
max-request-size: 10MB
#當文件達到多少時進行磁盤寫入
file-size-threshold: 20MB
# 設置臨時目錄
location: F://data//tempxxxxxxxxxxxx
-
- 創建uploadService處理文件上傳
package com.qbb.springboot.service;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.UUID;
/**
* @author QiuQiu&LL
* @version 1.0
* @createTime 2021-12-15 21:07
* @Description:
*/
@Service
@SuppressWarnings({"all"})
public class UploadService {
@Value("${file.uploadFolder}")
private String uploadFolder;
@Value("${file.staticPath}")
private String staticPath;
/**
* MultipartFile 這個對象是springMvc提供的文件上傳的接受的類,
* 它的底層自動會去和HttpServletRequest request中的request.getInputStream()融合
* 從而達到文件上傳的效果。也就是告訴你一個道理:
* 文件上傳底層原理是:request.getInputStream()
*
* @param multipartFile
* @param dir
* @return
*/
public String uploadImg(MultipartFile multipartFile, String dir) {
try {
String realfilename = multipartFile.getOriginalFilename(); // 上傳的文件:aaa.jpg
// 2:截圖文件名的后綴
String imgSuffix = realfilename.substring(realfilename.lastIndexOf("."));// 拿到:.jpg
// 3:生成的唯一的文件名:能不能用中文名:不能因為統一用英文命名。
String newFileName = UUID.randomUUID().toString() + imgSuffix;// 將aaa.jpg改寫成:SD23423k324-23423ms.jpg
// 4:日期目錄
// SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd");
// String datePath = dateFormat.format(new Date());// 日期目錄:2021/10/27
// 也可以使用JDK1.8的新時間類LocalDate/LocalDateTime
LocalDate now = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
String formatDatePath = formatter.format(now);
// 5: 指定文件上傳以后的目錄
String servrepath = uploadFolder;// 這不是tomcat服務目錄,別人不認識
File targetPath = new File(servrepath + dir, datePath);// 生成一個最終目錄:F://tmp/avatar/2021/10/27
if (!targetPath.exists()) targetPath.mkdirs(); // 如果目錄不存在:F://tmp/avatar/2021/10/27 遞歸創建
// 6: 指定文件上傳以后的服務器的完整的文件名
File targetFileName = new File(targetPath, newFileName);// 文件上傳以后在服務器上最終文件名和目錄是:F://tmp/avatar/2021/10/27/SD23423k324-23423ms.jpg
// 7: 文件上傳到指定的目錄
multipartFile.transferTo(targetFileName);//將用戶選擇的aaa.jpg上傳到F://tmp/avatar/2021/10/27/SD23423k324-23423ms.jpg
// 可訪問的路徑要返回頁面
// http://localhpst:9001/bbs/2021/10/27/5f61dea2-4b77-4068-8d0b-fdf415eac6df.png
String filename = dir + "/" + datePath + "/" + newFileName;
return staticPath + "/" + filename;
} catch (IOException e) {
e.printStackTrace();
return "fail";
}
}
}
- 9.測試
思考:從上面開似乎我們已經完成了文件上傳,但是復制該地址會發現,無法通過http請求該服務資源
解決辦法:
配置靜態資源服務映射
package com.qbb.springboot.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author QiuQiu&LL
* @version 1.0
* @createTime 2021-12-16 10:39
* @Description:
*/
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {
/**
* springmvc讓程序開發者配置文件上傳額外的靜態資源服務
* @param registry
*/
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/uploadimg/**").addResourceLocations("file:F://temp//");
}
}
核心代碼分析
registry.addResourceHandler("訪問的路徑").addResourceLocations("上傳資源的路徑");
registry.addResourceHandler("/uploadimg/**").addResourceLocations("file:F://tmp//");
配置完成后測試一下
- 哈哈,功夫不負有心人,效果出現了!!!但是還有問題,我們發現有很多“死代碼”不夠靈活。如:/uploadimg/** file:F://temp//,都是我們寫死的,如何改進呢?
使用配置文件環境隔離解決,使用 - 創建application-dev.yml開發環境配置文件和application-prod.yml生產環境配置文件
- application-dev.yml
# 本機配置
file:
staticPath: http://localhost:9001
staticPatternPath: /upimages/**
uploadFolder: F:/tmp/
- application-prod.yml
# 服務器配置
file:
staticPath: https://www.QIUQIU.com
staticPatternPath: /upimages/**
uploadFolder: /www/upload/
再來測試發現,依然可以