Java实现带表单参数的文件上传、下载和文件压缩打包下载

准备工作

知识准备

  1. SpringBoot
  2. Maven
  3. Spring Data JPA

工具准备
IDE:IDEA

说明

在此项目中, 我将文件上传的一些参数(例如上传路径、下载路径、文件名等)保存在数据库当中,这样更加灵活。当项目部署后,只需要更改数据库中的数据就可以实现不同的操作,不用再重新部署,但我也将不使用数据库的写法保留在代码中,以供参考

项目结构

在这里插入图片描述

实体类

FileConfiguration.java

import lombok.Data;

import javax.persistence.*;

/**
 * Created by FantasticPan on 2018/10/23.
 * 文件配置类,配置上传路径、下载路径、文件名等参数
 */
@Data
@Entity
@Table
public class FileConfiguration {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    //指定下载的文件名字
    //eg:file.docx
    private String downloadFileName; 
    
    //指定生成的zip压缩包名字
    //eg:file.zip
    private String downloadZipFileName; 
    
    //允许文件上传类型
    //eg:.txt,.docx,.doc 注意:逗号为英文符
    private String uploadFileType; 
    
    //提示信息
    //eg:文件内容为空 !,文件大小限制1M !,文件后缀名有误 !,提交成功!,提交失败,请与工作人员联系 注意:逗号为英文符
    private String tips; 
    
    //指定文件上传的位置
    //eg:windows系统:D:/uploadFies  Linux系统:/file/uploadFiles
    private String uploadFilePath; 
    
    //指定要下载文件的所在路径
    //eg:windows系统:D:/file  Linux系统:/file
    private String downLoadFilePath; 
}

实体类使用Lombok工具简化GET、SET方法,不知道的可以直接写Get、Set方法
特别注意:允许文件上传类型uploadFileType和提示信息tips在数据库中逗号分隔符要用英文符

Files.java

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

import javax.persistence.*;
import java.io.Serializable;
import java.sql.Timestamp;

/**
 * Created by FantasticPan on 2017/12/5.
 * 文件类,保存上传文件的一些参数(上传日期、上传路径等)
 */
@Entity
@Table(name = "files")
@Getter
@Setter
@ToString
public class Files implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    private String name;
    private String url;
    private Timestamp date;
}

文件上传,数据库一般是不保存文件的,只是将文件的位置等信息保存在数据库中,根据这些信息再到系统中去查找文件

Member.java

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;

/**
 * Created by FantasticPan on 2018/1/24.
 * 对象类
 */
@Entity
@Table(name = "member")
@Setter
@Getter
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    String username;
    String password;

    public Member() {}

    public Member(String username,String password) {
        this.username = username;
        this.password = password;
    }
}

这是对象类,带表单参数上传文件时使用

DAO层

针对上面的三个实体类创建三个DAO接口,操作数据库,这里我使用的持久层数据库为Jpa

1.

import com.pan.file.entity.Files;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by FantasticPan on 2017/12/5.
 */
public interface FileRepository extends JpaRepository<Files,Long> {
}

2.

import com.pan.file.entity.FileConfiguration;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;

/**
 * Created by FantasticPan on 2018/10/23.
 */
public interface ConfigurationRepository extends JpaRepository<FileConfiguration, Long> {

    @Query("select f.downloadFileName from FileConfiguration f where f.id =?1")
    String findDownloadFileName(Integer id);

    @Query("select f.downloadZipFileName from FileConfiguration f where f.id =?1")
    String findDownloadZipFileName(Integer id);

    @Query("select f.uploadFileType from FileConfiguration f where f.id =?1")
    String findUploadFileType(Integer id);

    @Query("select f.tips from FileConfiguration f where f.id =?1")
    String findTips(Integer id);

    @Query("select f.uploadFilePath from FileConfiguration f where f.id =?1")
    String findUploadFilePath(Integer id);

    @Query("select f.downLoadFilePath from FileConfiguration f where f.id =?1")
    String findDownLoadFilePath(Integer id);
}

3.

import com.pan.file.entity.Member;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by FantasticPan on 2018/1/24.
 */
public interface MemberRepository extends JpaRepository<Member, Long> {
}

1、文件上传

我将上传方法进行封装,方便调用:

import org.springframework.web.multipart.MultipartFile;
import java.io.File;

/**
  * 上传文件
  */
public static void uploadFile(String filePath, String fileName, MultipartFile multipartFile) throws Exception {
        File file = new File(filePath + fileName);
        if (!file.getParentFile().exists()) {
            file.getParentFile().mkdirs();
        }
        multipartFile.transferTo(file);
    }

第一个参数是要上传的位置,如果是本地可以是某一个盘下的文件夹路径,第二个参数是获取到的文件名字,第三个参数是我们使用 Multipartfile 来实现文件上传。
从数据库中查询默认查询主键id为1

上传方法调用

    @Autowired
    private FileRepository fileRepository;
    @Autowired
    private ConfigurationRepository configurationRepository;

    @PostMapping(value = "/submit")
    @ResponseBody
    public ModelAndView uploadFile(HttpServletRequest request, HttpServletResponse response, @RequestParam(value = "file") MultipartFile multipartFile) throws UnsupportedEncodingException {

        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        Long length = multipartFile.getSize();//返回的是字节,1M=1024KB=1048576字节 1KB=1024Byte
        String fileName = multipartFile.getOriginalFilename();
        //获取文件后缀名
        String suffix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase().trim();
        //获取文件后缀名
        //String prefix = fileName.substring(0,fileName.lastIndexOf("."));

        //String fileType = ".txt,.docx,.doc";
        //String[] typeArray = fileType.split(",");

        //从数据库查询上传的文件类型
        String fileType = configurationRepository.findUploadFileType(1);

        String tips = configurationRepository.findTips(1);
        //String information[] = {"文件内容为空 !", "文件大小限制1M !", "文件后缀名有误 !", "提交成功!", "提交失败,请与工作人员联系"};
        String information[] = tips.split(",");

        ModelAndView mav = new ModelAndView();

        if (multipartFile.isEmpty()) {
            mav.setViewName("message");
            mav.addObject("error", information[0]);
            return mav;
        } else if (length > 1048576) {
            mav.setViewName("message");
            mav.addObject("error", information[1]);
            return mav;
        } else if (!Arrays.asList(fileType.split(",")).contains(suffix)) {
            mav.setViewName("message");
            mav.addObject("error", information[2]);
            return mav;
        }

        //生成自定义的Files对象
        Files files = new Files();
        String uploadFilePath = configurationRepository.findUploadFilePath(1);
        String filePath = uploadFilePath + "/" + UUID.randomUUID() + "/";
        
        //路径写死的方法
        //String filePath = "d:/uploadFies" + "/" + UUID.randomUUID() + "/";
        //String filePath = request.getSession().getServletContext().getRealPath("/") + "upload/";
        String fileUrl = filePath + fileName;
        
        //设置属性
        files.setName(fileName);
        files.setUrl(fileUrl);
        files.setDate(new Timestamp(System.currentTimeMillis()));

        try {
            //上传文件到服务器
            FileUtil.uploadFile(filePath, fileName, multipartFile);
            //数据库保存文件信息
            fileRepository.save(files);

            mav.setViewName("message");
            mav.addObject("error", information[3]);
            return mav;
        } catch (Exception e) {
            e.printStackTrace();

            mav.setViewName("message");
            mav.addObject("error", information[4]);
            return mav;
        }
    }

在这里我进行了文件后缀名和大小等一系列的判断,并将文件的存储路径存到了数据库,这个在后面压缩文件会用到
这里的@RequestParam(value = "file") MultipartFile multipartFile中的 multipartFile就是前面说的要给上传方法传的第三个参数,当然我这里使用的是自动注入,value = “file”就是表单中file输入框name属性的名字,视图如下:

form.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file</title>
</head>
<body>
<!--文件上传-->
<form action="/submit" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/><br/>
    <button type="submit">提交</button>
</form>
</body>
</html>

注意:表单要加属性 enctype="multipart/form-data"

2、文件下载

下载方法封装

import java.io.*;

/**
 * 下载文件
 */
public static void downloadFile(File file, OutputStream output) {
        FileInputStream fileInput = null;
        BufferedInputStream inputStream = null;
        try {
            fileInput = new FileInputStream(file);
            inputStream = new BufferedInputStream(fileInput);
            byte[] buffer = new byte[8192];//1024*8
            int i;
            while ((i = inputStream.read(buffer)) != -1) {
                output.write(buffer,0,i);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (inputStream != null)
                    inputStream.close();
                if (fileInput != null)
                    fileInput.close();
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

方法调用

    @RequestMapping(value = "/fileDownload")
    @ResponseBody
    public void downloadFile(HttpServletResponse response) {

        //String fileName = "下学期公式表.doc";
        String fileName = configurationRepository.findDownloadFileName(1);
        //路径写死的方法
        //String filePath = "/file/";
        //String filePath = "D:\\file\\";
        //String filePath = "D:/file/";
        String filePath = configurationRepository.findDownLoadFilePath(1);
        File file = new File(filePath, fileName);

        try {
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setHeader("content-type", "application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(fileName, "UTF-8"));
            OutputStream output = response.getOutputStream();

            FileUtil.downloadFile(file, output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

fileName是要下载文件的名字,filePath是文件的位置,使用IO的File类将二者拼装在一起

3、文件打包下载

思路:先生成压缩包,再下载
文件压缩方法封装:

import com.pan.match.entity.Files;

import java.io.*;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

/**
 * 压缩文件
 */
public static void zipFile(File zipPath, List<Files> filesList) {
        FileOutputStream fileOutput;
        ZipOutputStream zipOutput;
        BufferedOutputStream bufferedOutput;
        FileInputStream fileInput = null;
        BufferedInputStream bufferedInput = null;
        try {
            fileOutput = new FileOutputStream(zipPath); //输出流,zipPath是生成的压缩包所在路径
            bufferedOutput = new BufferedOutputStream(fileOutput);
            zipOutput = new ZipOutputStream(bufferedOutput);

            for (int i = 0; i < filesList.size(); i++) {
                Files files = filesList.get(i);
                File filePath = new File(files.getUrl()); // 待压缩文件路径
                // 压缩条目
                ZipEntry entry = new ZipEntry(i + "." + filePath.getName());
                // 读取待压缩的文件并写进压缩包里
                fileInput = new FileInputStream(filePath);
                bufferedInput = new BufferedInputStream(fileInput);
                zipOutput.putNextEntry(entry);
                byte[] buffer = new byte[8192];//官方API文档推荐大小8192
                int num;
                while ((num = bufferedInput.read(buffer)) != -1) {
                    zipOutput.write(buffer, 0, num);
                }
                //不能写成  int i = bufferedInput.read(buffer);while(i != -1);否则形成死循环,一直写入
            }

            //关闭IO
            zipOutput.closeEntry();
            fileInput.close();
            bufferedInput.close();
            zipOutput.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

方法调用:

    @RequestMapping(value = "/zipDownload")
    @ResponseBody
    public void downloadZip(HttpServletResponse response) {

        List<Files> filesList = fileRepository.findAll();

        //路径写死的方法
        //String zipName = "file.zip";
        //String outPath = "/file/";
        //String outPath = "D:/file/";
        String outPath = configurationRepository.findDownLoadFilePath(1);
        String zipName = configurationRepository.findDownloadZipFileName(1);
        File zipPath = new File(outPath, zipName);//使用IO的File根据路径获取文件

        try {
            response.reset();
            response.setCharacterEncoding("utf-8");
            response.setHeader("content-type", "application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=" + URLEncoder.encode(zipName, "UTF-8"));//解决中文名乱码
            OutputStream output = response.getOutputStream();//得到服务器的输入流

            FileUtil.zipFile(zipPath, filesList);
            FileUtil.downloadFile(zipPath, output);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

这里的fileList就是要压缩文件所在的路径,因为多个文件,所以是集合,这个路径集合是从数据库中查询出来的
outPath是压缩生成的文件所在位置,zipName是生成压缩文件的名字

4、带表单参数的文件上传

文件上传方法同上
表单如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file</title>
    <link rel="icon" type="image/x-icon" href="/img/logo.png" />
</head>
<body>
<!--带表单参数的文件上传-->
<form action="/formFile" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/><br/>
    名字:<input type="text" name="username" /><br/>
    密码:<input type="password" name="password" /><br/>
    <input type="submit" name="submit" value="提交"/>
</form>
</body>
</html>

控制类:

    /**
     * 带表单参数的文件上传
     */
    @PostMapping(value = "/formFile")
    @ResponseBody
    public ModelAndView formUploadFile(HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

        request.setCharacterEncoding("utf-8");
        response.setCharacterEncoding("utf-8");
        response.setContentType("text/html;charset=utf-8");

        /*
		或者方法头这样写:
		单文件
	    public ModelAndView formUploadFile(@RequestParam(value = "file") MultipartFile multipartFile) {}
		多文件
	    public ModelAndView formUploadFile(@RequestParam(value = "file") MultipartFile[] multipartFile) {}
		*/

        //List<MultipartFile> files = ((MultipartHttpServletRequest)request).getFiles("files");
        //for (int i = 0;i<files.size();i++) {
        //    MultipartFile multipartFile = files.get(i);
        //    String file = multipartFile.getName();
        //}

        //单文件上传,对应上面的方法头
        MultipartFile multipartFile = ((MultipartHttpServletRequest) request).getFile("file");
        //多文件上传
        //MultipartFile multipartFile = multipartRequestgetFiles("file").get(0);

        //获取表单参数
        String username = request.getParameter("username");
        String password = request.getParameter("password");

        //生成Member对象,存入数据库
        Member member = new Member(username, password);

        //返回的是字节,1M=1024KB=1048576字节 1KB=1024Byte
        Long length = multipartFile.getSize();
        String fileName = multipartFile.getOriginalFilename();
        //获取文件后缀名
        String suffix = fileName.substring(fileName.lastIndexOf(".")).toLowerCase().trim();
        //获取文件后缀名
        //String prefix = fileName.substring(0,fileName.lastIndexOf("."));

        //指定符合要求的后缀
        //String fileType = ".txt,.docx,.doc";
        //数据库中查询符合要求的后缀
        String fileType = configurationRepository.findUploadFileType(1);
        //将字符串通过指定符号转变为数组
        //String[] typeArray = fileType.split(",");

        //String information[] = {"文件内容为空 !", "文件大小限制1M !", "文件后缀名有误 !", "提交成功!", "提交失败,请与工作人员联系"};
        String tips = configurationRepository.findTips(1);
        String information[] = tips.split(",");
        ModelAndView mav = new ModelAndView();

        if (multipartFile.isEmpty()) {
            mav.setViewName("message");
            mav.addObject("error", information[0]);
            return mav;
        } else if (length > 1048576) {
            mav.setViewName("message");
            mav.addObject("error", information[1]);
            return mav;
        } else if (!Arrays.asList(fileType.split(",")).contains(suffix)) {
            mav.setViewName("message");
            mav.addObject("error", information[2]);
            return mav;
        }

        Files files = new Files();
        //加上UUID,防止路径重复
        //String filePath = "/file/uploadFiles" + "/" + UUID.randomUUID() + "/";
        //String filePath = request.getSession().getServletContext().getRealPath("/") + "upload/";
        //String filePath = "d:/uploadFies" + "/" + UUID.randomUUID() + "/";
        String uploadFilePath = configurationRepository.findUploadFilePath(1); //eg:windows:D:/uploadFies Linux:/file/uploadFiles
        String filePath = uploadFilePath + "/" + UUID.randomUUID() + "/";
        String fileUrl = filePath + fileName;
        files.setName(fileName);
        files.setUrl(fileUrl);
        files.setDate(new Timestamp(System.currentTimeMillis()));

        try {
            //调用上传方法
            FileUtil.uploadFile(filePath, fileName, multipartFile);
            //数据库保存文件的存储路径
            fileRepository.save(files);

            memberRepository.save(member);

            mav.setViewName("message");
            mav.addObject("error", information[3]);
            return mav;
        } catch (Exception e) {
            e.printStackTrace();

            mav.setViewName("message");
            mav.addObject("error", information[4]);
            return mav;
        }
    }

其他

message.html信息提示页面

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8" />
    <title>信息提示</title>
    <link rel="icon" type="image/x-icon" href="/img/logo.png" />
    <script type="text/javascript">
        var time = 3; //时间,秒
        function Redirect() {
            window.location = "http://www.baidu.com";
        }
        var i = 0;
        function dis() {
            document.all.s.innerHTML = "还剩" + (time - i) + "秒";
            i++;
        }
        timer = setInterval('dis()', 1000); //显示时间
        timer = setTimeout('Redirect()', time * 1000); //跳转
    </script>
</head>
<body>
<br/><br/><br/><br/>
<center>
    <h1><p th:text="${error}"></p></h1>
    <h1><span id="s"></span></h1>
</center>
</body>
</html>

配置文件:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/fantasticpan?useUnicode=true&amp;characterEncoding=UTF-8
spring.datasource.username=root
spring.datasource.password=root

spring.thymeleaf.cache=false
spring.jpa.hibernate.ddl-auto=update
spring.jackson.serialization.indent-output=true

#单个文件大小
spring.http.multipart.max-file-size=1MB
#总上传的数据大小
spring.http.multipart.max-request-size=1MB

server.port=9090

这里设置了文件上传大小的限制

SpringBoot2.0之后有了新的写法

#单个文件大小
spring.servlet.multipart.max-file-size=10Mb
#总上传的数据大小
spring.servlet.multipart.max-request-size=10Mb

演示

1. 项目运行,这里我将上面的几个页面结合在了一起

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>file</title>
    <link rel="icon" type="image/x-icon" href="/img/logo.png" />
</head>
<body>
<!--文件上传-->
<h1>文件上传</h1>
<form action="/submit" method="post" enctype="multipart/form-data">
    <input type="file" name="file"/><br/>
    <button type="submit">提交</button>
</form>
<br/><br/>
<!--带表单参数的文件上传-->
<h1>带表单参数文件上传</h1>
<form action="/formFile" method="post" enctype="multipart/form-data">

    <input type="file" name="file"/><br/>
    名字:<input type="text" name="username" /><br/>
    密码:<input type="password" name="password" /><br/>
    <input type="submit" name="submit" value="提交"/>
</form>
<br/><br/>
<h1>文件下载</h1>
<a href="/fileDownload">下载文件</a><br/>
<a href="/zipDownload">压缩文件下载</a>
</body>
</html>

在这里插入图片描述
界面简陋请见谅

2. 数据库配置

在这里插入图片描述

3. 测试

3.1 上传文件

在这里插入图片描述
在这里插入图片描述
成功!

3.2 带表单参数的文件上传

在这里插入图片描述
在这里插入图片描述
成功!

3.3 下载文件

在这里插入图片描述

3.4 下载压缩包

在这里插入图片描述

4. 数据库信息查看

在这里插入图片描述
在这里插入图片描述
可以看到数据都是保存成功了的

总结

到此,文件的上传和下载就完成了

源码

源码放在GitHub上了。若有帮助,希望GitHub能给我一个Star,诚挚的感谢!
file

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章