Spring Boot demo學習之上傳文件

背景

最近在學習Spring Boot,跟着官方demo學習仍是會遇到很多坑,寫個文章記錄下,以便往後查閱。html

核心功能

使用@Controller註解聲明接受請求,調用@Autowired自動注入的servcie來保存上傳的文件,同時提供文件下載功能。spring

使用thymeleaf模板來處理html頁面請求。
用@ConfigurationProperties註解來聲明屬性,配置文件存放目錄。app

核心代碼

控制層

在控制器中@Controller註解來代表這是一個控制層bean,能夠接受http請求;
使用@Autowired註解來自動注入service類,用來執行對文件的操做;
分別使用@GetMapping和@PostMapping來接受GET、POST方法;
經過 return "uploadForm"; 的樣子,交給模板引擎thymeleaf去處理,返回template目錄下的uploadForm.html文件,並「注入」響應的屬性 如files、message等。ide

@Controller // 控制器註解
public class FileUploadController {
    private final StorageService storageService; // 下面自動注入

    @Autowired
    public FileUploadController(StorageService storageService) {
        this.storageService = storageService;
    }

    @GetMapping("/")
    public String listUploadedFiles(Model model) throws IOException {

        model.addAttribute("files", storageService.loadAll().map(
                path -> MvcUriComponentsBuilder.fromMethodName(FileUploadController.class,
                        "serveFile", path.getFileName().toString()).build().toString())
                .collect(Collectors.toList()));

        return "uploadForm"; // 由模板引擎負責返回 uploadForm.html,在template目錄下。
    }

    @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:/"; // 跳轉到 get的請求裏(上面的listUploadedFiles方法)
    }

}

服務層

這個類主要用來執行一些文件處理操做,沒什麼特殊的,spring-boot

比較坑的是,由於用到配置屬性,僅僅用Autowired來注入仍是不行的, 還必須使用 @EnableConfigurationProperties(StorageProperties.class) 來聲明配置屬性類,這個比較坑。。學習

@Service //聲明service
@EnableConfigurationProperties(StorageProperties.class) // 容許使用配置註解
public class FileSystemStorageService implements StorageService {

    private final Path rootLocation;

    @Autowired // 自動注入
    public FileSystemStorageService(StorageProperties properties) {
        this.rootLocation = Paths.get(properties.getLocation());
    }

屬性配置

使用@ConfigurationProperties聲明這是一個屬性配置類,參數聲明頂級命名空間。ui

比較坑的是, 須要在pom.xml裏引入如下依賴:this

<dependency>
            <groupId> org.springframework.boot </groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional> true </optional>
        </dependency>

而後就能夠正常使用了。。。code

@ConfigurationProperties("storage")
public class StorageProperties {

    /**
     * Folder location for storing files
     */
    private String location = "upload-dir";

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }

}

以上配置完成後,能夠在application.properties 文件裏添加 storage.location = myFiles來指明文件存儲路徑。。。orm

其它坑

在學習的過程當中可能會出現 「Re-run spring boot configuration annotation」的錯誤,這個就是由於在service中只用Autowired去自動注入了,而沒有使用 EnableConfigurationProperties 去聲明屬性配置類。 像上面說的同樣聲明就能夠正常運行了

參考連接

相關文章
相關標籤/搜索