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

准备工作

知识准备

  1. SpringBoot
  2. Maven
  3. Spring Data JPA

工具准备
IDE:IDEA

说明

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

项目结构

Java实现带表单参数的文件上传、下载和文件压缩打包下载_第1张图片

实体类

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


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>filetitle>
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、带表单参数的文件上传

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


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>filetitle>
    <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 files = ((MultipartHttpServletRequest)request).getFiles("files");
        //for (int i = 0;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信息提示页面


<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&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. 项目运行,这里我将上面的几个页面结合在了一起


<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>filetitle>
    <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>

Java实现带表单参数的文件上传、下载和文件压缩打包下载_第2张图片
界面简陋请见谅

2. 数据库配置

在这里插入图片描述

3. 测试

3.1 上传文件

Java实现带表单参数的文件上传、下载和文件压缩打包下载_第3张图片
Java实现带表单参数的文件上传、下载和文件压缩打包下载_第4张图片
成功!

3.2 带表单参数的文件上传

Java实现带表单参数的文件上传、下载和文件压缩打包下载_第5张图片
Java实现带表单参数的文件上传、下载和文件压缩打包下载_第6张图片
成功!

3.3 下载文件

Java实现带表单参数的文件上传、下载和文件压缩打包下载_第7张图片

3.4 下载压缩包

在这里插入图片描述

4. 数据库信息查看

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

总结

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

源码

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

你可能感兴趣的:(后端,java)