If we build a small web site and we just choose kotlin and Spring Boot technology stacks, then uploading files is essential. Of course, if you build a medium and large web site, it is recommended that you use cloud storage, which can save a lot of trouble.
This article introduces how to use kotlin and Spring Boot to upload files
Construction Project
If you are not very familiar with the construction project, you can refer to "My First Kotlin Application"
Complete build.gradle file
group 'name.quanke.kotlin'version '1.0-SNAPSHOT'buildscript { ext.kotlin_version = '1.2.10' ext.spring_boot_version = '1.5.4.RELEASE' repositories { mavenCentral() } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath("org.springframework.boot:spring-boot-gradle-plugin:$spring_boot_version")// Kotlin integrates SpringBoot's default parameterless constructor, and sets all classes to open class plugin classpath("org.jetbrains.kotlin:kotlin-noarg:$kotlin_version") classpath("org.jetbrains.kotlin:kotlin-allopen:$kotlin_version") }}apply plugin: 'kotlin'apply plugin: "kotlin-spring" // See https://kotlinlang.org/docs/reference/compiler-plugins.html#kotlin-spring-compiler-pluginapply plugin: 'org.springframework.boot'jar { baseName = 'chapter11-5-6-service' version = '0.1.0'}repositories { mavenCentral()}dependencies { compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:$kotlin_version" compile "org.springframework.boot:spring-boot-starter-web:$spring_boot_version" compile "org.springframework.boot:spring-boot-starter-thymeleaf:$spring_boot_version" testCompile "org.springframework.boot:spring-boot-starter-test:$spring_boot_version" testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version"}compileKotlin { kotlinOptions.jvmTarget = "1.8"} compileTestKotlin { kotlinOptions.jvmTarget = "1.8"}Create file upload controller
import name.quanke.kotlin.chaper11_5_6.storage.StorageFileNotFoundExceptionimport name.quanke.kotlin.chaper11_5_6.storage.StorageServiceimport org.springframework.beans.factory.annotation.Autowiredimport org.springframework.core.io.Resourceimport org.springframework.http.HttpHeadersimport org.springframework.http.ResponseEntityimport org.springframework.steretype.Controllerimport org.springframework.ui.Modelimport org.springframework.web.bind.annotation.*import org.springframework.web.multipart.MultipartFileimport org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilderimport org.springframework.web.servlet.mvc.support.RedirectAttributesimport java.io.IOExceptionimport java.util.stream.Collectors/** * File upload controller* Created by http://quanke.name on 2018/1/12. */@Controllerclass FileUploadController @Autowiredconstructor(private val storageService: StorageService) { @GetMapping("/") @Throws(IOException::class) fun listUploadedFiles(model: Model): String { model.addAttribute("files", storageService .loadAll() .map { path -> MvcUriComponentsBuilder .fromMethodName(FileUploadController::class.java, "serveFile", path.fileName.toString()) .build().toString() } .collect(Collectors.toList())) return "uploadForm" } @GetMapping("/files/{filename:.+}") @ResponseBody fun serveFile(@PathVariable filename: String): ResponseEntity<Resource> { val file = storageService.loadAsResource(filename) return ResponseEntity .ok() .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=/"" + file.filename + "/"") .body(file) } @PostMapping("/") fun handleFileUpload(@RequestParam("file") file: MultipartFile, redirectAttributes: RedirectAttributes): String { storageService.store(file) redirectAttributes.addFlashAttribute("message", "You successfully uploaded " + file.originalFilename + "!") return "redirect:/" } @ExceptionHandler(StorageFileNotFoundException::class) fun handleStorageFileNotFound(exc: StorageFileNotFoundException): ResponseEntity<*> { return ResponseEntity.notFound().build<Any>() }}The interface for uploading file service
import org.springframework.core.io.Resourceimport org.springframework.web.multipart.MultipartFileimport java.nio.file.Pathimport java.util.stream.Streaminterface StorageService { fun init() fun store(file: MultipartFile) fun loadAll(): Stream<Path> fun load(filename: String): Path fun loadAsResource(filename: String): Resource fun deleteAll()}Upload file service
import org.springframework.beans.factory.annotation.Autowiredimport org.springframework.core.io.Resourceimport org.springframework.core.io.UrlResourceimport org.springframework.stereotype.Serviceimport org.springframework.util.FileSystemUtilsimport org.springframework.util.StringUtilsimport org.springframework.web.multipart.MultipartFileimport java.io.IOExceptionimport java.net.MalformedURLExceptionimport java.nio.file.Filesimport java.nio.file.Pathimport java.nio.file.Pathsimport java.nio.file.StandardCopyOptionimport java.util.stream.Stream@Serviceclass FileSystemStorageService @Autowiredconstructor(properties: StorageProperties) : StorageService { private val rootLocation: Path init { this.rootLocation = Paths.get(properties.location) } override fun store(file: MultipartFile) { val filename = StringUtils.cleanPath(file.originalFilename) try { if (file.isEmpty) { throw StorageException("Failed to store empty file " + filename) } if (filename.contains("..")) { // This is a security check throw StorageException( "Cannot store file with relative path outside current directory " + filename) } Files.copy(file.inputStream, this.rootLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING) } catch (e: IOException) { throw StorageException("Failed to store file " + filename, e) } } override fun loadAll(): Stream<Path> { try { return Files.walk(this.rootLocation, 1) .filter { path -> path != this.rootLocation } .map { path -> this.rootLocation.relativize(path) } } catch (e: IOException) { throw StorageException("Failed to read stored files", e) } } override fun load(filename: String): Path { return rootLocation.resolve(filename) } override fun loadAsResource(filename: String): Resource { try { val file = load(filename) val resource = UrlResource(file.toUri()) return if (resource.exists() || resource.isReadable) { resource } else { throw StorageFileNotFoundException( "Could not read file: " + filename) } } catch (e: MalformedURLException) { throw StorageFileNotFoundException("Could not read file: " + filename, e) } } override fun deleteAll() { FileSystemUtils.deleteRecursively(rootLocation.toFile()) } override fun init() { try { Files.createDirectories(rootLocation) } catch (e: IOException) { throw StorageException("Could not initialize storage", e) } }}Custom exceptions
open class StorageException : RuntimeException { constructor(message: String) : super(message) constructor(message: String, cause: Throwable) : super(message, cause)}class StorageFileNotFoundException : StorageException { constructor(message: String) : super(message) constructor(message: String, cause: Throwable) : super(message, cause)}Configuration file upload directory
import org.springframework.boot.context.properties.ConfigurationProperties@ConfigurationProperties("storage")class StorageProperties { /** * Folder location for storage files */ var location = "upload-dir"}Start Spring Boot
/** * Created by http://quanke.name on 2018/1/9. */@SpringBootApplication@EnableConfigurationProperties(StorageProperties::class)class Application { @Bean internal fun init(storageService: StorageService) = CommandLineRunner { storageService.deleteAll() storageService.init() } companion object { @Throws(Exception::class) @JvmStatic fun main(args: Array<String>) { SpringApplication.run(Application::class.java, *args) } }}Create a simple html template src/main/resources/templates/uploadForm.html
<html xmlns:th="http://www.thymeleaf.org"><body><div th:if="${message}"> <h2 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>Configuration file application.yml
spring: http: multipart: max-file-size: 128KB max-request-size: 128KB
For more Spring Boot and kotlin related content, please follow "Spring Boot and kotlin Practical Battle"
Source code:
https://github.com/quanke/spring-boot-with-kotlin-in-action/
refer to:
https://spring.io/guides/gs/uploading-files/
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.