0062 Spring MVC的文件上传与下载--MultipartFile--ResponseEntity

文件上传功能在网页中见的太多了,比如上传照片作为头像、上传Excel文档导入数据等

先写个上传文件的html

<!DOCTYPE html>
<html>
<head>
    <title>Spring MVC文件上传与下载</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />   
</head>
    <body>
        <form action="upload" method="POST" enctype="multipart/form-data">   <!-- 上传文件注意enctype -->
            文件描述:<input type="text" name="desc" /> <br><br>
            选择文件:<input type="file" name="file" /> <br><br>
            <input type="submit" value="上传" /> 
        </form>
    </body>
</html>

写个controller接收上传的文件

package net.sonng.mvcdemo.controller;

import java.io.File;

import javax.servlet.http.HttpServletRequest;

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.multipart.MultipartFile;

@Controller
public class UploadController {
    @RequestMapping("/upload")
    public String upload(HttpServletRequest request,@RequestParam("desc") String desc,@RequestParam("file") MultipartFile file) throws Exception{
        //接收到的文件绑定到MultipartFile对象中
        System.out.println(desc);
        if (!file.isEmpty()){  //如果文件不为空,那么将它存起来
            String path=request.getServletContext().getRealPath("/images");  //接收的文件放在/images目录下,并获得文件系统目录
            String filename=file.getOriginalFilename();//获取文件名
            File filepath=new File(path,filename);     //根据文件所在目录和文件名创建File对象
            if(!filepath.getParentFile().exists()){    //如果所在目录不存在,那么创建
                filepath.getParentFile().mkdirs();
            }
            file.transferTo(new File(path+File.separator+filename)); //调用transferTo()方法将文件存储到目标位置
            //file.transferTo(filepath)                              //也可以用这条语句
            return "result";
        }else{
            return "error";
        }
    }
}

关于multipartFile

常用方法有:

  • String getContentType(): 获取文件的MIME类型
  • String getOriginalFilename(): 获取文件名
  • long getSize(): 获取文件大小,单位KB
  • boolean isEmpty(): 文件是否为空
  • void transferTo(File dest): 将文件存储到dest
  • String getName(): 获取表单的参数名
  • byte[] getBytes(): 获取文件数据
  • InputStream getInputStream(): 获取文件流

Spring MVC的文件上传组件需要MultipartResolver接口,依赖于Apache Commons FileUpload技术实现了一个实现类CommonsMultipartResolver,因此还需要两方面的工作:1. 引入Apache Commons FileUpload包;2. 配置xml

引入Apache Commons FileUpload及其依赖的Commons IO

配置xml

 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
        <property name="maxUploadSize">    <!-- 还可以限制上传文件的大小 -->
            <value>10485760</value>
        </property>
        <property name="defaultEncoding" >  <!-- 注意这个编码格式,要跟上传的页面的编码一致 -->
            <value>UTF-8</value>
        </property>
    </bean>

部署访问,检查Tomcat的该app目录下的/images目录下是否有上传的文件。

将上传的文件以对象属性的形式保存

比如头像,总是属于某个用户,因此在用户类中可以定义一个MultipartFile属性存储用户头像
上传用户头像的html

<!DOCTYPE html>
<html>
<head>
    <title>Spring MVC文件上传与下载</title>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
</head>
    <body>
        <form action="upload" method="POST" enctype="multipart/form-data">
            用户名:<input type="text" name="username" /> <br><br>
            选择图片:<input type="file" name="avatar" /> <br><br>
            <input type="submit" value="上传" /> 
        </form>
    </body>
</html>

实体类user:

package net.sonng.mvcdemo.entity;

import org.springframework.web.multipart.MultipartFile;

public class User {
    private String username;
    private MultipartFile avatar;   //上传的头像作为User的一个属性
    //。。。。。  
}

写controller:

package net.sonng.mvcdemo.controller;

import java.io.File;

import javax.servlet.http.HttpServletRequest;

import net.sonng.mvcdemo.entity.User;

import org.apache.commons.io.FileUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class UploadController {
    @RequestMapping("/upload")
    public String upload(HttpServletRequest request,@ModelAttribute User user,Model model) throws Exception{
        if (!user.getAvatar().isEmpty()){
            String path=request.getServletContext().getRealPath("/avatars/");
            String filename=user.getAvatar().getOriginalFilename();
            File filepath=new File(path,filename);
            if(!filepath.getParentFile().exists()){
                filepath.getParentFile().mkdirs();
            }
            user.getAvatar().transferTo(new File(path+File.separator+filename));
            model.addAttribute("user", user);
            return "result";
        }else{
            return "error";
        }
    }
    @RequestMapping("/download")  //上传了之后再下载
    public ResponseEntity<byte[]> download(HttpServletRequest request,@RequestParam("filename") String filename,Model model)throws Exception{
        String path=request.getServletContext().getRealPath("/avatars/");  //获取文件所在路径
        filename=new String(filename.getBytes("ISO-8859-1"),"UTF-8");     //不知何故,result.jsp的请求参数是ISO-8859-1编码的,但明明设置了charset=utf-8
        File file=new File(path+File.separator+filename);
        HttpHeaders headers=new HttpHeaders();
        String downloadFileName=new String(filename.getBytes("UTF-8"),"ISO-8859-1");  //少了这句,可能导致下载中文文件名的文档,只有后缀名的情况
        headers.setContentDispositionFormData("attachment", downloadFileName);//告知浏览器以下载方式打开
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);//设置MIME类型
        return new ResponseEntity<byte[]>(FileUtils.readFileToByteArray(file),headers,HttpStatus.CREATED);//
        //用FileUpload组件的FileUtils读取文件,并构建成ResponseEntity<byte[]>返回给浏览器
        //HttpStatus.CREATED是HTTP的状态码201
    }
}

上传成功后,返回页面result.jsp,

<%@page pageEncoding="utf-8" 
        contentType="text/html;charset=utf-8" %>
<html>
    <head>
        <title>文件的上传与下载</title>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
    </head>
    <body>
        <p>下载刚才上传的文件</p>
        <a href="download?filename=${user.avatar.originalFilename }">下载文件</a>
    </body>
</html>

部署测试,分别测试中文/英文文件名

总结

上传文件:上传的文件绑定到MultipartFile中;获取文件名;要存储的文件系统路径;创建目录;用MultipartFile的transferTo()存储
下载文件:获取要下载的文件名,注意编码;在HttpHeaders中设置以下载方式打开,设置MIME类型;用FileUtils.readFileToByteArray()读取文件数据;用ResponseEntity<byte[]>构建返回对象

posted @ 2017-04-04 14:36  sonng  阅读(6313)  评论(0编辑  收藏  举报