5、SpingBoot文件上传、多文件上传、文件下载(断点续传)

文件上传

SpringBoot的文件上传相对比较简单,文件信息都包含在MultipartFile对象中,只要从中获取文件信息即可
不煽情,直接上代码吧,这个部分出门右拐“百度一下”一大堆

/** * 单文件上传 * * @param name 携带的其他文本表单(可以省略) * @param file 文件内容 * @return */
@RequestMapping(value = "/upload_single", method = RequestMethod.POST)
public @ResponseBody String handleFileUpload(@RequestParam("name") String name,
            @RequestParam("file") MultipartFile file) {
    if (!file.isEmpty()) {
        BufferedOutputStream out = null;
        try {
            byte[] bytes = file.getBytes();
            out = new BufferedOutputStream(
                        new FileOutputStream(new File(BASE_PATH + "\\" + name + "-" + file.getOriginalFilename())));
            out.write(bytes);
            return "You successfully uploaded " + name + " into " + name + "-uploaded !";
        } catch (Exception e) {
            return "You failed to upload " + name + " => " + e.getMessage();
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                        e.printStackTrace();
                }
            }
        }
    } else {
        return "You failed to upload " + name + " because the file was empty.";
    }
}

测试:

单文件上传

method="POST" enctype="multipart/form-data" action="/upload_single"> File to upload: type="file" name="file"/>
Name: type="text" name="name"/> type="submit" value="单文件上传"/>

多文件上传

多文件上传需要接收解析出MultipartHttpServletRequest对象中包含的文件信息

/** * 多文件上传,主要是使用了MultipartHttpServletRequest和MultipartFile * * @param name 携带的其他文本表单(可以省略) * @param request * @return */
@RequestMapping(value = "/upload", method = RequestMethod.POST)
public @ResponseBody String handleFileUpload(HttpServletRequest request,@RequestParam("name") String name) {
    List files = ((MultipartHttpServletRequest) request).getFiles("file");
    System.out.println("name==>"+name);
    MultipartFile file = null;
    BufferedOutputStream out = null;
    for (int i = 0; i < files.size(); ++i) {
        file = files.get(i);
        if (!file.isEmpty()) {
            try {
                byte[] bytes = file.getBytes();
                out = new BufferedOutputStream(new FileOutputStream(new File(BASE_PATH + "\\" + file.getOriginalFilename())));
                out.write(bytes);
            } catch (Exception e) {
                return "failed to upload " + i + " => " + e.getMessage();
            } finally {
                if (null != out) {
                    try {
                        out.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    out = null;
                }
            }
        } else {
            return "failed to upload " + i + " because the file was empty.";
        }
    }
    return "upload successful";
}

测试:

<p>多文件上传p>
<form method="POST" enctype="multipart/form-data" action="/upload">
    Name: <input type="text" name="name"/>
    <p>文件1:<input type="file" name="file" />p>
    <p>文件2:<input type="file" name="file" />p>
    <p><input type="submit" value="多文件上传" />p>
form>

文件下载(断点续传)

相对于上传在文件下载的处理上,需要自己处理HttpServletResponse中流的返回,这里直接上一个有断点续传的代码:

@RequestMapping(value = "/download", method = RequestMethod.GET)
public void getDownload(String name, HttpServletRequest request, HttpServletResponse response) {
        // Get your file stream from wherever.
        String fullPath = "D:\\upload_test\\" + name;
        File downloadFile = new File(fullPath);

        ServletContext context = request.getServletContext();
        // get MIME type of the file
        String mimeType = context.getMimeType(fullPath);
        if (mimeType == null) {
            // set to binary type if MIME mapping not found
            mimeType = "application/octet-stream";
        }

        // set content attributes for the response
        response.setContentType(mimeType);
        // response.setContentLength((int) downloadFile.length());

        // set headers for the response
        String headerKey = "Content-Disposition";
        String headerValue = String.format("attachment; filename=\"%s\"", downloadFile.getName());
        response.setHeader(headerKey, headerValue);
        // 解析断点续传相关信息
        response.setHeader("Accept-Ranges", "bytes");
        long downloadSize = downloadFile.length();
        long fromPos = 0, toPos = 0;
        if (request.getHeader("Range") == null) {
            response.setHeader("Content-Length", downloadSize + "");
        } else {
            // 若客户端传来Range,说明之前下载了一部分,设置206状态(SC_PARTIAL_CONTENT)
            response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);
            String range = request.getHeader("Range");
            String bytes = range.replaceAll("bytes=", "");
            String[] ary = bytes.split("-");
            fromPos = Long.parseLong(ary[0]);
            if (ary.length == 2) {
                toPos = Long.parseLong(ary[1]);
            }
            int size;
            if (toPos > fromPos) {
                size = (int) (toPos - fromPos);
            } else {
                size = (int) (downloadSize - fromPos);
            }
            response.setHeader("Content-Length", size + "");
            downloadSize = size;
        }
        // Copy the stream to the response's output stream.
        RandomAccessFile in = null;
        OutputStream out = null;
        try {
            in = new RandomAccessFile(downloadFile, "rw");
            // 设置下载起始位置
            if (fromPos > 0) {
                in.seek(fromPos);
            }
            // 缓冲区大小
            int bufLen = (int) (downloadSize < 2048 ? downloadSize : 2048);
            byte[] buffer = new byte[bufLen];
            int num;
            int count = 0; // 当前写到客户端的大小
            out = response.getOutputStream();
            while ((num = in.read(buffer)) != -1) {
                out.write(buffer, 0, num);
                count += num;
                //处理最后一段,计算不满缓冲区的大小
                if (downloadSize - count < bufLen) {
                    bufLen = (int) (downloadSize-count);
                    if(bufLen==0){
                        break;
                    }
                    buffer = new byte[bufLen];
                }
            }
            response.flushBuffer();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (null != in) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
}

该部分本人直接在Android客户端上测试:
下载代码:

public static boolean downLoadFile(String url, int from, int to,String savePath) {
    try {
        URL link = new URL(url);
        HttpURLConnection conn = (HttpURLConnection) link.openConnection();
        // 设置断点续传的开始位置
        if (to != 0) {
                conn.setRequestProperty("Range", "bytes=" + from + "-" + to);
        }else{
            conn.setRequestProperty("Range", "bytes=" + from + "-");
        }
        Log.e("m_tag", "code:" + conn.getResponseCode());
        if (conn.getResponseCode() == 206) {
            RandomAccessFile file = new RandomAccessFile(savePath, "rw");
            file.seek(from);
            InputStream in = conn.getInputStream();
            byte[] buffer = new byte[1024];
            int num;
            while ((num = in.read(buffer)) > 0) {
                file.write(buffer, 0, num);
            }
            file.close();
            in.close();
            return true;
        }
    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    return false;
}

Activity中运用:

class MyTask extends AsyncTask {

        @Override
        protected Object doInBackground(Object... params) {
                String uri = (String) params[0];
                int from = (Integer) params[1];
                int to = (Integer) params[2];
                String savePath = (String) params[3];
                return HttpUtil.downLoadFile(uri, from, to, savePath);
        }

        @Override
        protected void onPostExecute(Object result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);
            tvRes.setText(result.toString());
        }

}

//这里用两个按钮点击模拟分段,第一个按钮下载0-50B,第二个从50B下载到末尾
...省略其他部分...
case R.id.btn_part_01:
    new MyTask().execute("http://192.168.2.183:8080/download?name=11.jpg",0, 50, "/mnt/sdcard/pic_123.jpg");
break;
case R.id.btn_part_02:
    new MyTask().execute("http://192.168.2.183:8080/download?name=11.jpg",50, 0, "/mnt/sdcard/pic_123.jpg");
break;
...省略其他部分...

[附]

文件上传时相对路径配置

以上的上传文件可以保存到服务器端的D:\upload_test但是对于这个路径,客户端如果想要使用一个相对路径来访问的话,需要做以下配置:

1、在application.properties中声明一个变量描述该地址

#图片上传存储路径
imagesPath=file:/D:/upload_test/

2、定义一个配置文件可以将该绝对路径映射到一个/images的相对路径上

package com.example.demo.config;

import org.apache.log4j.spi.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

@Configuration
public class FileConfig extends WebMvcConfigurerAdapter {

    @Value("${imagesPath}") 
    private String mImagesPath;

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        if (mImagesPath.equals("") || mImagesPath.equals("${imagesPath}")) {
            String imagesPath = FileConfig.class.getClassLoader().getResource("").getPath();
            if (imagesPath.indexOf(".jar") > 0) {
                imagesPath = imagesPath.substring(0, imagesPath.indexOf(".jar"));
            } else if (imagesPath.indexOf("classes") > 0) {
                imagesPath = "file:" + imagesPath.substring(0, imagesPath.indexOf("classes"));
            }
            imagesPath = imagesPath.substring(0, imagesPath.lastIndexOf("/")) + "/images/";
            mImagesPath = imagesPath;
        }
        System.out.println("imagesPath=" + mImagesPath);
        registry.addResourceHandler("/images/**").addResourceLocations(mImagesPath);
        super.addResourceHandlers(registry);
    }
}

这样之后对于服务器上D:\upload_test\1.jpg这个图片可以在客户端直接使用http://127.0.0.1:8080/images/1.jpg这个路径就可以访问了

你可能感兴趣的:(SpringBoot,java-web)