简介: 

【文件上传和下载】文件上传和下载是java web中常见的操作,文件上传主要是将文件通过IO流传放到服务器的某一个特定的文件夹下,而文件下载则是与文件上传相反,将文件从服务器的特定的文件夹下的文件通过IO流下载到本地。
  该文章主要完成简单的文件上传到本地和下载的功能。

文件上传和下载:

 1、在application.yml配置文件中设置文件存储路径,如下,也可以指定目录tempFilePath: D:/files/;以及在配置文件中设定文件上传大小限制 multipart,如下,如果需要设定具体值,则直接在文件size和请求size后面写上具体的大小,如:max-file-size: 50Mb

#配置文件大小上传限制,此处设定不限制大小
spring:
  application:
    name: fota-admin
  profiles:
    active: dev
  servlet:
    multipart:
      maxFileSize: -1
      maxRequestSize: -1

#临时文件地址
#此路径没有指定哪个磁盘,项目服务在哪个磁盘里启动,对应的会在该磁盘下创建该目录
tempFilePath: /tmp/

2、Controller层

/**
     * 文件上传
     */
    @PostMapping("/upload")
    public Long upload(@RequestParam MultipartFile file){
        return fileService.upload(file);
    }

    /**
     * 文件下载
     */
    @GetMapping("/download/{id}")
    public void download(@PathVariable Long id, HttpServletRequest req, HttpServletResponse res) {
        fileService.download(id, req, res);
    }

3、Service层
             路径存储在数据库,下载时通过数据库id,获取路径下载

@Value("${tempFilePath}")
    private String tempFilePath;

    @Override
    public Long upload(MultipartFile file) {
        if(file == null || file.isEmpty()){
            return null;
        }
        //获取文件名
        String fileName = file.getOriginalFilename();
        //获取文件的后缀名
        String suffixName = fileName.substring(fileName.lastIndexOf("."));
        //获取文件大小
        int fileSize = (int)file.getSize();
        //获取日期
        String date = formatDate("yyyy-MM-dd", System.currentTimeMillis());
        //文件路径
        String path = tempFilePath+date+"/"+fileName;
        //文件存储路径:保存到数据库
        String filePath = date+"/"+fileName;

        java.io.File dest = new java.io.File(path);
        // 判断路径是否存在,如果不存在则创建
        if(!dest.getParentFile().exists()) {
            dest.getParentFile().mkdirs();
        }

        try {
            //保存文件
            BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(path));
            outputStream.write(file.getBytes());
            outputStream.flush();
            outputStream.close();
            //保存相关信息到数据库
            File files = new File();
            files.setName(fileName);
            files.setObjectType(suffixName);
            files.setFileSize(fileSize);
            files.setFilePath(filePath);
            files.setCreateUser(BaseContextHandler.getLoginName());
            files.setCreateDate(System.currentTimeMillis());
            fileRepository.save(files);
            return files.getId();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BadRequestException(e.getMessage());
        }
    }

    @Override
    public void download(Long id, HttpServletRequest req, HttpServletResponse res){
        if (id != null) {
            File entity = fileRepository.findById(id).get();
            String path = tempFilePath+entity.getFilePath();
            setDownloadContent(entity.getName(), req, res);
            // 重要,需要设置此值,否则下载后打开文件会提示文件需要修复
            res.setContentLength(entity.getFileSize());
            java.io.File file = new java.io.File(path);
            if (file.exists()) {
                byte[] buffer = new byte[1024];
                //输出流
                OutputStream os;
                try (FileInputStream fis= new FileInputStream(file);
                     BufferedInputStream bis = new BufferedInputStream(fis);) {
                    os = res.getOutputStream();
                    int i = bis.read(buffer);
                    while (i != -1){
                        os.write(buffer,0,i);
                        i = bis.read(buffer);
                    }
                } catch (Exception e) {
                    log.error(e.getMessage(), e);
                    throw new BadRequestException(e.getMessage());
                }
            }
        }
    }

    /**
     * 客户端下载文件上response header的设置。
     *
     * @param fileName 文件名
     * @param request  请求
     * @param response 响应
     */
    private void setDownloadContent(String fileName, HttpServletRequest request, HttpServletResponse response) {
        String agent = request.getHeader("User-Agent");
        try {
            if (null != agent && agent.toUpperCase().indexOf("MSIE") > 0) {
                fileName = URLEncoder.encode(fileName, "UTF-8");
            } else {
                fileName = new String(fileName.getBytes("UTF-8"), "ISO8859-1");
            }
        } catch (UnsupportedEncodingException e1) {
        }
        response.setContentType("application/x-msdownload;");
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
    }

文件上传细节:

  • 文件大小限制配置
  • 文件覆盖:文件上传,在同一个目录下重名,后上传的文件会覆盖前一个文件,所以建议给文件名设置为唯一。可采用uuid设置文件名。
//在upload接口修改如下
   //获取文件名:保存到数据库,该文件原始的名字
   String fileName = file.getOriginalFilename();
   //获取唯一文件名:存储在磁盘和数据库里的路径用uuid
   String name = getUuid();
   //文件路径
   String path = tempFilePath+date+"/"+name;
   //文件存储路径:保存到数据库
   String filePath = date+"/"+name;


    /**
     * 获取uuid
     */
    public static String getUuid() {
        return UUID.randomUUID().toString();
    }