文件上傳和下載在項目中常常用到,這裏主要學習SpringBoot完成單個文件上傳/下載,批量文件上傳的場景應用。結合mysql數據庫、jpa數據層操做、thymeleaf頁面模板。html
<!--springboot核心-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!--springboot測試-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--thymeleaf前端模板-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!--springboot-web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--springboot熱部署-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<!--jpa-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mysql驅動-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
複製代碼
server:
port: 8081
tomcat:
max-swallow-size: 1MB
spring:
servlet:
multipart:
# 默認支持文件上傳
enabled: true
# 最大支持文件大小
max-file-size: 50MB
# 最大支持請求大小
max-request-size: 100MB
# 文件支持寫入磁盤
file-size-threshold: 0
# 上傳文件的臨時目錄
location: /test
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8&useSSL=true
username: root
password: root
jpa:
# 數據庫類型
database: mysql
#打印SQL
show-sql: true
hibernate:
ddl-auto: update #第一次啓動建立表,以後修改成update
thymeleaf:
# 是否啓用
enabled: true
# 模板編碼
encoding: UTF-8
# 模板模式
mode: HTML5
# 模板存放路徑
prefix: classpath:/templates/
# 模板後綴
suffix: .html
# 啓用緩存,建議生產開啓
cache: false
# 校驗模板是否存在
check-template-location: true
# Content-type值
servlet:
content-type: text/html
# 加配置靜態資源
resources:
static-locations: classpath:/
niaobulashi:
file:
path: D:\workspace\javaProject\spring-boot-learning\spring-boot-22-updownload\doc
extension: .gif,.jpeg,.png,.jpg,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt,.rar,.tif
複製代碼
最下面是自定義的配置屬性,定義了文件存放路徑和上傳文件容許的後綴名稱。前端
須要注意的是:niaobulashi.file.path
,爲你磁盤上的目錄,根據你實際的目錄修改。java
SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for `sys_file_info`
-- ----------------------------
DROP TABLE IF EXISTS `sys_file_info`;
CREATE TABLE `sys_file_info` (
`file_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '文件id',
`file_name` varchar(50) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '文件名稱',
`file_path` varchar(255) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '文件路徑',
`file_size` varchar(100) CHARACTER SET utf8mb4 DEFAULT '' COMMENT '文件大小',
PRIMARY KEY (`file_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='文件信息表';
複製代碼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>一、單文件上傳</p>
<form action="upload" method="POST" enctype="multipart/form-data">
文件:<input type="file" name="file"/>
<input type="submit"/>
</form>
<hr/>
<p>二、文件下載</p>
<form action="download" method="POST" enctype="multipart/form-data">
文件ID:<input type="text" name="fileId"/>
<input type="submit" value="下載文件"/>
</form>
<hr/>
<p>三、多文件上傳</p>
<form action="batchUpload" method="POST" enctype="multipart/form-data">
一次選擇多個文件的多文件上傳:<input type="file" name="files" multiple>
<input type="submit"/>
</form>
</body>
</html>
複製代碼
@Data
@AllArgsConstructor
public class ResponseCode extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public static final String CODE_TAG = "code";
public static final String MSG_TAG = "msg";
public static final String DATA_TAG = "data";
/** * 狀態類型 */
public enum Type
{
/** 成功 */
SUCCESS(100),
/** 警告 */
WARN(200),
/** 錯誤 */
ERROR(300);
private final int value;
Type(int value)
{
this.value = value;
}
public int value() {
return this.value;
}
}
/** 狀態類型 */
private Type type;
/** 狀態碼 */
private int code;
/** 返回內容 */
private String msg;
/** 數據對象 */
private Object data;
/** * 初始化一個新建立的 AjaxResult 對象 * * @param type 狀態類型 * @param msg 返回內容 */
public ResponseCode(Type type, String msg) {
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
}
/** * 初始化一個新建立的 AjaxResult 對象 * * @param type 狀態類型 * @param msg 返回內容 * @param data 數據對象 */
public ResponseCode(Type type, String msg, Object data) {
super.put(CODE_TAG, type.value);
super.put(MSG_TAG, msg);
if (data !=null)
{
super.put(DATA_TAG, data);
}
}
/** * 返回成功消息 * * @return 成功消息 */
public static ResponseCode success() {
return ResponseCode.success("操做成功");
}
/** * 返回成功數據 * * @return 成功消息 */
public static ResponseCode success(Object data) {
return ResponseCode.success("操做成功", data);
}
/** * 返回成功消息 * * @param msg 返回內容 * @return 成功消息 */
public static ResponseCode success(String msg) {
return ResponseCode.success(msg, null);
}
/** * 返回成功消息 * * @param msg 返回內容 * @param data 數據對象 * @return 成功消息 */
public static ResponseCode success(String msg, Object data) {
return new ResponseCode(Type.SUCCESS, msg, data);
}
/** * 返回警告消息 * * @param msg 返回內容 * @return 警告消息 */
public static ResponseCode warn(String msg) {
return ResponseCode.warn(msg, null);
}
/** * 返回警告消息 * * @param msg 返回內容 * @param data 數據對象 * @return 警告消息 */
public static ResponseCode warn(String msg, Object data) {
return new ResponseCode(Type.WARN, msg, data);
}
/** * 返回錯誤消息 * * @return */
public static ResponseCode error() {
return ResponseCode.error("操做失敗");
}
/** * 返回錯誤消息 * * @param msg 返回內容 * @return 警告消息 */
public static ResponseCode error(String msg) {
return ResponseCode.error(msg, null);
}
/** * 返回錯誤消息 * * @param msg 返回內容 * @param data 數據對象 * @return 警告消息 */
public static ResponseCode error(String msg, Object data) {
return new ResponseCode(Type.ERROR, msg, data);
}
}
複製代碼
@Data
@Entity
@Table(name = "sys_file_info")
public class SysFileInfo implements Serializable {
@Id
@GeneratedValue
private Integer fileId;
@Column(nullable = false)
private String fileName;
@Column(nullable = false)
private String filePath;
@Column(nullable = false)
private Long fileSize;
}
複製代碼
讀取配置文件信息mysql
@Data
@Component
public class GlobalProperties {
/** 文件存放路徑 */
@Value("${niaobulashi.file.path}")
private String serverPath;
/** 文件擴展名 */
@Value("${niaobulashi.file.extension}")
private String extension;
}
複製代碼
public interface SysFileInfoDao extends JpaRepository<SysFileInfo, Integer> {
}
複製代碼
關係的地方來了,其中有三部分:單文件上傳、下載、批量文件上傳git
@Controller
public class FileController {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* 默認大小 50M
*/
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
@Autowired
private SysFileInfoDao sysFileInfoDao;
@Autowired
private GlobalProperties globalProperties;
/**
* 文件上傳頁面
* @return
*/
@GetMapping("/")
public String updatePage() {
return "file";
}
///....具體邏輯在下方
}
複製代碼
/** * 單文件上傳 * @param file * @return */
@PostMapping("/upload")
@ResponseBody
private ResponseCode upload(@RequestParam("file") MultipartFile file) throws Exception {
// 獲取文件在服務器上的存儲位置
String serverPath = globalProperties.getServerPath();
// 獲取容許上傳的文件擴展名
String extension = globalProperties.getExtension();
File filePath = new File(serverPath);
logger.info("文件保存的路徑爲:" + filePath);
if (!filePath.exists() && !filePath.isDirectory()) {
logger.info("目錄不存在,則建立目錄:" + filePath);
filePath.mkdir();
}
// 判斷文件是否爲空
if (file.isEmpty()) {
return ResponseCode.error("文件爲空");
}
//判斷文件是否爲空文件
if (file.getSize() <= 0) {
return ResponseCode.error("文件大小爲空,上傳失敗");
}
// 判斷文件大小不能大於50M
if (DEFAULT_MAX_SIZE != -1 && file.getSize() > DEFAULT_MAX_SIZE) {
return ResponseCode.error("上傳的文件不能大於50M");
}
// 獲取文件名
String fileName = file.getOriginalFilename();
// 獲取文件擴展名
String fileExtension = fileName.substring(fileName.lastIndexOf(".")).toLowerCase();
// 判斷文件擴展名是否正確
if (!extension.contains(fileExtension)) {
return ResponseCode.error("文件擴展名不正確");
}
SysFileInfo sysFileInfo = new SysFileInfo();
// 從新生成的文件名
String saveFileName = System.currentTimeMillis() + fileExtension;
// 在指定目錄下建立該文件
File targetFile = new File(filePath, saveFileName);
logger.info("將文件保存到指定目錄");
try {
file.transferTo(targetFile);
} catch (IOException e) {
throw new Exception(e.getMessage());
}
// 保存數據
sysFileInfo.setFileName(fileName);
sysFileInfo.setFilePath(serverPath + "/" + saveFileName);
sysFileInfo.setFileSize(file.getSize());
logger.info("新增文件數據");
// 新增文件數據
sysFileInfoDao.save(sysFileInfo);
return ResponseCode.success("上傳成功");
}
複製代碼
下載的邏輯,我在前端經過input輸入框輸入fileId,後臺查詢數據庫來下載github
正常狀況下應該是列表,單選或者多選後下載文件的。web
/** * 下載 * @param fileId * @param request * @param response * @return */
@PostMapping("/download")
@ResponseBody
public ResponseCode downloadFile(@RequestParam("fileId") Integer fileId, HttpServletRequest request, HttpServletResponse response) {
logger.info("文件ID爲:" + fileId);
// 判斷傳入參數是否非空
if (fileId == null) {
return ResponseCode.error("請求參數不能爲空");
}
// 根據fileId查詢文件表
Optional<SysFileInfo> sysFileInfo = sysFileInfoDao.findById(fileId);
if (sysFileInfo.isEmpty()) {
return ResponseCode.error("下載的文件不存在");
}
// 獲取文件全路徑
File file = new File(sysFileInfo.get().getFilePath());
String fileName = sysFileInfo.get().getFileName();
// 判斷是否存在磁盤中
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);
}
return ResponseCode.success("下載成功");
} 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();
}
}
}
} else {
return ResponseCode.error("數據庫查詢存在,本地磁盤不存在文件");
}
return ResponseCode.success("下載失敗");
}
複製代碼
/** * 批量文件上傳 * @param files * @return * @throws Exception */
@PostMapping("/batchUpload")
@ResponseBody
public ResponseCode batchUpload(@RequestParam("files") MultipartFile[] files) throws Exception {
if (files == null) {
return ResponseCode.error("參數爲空");
}
for (MultipartFile multipartFile : files) {
upload(multipartFile);
}
return ResponseCode.success("批量上傳成功");
}
複製代碼
至此項目完成,開始測試spring
emmm,私藏的可愛圖片也給大家啦sql
源碼地址:spring-boot-learning數據庫
歡迎star、fork,給做者一些鼓勵