文件上傳和下載在項目中常常用到,這裏主要學習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,給做者一些鼓勵數據庫
原文出處:https://www.cnblogs.com/niaobulashi/p/springboot-updownload.html