Java框架学习:SpringMVC之文件的上传下载

文件上传

代码实现

index.jsp代码

<form enctype="multipart/form-data" action="/upload" method="post">
    请选择你要上传的文件:<input type="file" name="file">
    <input type="submit" value="上传文件">
</form>

处理器FileController

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.UUID;

@Controller
public class FileController {
    //SpringMVC识别多媒体文件后,会使用CommonsMultipartFile类对象进行读取文件
    @RequestMapping(value = "/upload",method = {RequestMethod.POST})
    public String upload(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
        //获取文件在客户端的真实名称
        String filename = file.getOriginalFilename();
        /*Tomcat默认将上传的文件存储在tomcat\bin目录下,在该目录下文件无法被访问,
        为了文件可以被访问,可以将文件上传到项目的根目录下*/
        //获取当前程序在tomcat中的运行目录	
        String realPath = request.getServletContext().getRealPath("/");
        //File.separator这个代表系统目录中的间隔符,不要用"/"拼串,避免跨平台失败
        File tfile = new File(realPath+File.separator+filename);
    	//输出文件的绝对路径
        System.out.println(tfile.getAbsolutePath());
        //存储文件
        file.transferTo(tfile);
        return "index";
    }
}

在springMVC.xml配置文件中配置如下内容:

<!--配置文件上传解析器,解析CommonsMultipartFile对象-->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>
注意:
1.可以使用UUID类获取一个随机的id增加到文件名上避免文件名的重复,如下所示
	String uuid = UUID.randomUUID().toString();
2.如果将文件将文件上传到项目的根目录下,如果项目重新部署,会造成上传的文件被覆盖;
可以将文件储存在本地非tomcat目录下,但是tomcat无法访问改文件,此时需要在tomcat中增加虚拟目录的配置;也可以将文件储存在文件服务器中。
显示文件上传进度

文件上传解析器CommonsMultipartResolver类通过parseRequest方法对文件进行解析,我们需要对该方法进行扩展,那么就需要自定义类继承CommonsMultipartResolver类并重写parseRequest方法,在原有的代码中,增加对文件上传进度的监听。

import org.apache.commons.fileupload.*;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import java.util.List;

public class MyCommonsMultipartResolver extends CommonsMultipartResolver {
	@Override
    protected MultipartParsingResult parseRequest(HttpServletRequest request) throws MultipartException {
        String encoding = this.determineEncoding(request);
        FileUpload fileUpload = this.prepareFileUpload(encoding);
        
        //设置文件上传进度的监听器
        MyProgressListener myProgressListener = new MyProgressListener(request.getSession());
        fileUpload.setProgressListener(myProgressListener);
        
        try {
            List<FileItem> fileItems = ((ServletFileUpload)fileUpload).parseRequest(request);
            return this.parseFileItems(fileItems, encoding);
        } catch (FileUploadBase.SizeLimitExceededException var5) {
            throw new MaxUploadSizeExceededException(fileUpload.getSizeMax(), var5);
        } catch (FileUploadBase.FileSizeLimitExceededException var6) {
            throw new MaxUploadSizeExceededException(fileUpload.getFileSizeMax(), var6);
        } catch (FileUploadException var7) {
            throw new MultipartException("Failed to parse multipart servlet request", var7);
        }
    }
}

自定义监听器
设置成员变量session,是为了将上传进度的数据存储到session域中,使处理器可以获取数据并返回给前台。

import org.apache.commons.fileupload.ProgressListener;

import javax.servlet.http.HttpSession;

public class MyProgressListener implements ProgressListener {
    private HttpSession session;

    public MyProgressListener(HttpSession session) {
        this.session = session;
    }

    /**
     * @param l - 已经处理的大小
     * @param l1 - 文件总大小
     * @param i - 处理文件的编号(客户端可能上传多个文件)
     */
    @Override
    public void update(long l, long l1, int i) {
        String msg=String.format("文件总大小%s,已经上传的大小%s,正在处理第%s个文件",l,l1,i);
        System.out.println(msg);
        if (l==l1){
            session.setAttribute("msg","ok");
        }else{
            session.setAttribute("msg",msg);
        }
    }
}

index.jsp代码
在前台需要设置定时器循环发送Ajax请求获取文件上传的进度。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <title>Title</title>
</head>
<body>
    <form enctype="multipart/form-data" action="/upload" method="post">
        请选择你要上传的文件:<input type="file" name="file">
        <input type="submit" id="btn1" value="上传文件">
    </form>
    <h3 id="uploadState"></h3>
</body>
<script>
    $(function() {
        $("#btn1").click(function () {
            var interval = setInterval(function () {
                $.ajax({
                    type: "get",
                    url: "uploadState",
                    success: function (result) {
                        console.log(result);
                        $("#uploadState").text(result.msg);
                        //如果上传完毕,关闭定时器
                        if(result.msg=="ok"){
                           clearInterval(interval);
                        }
                    }
                });
            }, 100);
        });
    })
</script>
</html>

控制器中的uploadState方法

//注意使用@ResponseBody注解时,需要导入jackson依赖
@RequestMapping("/uploadState")
@ResponseBody
public Map<String,String> uploadState(HttpSession session){
	Object obj = session.getAttribute("msg");
    Map<String,String> map=new HashMap<>();
    map.put("msg",obj.toString());
    return map;
}
Ajax实现文件上传

index.jsp代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>

<head>
    <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script>
    <title>Title</title>
</head>


<body>
    请选择你要上传的文件:<input type="file" name="uploadAjaxFile" id="uploadAjaxFile" >
    <input type="submit" id="btn2" value="上传文件">
    <h3 id="uploadState"></h3>
</body>
<script>
    $(function() {
    	//因为删除了表单,所以需要增加点击事件
        $("#btn2").click(function () {
            var formData=new FormData();
            //通过增加角标可将$("#uploadAjaxFile")JQuery对象转换为js对象,通过files[0]取出上传的第一个文件
            formData.append("file",$("#uploadAjaxFile")[0].files[0]);
            $.ajax({
                type: "post",
                url: "uploadAjax",
                data:formData,
                contentType:false,
                processData: false,
                success: function (result) {},
                //在beforeSend方法中发送请求请求文件上传的进度
                beforeSend:processState()
            });
        });
    })

    function processState() {
        var interval = setInterval(function () {
            $.ajax({
                type: "post",
                url: "uploadState",
                success: function (result) {
                    console.log(result);
                    $("#uploadState").text(result.msg);
                    if(result.msg=="ok"){
                        clearInterval(interval);
                    }

                }
            });
        }, 1000);
    }
</script>
</html>

处理器中的方法变化不大,处理文件上传请求的方法不需要返回视图,可返回JSON。

//后台无需返回视图,需要返回JSON
@RequestMapping(value = "/uploadAjax",method = {RequestMethod.POST})
@ResponseBody
public Map<String,String> uploadAjax(@RequestParam("file") CommonsMultipartFile file, HttpServletRequest request) throws IOException {
    String filename = file.getOriginalFilename();
    String realPath = request.getServletContext().getRealPath("/");
    File tfile = new File(realPath+File.separator+filename);
    file.transferTo(tfile);
    HashMap<String, String> map = new HashMap<>();
    map.put("msg","上传完毕");
    return map;
}

//处理文件上传进度请求的处理方法
@RequestMapping("/uploadState")
@ResponseBody
public Map<String,String> uploadState(HttpSession session){
    Object obj = session.getAttribute("msg");
    Map<String,String> map=new HashMap<>();
    map.put("msg",obj.toString());
    return map;
}
多文件上传

index.jsp代码
提供多个<input type=“file”>标签

<form enctype="multipart/form-data" action="/uploadFiles" method="post">
    请选择你要上传的文件:
    <input type="file" name="file"><br>
    <input type="file" name="file"><br>
    <input type="file" name="file"><br>
    <input type="submit" value="上传文件">
</form>
@RequestMapping(value = "/uploadFiles",method = {RequestMethod.POST})
@ResponseBody
//使用数组接收上传的文件,循环解析数组中的文件
public String uploadFiles(@RequestParam("file") CommonsMultipartFile[] files, HttpServletRequest request){
    for (CommonsMultipartFile file : files) {
        String filename = file.getOriginalFilename();
        String realPath = request.getServletContext().getRealPath("/");
        File tfile = new File(realPath+File.separator+filename);
        try {
            file.transferTo(tfile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    System.out.println("多文件上传完毕");
    return "index";
}

往往在文件上传时会在数据库中存储上传文件的名称、存放位置、大小、上传时间等…

文件下载

JavaWeb方式文件下载

@RequestMapping(value = "/download")
public void download(String filename, HttpServletRequest request, HttpServletResponse response) throws IOException {
    String realPath = request.getServletContext().getRealPath("/");
    File file = new File(realPath + File.separator + filename);
    //设置响应类型为二进制内容
    response.setContentType("application/octet-stream");
    //设置内容描述,在响应头中设置
    response.setHeader("Content-Disposition","attachment;filename="+filename);
    //读取存在于项目根路径下的文件
    FileInputStream in = new FileInputStream(file);
    //通过response获取的字节流写出数据
    ServletOutputStream out = response.getOutputStream();

    byte[] bytes = new byte[1024];
    int len=0;
    while ((len=in.read(bytes))!=-1){
        out.write(bytes,0,len);
    }
    out.close();
    in.close();
}

运行程序,在地址栏输入"/download?filename=index.jsp"向服务器发送请求,便可以下载index.jsp文件。

返回值为ResponseEntity对象实现文件下载

@RequestMapping(value = "/download/{filename}/{ext}")
public ResponseEntity download(@PathVariable("filename") String filename,@PathVariable("ext") String ext, HttpServletRequest request) throws IOException {
    String realPath = request.getServletContext().getRealPath("/");
    File file = new File(realPath + File.separator + filename+"."+ext);
    //将文件内容读取为字节数组
    byte[] bytes = FileUtils.readFileToByteArray(file);
    HttpHeaders headers = new HttpHeaders();
    //设置响应内容类型
    headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
    //设置内容描述
    headers.setContentDispositionFormData("attachment",new String((filename+"."+ext).getBytes("utf-8"),"iso-8859-1"));
    ResponseEntity result=new ResponseEntity(bytes,headers, HttpStatus.OK);
    return result;
}

运行程序,在地址栏输入"/download/index/jsp"向服务器发送请求,便可以下载index.jsp文件。
因为这种方式将文件一次性读取为一个字节数组,所以只适用于文件较小时使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值