Springboot上传文件,下载文件

我这是使用springboot写的不用导额外的包,如果ssm做的话需要导包可以查看下面这个

https://blog.csdn.net/kxj19980524/article/details/83536366

上传文件

在input框里加上multiple属性,就可以一个input框一下上传多个文件

这是上传按钮的事件 FormData这一行就这么写就行,参数换成form表单的id,直接就把form表单里所有参数传到后台了,包括上传的文件.

   //点击上传
    $("#businessLicenseBtn").click(function () {  //加一个单击事件按钮
        var formd = new FormData($("#userCompleteForm")[0]);    //$("#userCompleteForm")[0]:把form表单对象转换为js对象
        $.ajax({
            url:"${pageContext.request.contextPath}/WitkeyDemandScheme/uploadSchemes",//跳转到后台路径
            type:"post",
            data:formd,
            dataType:"json",
            processData:false,    //用form表单的enctype对象   这两个属性加上就行了
            contentType:false,      //默认为true,上传数据转为对象,为false  不转为对象
            success:function (data) {
                var div1 = $("#div1");
                $(data).each(function (a,b) {
                    div1.append(b+"<input type='button' onclick='deleteScheme("+b+")' value='删除'/><br/>")
                })
            },
            error:function(){
                alert("上传失败!")
            }
        })
    })

 这是后台上传文件的代码,跟上传单个文件一样,只不过,sql语句使用foreach变量就好了,这里面逻辑就是把文件名字多加了点避免上传上去的文件名重复.

    //批量上传文件
    @RequestMapping("/uploadSchemes")
    @ResponseBody
    public List<String> uploadSchemes(MultipartFile[] files,Integer demandId,Integer userId){
        List<String> list = new ArrayList<>();
        String realPath = "E:\\idea\\project\\springboot\\witkey\\src\\main\\webapp\\uploads\\files";
       for(int i=0;i<files.length;i++){
           long size = files[i].getSize();
           if(size>1000000){
               list.add("该文件太大,无法上传");
               return list;
           }
           //获取文件名称
           String filename = files[i].getOriginalFilename();
           filename = saveNewFileName(filename,demandId,userId);
           list.add(filename);
           File f = new File(realPath+File.separator+filename);
           try {
               files[i].transferTo(f);
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
        witkeyDemandSchemeService.insertDemandSchemes(demandId,userId,list);
        return list;
    }

    private String saveNewFileName(String filename, Integer demandId, Integer userId) {
        int index = filename.indexOf(".");
        return filename.substring(0,index)+"_"+demandId+"_"+userId+filename.substring(index);
    }

文件下载

前台就是写了个单击事件,把文件名称传到后台了,这个跳转路径别用ajax方式跳转.

 

这是后台的controller方法,接收方式必须是restful风格接收参数不然会下载不正确

import org.apache.tomcat.util.http.fileupload.IOUtils;
 
   @RequestMapping("/downloadScheme/{filename:.+}")
    public void downloadScheme(@PathVariable String filename, HttpServletResponse response){
        //获取下载路径
        String realPath = "E:\\idea\\project\\springboot\\witkey\\src\\main\\webapp\\uploads\\files";

        File file = new File(realPath,filename);
        //读取下载的文件
        try(
                InputStream in = new FileInputStream(file);
                OutputStream out = response.getOutputStream();
                ){
            response.setContentType("application/x-download");
            filename= URLEncoder.encode(filename,"UTF-8");
            response.addHeader("ContentDisposition","attachment;filename="+filename);
            IOUtils.copy(in,out);
            out.flush();
        }catch (Exception e){
            e.printStackTrace();
        }
    }

实现效果

 

断点续传版文件下载

    //实现文件下载功能
    @RequestMapping("/downloadScheme/{filename:.+}")
    public void downloadFile(@PathVariable String filename, HttpServletResponse response, HttpServletRequest request){
        File dir = new File("/var/www/tena-service/log");//获取文件路劲

        File downloadFile = new File(dir, filename);//在指定目录下查找文件

        try {
            downloadFileRanges(downloadFile, request,  response,filename);
        } catch(ClientAbortException e){
            System.out.println("连接被终止");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void downloadFileRanges(File downloadFile, HttpServletRequest request, HttpServletResponse response,String filename) throws IOException {
        // 要下载的文件大小
        long fileLength = downloadFile.length();
        // 已下载的文件大小
        long pastLength = 0;
        // 是否快车下载,否则为迅雷或其他
        boolean isFlashGet = true;
        // 用于记录需要下载的结束字节数(迅雷或其他下载)
        long lenEnd = 0;
        // 用于记录客户端要求下载的数据范围字串
        String rangeBytes = request.getHeader("Range");
        //用于随机读取写入文件
        RandomAccessFile raf = null;
        OutputStream os = null;
        OutputStream outPut = null;
        byte b[] = new byte[1024];
        // 如果客户端下载请求中包含了范围
        if (null != rangeBytes)
        {
            // 返回码 206
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            rangeBytes = request.getHeader("Range").replaceAll("bytes=", "");
            // 判断 Range 字串模式
            if (rangeBytes.indexOf('-') == rangeBytes.length() - 1)
            {
                // 无结束字节数,为快车
                isFlashGet = true;
                rangeBytes = rangeBytes.substring(0, rangeBytes.indexOf('-'));
                pastLength = Long.parseLong(rangeBytes.trim());
            }
            else
            {
                // 迅雷下载
                isFlashGet = false;
                String startBytes = rangeBytes.substring(0,
                        rangeBytes.indexOf('-'));
                String endBytes = rangeBytes.substring(
                        rangeBytes.indexOf('-') + 1, rangeBytes.length());
                // 已下载文件段
                pastLength = Long.parseLong(startBytes.trim());
                // 还需下载的文件字节数(从已下载文件段开始)
                lenEnd = Long.parseLong(endBytes);
            }
        }
        // 通知客户端允许断点续传,响应格式为:Accept-Ranges: bytes
        response.setHeader("Accept-Ranges", "bytes");
        // response.reset();
        // 如果为第一次下载,则状态默认为 200,响应格式为: HTTP/1.1 200 ok
        if (0 != pastLength)
        {
            // 内容范围字串
            String contentRange = "";
            // 响应格式
            // Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]||[文件的总大小]
            if (isFlashGet)
            {
                contentRange = new StringBuffer("bytes")
                        .append(new Long(pastLength).toString()).append("-")
                        .append(new Long(fileLength - 1).toString())
                        .append("/").append(new Long(fileLength).toString())
                        .toString();
            }
            else
            {
                contentRange = new StringBuffer(rangeBytes).append("/")
                        .append(new Long(fileLength).toString()).toString();
            }
            response.setHeader("Content-Range", contentRange);
        }
        String fileName = getDownloadChineseFileName(filename);
        response.setHeader("Content-Disposition",
                "attachment;filename=" + fileName + "");
        // 响应的格式是:
        response.setContentType("application/octet-stream");
        response.addHeader("Content-Length", String.valueOf(fileLength));
        try
        {
            os = response.getOutputStream();
            outPut = new BufferedOutputStream(os);
            raf = new RandomAccessFile(downloadFile, "r");
            // 跳过已下载字节
            raf.seek(pastLength);
            if (isFlashGet)
            {
                // 快车等
                int n = 0;
                while ((n = raf.read(b, 0, 1024)) != -1)
                {
                    outPut.write(b, 0, n);
                }
            }
            else
            {
                // 迅雷等
                while (raf.getFilePointer() < lenEnd)
                {
                    outPut.write(raf.read());
                }
            }
            outPut.flush();
        }
        catch (IOException e)
        {
            /**
             * 在写数据的时候 对于 ClientAbortException 之类的异常
             * 是因为客户端取消了下载,而服务器端继续向浏览器写入数据时, 抛出这个异常,这个是正常的。 尤其是对于迅雷这种吸血的客户端软件。
             * 明明已经有一个线程在读取 bytes=1275856879-1275877358,
             * 如果短时间内没有读取完毕,迅雷会再启第二个、第三个。。。线程来读取相同的字节段, 直到有一个线程读取完毕,迅雷会 KILL
             * 掉其他正在下载同一字节段的线程, 强行中止字节读出,造成服务器抛 ClientAbortException。
             * 所以,我们忽略这种异常
             */
        }
        finally
        {
            if(outPut != null)
            {
                outPut.close();
            }
            if(raf != null)
            {
                raf.close();
            }
        }
    }



    private String getDownloadChineseFileName(String paramName)
    {
        String downloadChineseFileName = "";
        try
        {
            downloadChineseFileName = new String(paramName.getBytes("GBK"),
                    "ISO8859-1");
        }
        catch (UnsupportedEncodingException e)
        {
            e.printStackTrace();
        }
        return downloadChineseFileName;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值