您好,登錄后才能下訂單哦!
本小節你將建立一個可以接受HTTP multi-part 文件的服務。
你將建立一個后臺服務來接收文件以及前臺頁面來上傳文件。
要利用servlet容器上傳文件,你要注冊一個MultipartConfigElement類,以往需要在web.xml 中配置<multipart-config>,
而在這里,你要感謝SpringBoot,一切都為你自動配置好了。
1、新建一個文件上傳的Controller:
應用已經包含一些 存儲文件 和 從磁盤中加載文件 的類,他們在cn.tiny77.guide05這個包下。我們將會在FileUploadController中用到這些類。
package cn.tiny77.guide05; import java.io.IOException; import java.util.List; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.io.Resource; import org.springframework.http.HttpHeaders; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import org.springframework.web.servlet.mvc.support.RedirectAttributes; @Controller public class FileUploadController { private final StorageService storageService; @Autowired public FileUploadController(StorageService storageService) { this.storageService = storageService; } @GetMapping("/") public String listUploadedFiles(Model model) throws IOException { List<String> paths = storageService.loadAll().map( path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class, "serveFile", path.getFileName().toString()).build().toString()) .collect(Collectors.toList()); model.addAttribute("files", paths); return "uploadForm"; } @GetMapping("/files/{filename:.+}") @ResponseBody public ResponseEntity<Resource> serveFile(@PathVariable String filename) { Resource file = storageService.loadAsResource(filename); return ResponseEntity.ok().header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.getFilename() + "\"").body(file); } @PostMapping("/") public String handleFileUpload(@RequestParam("file") MultipartFile file, RedirectAttributes redirectAttributes) { storageService.store(file); redirectAttributes.addFlashAttribute("message", "You successfully uploaded " + file.getOriginalFilename() + "!"); return "redirect:/"; } @ExceptionHandler(StorageFileNotFoundException.class) public ResponseEntity<?> handleStorageFileNotFound(StorageFileNotFoundException exc) { return ResponseEntity.notFound().build(); } }
該類用@Controller注解,因此SpringMvc可以基于它設定相應的路由。每一個@GetMapping和@PostMapping注解將綁定對應的請求參數和請求類型到特定的方法。
GET / 通過StorageService 掃描文件列表并 將他們加載到 Thymeleaf 模板中。它通過MvcUriComponentsBuilder來生成資源文件的連接地址。
GET /files/{filename} 當文件存在時候,將加載文件,并發送文件到瀏覽器端。通過設置返回頭"Content-Disposition"來實現文件的下載。
POST / 接受multi-part文件并將它交給StorageService保存起來。
你需要提供一個服務接口StorageService來幫助Controller操作存儲層。接口大致如下
package cn.tiny77.guide05; import org.springframework.core.io.Resource; import org.springframework.web.multipart.MultipartFile; import java.nio.file.Path; import java.util.stream.Stream; public interface StorageService { void init(); void store(MultipartFile file); Stream<Path> loadAll(); Path load(String filename); Resource loadAsResource(String filename); void deleteAll(); }
以下是接口實現類
package cn.tiny77.guide05; 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; import java.util.stream.Stream; 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.FileSystemUtils; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; @Service public class FileSystemStorageService implements StorageService { private final Path rootLocation; @Autowired public FileSystemStorageService(StorageProperties properties) { this.rootLocation = Paths.get(properties.getLocation()); } @Override public void store(MultipartFile file) { String filename = StringUtils.cleanPath(file.getOriginalFilename()); try { if (file.isEmpty()) { throw new StorageException("無法保存空文件 " + filename); } if (filename.contains("..")) { // This is a security check throw new StorageException( "無權訪問該位置 " + filename); } Files.copy(file.getInputStream(), this.rootLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING); } catch (IOException e) { throw new StorageException("無法保存文件 " + filename, e); } } @Override public Stream<Path> loadAll() { try { return Files.walk(this.rootLocation, 1) .filter(path -> !path.equals(this.rootLocation)) .map(path -> this.rootLocation.relativize(path)); } catch (IOException e) { throw new StorageException("讀取文件異常", e); } } @Override public Path load(String filename) { return rootLocation.resolve(filename); } @Override public Resource loadAsResource(String filename) { try { Path file = load(filename); Resource resource = new UrlResource(file.toUri()); if (resource.exists() || resource.isReadable()) { return resource; } else { throw new StorageFileNotFoundException( "無法讀取文件: " + filename); } } catch (MalformedURLException e) { throw new StorageFileNotFoundException("無法讀取文件: " + filename, e); } } @Override public void deleteAll() { FileSystemUtils.deleteRecursively(rootLocation.toFile()); } @Override public void init() { try { Files.createDirectories(rootLocation); } catch (IOException e) { throw new StorageException("初始化存儲空間出錯", e); } } }
2、建立一個Html頁面
這里使用Thymeleaf模板
<html xmlns:th="http://www.thymeleaf.org"> <body> <div th:if="${message}"> <h3 th:text="${message}"/> </div> <div> <form method="POST" enctype="multipart/form-data" action="/"> <table> <tr><td>File to upload:</td><td><input type="file" name="file" /></td></tr> <tr><td></td><td><input type="submit" value="Upload" /></td></tr> </table> </form> </div> <div> <ul> <li th:each="file : ${files}"> <a th:href="${file}" rel="external nofollow" th:text="${file}" /> </li> </ul> </div> </body> </html>
頁面主要分為三部分分
- 頂部展示SpringMvc傳過來的信息
- 一個提供用戶上傳文件的表單
- 一個后臺提供的文件列表
3、限制上傳文件的大小
在文件上傳的應用中通常要設置文件大小的,想象一下后臺處理的文件如果是5GB,那得多糟糕!在SpringBoot中,我們可以通過屬性文件來控制。
新建一個application.properties,代碼如下:
spring.http.multipart.max-file-size=128KB #文件總大小不能超過128kb
spring.http.multipart.max-request-size=128KB #請求數據的大小不能超過128kb
4、應用啟動函數
package cn.tiny77.guide05; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @SpringBootApplication @EnableConfigurationProperties(StorageProperties.class) public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } @Bean CommandLineRunner init(StorageService storageService) { return (args) -> { storageService.deleteAll(); storageService.init(); }; } }
5、運行結果
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。