SpringMVC框架06——文件上传与下载

1、文件上传

Spring MVC框架的文件上传是基于commons-fileupload组件的文件上传,只不过Spring MVC框架在原有文件上传组件上做了进一步封装,简化了文件上传的代码实现。

1.1、单文件上传

需要commons-fileupload组件相关依赖

<dependency>
  <groupId>commons-fileupload</groupId>
  <artifactId>commons-fileupload</artifactId>
  <version>1.3.1</version>
</dependency>
<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
</dependency>

 页面中的form表单上添加多部件属性,fileupload.jsp

<form action="${pageContext.request.contextPath}/onefile" method="post" enctype="multipart/form-data">
    选择文件:<input type="file" name="myfile"><br>
    文件描述:<input type="text" name="description"><br>
    <input type="submit" value="上传">
</form>

enctype属性指定的是表单数据的编码方式,该属性有以下3个值:

  • application/x-www-form-urlencoded:默认的编码方式,只处理表单域里的value属性值;
  • multipart/form-data:以二进制流的方式来处理表单数据,并将文件域指定文件的内容封装到请求参数里;
  • text/plain:只有当表单的action属性为mailto:URL的形式时才使用,主要适用于直接通过表单发送邮件的方式。

创建POJO实体类

import org.springframework.web.multipart.MultipartFile;

public class FileDomain {
    private String description;
    private MultipartFile myfile;
    
    //getter和setter
}

在实体类中声明MultipartFile类型的属性封装被上传的文件信息,属性名与文件上传页面fileupload.jsp中的file类型的表单参数名myfile相同。

创建控制器类

@Controller
public class FileUploadController {

    @RequestMapping("/onefile")
    public String oneFileUpload(@ModelAttribute FileDomain fileDomain, HttpServletRequest request){
        //文件上传的位置
        String realpath = request.getServletContext().getRealPath("uploadfiles");
        //上传文件的名称
        String fileName = fileDomain.getMyfile().getOriginalFilename();
        File targetFile = new File(realpath,fileName);
        if(!targetFile.exists()){
            targetFile.mkdirs();//创建目录
        }
        try {
            fileDomain.getMyfile().transferTo(targetFile);
            System.out.println("文件上传成功");
        } catch (Exception e){
            e.printStackTrace();
        }

        return "showFile";
    }
}

配置springmvc.xml

<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"></bean>

创建showFile.jsp用于展示结果:

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<html>
<head>
    <title>文件上传信息</title>
</head>
<body>
    文件名称:${fileDomain.myfile.originalFilename}<br>
    文件描述:${fileDomain.description}
</body>
</html>

上传页面展示:

上传结果展示:

注意事项:

  • 在上传页面fileupload.jsp中,form表单一定要加enctype属性,值为multipart/form-data,表单提交方式设置为post;
  • form表单中的file标签的name属性要和实体类的MultipartFile属性的名称保持一致;
  • 要在springmvc.xml中使用CommonsMultipartResolver类配置multipartResolver用于文件上传;

1.2、多文件上传

创建multifiles.jsp文件上传页面:

<form action="${pageContext.request.contextPath}/multifile" method="post" enctype="multipart/form-data">
    <p>
        选择文件1:<input type="file" name="myfile"><br>
        文件描述1:<input type="text" name="description">
    </p>
    <p>
        选择文件2:<input type="file" name="myfile"><br>
        文件描述2:<input type="text" name="description">
    </p>
    <p>
        选择文件3:<input type="file" name="myfile"><br>
        文件描述3:<input type="text" name="description">
    </p>
    <p>
        <input type="submit" value="提交">
    </p>
</form>

创建POJO类:

public class MultiFileDomain {
    private List<String> description;
    private List<MultipartFile> myfile;
    //getter和setter
}

创建Controller类,接收上传参数:

@Controller
public class FileUploadController {

    //多文件上传
    @RequestMapping("/multifile")
    public String multiFileUpload(@ModelAttribute MultiFileDomain multiFileDomain,HttpServletRequest request){
        String realpath = request.getServletContext().getRealPath("uploadfiles");
        File targetDir = new File(realpath);
        if(!targetDir.exists()){
            targetDir.mkdirs();
        }
        List<MultipartFile> files = multiFileDomain.getMyfile();
        for (int i=0;i<files.size();i++){
            MultipartFile file = files.get(i);
            String fileName = file.getOriginalFilename();
            File targetFile = new File(realpath,fileName);
            //上传
            try {
                file.transferTo(targetFile);
            } catch (Exception e){
                e.printStackTrace();
            }
        }
        System.out.println("文件上传成功!");
        return "showMulti";
    }
}

创建成功信息页面showMulti.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>多文件上传结果</title>
</head>
<body>
    <table width="50%" border="1">
        <tr>
            <td>文件名</td>
            <td>详情</td>
        </tr>
        <c:forEach var="des" items="${multiFileDomain.description}" varStatus="loop">
            <tr>
                <td>${multiFileDomain.myfile[loop.count-1].originalFilename}</td>
                <td>${des}</td>
            </tr>
        </c:forEach>
    </table>
</body>
</html>

测试多文件上传

上传结果:

2、文件下载

2.1、文件下载相关介绍

实现文件下载有两种方法:一种是通过超链接实现下载,另一种是利用程序编码实现下载。通过超链接实现下载比较简单,但是会暴露下载文件的真实位置,利用程序编码实现下载可以增加安全访问控制。
利用程序实现下载需要设置两个报头:
(1)设置Content-Type的值为application/x-msdownload
这项设置主要是为了告诉浏览器,其所输出内容的类型不是普通文本文件或HTML文件,而是一个要保存到本地的下载文件。
(2)设置Content-Disposition的值为attachment,并且在后面指定filename参数
这项设置主要是让浏览器不要直接处理相应的实体内容,而是由用户选择将相应的实体内容保存到一个文件中。该报头指定了接收程序处理数据内容的方式,在HTTP应用中只有attachment是标准方式,attachment表示要求用户干预。在attachment后面还可以指定filename参数,该参数是服务器建议浏览器将实体内容保存到文件中的文件名称。
设置报头的示例代码如下:

//设置下载文件使用的报头
response.setHeader("Content-Type","application/x-msdownload");
response.setHeader("Content-Disposition","attachment;filename="+filename);

2.2、文件下载的功能实现

创建FileDownController类,并编写下载功能的方法:

@Controller
public class FileDownController {

    @RequestMapping("/down")
    public String down(@RequestParam String filename, HttpServletRequest request, HttpServletResponse response){
        String filePath = null; //要下载的文件路径
        FileInputStream in = null; //输入流
        ServletOutputStream out = null; //输出流
        try {
            //文件下载路径
            filePath = request.getServletContext().getRealPath("uploadfiles");
            //设置下载文件使用的报头
            response.setHeader("Content-Type","application/x-msdownload");
            response.setHeader("Content-Disposition","attachment;filename="+toUTF8String(filename));
            //读入文件
            in = new FileInputStream(filePath+"\\"+filename);
            //得到响应对象的输出流,用于向客户端输出二进制数据
            out = response.getOutputStream();
            out.flush();
            int aRead = 0;
            byte[] b = new byte[1024];
            while ((aRead=in.read(b))!=-1 && in!=null){
                out.write(b,0,aRead);
            }
            out.flush();
            in.close();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println("下载成功!");
        return null;

    }

    /**
     * 下载保存时中文文件名的字符编码转换方法
     */
    public String toUTF8String(String str){
        StringBuffer sb = new StringBuffer();
        int len = str.length();
        for (int i=0;i<len;i++) {
            //取出字符中的每个字符
            char c = str.charAt(i);
            //Unicode码值为0-255时,不做处理
            if(c>=0 && c<=255){
                sb.append(c);
            }else{
                //转换UTF-8编码
                byte[] b;
                try {
                    b = Character.toString(c).getBytes("UTF-8");
                } catch (Exception e){
                    e.printStackTrace();
                    b = null;
                }
                //转换为%HH的字符串形式
                for (int j=0;j<b.length;j++){
                    int k = b[j];
                    if(k<0){
                        k&=255;
                    }
                    sb.append("%"+Integer.toHexString(k).toUpperCase());
                }
            }
        }
        return sb.toString();
    }

}

创建页面展示可下载文件的Controller类和方法:

@RequestMapping("/show")
public String show(HttpServletRequest request, Model model){
    //文件下载路径
    String realPath = request.getServletContext().getRealPath("uploadfiles");
    File dir = new File(realPath);
    File[] files = dir.listFiles();
    //获取该目录下的所有文件名
    ArrayList<String> fileNames = new ArrayList<String>();
    for (int i=0;i<files.length;i++) {
        fileNames.add(files[i].getName());
    }
    model.addAttribute("files",fileNames);
    return  "showDown";
}

创建用于文件下载展示的showDown.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" isELIgnored="false" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>文件下载</title>
</head>
<body>

    <table width="50%" border="1">
        <tr>
            <th>文件名</th>
            <th>操作</th>
        </tr>
        <c:forEach var="filename" items="${files}">
            <tr>
                <td>${filename} </td>
                <td>
                    <a href="${pageContext.request.contextPath}/down?filename=${filename}">下载</a>
                </td>
            </tr>
        </c:forEach>
    </table>

</body>
</html>

效果展示:

点击下载链接

posted @ 2019-03-16 16:27  Web1024  阅读(1372)  评论(0编辑  收藏  举报