文件上传和下载

Posted xjjd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文件上传和下载相关的知识,希望对你有一定的参考价值。

FileUploadController:

package com.activiti.web;

import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import com.activiti.service.FileService;
import com.cinms.common.ResultModel;
/**
 * @author Jump
 * @version 创建时间:2018年6月20日 下午4:47:37 
 * 文件上传控制器
 */
@Controller
public class FileUploadController {
    @Autowired
    private FileService fileService;

    private Logger logger = LoggerFactory.getLogger(FileUploadController.class);
    
    @RequestMapping("upload")
    @ResponseBody
    public ResultModel upload(
            HttpServletRequest request) {
         MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        List<MultipartFile> files = multipartRequest.getFiles("file");
        //MultipartFile[] files = (MultipartFile[])request.getAttribute("file");
        ResultModel rm = fileService.upload(files, request);
        return rm;
    }
    
    @RequestMapping("download")
    @ResponseBody
    public void download(@RequestBody Map<String, String> map,
            HttpServletResponse response,HttpServletRequest request) {
        try {
            String fileName = map.get("fileName");
            fileService.download(fileName,response,request);
        } catch (Exception e) {
            e.printStackTrace();
            logger.error("文件上传失败:"+ e);
        }
    }
}

FileServiceImpl:

package com.activiti.serviceImpl;

import org.springframework.stereotype.Service;

import com.activiti.service.FileService;
import com.activiti.tools.PropertiesUtil;
import com.cinms.common.ResultModel;
import com.google.common.collect.Lists;

import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Jump
 * @version 创建时间:2018年6月20日 上午10:22:40 类说明
 */
@Service("iFileService")
public class FileServiceImpl implements FileService {

    private Logger logger = LoggerFactory.getLogger(FileServiceImpl.class);

    @Override
    public ResultModel upload(List<MultipartFile> files, HttpServletRequest request) {
        ResultModel rm = new ResultModel();
        // 得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
        //String savePath = request.getSession().getServletContext().getRealPath("/WEB-INF/upload");
        //String savePath = PropertiesUtil.getProperty("FILELOCATION");
        String savePath = "./upload";
        // 上传时生成的临时文件保存目录
        String tempPath = request.getSession().getServletContext().getRealPath("/WEB-INF/temp");
        File tmpFile = new File(tempPath);
        if (!tmpFile.exists()) {
            // 创建临时目录
            tmpFile.mkdir();
        }

        try {
            // 使用Apache文件上传组件处理文件上传步骤:
            // 1、创建一个DiskFileItemFactory工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
            factory.setSizeThreshold(1024 * 100);// 设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB
            // 设置上传时生成的临时文件的保存目录
            factory.setRepository(tmpFile);
            // 2、创建一个文件上传解析器
            ServletFileUpload upload = new ServletFileUpload(factory);
            // 监听文件上传进度
            upload.setProgressListener(new ProgressListener() {
                @Override
                public void update(long pBytesRead, long pContentLength, int arg2) {
                    System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
                    /**
                     * 文件大小为:14608,当前已处理:4096 文件大小为:14608,当前已处理:7367
                     * 文件大小为:14608,当前已处理:11419 文件大小为:14608,当前已处理:14608
                     */
                }
            });
            // 解决上传文件名的中文乱码
            upload.setHeaderEncoding("UTF-8");
            // 3、判断提交上来的数据是否是上传表单的数据
            if (!ServletFileUpload.isMultipartContent(request)) {
                // 按照传统方式获取数据
                return null;
            }

            // 设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
            upload.setFileSizeMax(1024 * 1024);
            // 设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
            upload.setSizeMax(1024 * 1024 * 10);
            /*
             * // 4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,
             * 每一个FileItem对应一个Form表单的输入项 List<FileItem> list =
             * upload.parseRequest(request);
             */
            String filenames = "";
            HashMap<String, String> hm = new HashMap<String, String>();
            ArrayList<HashMap<String, String>> arrayList = Lists.newArrayList();
            for (MultipartFile item : files) {
                // 如果fileitem中封装的是上传文件
                // 得到上传的文件名称,
                String filename = item.getOriginalFilename();
                System.out.println(filename);
                if (filename == null || filename.trim().equals("")) {
                    continue;
                }
                // 注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如:
                // c:a1.txt,而有些只是单纯的文件名,如:1.txt
                // 处理获取到的上传文件的文件名的路径部分,只保留文件名部分
                filename = filename.substring(filename.lastIndexOf("\") + 1);
                // 得到上传文件的扩展名
                String fileExtName = filename.substring(filename.lastIndexOf(".") + 1);
                // 如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
                System.out.println("上传的文件的扩展名是:" + fileExtName);
                // 获取item中的上传文件的输入流
                InputStream in = item.getInputStream();
                // 得到文件保存的名称
                String saveFilename = makeFileName(filename);
                // 得到文件的保存目录
                String realSavePath = makePath(saveFilename, savePath);
                // 创建一个文件输出流
                FileOutputStream out = new FileOutputStream(realSavePath + "\" + saveFilename);
                // 创建一个缓冲区
                byte buffer[] = new byte[1024];
                // 判断输入流中的数据是否已经读完的标识
                int len = 0;
                // 循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
                while ((len = in.read(buffer)) > 0) {
                    // 使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\"
                    // + filename)当中
                    out.write(buffer, 0, len);
                }
                // 关闭输入流
                in.close();
                // 关闭输出流
                out.close();
                filenames = realSavePath + "\" + saveFilename;
                hm.put("name", filename);
                hm.put("path", filenames);
                arrayList.add(hm);
            }
            rm.setData(arrayList);
            rm.setMessage("文件上传成功!");
            rm.setSuccess(true);
        } catch (Exception e) {
            e.printStackTrace();
            rm.setMessage("文件上传失败!");
            rm.setSuccess(false);
            logger.error("文件上传失败!");
        }
        return rm;
    }

    /**
     * 为防止一个目录下面出现太多文件,要使用hash算法打散存储
     * 
     * @Method: makePath
     * @Description:
     *
     * @param filename
     *            文件名,要根据文件名生成存储目录
     * @param savePath
     *            文件存储路径
     * @return 新的存储目录
     */
    private String makePath(String filename, String savePath) {
        // 得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
        int hashcode = filename.hashCode();
        int dir1 = hashcode & 0xf; // 0--15
        int dir2 = (hashcode & 0xf0) >> 4; // 0-15
        // 构造新的保存目录
        String dir = savePath + "\" + dir1 + "\" + dir2; // upload23
                                                            // upload35
        // File既可以代表文件也可以代表目录
        File file = new File(dir);
        // 如果目录不存在
        if (!file.exists()) {
            // 创建目录
            file.mkdirs();
        }
        return dir;
    }

    /**
     * @Method: makeFileName
     * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
     * @param filename
     *            文件的原始名称
     * @return uuid+"_"+文件的原始名称
     */
    private String makeFileName(String filename) { // 2.jpg
        // 为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
        return UUID.randomUUID().toString() + "_" + filename;
    }

    @Override
    public void download(String fileName, HttpServletResponse response, HttpServletRequest request) throws Exception {
        fileName = new String(fileName.getBytes("iso8859-1"), "UTF-8");
        // 上传的文件都是保存在/WEB-INF/upload目录下的子目录当中
        String fileSaveRootPath = request.getSession().getServletContext().getRealPath("/WEB-INF/upload");
        // 通过文件名找出文件的所在目录
        String path = findFileSavePathByFileName(fileName, fileSaveRootPath);
        // 得到要下载的文件
        File file = new File(path + "\" + fileName);
        // 如果文件不存在
        ResultModel rm = new ResultModel();
        if (!file.exists()) {
            rm.setMessage("您要下载的资源不存在!!");
            rm.setSuccess(false);
        }
        // 处理文件名
        String realname = fileName.substring(fileName.indexOf("_") + 1);
        // 设置响应头,控制浏览器下载该文件
        response.setHeader("content-disposition", "attachment;filename=" + URLEncoder.encode(realname, "UTF-8"));
        // 读取要下载的文件,保存到文件输入流
        FileInputStream in = new FileInputStream(fileName);
        // 创建输出流
        OutputStream out = response.getOutputStream();
        // 创建缓冲区
        byte buffer[] = new byte[1024];
        int len = 0;
        // 循环将输入流中的内容读取到缓冲区当中
        while ((len = in.read(buffer)) > 0) {
            // 输出缓冲区的内容到浏览器,实现文件下载
            out.write(buffer, 0, len);
        }
        // 关闭文件输入流
        in.close();
        // 关闭输出流
        out.close();
    }

    /**
     * @Method: findFileSavePathByFileName
     * @Description: 通过文件名和存储上传文件根目录找出要下载的文件的所在路径
     * @param filename
     *            要下载的文件名
     * @param saveRootPath
     *            上传文件保存的根目录,也就是/WEB-INF/upload目录
     * @return 要下载的文件的存储目录
     */
    public String findFileSavePathByFileName(String filename, String saveRootPath) {
        int hashcode = filename.hashCode();
        int dir1 = hashcode & 0xf; // 0--15
        int dir2 = (hashcode & 0xf0) >> 4; // 0-15
        String dir = saveRootPath + "\" + dir1 + "\" + dir2; // upload23
                                                                // upload35
        File file = new File(dir);
        if (!file.exists()) {
            // 创建目录
            file.mkdirs();
        }
        return dir;
    }

}

FileService:

package com.activiti.service;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.multipart.MultipartFile;

import com.cinms.common.ResultModel;

/**
* @author Jump
* @version 创建时间:2018年6月20日 上午10:26:53
* 类说明
*/
public interface FileService {

    ResultModel upload(List<MultipartFile> files, HttpServletRequest request);
    
    void download(String fileName, HttpServletResponse response, HttpServletRequest request) throws Exception;
}

 

以上是关于文件上传和下载的主要内容,如果未能解决你的问题,请参考以下文章

用于从 cloudkit 检索单列的代码模式/片段

大文件上传下载分片断点续传教程

Alamofire 文件上传出现错误“JSON 文本未以数组或对象开头,并且允许未设置片段的选项”

VIM 代码片段插件 ultisnips 使用教程

代码学习PHP文件的上传和下载

SpringMVC_[4]文件上传和下载