Spring Boot2(十四):單文件上傳/下載,文件批量上傳

文件上傳和下載在項目中常常用到,這裏主要學習SpringBoot完成單個文件上傳/下載,批量文件上傳的場景應用。結合mysql數據庫、jpa數據層操做、thymeleaf頁面模板。html

1、準備

添加maven依賴

<!--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>

配置文件application.yml

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

數據庫表sys_file_info

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='文件信息表';

2、代碼實現

結構目錄

頁面file.html

<!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>

統一返回ResponseCode

@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);
    }

}

model實體類SysFileInfo

@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;

}

dao層

public interface SysFileInfoDao extends JpaRepository<SysFileInfo, Integer> {

}

Controller層

關係的地方來了,其中有三部分:單文件上傳、下載、批量文件上傳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

3、測試

4、源碼

emmm,私藏的可愛圖片也給大家啦sql

源碼地址:spring-boot-learning 歡迎star、fork,給做者一些鼓勵數據庫

原文出處:https://www.cnblogs.com/niaobulashi/p/springboot-updownload.html

相關文章
相關標籤/搜索