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

基于Spring实现文件上传功能

程序员文章站 2024-03-31 11:47:28
本小节你将建立一个可以接受http multi-part 文件的服务。 你将建立一个后台服务来接收文件以及前台页面来上传文件。 要利用servlet容器上传文件,你要注...

本小节你将建立一个可以接受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}">
  <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>

页面主要分为三部分分

- 顶部展示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、运行结果

基于Spring实现文件上传功能

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