11、SpringMVC:文件上传和下载

2020-12-30 05:29

阅读:647

标签:common   设置   query   origin   ext   base   一个   api   comm   

引用学习

1、准备工作

文件上传是项目开发中最常见的功能之一 ,springMVC 可以很好的支持文件上传,但是SpringMVC上下文中默认没有装配MultipartResolver,因此默认情况下其不能处理文件上传工作。如果想使用Spring的文件上传功能,则需要在上下文中配置MultipartResolver

前端表单要求:为了能上传文件,必须将表单的method设置为POST,并将enctype设置为multipart/form-data。只有在这样的情况下,浏览器才会把用户选择的文件以二进制数据发送给服务器;

对表单中的 enctype 属性做个详细的说明:

  • application/x-www=form-urlencoded:默认方式,只处理表单域中的 value 属性值,采用这种编码方式的表单会将表单域中的值处理成 URL 编码方式。

  • multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,这种编码方式会把文件域指定文件的内容也封装到请求参数中,不会对字符编码。

  • text/plain:除了把空格转换为 "+" 号外,其他字符都不做编码处理,这种方式适用直接通过表单发送邮件。

form action="" enctype="multipart/form-data" method="post">
    input type="file" name="file"/>
    input type="submit">
form>

一旦设置了enctype为multipart/form-data,浏览器即会采用二进制流的方式来处理表单数据,而对于文件上传的处理则涉及在服务器端解析原始的HTTP响应。

在2003年,Apache Software Foundation发布了开源的Commons FileUpload组件,其很快成为Servlet/JSP程序员上传文件的最佳选择。

  • Servlet3.0规范已经提供方法来处理文件上传,但这种上传需要在Servlet中完成。

  • 而Spring MVC则提供了更简单的封装。

  • Spring MVC为文件上传提供了直接的支持,这种支持是用即插即用的MultipartResolver实现的。

  • Spring MVC使用Apache Commons FileUpload技术实现了一个MultipartResolver实现类:CommonsMultipartResolver。因此,SpringMVC的文件上传还需要依赖Apache Commons FileUpload的组件

2、文件上传

单文件上传

1)使用IO流手动实现文件上传

一、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;


dependency>
    groupId>commons-fileuploadgroupId>
    artifactId>commons-fileuploadartifactId>
    version>1.3.3version>
dependency>

dependency>
    groupId>javax.servletgroupId>
    artifactId>javax.servlet-apiartifactId>
    version>4.0.1version>
dependency>

二、配置bean:multipartResolver

【注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!】


bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    
    property name="defaultEncoding" value="utf-8"/>
    
    property name="maxUploadSize" value="10485760"/>
    property name="maxInMemorySize" value="40960"/>
bean>

CommonsMultipartFile 的 常用方法:

  • String getOriginalFilename():获取上传文件的原名

  • InputStream getInputStream():获取文件流

  • void transferTo(File dest):将上传文件保存到一个目录文件中

我们去实际测试一下

三、编写前端页面

@ page contentType="text/html;charset=UTF-8" language="java" %>
@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
html>
head>
    title>Titletitle>
head>
body>
    h1>上传成功h1>
    c:forEach items="${urls}" var="url">
        img src="${url}" style="width: 300px; height: 200px;">
    c:forEach>
body>
html>

四、Controller

@Controller
public class FileController {
    private static final String PATH = "/upload/";
    /**
     * 文件上传(单文件上传)
     * @param file
     * @param request
     * @return
     * @throws IOException
     */
    @RequestMapping("/upload1")
    public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request, Model model) throws IOException {
        //获取文件名 : file.getOriginalFilename();
        String uploadFileName = file.getOriginalFilename();
?
        //如果文件名为空,直接回到首页!
        if ("".equals(uploadFileName)){
            return "redirect:/index.jsp";
        }
        // 时间路径
        String dateFormat = getTimePath();
        //上传路径保存设置
        String path = request.getServletContext().getRealPath(PATH) + dateFormat;
        //如果路径不存在,创建一个
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }
?
        InputStream is = file.getInputStream(); //文件输入流
        OutputStream os = new FileOutputStream(new File(realPath, uploadFileName)); //文件输出流
?
        //读取写出
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer, 0, len);
            os.flush();
        }
        os.close();
        is.close();
        // 上传成功后,拼接文件在服务器上的路径
        String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + PATH + dateFormat + uploadFileName;
        System.out.println(url);
        model.addAttribute("urls", Arrays.asList(url));
        return "ok";
    }
    // 按上传时间设置路径
    public String getTimePath(){
        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/");
        String dateFormat = format.format(new Date());
        return dateFormat;
    }
?
}

五、响应页面

@ page contentType="text/html;charset=UTF-8" language="java" %>
@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
html>
head>
    title>Titletitle>
head>
body>
    h1>上传成功h1>
    c:forEach items="${urls}" var="url">
        img src="${url}" style="width: 300px; height: 200px;">
    c:forEach>
body>
html>

六、测试上传文件,OK!

技术图片技术图片

 技术图片

2)采用file.Transto 来保存上传的文件

1、编写Controller

/*
 * 采用file.Transto 来保存上传的文件
 */
// 使用SpringMVC提供的方法上传文件(单文件上传)
@RequestMapping("/upload3")
public String fileUploads2(@RequestParam("file") MultipartFile file, HttpServletRequest request, Model model){
    try {
        String url = upload(file, request);
        model.addAttribute("urls", Arrays.asList(url));
        return "ok";
    } catch (IOException e) {
        return "redirect:/index.jsp";
    }
}
// 文件上传方法,单文件上传
public String upload(MultipartFile file, HttpServletRequest request) throws IOException {
    String dateFormat = getTimePath();  // 时间路径

    // 用随机UUID作为文件名
    String oldFileName = file.getOriginalFilename();
    String newFileName = UUID.randomUUID().toString().replaceAll("-", "") +
        oldFileName.substring(oldFileName.lastIndexOf("."));

    // 获取项目在服务器上的路径,下面的路径为:项目在服务器上的路径/upload/2020/05/
    String realPath = request.getServletContext().getRealPath(PATH) + dateFormat;
    // 如果将要保存文件的目录不存在则创建
    File direcotry = new File(realPath);
    if (!direcotry.exists()) direcotry.mkdirs();
    // 拼接文件路径
    realPath += newFileName;
    // 文件上传
    file.transferTo(new File(realPath));

    // 上传成功后,拼接文件在服务器上的路径
    String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + PATH + dateFormat + newFileName;
    return url;
}
// 按上传时间设置路径
public String getTimePath(){
    SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/");
    String dateFormat = format.format(new Date());
    return dateFormat;
}

2、前端表单提交地址修改

3、访问提交测试,OK!

 技术图片

多文件上传

1)使用IO流手动实现文件上传

一、导入文件上传的jar包,commons-fileupload , Maven会自动帮我们导入他的依赖包 commons-io包;


dependency>
    groupId>commons-fileuploadgroupId>
    artifactId>commons-fileuploadartifactId>
    version>1.3.3version>
dependency>

dependency>
    groupId>javax.servletgroupId>
    artifactId>javax.servlet-apiartifactId>
    version>4.0.1version>
dependency>

二、配置bean:multipartResolver

【注意!!!这个bena的id必须为:multipartResolver , 否则上传文件会报400的错误!在这里栽过坑,教训!】


bean id="multipartResolver"  class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    
    property name="defaultEncoding" value="utf-8"/>
    
    property name="maxUploadSize" value="10485760"/>
    property name="maxInMemorySize" value="40960"/>
bean>

CommonsMultipartFile 的 常用方法:

  • String getOriginalFilename():获取上传文件的原名

  • InputStream getInputStream():获取文件流

  • void transferTo(File dest):将上传文件保存到一个目录文件中

我们去实际测试一下

三、编写前端页面

@ page contentType="text/html;charset=UTF-8" language="java" %>
html>
  head>
    title>$Title$title>
    script src="${pageContext.request.contextPath}/statics/js/jquery-3.3.1.js">script>
    script>
        function check() {
            var f1 = document.getElementById("f1").files;
            var f2 = document.getElementById("f2").files;
            if (f1[0].size + f2[0].size > 1024 * 1024 * 10){
                alert("文件总和过大");
                return false;
            }else{
                return true;
            }
        }
        function getFileSize(file) {
            var fileSize = file.files[0].size;
            if (fileSize > 1024 * 1024 * 10) {
                alert("文件大小不能超过10M,请重新选择文件"); // 提示消息
                $(file).val(""); // 清空已选择的文件
            }
        }
    script>
  head>
  body>
?
  form action="${pageContext.request.contextPath}/upload2" method="post" enctype="multipart/form-data" onsubmit="return check()">
    input type="file" name="file" id="f1" onchange="getFileSize(this)">br/>
    input type="file" name="file" id="f2" onchange="getFileSize(this)">br/>
    input type="submit" value="上传">
    -- 或者添加multiple属性,可以直接选择一个或者多个文件上传 --%>
    --form action="/upload4" method="post" enctype="multipart/form-data">--%>
        --input type="file" name="file" multiple>--%>
        --input type="submit" value="上传">--%>
    --form>--%>
  form>
?
  body>
html>

四、Controller

package com.zxh.controller;
?
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
?
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
?
@RestController
public class FileController {
    // CommonsMultipartFile 实现了MultipartFile解耦
        // 手动实现文件上传(多文件上传)
    @RequestMapping("/upload2")
    public String fileUploads(@RequestParam("file") MultipartFile[] files, HttpServletRequest request, Model model) throws IOException {
        List urls = new ArrayList();
        for (MultipartFile file :
                files) {
            //获取文件名 : file.getOriginalFilename();
            String uploadFileName = file.getOriginalFilename();
?
            //如果文件名为空,直接回到首页!
            if ("".equals(uploadFileName)){
                continue;
            }
            // 时间路径
            String dateFormat = getTimePath();
            //上传路径保存设置
            String path = request.getServletContext().getRealPath(PATH) + dateFormat;
            //如果路径不存在,创建一个
            File realPath = new File(path);
            if (!realPath.exists()){
                realPath.mkdir();
            }
            path += uploadFileName;
            InputStream inputStream = file.getInputStream();
            OutputStream outputStream = new FileOutputStream(path);
            byte[] bs = new byte[1024];
            int len = -1;
            while ((len = inputStream.read(bs)) != -1) {
                outputStream.write(bs,0,len);
            }
            inputStream.close();
            outputStream.close();
            // 上传成功后,拼接文件在服务器上的路径
            String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + PATH + dateFormat + uploadFileName;
            System.out.println(url);
            urls.add(url);
        }
        model.addAttribute("urls", urls);
        return "ok";
    }
    // 按上传时间设置路径
    public String getTimePath(){
        SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/");
        String dateFormat = format.format(new Date());
        return dateFormat;
    }
}

五、测试上传文件,OK!

技术图片

技术图片

 技术图片

2)采用file.Transto 来保存上传的文件

1、编写Controller

/*
 * 采用file.Transto 来保存上传的文件
 */
// 使用SpringMVC提供的方法上传文件(多文件上传)
@RequestMapping("/upload4")
public String fileUploads2(@RequestParam("file") MultipartFile[] files, HttpServletRequest request, Model model){
    try {
        List urls = upload(files, request);
        model.addAttribute("urls", urls);
        return "ok";
    } catch (IOException e) {
        return "redirect:/index.jsp";
    }
}
// 文件上传方法,单文件上传
public String upload(MultipartFile file, HttpServletRequest request) throws IOException {
    String dateFormat = getTimePath();  // 时间路径

    // 用随机UUID作为文件名
    String oldFileName = file.getOriginalFilename();
    String newFileName = UUID.randomUUID().toString().replaceAll("-", "") +
        oldFileName.substring(oldFileName.lastIndexOf("."));

    // 获取项目在服务器上的路径,下面的路径为:项目在服务器上的路径/upload/2020/05/
    String realPath = request.getServletContext().getRealPath(PATH) + dateFormat;
    // 如果将要保存文件的目录不存在则创建
    File direcotry = new File(realPath);
    if (!direcotry.exists()) direcotry.mkdirs();
    // 拼接文件路径
    realPath += newFileName;
    // 文件上传
    file.transferTo(new File(realPath));

    // 上传成功后,拼接文件在服务器上的路径
    String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + PATH + dateFormat + newFileName;
    return url;
}
// 文件上传方法,多文件上传
public List upload(MultipartFile[] files, HttpServletRequest request) throws IOException {
    List urls = new ArrayList();
    if (files != null && files.length != 0){
        for (MultipartFile file : files) {
            if ("".equals(file.getOriginalFilename())) continue;
            urls.add(upload(file, request));
        }
    }
    return urls;
}
// 按上传时间设置路径
public String getTimePath(){
    SimpleDateFormat format = new SimpleDateFormat("yyyy/MM/");
    String dateFormat = format.format(new Date());
    return dateFormat;
}

2、前端表单提交地址修改

3、访问提交测试,OK! 

技术图片

技术图片 

3、文件下载

文件下载步骤:

  1. 设置 response 响应头

  2. 读取文件 -- InputStream

  3. 写出文件 -- OutputStream

  4. 执行操作

  5. 关闭流 (先开后关)

controller

// 文件下载
@RequestMapping("/download")
public void downloads(String url, HttpServletResponse response , HttpServletRequest request) throws Exception{
    // 要下载的图片地址
    String path = request.getServletContext().getRealPath(PATH);
    url = url.replace("upload/", "");
    // 获取文件名
    String fileName = url.substring(url.lastIndexOf("/") + 1);

    //1、设置response 响应头
    response.reset(); //设置页面不缓存,清空buffer
    response.setCharacterEncoding("UTF-8"); //字符编码
    response.setContentType("multipart/form-data"); //二进制传输数据
    //设置响应头
    response.setHeader("Content-Disposition",
                       "attachment;fileName="+URLEncoder.encode(fileName, "UTF-8"));

    File file = new File(path, url);
    //2、 读取文件--输入流
    InputStream input=new FileInputStream(file);
    //3、 写出文件--输出流
    OutputStream out = response.getOutputStream();

    byte[] buff =new byte[1024];
    int index=0;
    //4、执行 写出操作
    while((index= input.read(buff))!= -1){
        out.write(buff, 0, index);
        out.flush();
    }
    out.close();
    input.close();
}

前端

  • 在图片上添加标签请求后台,进行下载

@ page contentType="text/html;charset=UTF-8" language="java" %>
@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
html>
head>
    title>Titletitle>
head>
body>
    h1>上传成功h1>
    c:forEach items="${urls}" var="url">
        a href="/download?url=${url.substring(url.lastIndexOf("upload/"))}">img src="${url}" style="width: 300px; height: 200px;">a>
    c:forEach>
body>
html>

测试,文件下载OK!技术图片

 技术图片

4、整合代码

项目结构

技术图片

代码

controller

package com.zxh.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.*;

@Controller
public class FileController {
    private static final String PATH = "/upload/";
    // 手动实现文件上传(单文件上传)
    @RequestMapping("/upload1")
    public String fileUpload(@RequestParam("file") CommonsMultipartFile file , HttpServletRequest request, Model model) throws IOException {
        //获取文件名 : file.getOriginalFilename();
        String uploadFileName = file.getOriginalFilename();

        //如果文件名为空,直接回到首页!
        if ("".equals(uploadFileName)){
            return "redirect:/index.jsp";
        }
        // 时间路径
        String dateFormat = getTimePath();
        //上传路径保存设置
        String path = request.getServletContext().getRealPath(PATH) + dateFormat;
        //如果路径不存在,创建一个
        File realPath = new File(path);
        if (!realPath.exists()){
            realPath.mkdir();
        }

        InputStream is = file.getInputStream(); //文件输入流
        OutputStream os = new FileOutputStream(new File(realPath, uploadFileName)); //文件输出流

        //读取写出
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len=is.read(buffer))!=-1){
            os.write(buffer, 0, len);
            os.flush();
        }
        os.close();
        is.close();
        // 上传成功后,拼接文件在服务器上的路径
        String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + PATH + dateFormat + uploadFileName;
        System.out.println(url);
        model.addAttribute("urls", Arrays.asList(url));
        return "ok";
    }
    // 手动实现文件上传(多文件上传)
    @RequestMapping("/upload2")
    public String fileUploads(@RequestParam("file") MultipartFile[] files, HttpServletRequest request, Model model) throws IOException {
        List urls = new ArrayList();
        for (MultipartFile file :
                files) {
            //获取文件名 : file.getOriginalFilename();
            String uploadFileName = file.getOriginalFilename();

            //如果文件名为空,直接回到首页!
            if ("".equals(uploadFileName)){
                continue;
            }
            // 时间路径
            String dateFormat = getTimePath();
            //上传路径保存设置
            String path = request.getServletContext().getRealPath(PATH) + dateFormat;
            //如果路径不存在,创建一个
            File realPath = new File(path);
            if (!realPath.exists()){
                realPath.mkdir();
            }
            path += uploadFileName;
            InputStream inputStream = file.getInputStream();
            OutputStream outputStream = new FileOutputStream(path);
            byte[] bs = new byte[1024];
            int len = -1;
            while ((len = inputStream.read(bs)) != -1) {
                outputStream.write(bs,0,len);
            }
            inputStream.close();
            outputStream.close();
            // 上传成功后,拼接文件在服务器上的路径
            String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + PATH + dateFormat + uploadFileName;
            System.out.println(url);
            urls.add(url);
        }
        model.addAttribute("urls", urls);
        return "ok";
    }

    // 使用SpringMVC提供的方法上传文件(单文件上传)
    @RequestMapping("/upload3")
    public String fileUploads2(@RequestParam("file") MultipartFile file, HttpServletRequest request, Model model){
        try {
            String url = upload(file, request);
            model.addAttribute("urls", Arrays.asList(url));
            return "ok";
        } catch (IOException e) {
            return "redirect:/index.jsp";
        }
    }

    // 使用SpringMVC提供的方法上传文件(多文件上传)
    @RequestMapping("/upload4")
    public String fileUploads2(@RequestParam("file") MultipartFile[] files, HttpServletRequest request, Model model){
        try {
            List urls = upload(files, request);
            model.addAttribute("urls", urls);
            return "ok";
        } catch (IOException e) {
            return "redirect:/index.jsp";
        }
    }

    // 文件上传方法,单文件上传
    public String upload(MultipartFile file, HttpServletRequest request) throws IOException {
        String dateFormat = getTimePath();  // 时间路径

        // 用随机UUID作为文件名
        String oldFileName = file.getOriginalFilename();
        String newFileName = UUID.randomUUID().toString().replaceAll("-", "") +
                oldFileName.substring(oldFileName.lastIndexOf("."));

        // 获取项目在服务器上的路径,下面的路径为:项目在服务器上的路径/upload/2020/05/
        String realPath = request.getServletContext().getRealPath(PATH) + dateFormat;
        // 如果将要保存文件的目录不存在则创建
        File direcotry = new File(realPath);
        if (!direcotry.exists()) direcotry.mkdirs();
        // 拼接文件路径
        realPath += newFileName;
        // 文件上传
        file.transferTo(new File(realPath));

        // 上传成功后,拼接文件在服务器上的路径
        String url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + PATH + dateFormat + newFileName;
        return url;
    }
    // 文件上传方法,多文件上传
    public List upload(MultipartFile[] files, HttpServletRequest request) throws IOException {
        List urls = new ArrayList();
        if


评论


亲,登录后才可以留言!