java文件上传与下载

本文介绍了JavaWeb中实现文件上传与下载的基本方法,包括如何搭建上传界面、处理上传请求的Servlet,以及如何进行文件下载。针对文件上传,还提出了安全性优化措施。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天我们来看一下java web中的文件上传与下载
1.首先我们给出一个上传文件的界面,一个jsp页面。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%--
 application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。
 multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分,这个一般文件上传时用。 
 text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。 

 --%>
<form action="UpLoadHandler"enctype="multipart/form-data" method="post">
<input type="text" name="username"><br>
<input type="password" name="password"><br>
<input type="file" name="file1"><br>
<input type="file" name="file2"><br>
<input type="submit" value="提交">
</form>
</body>
</html>

注意,这里需要加上enctype=”multipart/form-data”,告诉服务器,我们将表单数据以二进制数据的方式传递给你。所以这时服务器用request.getParameter(“name”);是无法得到值得。此时的数据都是以byte来传递的。
Form的enctype属性为编码,他有下列几个常用值:
application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。
multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分,这个一般文件上传时用。
text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。
2.我们还需要有个处理文件上传的Servlet.

package wangcc.upload;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

@WebServlet("/UpLoadHandler")
public class UpLoadHandler extends HttpServlet {

    /**
     * Constructor of the object.
     */
    public UpLoadHandler() {
        super();
    }

    /**
     * Destruction of the servlet. <br>
     */
    public void destroy() {
        super.destroy(); // Just puts "destroy" string in log
        // Put your code here
    }

    /**
     * The doGet method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to get.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        this.doPost(request, response);
    }

    /**
     * The doPost method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to
     * post.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String savepath = this.getServletContext().getRealPath(
                "/WEB-INF/upload");
        System.out.println("存储路径为:" + savepath);
        File file = new File(savepath);
        if (!file.exists() && !file.isDirectory()) {
            // 创建此抽象路径名指定的目录
            // mkdirs()创建此抽象路径名指定的目录,包括所有必须但不存在的父目录
            file.mkdir();
        }
        String message = "";
        try {
            // 1. 创建一个工厂
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 2.创建一个文件解析器
            ServletFileUpload upload = new ServletFileUpload(factory);
            // 解决文件名中文乱码问题
            upload.setHeaderEncoding("UTF-8");
            // 3. 判断是否为为表单传递方法
            if (!ServletFileUpload.isMultipartContent(request)) {
                return;
            }
            // 4.使用ServletFileUpload解析器解析上传数据
            /**
             * 会把表单的每个数据当做一个FileItem
             * 是以流的方式上传,所以这个时候我们无法通过request.getParameter(""); 来获取数据
             */
            List<FileItem> list = upload.parseRequest(request);
            for (FileItem item : list) {
                // 首先判断这是否为表单普通数据
                if (item.isFormField()) {
                    String name = item.getFieldName();
                    String value = item.getString("UTF-8");
                    System.out.println("name:" + name + "value:" + value);
                } else {
                    String filename = item.getName();
                    System.out.println("文件路径全名:" + filename);
                    // 处理字符串,我们要对字符串filename进行处理,因为不同的浏览器返回的路径不一定相同
                    // 目录层可能不一样,所以在这里我们只需要获得文件名即可
                    if (filename == null || filename.trim().equals("")) {
                        continue;
                    }

                    filename = filename
                            .substring(filename.lastIndexOf("\\") + 1);
                    String realPath = savepath + "\\" + filename;
                    InputStream in = item.getInputStream();
                    FileOutputStream out = new FileOutputStream(realPath);
                    int len = 0;
                    byte[] buffer = new byte[1024];
                    while ((len = in.read(buffer)) != -1) {
                        out.write(buffer, 0, len);
                    }
                    in.close();
                    out.close();
                    message = "上传文件成功";
                }
            }
        } catch (Exception e) {
            message = "上传文件失败";
            // TODO: handle exception
        }
        request.setAttribute("message", message);
        request.getRequestDispatcher("/message.jsp").forward(request, response);
    }

    /**
     * Initialization of the servlet. <br>
     * 
     * @throws ServletException
     *             if an error occurs
     */
    public void init() throws ServletException {
        // Put your code here
    }

}

3.我们再写一个jsp页面,来告诉用户是否上传成功。

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${message}
</body>
</html>

以上就是一个最基本的文件上传操作的展示了。但是这里还有很多问题没有考虑进去。上传文件有一下几点需要特别注意
  **1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
  2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
  3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。
  4、要限制上传文件的最大值。
  5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。**
  下面给出改进后的代码:
  

package wangcc.upload;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadBase;
import org.apache.commons.fileupload.ProgressListener;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;

/**
 * @ClassName: NewUpLoadHandler
 * @Description: TODO(这里用一句话描述这个类的作用)
 * @author wangcc
 * @date 2016年12月11日 下午8:47:20  1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。
 * 
 *         2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。
 * 
 *         3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。
 * 
 *         4、要限制上传文件的最大值。
 * 
 *         5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。
 * 
 */
@WebServlet("/NewUpLoadHandler")
public class NewUpLoadHandler extends HttpServlet {

    /**
     * Constructor of the object.
     */
    public NewUpLoadHandler() {
        super();
    }

    /**
     * Destruction of the servlet. <br>
     */
    public void destroy() {
        super.destroy(); // Just puts "destroy" string in log
        // Put your code here
    }

    /**
     * The doGet method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to get.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        this.doPost(request, response);
    }

    /**
     * The doPost method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to
     * post.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        String savePath = this.getServletContext().getRealPath(
                "/WEB-INF/newUpload");
        String tempPath = this.getServletContext().getRealPath("WEB-INF/temp");
        String message = "";
        File temp = new File(tempPath);
        if (!temp.exists() && !temp.isDirectory()) {
            temp.mkdir();
        }
        try {
            DiskFileItemFactory factory = new DiskFileItemFactory();
            // 设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
            factory.setSizeThreshold(1024 * 100);// //设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB
            // 指定临时目录
            factory.setRepository(temp);
            ServletFileUpload newUpload = new ServletFileUpload(factory);
            // 监听上传文件进度,
            // thinking:是否可以通过ajax异步传输技术使得用户可以在页面中得到文件上传进度。
            newUpload.setProgressListener(new ProgressListener() {

                @Override
                public void update(long pBytesReaded, long PContentLength,
                        int arg2) {
                    // TODO Auto-generated method stub
                    System.out.println("文件大小:" + PContentLength + ",当前已处理:"
                            + pBytesReaded);

                }
            });
            newUpload.setHeaderEncoding("UTF-8");

            // 判断是否是传统方式传输:
            /**
             * 也就是说:判断是否是<form
             * action="UpLoadHandler"enctype="multipart/form-data"
             * method="post"> 而不是<form action="UpLoadHandler"method="post">的传统方式
             */
            if (!ServletFileUpload.isMultipartContent(request)) {
                return;
            }
            // 设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
            newUpload.setFileSizeMax(1024 * 1024);
            // 设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
            newUpload.setFileSizeMax(1024 * 1024 * 10);
            List<FileItem> list = newUpload.parseRequest(request);
            for (FileItem item : list) {
                if (item.isFormField()) {
                    String name = item.getName();
                    String value = item.getString("UTF-8");
                    System.out.println(name + " " + value);
                } else {
                    String filename = item.getName();
                    filename = filename
                            .substring(filename.lastIndexOf("\\") + 1);
                    // 可以获得文件的后缀扩展名,可以通过获取这个来限制上传文件的类型
                    String fileExtName = filename.substring(filename
                            .lastIndexOf(".") + 1);
                    System.out.println("上传的文件的扩展名是:" + fileExtName);
                    filename = makeFileName(filename);
                    String realparentpath = makePath(filename, savePath);

                    String realPath = realparentpath + "\\" + filename;
                    InputStream in = item.getInputStream();
                    FileOutputStream out = new FileOutputStream(realPath);
                    int len = 0;
                    byte[] buffer = new byte[1024];
                    while ((len = in.read(buffer)) != -1) {
                        out.write(buffer, 0, len);
                    }
                    in.close();
                    out.close();
                    message = "上传文件成功";

                }
            }

        } catch (FileUploadBase.FileSizeLimitExceededException e) {
            e.printStackTrace();
            message = "抱歉,上传失败,单个文件太大";

        } catch (FileUploadBase.SizeLimitExceededException e) {
            e.printStackTrace();
            message = "抱歉,上传失败,文件总量太大";
        } catch (Exception e) {
            message = "上传失败";
            // TODO: handle exception
        }
        request.setAttribute("message", message);
        request.getRequestDispatcher("/message.jsp").forward(request, response);
    }

    private String makeFileName(String filename) {
        return UUID.randomUUID().toString() + "_" + filename;
    }

    private String makePath(String filename, String savePath) {
        int hashcode = filename.hashCode();
        // 0x代表这个数字是16进制
        /**
         * 0xf f:15 1111 0xf0 11110000 & 运算符 均为1时才为1
         */
        int dir1 = hashcode & 0xf;// 得到的值在0-15
        // >>右移运算符,移出的部分将被抛弃
        int dir2 = (hashcode & 0xf0) >> 4;// 得到的值在0-15之间
        /**
         * 其实上面两行的代码得到的值得差别便是: 一个用hashcode的低八位中的高四位来与0xf来进行与操作
         * 一个用hashcode的低八位中的低四位来与0xf来进行与操作
         */
        String dir = savePath + "\\" + dir1 + "\\" + dir2;
        File file = new File(dir);
        if (!file.exists()) {
            file.mkdirs();
        }
        return dir;
    }

    /**
     * Initialization of the servlet. <br>
     * 
     * @throws ServletException
     *             if an error occurs
     */
    public void init() throws ServletException {
        // Put your code here
    }

}

1.下面来看一下文件下载:

package wangcc.download;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/ListFileServlet")
public class ListFileServlet extends HttpServlet {

    /**
     * Constructor of the object.
     */
    public ListFileServlet() {
        super();
    }

    /**
     * Destruction of the servlet. <br>
     */
    public void destroy() {
        super.destroy(); // Just puts "destroy" string in log
        // Put your code here
    }

    /**
     * The doGet method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to get.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        this.doPost(request, response);
    }

    /**
     * The doPost method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to
     * post.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 通常在开发中我们通过查找数据库来获取文件路径以及文件路径名
        Map<String, String> map = new HashMap<String, String>();
        String savePath = this.getServletContext().getRealPath(
                "/WEB-INF/upload");
        map.put("QQ图片20160925162552.png", savePath
                + "\\:QQ图片20160925162552.png");
        map.put("1.png", savePath + "\\:1.png");
        request.setAttribute("filelist", map);
        request.getRequestDispatcher("/list.jsp").forward(request, response);

    }

    /**
     * Initialization of the servlet. <br>
     * 
     * @throws ServletException
     *             if an error occurs
     */
    public void init() throws ServletException {
        // Put your code here
    }

}
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">

    <title>My JSP 'list.jsp' starting page</title>

    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>

  <body>
    This is my JSP page. <br>
    <c:forEach items="${filelist}" var="myfile">
    <c:url var="downurl" value="/DownLoadHandler" >
    <c:param name="filepath" value="${myfile.value}"></c:param>
    </c:url><c:out value="${myfile.key}"></c:out><a href="${downurl }">下载</a><br>
    </c:forEach>



  </body>
</html>
package wangcc.download;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/DownLoadHandler")
public class DownLoadHandler extends HttpServlet {

    /**
     * Constructor of the object.
     */
    public DownLoadHandler() {
        super();
    }

    /**
     * Destruction of the servlet. <br>
     */
    public void destroy() {
        super.destroy(); // Just puts "destroy" string in log
        // Put your code here
    }

    /**
     * The doGet method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to get.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        this.doPost(request, response);
    }

    /**
     * The doPost method of the servlet. <br>
     * 
     * This method is called when a form has its tag value method equals to
     * post.
     * 
     * @param request
     *            the request send by the client to the server
     * @param response
     *            the response send by the server to the client
     * @throws ServletException
     *             if an error occurred
     * @throws IOException
     *             if an error occurred
     */
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 得到文件路径名
        String filepath = request.getParameter("filepath");// 设置给用户(浏览器)呈现的文件的文件名
        String filename = filepath.substring(filepath.lastIndexOf(":") + 1);
        response.setHeader("content-disposition", "attachment;filename="
                + URLEncoder.encode(filename, "UTF-8"));
        /**
         * 直接用filename="+ filename会出现中文乱码
         * 需要用URLEncoder.encode(filepath,"UTF-8");来防止中文乱码的产生
         * 
         * URLEncoder HTML 格式编码的实用工具类。该类包含了将 String 转换为
         * application/x-www-form-urlencoded MIME 格式的静态方法。 encode(String s,
         * String enc) 使用指定的编码机制将字符串转换为 application/x-www-form-urlencoded
         * 格式。该方法使用提供的编码机制获取不安全字符的字节。
         */
        // 得到这个文件,然后通过response将文件响应到浏览器 :response.getOutputStream;
        File file = new File(filepath);
        if (!file.exists()) {
            request.setAttribute("message", "该资源已被删除");
            request.getRequestDispatcher("/message.jsp").forward(request,
                    response);
            return;
        }
        FileInputStream in = new FileInputStream(file);
        OutputStream out = response.getOutputStream();
        int len = 0;
        byte[] buffer = new byte[1024];
        while ((len = in.read()) != -1) {
            out.write(buffer, 0, len);
        }
        in.close();

    }

    /**
     * Initialization of the servlet. <br>
     * 
     * @throws ServletException
     *             if an error occurs
     */
    public void init() throws ServletException {
        // Put your code here
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值