欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Boot 文件上傳與下載的示例代碼

 更新時(shí)間:2019年03月31日 14:25:03   作者:gekylin  
這篇文章主要介紹了Spring Boot 文件上傳與下載的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

文件的上傳及下載功能是開(kāi)發(fā)人員在日常應(yīng)用及編程開(kāi)發(fā)中經(jīng)常會(huì)遇到的。正好最近開(kāi)發(fā)需要用到此功能,雖然本人是 Android 開(kāi)發(fā)人員,但還是業(yè)余客串了一下后臺(tái)開(kāi)發(fā)。

在本文中,您將學(xué)習(xí)如何使用 Spring Boot 實(shí)現(xiàn) Web 服務(wù)中的文件上傳和下載功能。首先會(huì)構(gòu)建一個(gè) REST APIs 實(shí)現(xiàn)上傳及下載的功能,然后使用 Postman 工具來(lái)測(cè)試這些接口,最后創(chuàng)建一個(gè) Web 界面使用 JavaScript 調(diào)用接口演示完整的功能。最終界面及功能如下:

項(xiàng)目環(huán)境

- Spring Boot : 2.1.3.RELEASE
- Gredle : 5.2.1
- Java : 1.8
- Intellij IDEA : 2018.3.3

項(xiàng)目創(chuàng)建

開(kāi)發(fā)環(huán)境為 Intellij IDEA,項(xiàng)目創(chuàng)建很簡(jiǎn)單,按照下面的步驟創(chuàng)建即可:

  1. File -> New -> Project...
  2. 選擇 Spring Initializr,點(diǎn)擊 Next
  3. 填寫(xiě) Group (項(xiàng)目域名) 和 Artifact (項(xiàng)目別名)
  4. 構(gòu)建類(lèi)型可以選擇 Maven 或 Gradle, 看個(gè)人習(xí)慣
  5. 添加 Web 依賴(lài)
  6. 輸入項(xiàng)目名稱(chēng)及保存路徑,完成創(chuàng)建

項(xiàng)目創(chuàng)建完畢之后就可以進(jìn)行開(kāi)發(fā),項(xiàng)目的完整結(jié)構(gòu)如下圖所示:

參數(shù)配置

項(xiàng)目創(chuàng)建完成之后,需要設(shè)置一些必要的參數(shù),打開(kāi)項(xiàng)目resources目錄下配置文件application.properties,在其中添加以下參數(shù):

server.port=80

## MULTIPART (MultipartProperties)
# 開(kāi)啟 multipart 上傳功能
spring.servlet.multipart.enabled=true
# 文件寫(xiě)入磁盤(pán)的閾值
spring.servlet.multipart.file-size-threshold=2KB
# 最大文件大小
spring.servlet.multipart.max-file-size=200MB
# 最大請(qǐng)求大小
spring.servlet.multipart.max-request-size=215MB

## 文件存儲(chǔ)所需參數(shù)
# 所有通過(guò) REST APIs 上傳的文件都將存儲(chǔ)在此目錄下
file.upload-dir=./uploads

其中file.upload-dir=./uploads參數(shù)為自定義的參數(shù),創(chuàng)建FileProperties.javaPOJO類(lèi),使配置參數(shù)可以自動(dòng)綁定到POJO類(lèi)。

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "file")
public class FileProperties {
  private String uploadDir;

  public String getUploadDir() {
    return uploadDir;
  }
  public void setUploadDir(String uploadDir) {
    this.uploadDir = uploadDir;
  }
}

然后在@SpringBootApplication注解的類(lèi)中添加@EnableConfigurationProperties注解以開(kāi)啟ConfigurationProperties功能。

SpringBootFileApplication.java

@SpringBootApplication
@EnableConfigurationProperties({
    FileProperties.class
})
public class SpringBootFileApplication {

  public static void main(String[] args) {
    SpringApplication.run(SpringBootFileApplication.class, args);
  }
}

配置完成,以后若有file前綴開(kāi)頭的參數(shù)需要配置,可直接在application.properties配置文件中配置并更新FileProperties.java即可。

另外再創(chuàng)建一個(gè)上傳文件成功之后的Response響應(yīng)實(shí)體類(lèi)UploadFileResponse.java及異常類(lèi)FileException.java來(lái)處理異常信息。

UploadFileResponse.java

public class UploadFileResponse {
  private String fileName;
  private String fileDownloadUri;
  private String fileType;
  private long size;

  public UploadFileResponse(String fileName, String fileDownloadUri, String fileType, long size) {
    this.fileName = fileName;
    this.fileDownloadUri = fileDownloadUri;
    this.fileType = fileType;
    this.size = size;
  }
  // getter and setter ...
}

FileException.java

public class FileException extends RuntimeException{
  public FileException(String message) {
    super(message);
  }

  public FileException(String message, Throwable cause) {
    super(message, cause);
  }
}

創(chuàng)建接口

下面需要?jiǎng)?chuàng)建文件上傳下載所需的 REST APIs 接口。創(chuàng)建文件FileController.java。

import com.james.sample.file.dto.UploadFileResponse;
import com.james.sample.file.service.FileService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@RestController
public class FileController {

  private static final Logger logger = LoggerFactory.getLogger(FileController.class);

  @Autowired
  private FileService fileService;

  @PostMapping("/uploadFile")
  public UploadFileResponse uploadFile(@RequestParam("file") MultipartFile file){
    String fileName = fileService.storeFile(file);

    String fileDownloadUri = ServletUriComponentsBuilder.fromCurrentContextPath()
        .path("/downloadFile/")
        .path(fileName)
        .toUriString();

    return new UploadFileResponse(fileName, fileDownloadUri,
        file.getContentType(), file.getSize());
  }


  @PostMapping("/uploadMultipleFiles")
  public List<UploadFileResponse> uploadMultipleFiles(@RequestParam("files") MultipartFile[] files) {
    return Arrays.stream(files)
        .map(this::uploadFile)
        .collect(Collectors.toList());
  }

  @GetMapping("/downloadFile/{fileName:.+}")
  public ResponseEntity<Resource> downloadFile(@PathVariable String fileName, HttpServletRequest request) {
    // Load file as Resource
    Resource resource = fileService.loadFileAsResource(fileName);

    // Try to determine file's content type
    String contentType = null;
    try {
      contentType = request.getServletContext().getMimeType(resource.getFile().getAbsolutePath());
    } catch (IOException ex) {
      logger.info("Could not determine file type.");
    }

    // Fallback to the default content type if type could not be determined
    if(contentType == null) {
      contentType = "application/octet-stream";
    }

    return ResponseEntity.ok()
        .contentType(MediaType.parseMediaType(contentType))
        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + resource.getFilename() + "\"")
        .body(resource);
  }
}

FileController類(lèi)在接收到用戶的請(qǐng)求后,使用FileService類(lèi)提供的storeFile()方法將文件寫(xiě)入到系統(tǒng)中進(jìn)行存儲(chǔ),其存儲(chǔ)目錄就是之前在application.properties配置文件中的file.upload-dir參數(shù)的值./uploads。

下載接口downloadFile()在接收到用戶請(qǐng)求之后,使用FileService類(lèi)提供的loadFileAsResource()方法獲取存儲(chǔ)在系統(tǒng)中文件并返回文件供用戶下載。

FileService.java

import com.james.sample.file.exception.FileException;
import com.james.sample.file.property.FileProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.net.MalformedURLException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;

@Service
public class FileService {

  private final Path fileStorageLocation; // 文件在本地存儲(chǔ)的地址

  @Autowired
  public FileService(FileProperties fileProperties) {
    this.fileStorageLocation = Paths.get(fileProperties.getUploadDir()).toAbsolutePath().normalize();
    try {
      Files.createDirectories(this.fileStorageLocation);
    } catch (Exception ex) {
      throw new FileException("Could not create the directory where the uploaded files will be stored.", ex);
    }
  }

  /**
   * 存儲(chǔ)文件到系統(tǒng)
   *
   * @param file 文件
   * @return 文件名
   */
  public String storeFile(MultipartFile file) {
    // Normalize file name
    String fileName = StringUtils.cleanPath(file.getOriginalFilename());

    try {
      // Check if the file's name contains invalid characters
      if(fileName.contains("..")) {
        throw new FileException("Sorry! Filename contains invalid path sequence " + fileName);
      }

      // Copy file to the target location (Replacing existing file with the same name)
      Path targetLocation = this.fileStorageLocation.resolve(fileName);
      Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);

      return fileName;
    } catch (IOException ex) {
      throw new FileException("Could not store file " + fileName + ". Please try again!", ex);
    }
  }

  /**
   * 加載文件
   * @param fileName 文件名
   * @return 文件
   */
  public Resource loadFileAsResource(String fileName) {
    try {
      Path filePath = this.fileStorageLocation.resolve(fileName).normalize();
      Resource resource = new UrlResource(filePath.toUri());
      if(resource.exists()) {
        return resource;
      } else {
        throw new FileException("File not found " + fileName);
      }
    } catch (MalformedURLException ex) {
      throw new FileException("File not found " + fileName, ex);
    }
  }
}

接口測(cè)試

在完成上述的代碼之后,打開(kāi)SpringBootFileApplication.java并運(yùn)行,運(yùn)行完成之后就可以使用 Postman 進(jìn)行測(cè)試了。

單個(gè)文件上傳結(jié)果:

多個(gè)文件上傳結(jié)果:

文件下載結(jié)果:

Web 前端開(kāi)發(fā)

index.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <!-- Required meta tags -->
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  <title>Spring Boot File Upload / Download Rest API Example</title>

  <!-- Bootstrap CSS -->
  <link href="/css/main.css" rel="external nofollow" rel="stylesheet"/>
</head>
<body>

<noscript>
  <h2>Sorry! Your browser doesn't support Javascript</h2>
</noscript>

<div class="upload-container">
  <div class="upload-header">
    <h2>Spring Boot File Upload / Download Rest API Example</h2>
  </div>
  <div class="upload-content">
    <div class="single-upload">
      <h3>Upload Single File</h3>
      <form id="singleUploadForm" name="singleUploadForm">
        <input id="singleFileUploadInput" type="file" name="file" class="file-input" required/>
        <button type="submit" class="primary submit-btn">Submit</button>
      </form>
      <div class="upload-response">
        <div id="singleFileUploadError"></div>
        <div id="singleFileUploadSuccess"></div>
      </div>
    </div>
    <div class="multiple-upload">
      <h3>Upload Multiple Files</h3>
      <form id="multipleUploadForm" name="multipleUploadForm">
        <input id="multipleFileUploadInput" type="file" name="files" class="file-input" multiple required/>
        <button type="submit" class="primary submit-btn">Submit</button>
      </form>
      <div class="upload-response">
        <div id="multipleFileUploadError"></div>
        <div id="multipleFileUploadSuccess"></div>
      </div>
    </div>
  </div>
</div>

<!-- Optional JavaScript -->
<script src="/js/main.js"></script>
</body>
</html>

main.css

* {
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

body {
  margin: 0;
  padding: 0;
  font-weight: 400;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 1rem;
  line-height: 1.58;
  color: #333;
  background-color: #f4f4f4;
}

body:before {
  height: 50%;
  width: 100%;
  position: absolute;
  top: 0;
  left: 0;
  background: #128ff2;
  content: "";
  z-index: 0;
}

.clearfix:after {
  display: block;
  content: "";
  clear: both;
}


h1, h2, h3, h4, h5, h6 {
  margin-top: 20px;
  margin-bottom: 20px;
}

h1 {
  font-size: 1.7em;
}

a {
  color: #128ff2;
}

button {
  box-shadow: none;
  border: 1px solid transparent;
  font-size: 14px;
  outline: none;
  line-height: 100%;
  white-space: nowrap;
  vertical-align: middle;
  padding: 0.6rem 1rem;
  border-radius: 2px;
  transition: all 0.2s ease-in-out;
  cursor: pointer;
  min-height: 38px;
}

button.primary {
  background-color: #128ff2;
  box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.12);
  color: #fff;
}

input {
  font-size: 1rem;
}

input[type="file"] {
  border: 1px solid #128ff2;
  padding: 6px;
  max-width: 100%;
}

.file-input {
  width: 100%;
}

.submit-btn {
  display: block;
  margin-top: 15px;
  min-width: 100px;
}

@media screen and (min-width: 500px) {
  .file-input {
    width: calc(100% - 115px);
  }

  .submit-btn {
    display: inline-block;
    margin-top: 0;
    margin-left: 10px;
  }
}

.upload-container {
  max-width: 700px;
  margin-left: auto;
  margin-right: auto;
  background-color: #fff;
  box-shadow: 0 1px 11px rgba(0, 0, 0, 0.27);
  margin-top: 60px;
  min-height: 400px;
  position: relative;
  padding: 20px;
}

.upload-header {
  border-bottom: 1px solid #ececec;
}

.upload-header h2 {
  font-weight: 500;
}

.single-upload {
  padding-bottom: 20px;
  margin-bottom: 20px;
  border-bottom: 1px solid #e8e8e8;
}

.upload-response {
  overflow-x: hidden;
  word-break: break-all;
}

main.js

'use strict';

var singleUploadForm = document.querySelector('#singleUploadForm');
var singleFileUploadInput = document.querySelector('#singleFileUploadInput');
var singleFileUploadError = document.querySelector('#singleFileUploadError');
var singleFileUploadSuccess = document.querySelector('#singleFileUploadSuccess');

var multipleUploadForm = document.querySelector('#multipleUploadForm');
var multipleFileUploadInput = document.querySelector('#multipleFileUploadInput');
var multipleFileUploadError = document.querySelector('#multipleFileUploadError');
var multipleFileUploadSuccess = document.querySelector('#multipleFileUploadSuccess');

function uploadSingleFile(file) {
  var formData = new FormData();
  formData.append("file", file);

  var xhr = new XMLHttpRequest();
  xhr.open("POST", "/uploadFile");

  xhr.onload = function() {
    console.log(xhr.responseText);
    var response = JSON.parse(xhr.responseText);
    if(xhr.status == 200) {
      singleFileUploadError.style.display = "none";
      singleFileUploadSuccess.innerHTML = "<p>File Uploaded Successfully.</p><p>DownloadUrl : <a href='" + response.fileDownloadUri + "' target='_blank'>" + response.fileDownloadUri + "</a></p>";
      singleFileUploadSuccess.style.display = "block";
    } else {
      singleFileUploadSuccess.style.display = "none";
      singleFileUploadError.innerHTML = (response && response.message) || "Some Error Occurred";
    }
  }

  xhr.send(formData);
}

function uploadMultipleFiles(files) {
  var formData = new FormData();
  for(var index = 0; index < files.length; index++) {
    formData.append("files", files[index]);
  }

  var xhr = new XMLHttpRequest();
  xhr.open("POST", "/uploadMultipleFiles");

  xhr.onload = function() {
    console.log(xhr.responseText);
    var response = JSON.parse(xhr.responseText);
    if(xhr.status == 200) {
      multipleFileUploadError.style.display = "none";
      var content = "<p>All Files Uploaded Successfully</p>";
      for(var i = 0; i < response.length; i++) {
        content += "<p>DownloadUrl : <a href='" + response[i].fileDownloadUri + "' target='_blank'>" + response[i].fileDownloadUri + "</a></p>";
      }
      multipleFileUploadSuccess.innerHTML = content;
      multipleFileUploadSuccess.style.display = "block";
    } else {
      multipleFileUploadSuccess.style.display = "none";
      multipleFileUploadError.innerHTML = (response && response.message) || "Some Error Occurred";
    }
  }

  xhr.send(formData);
}

singleUploadForm.addEventListener('submit', function(event){
  var files = singleFileUploadInput.files;
  if(files.length === 0) {
    singleFileUploadError.innerHTML = "Please select a file";
    singleFileUploadError.style.display = "block";
  }
  uploadSingleFile(files[0]);
  event.preventDefault();
}, true);

multipleUploadForm.addEventListener('submit', function(event){
  var files = multipleFileUploadInput.files;
  if(files.length === 0) {
    multipleFileUploadError.innerHTML = "Please select at least one file";
    multipleFileUploadError.style.display = "block";
  }
  uploadMultipleFiles(files);
  event.preventDefault();
}, true);

總結(jié)

至此,文件的上傳及下載功能已完成。在正式環(huán)境中可能還需要將上傳的文件存儲(chǔ)到數(shù)據(jù)庫(kù),此處按照實(shí)際需求去處理即可。

本文源代碼地址:https://github.com/JemGeek/SpringBoot-Sample/tree/master/SpringBoot-File

本文參考(需要FQ):https://www.callicoder.com/spring-boot-file-upload-download-rest-api-example/

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Hutool?Java工具類(lèi)庫(kù)_ExcelUtil的使用

    Hutool?Java工具類(lèi)庫(kù)_ExcelUtil的使用

    這篇文章主要介紹了Hutool?Java工具類(lèi)庫(kù)_ExcelUtil的使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • javascript最新2020經(jīng)典面試題

    javascript最新2020經(jīng)典面試題

    這篇文章主要介紹了javascript最新2020經(jīng)典面試題的相關(guān)內(nèi)容,有需要的朋友們可以學(xué)習(xí)下。
    2020-02-02
  • JavaWeb實(shí)現(xiàn)自動(dòng)登錄功能

    JavaWeb實(shí)現(xiàn)自動(dòng)登錄功能

    這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)自動(dòng)登錄功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-08-08
  • Java中常見(jiàn)的并發(fā)控制手段淺析

    Java中常見(jiàn)的并發(fā)控制手段淺析

    所謂并發(fā)控制就是幫助我們程序員更容易的讓線程之間合作,讓線程之間相互配合來(lái)滿足業(yè)務(wù)邏輯,這篇文章主要給大家介紹了關(guān)于Java中常見(jiàn)的并發(fā)控制手段的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • MyBatis動(dòng)態(tài)SQL與緩存原理深入分析

    MyBatis動(dòng)態(tài)SQL與緩存原理深入分析

    這篇文章主要介紹了MyBatis動(dòng)態(tài)SQL與緩存原理,Mybatis框架的動(dòng)態(tài)SQL技術(shù)是一種根據(jù)特定條件動(dòng)態(tài)拼裝SQL語(yǔ)句的功能,它存在的意義是為了解決拼接SQL語(yǔ)句字符串時(shí)的痛點(diǎn)問(wèn)題
    2023-02-02
  • Java OpenCV4.0.0實(shí)現(xiàn)實(shí)時(shí)人臉識(shí)別

    Java OpenCV4.0.0實(shí)現(xiàn)實(shí)時(shí)人臉識(shí)別

    這篇文章主要為大家詳細(xì)介紹了Java OpenCV4.0.0實(shí)現(xiàn)實(shí)時(shí)人臉識(shí)別,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • 使用Properties讀取配置文件的示例詳解

    使用Properties讀取配置文件的示例詳解

    開(kāi)發(fā)SpringBoot項(xiàng)目時(shí),使用配置文件配置項(xiàng)目相關(guān)屬性是必不可少的,所以下文為大家準(zhǔn)備了使用Properties讀取配置文件的示例代碼,希望對(duì)大家有所幫助
    2023-06-06
  • java后臺(tái)判斷客戶端是手機(jī)/PC并返回不同頁(yè)面的實(shí)例

    java后臺(tái)判斷客戶端是手機(jī)/PC并返回不同頁(yè)面的實(shí)例

    下面小編就為大家分享一篇java后臺(tái)判斷客戶端是手機(jī)/PC并返回不同頁(yè)面的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01
  • Java實(shí)現(xiàn)鼠標(biāo)拖拽移動(dòng)界面組件

    Java實(shí)現(xiàn)鼠標(biāo)拖拽移動(dòng)界面組件

    在Java中,F(xiàn)rame或者JFrame自身已經(jīng)實(shí)現(xiàn)了鼠標(biāo)拖拽標(biāo)題欄移動(dòng)窗口的功能。但是Jframe的樣式實(shí)在無(wú)法令人滿意,那你又該怎么實(shí)現(xiàn)鼠標(biāo)拖拽移動(dòng)窗口的目的呢?今天我們來(lái)探討下
    2014-09-09
  • Spring?Cloud詳細(xì)講解zuul集成Eureka流程

    Spring?Cloud詳細(xì)講解zuul集成Eureka流程

    這篇文章主要介紹了Spring?Cloud?zuul集成Eureka,Eureka?Client中內(nèi)置一個(gè)負(fù)載均衡器,用來(lái)進(jìn)行基本的負(fù)載均衡,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-06-06

最新評(píng)論