文件的上传和下载,是非常常见的功能,很多系统,或者软件中经常使用文件的上传和下载. 比如QQ头像/邮箱中的上传和下载功能/OA系统中审批中附件的上传.

1. 文件的上传
步骤:

有一个form标签,method=post 请求

form标签的encType属性的值必须为multipart/form-data值

在form标签中,使用input type=file添加上传的文件

编写服务器代码(Servlet程序)接收,处理上传的数据

encType = multipart/form-data 表示提交的数据,以多段(每一个表单项是一个数据段) 的形式进行拼接,然后以二进制流形式发送给服务器.

2. 常用API介绍说明
第一步:引入两个jar包:

commons-fileupload-1.2.1.jar
commons-io-1.4.jar

第二步:编写UploadServlet上传服务器文件:

public class UploadServlet extends HttpServlet {
    /**
     * 用来处理文件上传
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        //System.out.println("文件已上传");
        //ServletInputStream inputStream = req.getInputStream();
        //byte[] buffer = new byte[10240];
        //int read = inputStream.read(buffer);
        //System.out.println(new String(buffer,0,read));        //1.判断上传的数据是否是多段数据(只有是多段的数据,才是文件上传的)
        if (ServletFileUpload.isMultipartContent(req)){            //创建FileItemFactory实现类
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
            //创建用于解析上传数据的工具类ServletFileUpload类
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
            //解析上传的数据,得到每一个表单的FileItem
            try{
                List<FileItem> list = servletFileUpload.parseRequest(req);                //循环判断:每一个表单项是普通类型还是上传的文件
                for (FileItem fileItem:list){
                    if (fileItem.isFormField()){
                        //普通表单项
                        System.out.println("表单项name的属性值"+fileItem.getFieldName());
                        //参数UTF-8解决乱码问题
                        System.out.println("表单项value的属性值"+fileItem.getString("UTF-8"));                    }else{
                        //上传文件
                        System.out.println("表单项的name属性值"+fileItem.getFieldName());
                        System.out.println("上传的文件名:"+fileItem.getName());                        fileItem.write(new File("C:\\Users\\Abraham CHM\\Desktop\\"+fileItem.getName()));
                    }                }
            }catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    }
}

第三步: 编写web.xml映射文件:

<servlet>
    <servlet-name>UploadServlet</servlet-name>
    <servlet-class>com.cj.servlet.UploadServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>UploadServlet</servlet-name>
    <url-pattern>/uploadServlet</url-pattern>
</servlet-mapping>



第四步: 编写JspUpload.jsp 上传页面:

<body>
    <form action="http://localhost:8080/Demo09_EL_JSTL/uploadServlet" method="post" enctype="multipart/form-data">
        用户名: <input type="text" name="username" /> <br>
        头像: <input type="file" name="photo" /> <br>
        <input type="submit" value="上传">
    </form></body>



3. 文件的下载
在资源文件夹目录下设置供下载的资源文件夹: file

在servlet文件夹下添加UploadServlet.java 文件

public class DownloadServlet extends HttpServlet {
    //二. 基于UTF-8浏览器的下载方式(Chrome):
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 获取要下载的文件名
        String downloadFilename = "1.png";
        //2. 读取要下载的文件内容(通过ServletContext对象可以读取)
        ServletContext servletContext = getServletContext();
        //获取要下载的文件类型
        String mimeType = servletContext.getMimeType("/file/"+downloadFilename);
        System.out.println("下载的文件类型:"+mimeType);        //4. 在回传前,通过响应头告诉客户端返回的数据类型
        resp.setContentType(mimeType);
        //5. 通过响应头告诉客户端收到的数据是用于下载的
        //Content-Disposition 响应头,表示收到的数据怎么处理
        //attachment表示下载的附件
        //filename表示指定下载的文件名字
        //resp.setHeader("Content-Disposition","attachment;filename="+downloadFilename);
        //a.若下载的文件不想使用服务器上的文件名,则可以在filename=后面想要的名字
        //resp.setHeader("Content-Disposition","attachment;filename=我就是要这个名字.jpg");

        //if选择实现火狐浏览器和其他浏览器下载中文名文件时不出现乱码问题
        if(req.getHeader("User-Agent").contains("Firefox")){
         //c.基于火狐浏览器下载有中文名的文件
         resp.setHeader("Content-Disposition","attachment;filename==?UTF-8?B?" + new BASE64Encoder().encode("我就是要个中文名字.png".getBytes("UTF-8"))+"?=");
     }else {
         //b.若其他浏览器下载的文件名中有汉字,下载的文件名会出现乱码,则需要转码
         resp.setHeader("Content-Disposition","attachment;filename=" + URLEncoder.encode("我就是要个中文名字.png","UTF-8"));
     }

        /**
         * /file 中 斜杠 表示被服务器解析表示地址为http://ip:port/工程名/  映射到代码的web目录
         */
        InputStream resourceAsStream = servletContext.getResourceAsStream("/file/" + downloadFilename);
        //获取响应的输出流
        OutputStream outputStream = resp.getOutputStream();        //3. 把下载的文件内容回传给客户端
        // 获取输入流中全部的数据,复制给输出流,输出到客户端
        IOUtils.copy(resourceAsStream,outputStream);    }
}

BASE64编码操作:

基于火狐浏览器: 对中文名进行BASE64编码操作:

需要把请求头Content-Disposition,attachment;filename=中文名, 编码成为:Content-Disposition,attachment;filename=?charset?B?xxxxx?=
其中:
=?charset?B?xxxxx?=
=? 表示编码内容的开始
charset 表示字符集
B 表示BASE64编码
xxxx 表示文件名BASE编码后的内容
?= 表示编码内容的结束
//c.基于火狐浏览器下载有中文名的文件
resp.setHeader("Content-Disposition","attachment;filename==?UTF-8?B?" + new BASE64Encoder().encode("我就是要个中文名字.png".getBytes("UTF-8"))+"?=");

public class Base64Test {
    //一.基于Base64浏览器的下载方式(FireFox):
    public static void main(String[] args) throws Exception {
        String content = "这是需要Base64编码的内容";
        //创建一个Base64编码器
        BASE64Encoder base64Encoder = new BASE64Encoder();
        //执行Base64编码操作
        String encodeString = base64Encoder.encode(content.getBytes("UTF-8"));
        System.out.println("编码后,转换位二进制:"+encodeString);
        BASE64Decoder base64Decoder = new BASE64Decoder();
        //解码操作
        byte[] bytes = base64Decoder.decodeBuffer(encodeString);
        String preContent = new String(bytes,"UTF-8");
        System.out.println("解码后,转换为字符串:"+preContent);
    }
}

参考文章:http://blog.ncmem.com/wordpress/2023/11/26/javaweb实现文件的上传和下载/