激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Spring Boot + thymeleaf 實現文件上傳下載功能

Spring Boot + thymeleaf 實現文件上傳下載功能

2021-03-22 14:01卡巴拉的樹 Java教程

最近同事問我有沒有有關于技術的電子書,我打開電腦上的小書庫,但是郵件發給他太大了,公司又禁止用文件夾共享,于是花半天時間寫了個小的文件上傳程序,部署在自己的Linux機器上,需要的朋友可以參考下

最近同事問我有沒有有關于技術的電子書,我打開電腦上的小書庫,但是郵件發給他太大了,公司又禁止用文件夾共享,于是花半天時間寫了個小的文件上傳程序,部署在自己的linux機器上。

提供功能: 1 .文件上傳 2.文件列表展示以及下載

原有的上傳那塊很丑,寫了點js代碼優化了下,最后界面顯示如下圖:

Spring Boot + thymeleaf 實現文件上傳下載功能

先給出成果,下面就一步步演示怎么實現。

1.新建項目

首先當然是新建一個spring-boot工程,你可以選擇在網站初始化一個項目或者使用ide的spring initialier功能,都可以新建一個項目。這里我從idea新建項目:

Spring Boot + thymeleaf 實現文件上傳下載功能

下一步,然后輸入group和artifact,繼續點擊next:

Spring Boot + thymeleaf 實現文件上傳下載功能

這時候出現這個模塊選擇界面,點擊web選項,勾上web,證明這是一個webapp,再點擊template engines選擇前端的模板引擎,我們選擇thymleaf,spring-boot官方也推薦使用這個模板來替代jsp。

Spring Boot + thymeleaf 實現文件上傳下載功能

 
Spring Boot + thymeleaf 實現文件上傳下載功能

 

最后一步,然后等待項目初始化成功。

Spring Boot + thymeleaf 實現文件上傳下載功能

2.pom設置

首先檢查項目需要添加哪些依賴,直接貼出我的pom文件:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
<?xml version="1.0" encoding="utf-8"?>
<project xmlns="http://maven.apache.org/pom/4.0.0" xmlns:xsi="http://www.w3.org/2001/xmlschema-instance"
 xsi:schemalocation="http://maven.apache.org/pom/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 <modelversion>4.0.0</modelversion>
 <groupid>com.shuqing28</groupid>
 <artifactid>upload</artifactid>
 <version>0.0.1-snapshot</version>
 <packaging>jar</packaging>
 <name>upload</name>
 <description>demo project for spring boot</description>
 <parent>
 <groupid>org.springframework.boot</groupid>
 <artifactid>spring-boot-starter-parent</artifactid>
 <version>1.5.9.release</version>
 <relativepath/> <!-- lookup parent from repository -->
 </parent>
 <properties>
 <project.build.sourceencoding>utf-8</project.build.sourceencoding>
 <project.reporting.outputencoding>utf-8</project.reporting.outputencoding>
 <java.version>1.8</java.version>
 </properties>
 <dependencies>
 <dependency>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-starter</artifactid>
 </dependency>
 <dependency>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-starter-thymeleaf</artifactid>
 </dependency>
 <dependency>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-configuration-processor</artifactid>
  <optional>true</optional>
 </dependency>
 <dependency>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-starter-test</artifactid>
  <scope>test</scope>
 </dependency>
 <!-- https://mvnrepository.com/artifact/org.webjars/bootstrap -->
 <dependency>
  <groupid>org.webjars</groupid>
  <artifactid>bootstrap</artifactid>
  <version>3.3.5</version>
 </dependency>
 <!-- https://mvnrepository.com/artifact/org.webjars.bower/jquery -->
 <dependency>
  <groupid>org.webjars.bower</groupid>
  <artifactid>jquery</artifactid>
  <version>2.2.4</version>
 </dependency>
 </dependencies>
 <build>
 <plugins>
  <plugin>
  <groupid>org.springframework.boot</groupid>
  <artifactid>spring-boot-maven-plugin</artifactid>
  </plugin>
 </plugins>
 </build>
</project>

可以查看到 spring-boot-starter-thymeleaf 包含了webapp,最后兩個webjars整合了bootstrap和jquery,其它的等代碼里用到再說。

最后一個spring boot maven plugin是系統創建時就添加的,它有以下好處:

1 . 它能夠打包classpath下的所有jar,構建成一個可執行的“über-jar”,方便用戶轉移服務

2 . 自動搜索 public static void main() 方法并且標記為可執行類

3 . 根據spring-boot版本,提供內建的依賴解釋。

3. 上傳文件控制器

如果你只是使用springmvc上傳文件,是需要配置一個 multipartresolver 的bean的,或者在 web.xml 里配置一個 <multipart-config> ,不過借助于spring-boot的自動配置,你什么都不必做。直接寫控制器類,我們在 src/main/java 下新建controller的package,并且新建fileuploadcontroller:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
package com.shuqing28.upload.controller;
import com.shuqing28.uploadfiles.pojo.linker;
import com.shuqing28.uploadfiles.exceptions.storagefilenotfoundexception;
import com.shuqing28.uploadfiles.service.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.list;
import java.util.stream.collectors;
@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<linker> linkers = storageservice.loadall().map(
        path -> new linker(mvcuricomponentsbuilder.frommethodname(fileuploadcontroller.class,
            "servefile", path.getfilename().tostring()).build().tostring(),
            path.getfilename().tostring())
    ).collect(collectors.tolist());
    model.addattribute("linkers", linkers);
    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 注解,證明這是一個controller,每個方法前添加了 @getmapping 和 @postmapping 分別相應get和post請求。

首先是 @getmapping("/") ,方法 listuploadedfiles ,顧名思義,顯示文件列表,這里我們借助于storageservice遍歷文件夾下的所有文件,并且用map方法提合成了鏈接和文件名列表,返回了一個linker對象的數組,linker對象是一個簡單pojo,只包含下面兩部分:

?
1
2
private string fileurl;
private string filename;

這個方法包含了對java8中stream的使用,如果有不理解的可以看看這篇文章 java8 特性詳解(二) stream api .

接下來是 @getmapping("/files/{filename:.+}") ,方法是 servefile ,該方法提供文件下載功能,還是借助于storageservice,后面會貼出storageservice的代碼。最后使用responseentity,把文件作為body返回給請求方。

@postmapping("/") 的 handlefileupload 使用post請求來上傳文件,參數 @requestparam("file") 提取網頁請求里的文件對象,還是使用storageservice來保存對象,最后使用重定向來刷新網頁,并且給出成功上傳的message。

4. 文件處理

上面controller調用的很多方法由storageservice提供,我們定義一個接口,包含以下方法:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
package com.shuqing28.uploadfiles.service;
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();
}

因為我這里只是借助于本地文件系統處理文件的長傳下載,所以有了以下實現類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package com.shuqing28.uploadfiles.service;
import com.shuqing28.uploadfiles.exceptions.storageexception;
import com.shuqing28.uploadfiles.exceptions.storagefilenotfoundexception;
import com.shuqing28.uploadfiles.config.storageproperties;
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
public class filesystemstorageservice implements storageservice {
  private final path rootlocation;
  @autowired
  public filesystemstorageservice(storageproperties properties) {
    this.rootlocation = paths.get(properties.getlocation());
  }
  @override
  public void init() {
    try {
      files.createdirectories(rootlocation);
    }
    catch (ioexception e) {
      throw new storageexception("could not initialize storage", e);
    }
  }
  @override
  public void store(multipartfile file) {
    string filename = stringutils.cleanpath(file.getoriginalfilename());
    try {
      if (file.isempty()) {
        throw new storageexception("failed to store empty file" + filename);
      }
      if (filename.contains("..")) {
        // this is a security check
        throw new storageexception(
            "cannot store file with relative path outside current directory "
                + filename);
      }
      files.copy(file.getinputstream(), this.rootlocation.resolve(filename), standardcopyoption.replace_existing);
    } catch (ioexception e) {
      throw new storageexception("failed to store file" + 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("failed to read stored files", 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(
            "could not read file: " + filename);
      }
    }
    catch (malformedurlexception e) {
      throw new storagefilenotfoundexception("could not read file: " + filename, e);
    }
  }
  @override
  public void deleteall() {
    filesystemutils.deleterecursively(rootlocation.tofile());
  }
}

這個類也基本運用了java的nio,使用path對象定義了location用于文件的默認保存路徑。

先看 store 方法,store接受一個multipartfile對象作為參數,想比于傳統jsp中只是傳二進制字節數組,multipartfile提供了很多方便調用的方法讓我們可以獲取到上傳文件的各項信息:

?
1
2
3
4
5
6
7
8
9
10
public interface multipartfile extends inputstreamsource {
 string getname();
 string getoriginalfilename();
 string getcontenttype();
 boolean isempty();
 long getsize();
 byte[] getbytes() throws ioexception;
 inputstream getinputstream() throws ioexception;
 void transferto(file dest) throws ioexception, illegalstateexception;
}

代碼里使用了files的copy方法把文件流拷到location對應的path里,當然我們也可以使用transferto方法保存文件, file.transferto(this.rootlocation.resolve(filename).tofile());

loadall方法加載該路徑下的所有文件path信息, loadasresource 則是加載文件為一個resource對象,再看controller的代碼,最后是接受一個resource對象作為body返回給請求方。

5. 前端模板

最后定義了前端模板,這里依舊先看代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<html xmlns:th="http://www.thymeleaf.org">
<head>
  <title>share files</title>
</head>
<body>
<div class="col-md-8 col-md-offset-2" th:if="${message}">
  <h2 th:text="${message}"/>
</div>
<div class="col-md-8 col-md-offset-2">
  <form method="post" action="/" enctype="multipart/form-data">
    <!-- component start -->
    <input type="file" name="file" class="input-ghost" style="visibility:hidden; height:0"/>
    <div class="form-group">
      <div class="input-group input-file" name="fichier1">
        <input type="text" class="form-control" placeholder='choose a file...'/>
        <span class="input-group-btn">
          <button class="btn btn-default btn-choose" type="button">choose</button>
     </span>
      </div>
    </div>
    <!-- component end -->
    <div class="form-group">
      <button type="submit" class="btn btn-primary pull-right">submit</button>
      <button type="reset" class="btn btn-danger">reset</button>
    </div>
  </form>
</div>
<div class="col-md-8 col-md-offset-2">
  <ul>
    <li th:each="linker: ${linkers}">
      <a th:href="${linker.fileurl}" rel="external nofollow" th:text="${linker.filename}" />
    </li>
  </ul>
</div>
<script src="//ajax.aspnetcdn.com/ajax/jquery/jquery-1.9.1.min.js"></script>
<script src="/webjars/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script type="text/javascript" th:inline="javascript">
  function bs_input_file() {
    $(".input-file").before(
      function() {
        if ( ! $(this).prev().hasclass('input-ghost') ) {
          var element = $(".input-ghost");
          element.change(function(){
            element.next(element).find('input').val((element.val()).split('\\').pop());
          });
          $(this).find("button.btn-choose").click(function(){
            element.click();
          });
          $(this).find("button.btn-reset").click(function(){
            element.val(null);
            $(this).parents(".input-file").find('input').val('');
          });
          $(this).find('input').css("cursor","pointer");
          $(this).find('input').mousedown(function() {
            $(this).parents('.input-file').prev().click();
            return false;
          });
          return element;
        }
      }
    );
  }
  $(function() {
    bs_input_file();
  });
</script>
<link rel="stylesheet" href="/webjars/bootstrap/3.3.5/css/bootstrap.min.css" rel="external nofollow" />
</body>
</html>

這里重要的地方還是 <form> 標簽內的內容, <form method="post" action="/" enctype="multipart/form-data"> enctype 一定要寫成 multipart/form-data ,使用post上傳文件,原有的上傳控件很丑,所以做了一個text+input放在表面,在下面放了一個隱形的上傳文件的input,可以自己看看代碼,本文就不啰嗦了。

下面還放了一個list用于展示文件列表,這里我們獲取到服務端提供的linkers對象,不斷foreach就可以獲得里面的兩個元素fileurl和filename。

這里jquery換成了微軟的cdn,webjars的總是引入不進來,不知道什么原因。

其它設置

在 src/main/resources/application.properties 里設置上傳文件大小限制

?
1
2
spring.http.multipart.max-file-size=128mb
spring.http.multipart.max-request-size=128mb

另外在``還設置了文件默認保存路徑:

?
1
2
3
4
5
6
7
8
9
10
11
12
package com.shuqing28.uploadfiles.config;
import org.springframework.boot.context.properties.configurationproperties;
@configurationproperties("storage")
public class storageproperties {
  private string location = "/home/jenkins/upload-files/";
  public string getlocation() {
    return location;
  }
  public void setlocation(string location) {
    this.location = location;
  }
}

這里注意,由于storageproperties的設置,在application的那個類中要添加上

?
1
2
3
4
5
6
7
8
@enableconfigurationproperties注解
@springbootapplication
@enableconfigurationproperties(storageproperties.class)
public class uploadapplication {
 public static void main(string[] args) {
 springapplication.run(uploadapplication.class, args);
 }
}

總結

以上所述是小編給大家介紹的spring boot + thymeleaf 實現文件上傳下載功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!

原文鏈接:https://juejin.im/post/5a326dcaf265da431048685e

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 9999视频 | 本站只有精品 | 亚洲午夜不卡 | 污视频在线免费播放 | 黄网站免费观看视频 | 天天操天天操天天操天天操天天操天天操 | 一本色道久久综合狠狠躁篇适合什么人看 | 国产精品亚洲综合一区二区三区 | 美女网站黄在线观看 | 欧美爱爱视频网站 | av在线免费观看播放 | 黄色av片三级三级三级免费看 | 一区二区三区欧美在线 | 国产一区二区久久精品 | 亚洲影院在线播放 | av电影免费在线看 | 日韩精品中文字幕在线观看 | 91九色视频在线播放 | 午夜精品在线视频 | 中文字幕亚洲一区二区三区 | 欧美18一19sex性护士农村 | 色污视频在线观看 | 91精品国 | 美国黄色毛片女人性生活片 | 精品无码久久久久久国产 | 国产精品片一区二区三区 | 国产99久久精品 | 福利在线免费 | 国产刺激高潮av | 91色爱 | 欧美日韩国产一区二区三区在线观看 | 精品国产一区二区三区四区阿崩 | 欧美性受xxxx白人性爽 | 国产成人av在线播放 | 关键词| 亚洲美女网站在线观看 | 免费看毛片的网站 | 国产一级二级视频 | 久草亚洲视频 | 黄视频免费观看 | 亚洲乱码精品久久久久 |