java文件的上传与下载

发布时间 2023-12-12 18:49:22作者: Xproer-松鼠

1、文件上传下载

1.1 文件上传

什么是文件上传?

要将客户端(浏览器)大数据存储到服务器端,不将数据直接存储到数据库中,而是要将数据存储到服务器所在的磁盘上,这就要使用文件上传。

为什么使用文件上传?

通过文件上传,可以将浏览器端的大数据直接保存到服务器端。不将数据保存到数据库中,而是保存到服务器磁盘上,这样减少了数据库服务器的压力,对数据的操作更加灵活

1.2 commons-fileupload介绍

Apache 开源组织提供了一个用来处理表单文件上传的一个开源组件( Commons-fileupload ),该组件性能优异,并且其API使用极其简单,可以让开发人员轻松实现web文件上传功能,因此在web开发中实现文件上传功能,通常使用Commons-fileupload组件实现。使用Commons-fileupload组件实现文件上传,需要导入该组件相应的支撑jar包:Commons-fileupload和commons-io。commons-io 不属于文件上传组件的开发jar文件,但Commons-fileupload 组件从1.1 版本开始,它工作时需要commons-io包的支持。

1.2.1 fileupload的核心类有:

DiskFileItemFactory类

1.设置缓存大小

DiskFileItemFactory factory = new DiskFileItemFactory()
factory.setSizeThreshold(1024*1024); //设置为1m 默认是10k

2.设置临时文件存储位置

File temp=new 	File(this.getServletContext().getRealPath("/temp"));
factory.setRepository(temp); //可以指定	临时文件存储位置,默认是系统的临时文件	存储位置
ServletFileUpload类

1.parseRequest方法

  • List<FileItem> pareRequest(HttpServletRequest r equest)
  • 该方法得到所有的上传信息,将每一部分映射成FileItem对象

2.isMultipartContent方法

  • boolean isMultipartContent(HttpServletRequest request)
  • 这个方法返回值是boolean,它是用于判断当前表单是否是一个上传的表单,简单说,就判断它的encType的值是否是 multipart/form-data

3.setHeaderEncoding方法

  • 用于解决上传文件名称中文乱码问题

4.设置上传文件大小

  • void setFileSizeMax(long fileSizeMax)设置单个文件上传大小
  • void setSizeMax(long sizeMax) 设置总文件上传大小
FileItem类

1.isFormField方法

  • 这个方法返回的是boolean类型,它是判断当前组件是否是上传组件简单说,就是判断type="file",如果返回true,代表不是上传组件,返回false,代表是上传组件

2.getName方法

  • 获取非上传组件的上传文件的名称,如果是非上传组件,返回的是null

3.getFieldName方法

  • 获取组件名称,简单说,就是表单的元素的name值。

4.getString方法

  • 获取非上传组件的value值
  • getString()有一个重载的方法getString(String encoding)可以解决乱码问题

5.void write(File)方法

  • 把上传的文件保存到指定文件中

1.2.2 使用fileupload核心类的步骤如下:

1.创建工厂类DiskFileItemFactory对象:

DiskFileItemFactory factory = new DiskFileItemFactory();

2.使用工厂创建解析器对象:

ServletFileUpload fileUpload = new ServletFileUpload(factory);

3.使用解析器来解析request对象:

List<FileItem> list = fileUpload.parseRequest(request);

1.3 文件上传细节

1.3.1 文件重名问题

上传操作文件重名问题分析

  • 每一个客户端都可以进行文件上传操作,那么当我们上传的文件过多,一定会出现同名的文件,那么在服务器端只能保存一个,对于这个问题,我们在上传文件时,就需要考虑文件重名问题

上传操作文件重名解决方案

一般情况下,对于上传文件,为了保证不重名,会给文件起一个随机名.

  • 一种方案是使用uuid
  • 一种方案是使用毫秒值

传统的Servlet文件上传

1)导入依赖

    <dependency>
        <groupId>commons-fileupload</groupId>
        <artifactId>commons-fileupload</artifactId>
        <version>1.4</version>
    </dependency>

2)编写表单

文件上传的必要前提:

表单文件上传的三个要素:

  1. form标签要添加enctype="multipart/form-data"
  2. 提交方法为post
  3. input类型为file
<form  action="/upload" method="post" enctype="multipart/form-data">
    ...
    <input type="file" name="file" >
    ...
</form>

1.4 servlet中上传主要代码实现

1.4.1 原生1.0版本

@WebServlet("/Upload")
public class UploadServlet extends HttpServlet {

    
    //多文件上传
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
        ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
        servletFileUpload.setHeaderEncoding("utf-8");
        List<String> filenames = new ArrayList<>();
        try {
            List<FileItem> fileItems = servletFileUpload.parseRequest(request);
            for (FileItem fileItem : fileItems) {
                if(fileItem.isFormField()){
                    String string = fileItem.getString();
                    String fieldName = fileItem.getFieldName();
                    System.out.println(fieldName+" "+string);
                }else{
                    filenames.add(uploadFile(fileItem));
                }
            }
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        request.setAttribute("filenames",filenames);

        request.getRequestDispatcher("upload.jsp").forward(request,response);

    }

    // 将上传文件表单项封装
    private String uploadFile(FileItem fileItem) {
        // 如果上传表单项
        // 得到文件输入流
        // 创建物理目录路径
        String realPath = this.getServletContext().getRealPath("/upload");
        // 根据该路径创建一个目录对象
        File dir = new File(realPath);
        if (!dir.exists()) {
            dir.mkdirs();// 创建一个指定的目录
        }
        // 得到上传的名子
        String filename = fileItem.getName();// 美女.jpg
        if (filename != null) {
            // 得到文件后缀
            String extend = filename.substring(filename.indexOf("."));
            System.out.println(extend);
            // 重写生成一个唯一的文件名
            filename = UUID.randomUUID() + extend;
        }
        // 上传文件,自动删除临时文件
        try {
            fileItem.write(new File(realPath, "/" + filename));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return filename;
    }
}

1.4.2 2.0版本-基于java反射改造

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        DiskFileItemFactory diskFileItemFactory = new DiskFileItemFactory();
        ServletFileUpload servletFileUpload = new ServletFileUpload(diskFileItemFactory);
        servletFileUpload.setHeaderEncoding("UTF-8");

        Book book = new Book();
        try {
            List<FileItem> fileItems = servletFileUpload.parseRequest(request);

            for(FileItem fileItem : fileItems){
                if(fileItem.isFormField()){
                    //动态获取类的方法
                    String method = "set"+fileItem.getFieldName().substring(0,1).toUpperCase()+fileItem.getFieldName().substring(1);
                    Method method1 = book.getClass().getMethod(method,String.class);
                    method1.invoke(book, fileItem.getString());
                }else{

                    book.setImage(uploadFile(fileItem));
                }
            }

            System.out.println(book);


            //执行添加数据操作
            int i = bookService.addBook(book);
            if(i == 1){
                response.sendRedirect("BookListServlet");
            }else{
                request.getRequestDispatcher("addBook.jsp?m=af").forward(request,response);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    // 将上传文件表单项封装
    private String uploadFile(FileItem fileItem) {
        // 如果上传表单项
        // 得到文件输入流
        // 创建物理目录路径
        String realPath = this.getServletContext().getRealPath("/img");
        // 根据该路径创建一个目录对象
        File dir = new File(realPath);
        if (!dir.exists()) {
            dir.mkdirs();// 创建一个指定的目录
        }
        // 得到上传的名子
        String filename = fileItem.getName();// 美女.jpg
        if (filename != null) {
            // 得到文件后缀
            String extend = filename.substring(filename.indexOf("."));
            System.out.println(extend);
            // 重写生成一个唯一的文件名
            filename = UUID.randomUUID() + extend;
        }
        // 上传文件,自动删除临时文件
        try {
            fileItem.write(new File(realPath, "/" + filename));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return filename;
    }

1.4.3 3.0版本-基于ajax异步文件上传

使用异步上传图片,只负责照片的上传,返回图片的名称,然后其他表单参数所有都通过form表单上传

/**
     * 上传图片
     *
     * @param request
     * @param response
     * @throws Exception
     */
    public void upload(HttpServletRequest request, HttpServletResponse response) throws Exception {
        // 创建一个DiskFileItemfactory工厂类
        DiskFileItemFactory factory = new DiskFileItemFactory();
        // 创建一个ServletFileUpload核心对象
        ServletFileUpload sfu = new ServletFileUpload(factory);
        // 解决上传文件名中文乱码
        sfu.setHeaderEncoding("utf-8");

        String filename = "";
        // 解析request对象
        try {
            FileItem fileItem = sfu.parseRequest(request).get(0);
            filename = uploadFile(fileItem);
            response.getWriter().print(filename);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            response.getWriter().print("N");
        }

    }


    /**
     * 将上传文件表单项封装
     *
     * @param fileItem
     * @return
     */
    private String uploadFile(FileItem fileItem) {
        // 如果上传表单项
        // 得到文件输入流
        // 创建物理目录路径

        String realPath = this.getServletContext().getRealPath("/upload");
        // 根据该路径创建一个目录对象
        File dir = new File(realPath);
        if (!dir.exists()) {
            dir.mkdirs();// 创建一个指定的目录
        }
        // 得到上传的名子
        String filename = fileItem.getName();
        if (filename != null) {
            // 得到文件后缀
            String extend = filename.substring(filename.indexOf("."));
            System.out.println(extend);
            // 重写生成一个唯一的文件名
            filename = UUID.randomUUID() + extend;
        }
        // 上传文件,自动删除临时文件
        try {
            fileItem.write(new File(realPath, "/" + filename));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return filename;
    }



      /**
         * 上传图片
         */
        const uploadPic = ()=> {
            if ($("#pic").val() == '') {
                return;
            }
            let formData = new FormData();
            formData.append('pic', $('#pic')[0].files[0]);
            $.ajax({
                url : "upload/uploadPic",
                type : "post",
                data : formData,
                contentType : false,
                processData : false,
                success : function(data) {
                    pic = data;

                }
            });
        }



1.4.5 4.0版本-springmvc文件上传

springmvc单文件上传

前端form表单

<form  action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="upload" >
    <button>上传</button>
</form>

上传方法中使用MultipartFile参数获得上传文件

@RequestMapping("/upload")
public String fileupload(HttpServletRequest request, MultipartFile upload) throws Exception {
    //获取项目目录下的upload目录路径
    String path = request.getSession().getServletContext().getRealPath("/upload/");
    System.out.println(path);
    File file = new File(path);
    if (!file.exists()) {
        file.mkdirs();
    }
    //获取上传文件名字
    String filename = upload.getOriginalFilename();
    String suffix = filename.substring(filename.lastIndexOf("."));
    //创建唯一的文件名
    String uuid= UUID.randomUUID().toString().replace("-","");
    filename = uuid + suffix;
    //完成文件上传
    upload.transferTo(new File(path,filename));
    return "success";
}

需要在springmvc的配置中添加上传处理器

<!--上传处理器-->
<bean class="org.springframework.web.multipart.commons.CommonsMultipartResolver" id="multipartResolver">
    <!--上传文件最大字节数-->
    <property name="maxUploadSize" value="10485760"/>
</bean>

SpringMVC多文件上传

给表单添加多个文件项

<form action="/upload" method="post" enctype="multipart/form-data">
    <input type="file" name="uploads">
    <input type="file" name="uploads">
    <input type="file" name="uploads">
    <input type="submit" value="MVC多文件上传">
</form>

添加MultipartFile数组为参数,参数名和表单name一致

@RequestMapping("/upload3")
public String fileupload3(HttpServletRequest request, MultipartFile[] uploads) throws Exception {
    //获取tomcat项目目录下的upload目录路径
    String path = request.getSession().getServletContext().getRealPath("/upload/");
    System.out.println(path);
    File file = new File(path);
    if (!file.exists()) {
        file.mkdirs();
    }
    for(MultipartFile upload : uploads) {
        //获取上传文件名字
        String filename = upload.getOriginalFilename();
        String suffix = filename.substring(filename.lastIndexOf("."));
        //创建唯一的文件名
        String uuid = UUID.randomUUID().toString().replace("-", "");
        filename = uuid + "-" + suffix;
        //完成文件上传
        upload.transferTo(new File(path, filename));
    }
    return "success";
}

SpringMVC其它上传类

SpringMVC还提供了其它API支持上传:

  • CommonsMultipartResolver 多部分解析器,用于判断请求是否存在上传文件
  • MultipartHttpServletRequest 多部分请求,用于获得文件相关信息

具体用法:

@RequestMapping("upload4")
public String  fileupload4(HttpServletRequest request) throws IllegalStateException, IOException
{
    String path = request.getSession().getServletContext().getRealPath("/upload/");
    //创建多部分解析器
    CommonsMultipartResolver multipartResolver=new CommonsMultipartResolver(
            request.getSession().getServletContext());
    //检查表单是否支持文件上传
    if(multipartResolver.isMultipart(request)){
        //将请求转换为多部分请求,支持上传
        MultipartHttpServletRequest multiRequest=(MultipartHttpServletRequest)request;
        //获取请求中所有的文件名
        Iterator iter=multiRequest.getFileNames();
        while(iter.hasNext()) {
            //遍历所有文件
            MultipartFile file=multiRequest.getFile(iter.next().toString());
            if(file!=null) {
                //获取上传文件名字
                String filename = file.getOriginalFilename();
                String suffix = filename.substring(filename.lastIndexOf("."));
                //创建唯一的文件名
                String uuid = UUID.randomUUID().toString().replace("-", "");
                filename = uuid + suffix;
                //上传
                file.transferTo(new File(path,filename));
            }
        }
    }
    return "success";
}

1.5 文件下载

/**
 * 下载控制器
 */
@Controller
public class DownloadController {

    @RequestMapping("download")
    public void download(String file,  HttpServletResponse response) throws IOException {
        //下载文件的路径
        String path = "D:\\install\\";
        File downFile = new File(path+file);
        if(downFile.exists()){
            //设置浏览器下载内容类型,响应头
            response.setContentType("application/x-msdownload");
            response.setHeader("Content-Disposition","attachment;filename="+file);
            //通过流发送文件
            Files.copy(downFile.toPath(),response.getOutputStream());
        }
    }
}
 
 

参考文章:http://blog.ncmem.com/wordpress/2023/12/12/java%e6%96%87%e4%bb%b6%e7%9a%84%e4%b8%8a%e4%bc%a0%e4%b8%8e%e4%b8%8b%e8%bd%bd/

欢迎入群一起讨论