欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Spring Boot 与 Kotlin 上传文件的示例代码

程序员文章站 2023-12-02 20:10:28
如果我们做一个小型的web站,而且刚好选择的kotlin 和spring boot技术栈,那么上传文件的必不可少了,当然,如果你做一个中大型的web站,那建议你使用云存储,...

如果我们做一个小型的web站,而且刚好选择的kotlin 和spring boot技术栈,那么上传文件的必不可少了,当然,如果你做一个中大型的web站,那建议你使用云存储,能省不少事情。

这篇文章就介绍怎么使用kotlin 和spring boot上传文件

构建工程

如果对于构建工程还不是很熟悉的可以参考《我的第一个kotlin应用

完整 build.gradle 文件

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整合springboot的默认无参构造函数,默认把所有的类设置open类插件
    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-plugin
apply 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"
}

创建文件上传controller

import name.quanke.kotlin.chaper11_5_6.storage.storagefilenotfoundexception
import name.quanke.kotlin.chaper11_5_6.storage.storageservice
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.*
import org.springframework.web.multipart.multipartfile
import org.springframework.web.servlet.mvc.method.annotation.mvcuricomponentsbuilder
import org.springframework.web.servlet.mvc.support.redirectattributes

import java.io.ioexception
import java.util.stream.collectors


/**
 * 文件上传控制器
 * created by http://quanke.name on 2018/1/12.
 */

@controller
class fileuploadcontroller @autowired
constructor(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>()
  }

}

上传文件服务的接口

import org.springframework.core.io.resource
import org.springframework.web.multipart.multipartfile

import java.nio.file.path
import java.util.stream.stream

interface storageservice {

  fun init()

  fun store(file: multipartfile)

  fun loadall(): stream<path>

  fun load(filename: string): path

  fun loadasresource(filename: string): resource

  fun deleteall()

}

上传文件服务

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

@service
class filesystemstorageservice @autowired
constructor(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)
    }

  }
}

自定义异常

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

配置文件上传目录

import org.springframework.boot.context.properties.configurationproperties

@configurationproperties("storage")
class storageproperties {

  /**
   * folder location for storing files
   */
  var location = "upload-dir"

}

启动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)
    }
  }
}

创建一个简单的 html模板 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>

配置文件 application.yml

spring:
 http:
  multipart:
   max-file-size: 128kb
   max-request-size: 128kb

更多spring boot 和 kotlin相关内容,欢迎关注 《spring boot 与 kotlin 实战》

源码:


参考:


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。