SpringMVC中的上传和下载

一、概述

文件的上传和下载,一直以来都是开发中必不可少的功能。在没有SpringMVC之前对于文件的上传和下载的操作,一般都是通过Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload )来实现的。现在SpringMVC提供了文件的上传和下载功能,而且使用起来十分简便。

二、SpringMVC的文件的上传和下载

配置Spring-web.xml

文件的上传是通过 MultipartResolver 实现的,所以要实现上传,只要注册相应的 MultipartResolver 即可。

MultipartResolver 的实现类有两个:

  • CommonsMultipartResolver (需要 Apache 的 commons-fileupload 支持,它能在比较旧的 servlet 版本中使用,兼容性好)

  • StandardServletMultipartResolver (不需要第三方 jar 包支持,它使用 servlet 内置的上传功能,但是只能在 Servlet 3 以上的版本使用)

这里我们注册使用第二个,无需配置额外的架包

<!--配置上传下载-->
<bean id="multipartResolver" class="org.springframework.web.multipart.support.StandardServletMultipartResolver"/>

配置web.xml

<servlet>
    <servlet-name>app</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring/spring-web.xml</param-value>
    </init-param>

    <!--配置文件的上传和下载-->
    <load-on-startup>1</load-on-startup>
    <multipart-config>
	  <!--里面的配置可以在代码中实现,也可已在这里进行配置-->
      <!--<location>D:\IdeaWork\ssm_blog\src\main\webapp\images</location>-->
      <max-file-size>-1</max-file-size>
      <max-request-size>-1</max-request-size>
    </multipart-config>
</servlet>

上传文件的后台代码

我们对于文件的上传将会以常用的图片上传为例进行讲解。

//页面跳转
@GetMapping("/up")
public String getIndex(Model model) {
    return "upFile";
}


@PostMapping("/up")
public String upFiles(@RequestPart("file") MultipartFile file, HttpServletRequest re,Model model) {

    // 获得上传的文件格式
    String contextType = file.getContentType();

    // 判断文件是否符合要求的类型.
    if (!contextTypecontains("image/")) {
        model.addAttribute("msg", "只允许上传图片");
        return "upFile";
    }
    // 判断上传的文件大小
    if (file.getSize() > 1024 * 1024 * 5) {
        model.addAttribute("msg", "文件过大");
        return "upFile";
    }

    try {
        // 获取当前类加载的路径
        String path = re.getServletContext().getRealPath(File.separator+"img");
        File img = new File(path);
        // 如果文件夹不存在就创建一个
        if(!img.exists()){
            img.mkdir();
        }
        // file.getOriginalFilename()为文件的逻辑名
        File fileName= new File(path+File.separator+getNewName(file.getOriginalFilename()));
        // 这里是写入文件,最为重要的一段代码
        file.transferTo(fileName);
    } catch (IOException e) {
        model.addAttribute("msg", "写入失败");
    }
    return "upFile";
}

表单上传

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<h1>${msg}</h1>
<form action="/up" method="post" enctype="multipart/form-data">
    <label>文件上传:</label>
    <input type="file" name="file"><br/>
    <input type="submit" value="提交">
</form>
</body>
</html>

上传图片的新需求

上面我们采取的是表单上传的方式,实际开发中,我们用的更多的是采取异步上传的方式。接下来我们提出以下几点需求:

  • 上传的图片左下角加上水印
  • 动态显示图片上传百分比
  • 动态展示上传的精度
  • 压缩图片

后台代码不变,前台实现

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<input type="file" multiple="multiple" id="myFile"/>
<br/>
<canvas id="myCanvas"></canvas>
<br/>
<button id="myBtn">上传</button>
<progress value="0" max="100" id="myPro"></progress>
</body>
<script type="text/javascript" src="../js/jquery.js"></script>
<script>

    var myFile = document.getElementById("myFile");
    var myBtn = document.getElementById("myBtn");
    var myCanvas = document.getElementById("myCanvas");
    window.addEventListener("load", () => {
        all();
    });

    function all() {
        myFile.addEventListener("change", () => {
            $("#myPro").val(0);
            loadImg();
        });
        myBtn.addEventListener("click", () => {
            ajax(myFile.files[0]);
        });
    }


    var myImg = new Image();
    var pen = myCanvas.getContext("2d");

    function loadImg(callback) {
        var url = URL.createObjectURL(myFile.files[0]);
        myImg.src = url;
        //console.log(myImg);
        console.log("压缩前:" + myFile.files[0].size);
        // 这里是异步
        myImg.onload = function () {
            URL.revokeObjectURL(url);
            // 压缩图片
            myCanvas.width = myImg.width / 2;
            myCanvas.height = myImg.height / 2;
            pen.drawImage(myImg, 0, 0, myImg.width / 2, myImg.height / 2);
            pen.font = "30px yahei";
            pen.fillText("lzx绘制", (myImg.width / 2) - 100, (myImg.height / 2) - 10);
            if (callback) () => callBack();
        }
    }


    function ajax(blob) {
        var form = new FormData();
        form.append("file", blob);
        $.ajax({
            url: '/up',
            type: 'post',
            data: form,
            cache: false,
            contentType: false, //必须false才会自动加上正确的Content-Type
            processData: false,  //必须false才会避开jQuery对 formdata 的默认处理
            xhr: function () {
                var myXhr = $.ajaxSettings.xhr();
                if (myXhr.upload) { // check if upload property exists
                    myXhr.upload.addEventListener('progress', function (e) {
                        var loaded = e.loaded;//已经上传大小情况
                        var total = e.total;//附件总大小
                        var per = Math.floor(100 * loaded / total);  //已经上传的百分比
                          if (e.lengthComputable) {
                            $("#myPro").val(per);
                            //清空画板
                            pen.clearRect(0, 0, myCanvas.width, myCanvas.height);
                            //从左下角不停地画
                            pen.globalAlpha = 0.5;
                            pen.drawImage(myImg, 0, myCanvas.height, myCanvas.width, -myCanvas.height * per/100);
                            pen.font = "30px yahei";
                            pen.fillText("lzx绘制", (myImg.width / 2) - 100, (myImg.height / 2) - 10);
                            //显示百分比
                            pen.font = "80px yahei";
                            pen.fillText(per + "%", myCanvas.width / 2 - 20, myCanvas.height / 2 - 20);

                        }
                    }, false);
                }
                return myXhr;
            }
        });
    }
</script>
</html>

文件的下载

文件的下载主要是对字节流的操作,它也是具有一定的套路的,直接复制粘贴使用即可。

这里我们以导出数据为excel表格并进行下载为例,这里我们是使用了poi来实现对表格的操作

service导出表格数据,存入字节流

public byte[] writeExcel(List<Employee> list) throws IOException {
    HSSFWorkbook workbook = new HSSFWorkbook();
    HSSFSheet sheet = workbook.createSheet("客户信息表");
    HSSFRow row1 = sheet.createRow(0);
    row1.createCell(0).setCellValue("编号");
    row1.createCell(1).setCellValue("姓名");
    row1.createCell(2).setCellValue("性别");
    row1.createCell(3).setCellValue("学历");
    row1.createCell(4).setCellValue("月薪");

    HSSFRow row = null;
    for (int i = 1; i <= list.size(); i++) {
        employee = list.get(i - 1);
        row = sheet.createRow(i);
        row.createCell(0).setCellValue(employee.getId());
        row.createCell(1).setCellValue(employee.getName());
        row.createCell(2).setCellValue(employee.getSex());
        row.createCell(3).setCellValue(employee.getEducation());
        row.createCell(4).setCellValue(String.valueOf(employee.getSalary()));
    }

    ByteArrayOutputStream stream = new ByteArrayOutputStream();
    workbook.write(stream);
    
    return stream.toByteArray();
}

controller下载表格到本地

@GetMapping("/outExcel")
public ResponseEntity outExcel() throws IOException {

//        HSSFWorkbook workbook = writeExcel();
//        File files = new File( UUID.randomUUID() + ".xls");
//        workbook.write(files);
//        FileSystemResource file = new FileSystemResource(files);
        // 这种方法也是可行的
//        HttpHeaders headers = new HttpHeaders();
//        headers.setCacheControl("no-cache, no-store, must-revalidate");
//        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
//        headers.setContentLength(file.contentLength());
//        headers.setContentDispositionFormData("attachment", file.getFilename());
//        return ResponseEntity.ok().headers(headers).body(new InputStreamResource(file.getInputStream()));

		
        byte[] file = service.writeExcel(service.listAll());
        HttpHeaders headers = new HttpHeaders();
        headers.setCacheControl("no-cache, no-store, must-revalidate");
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        headers.setContentLength(file.length);
        headers.setContentDispositionFormData("attachment", UUID.randomUUID()+".xls");
        return ResponseEntity.ok().headers(headers).body(file);

}

我们发现contoller字节是对byte[]数组,字节流进行操作的。拓展使用起来就十分方便了,我们只需要把要下载的文件转为字节流,存入byte[]数组,再controller中调用即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值