文件的上传和下载

2022-11-18 17:04:00 浏览数 (1)

文章目录

  • 前言
  • 一、文件的上传介绍
    • 1.1、文件上传,HTTP协议的说明
    • 1.2、commons-fileupload.jar 常用API介绍说明
    • 1.3、fileupload类库的使用:
  • 二、文件下载
  • 三、附件中文名乱码的解决方案:
    • 方案一:URLEncoder解决IE和谷歌浏览器中的附件中文名问题
    • 方案二:BASE64编解码解决火狐浏览器的附件中文名问题
    • 总结以上两种解决方案

前言

文件的上传和下载,是非常常见的功能,在很多的系统中,或者软件中都经常使用文件的上传和下载。 比如:QQ头像,就使用了上传 邮箱中也有附件的上传和下载的功能


一、文件的上传介绍

1、要有一个form标签,method = post 请求 2、form标签的encType属性值必须为multipart/form-data值 3、在form标签中使用input type=file添加上传文件 4、编写服务器代码(Servlet程序)接收,处理上传的数据。

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

1.1、文件上传,HTTP协议的说明

1.2、commons-fileupload.jar 常用API介绍说明

commons-fileupload.jar 需要依赖commons-io.jar这个包,所以两个包我们都要引入。 第一步,就是需要导入两个jar包; commons-fileupload.jar commons-io.jar 这两个jar包中常用的类和方法: ServletFileUpload类,用于解析上传的数据 FileItem类,表示每一个表单项 boolean ServletFileUpload.isMultipartContent(HttpServletRequest request); 判断当前上传的数据格式是否是多段的格式

String FileItem.getString(); 获取当前表单项的值 String FileItem,getName(); 获取上传的文件名 String FileItem,write(file); 将上传的文件写到参数file所指向的硬盘位置。

1.3、fileupload类库的使用:

上传文件的表单:

代码语言:javascript复制
<body>
<form action="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>

解析上传的数据的代码:

代码语言:javascript复制
public class UploadServlet extends HttpServlet {
    @Override
    //用来处理上传的数据
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //先判断上传的数据是否是多段数据(只有是多段的数据,才是文件上传的)
        if(ServletFileUpload.isMultipartContent(req)) {
            //创建FileItemFactory工厂实现类
            FileItemFactory fileItemFactory = new DiskFileItemFactory();
            //创建用于解析上传数据的工具类ServletFileUpload类
            ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
            try {
                //解析上传数据,得到每一个表单项FileItem
                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("E:\"  fileItem.getName()));
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

结果:

二、文件下载

下载常用的API说明: response.getOutputStream(); servletContext.getResourceAsStream(); servletContext.getMimeType(); response.setContentType();

response.setHeader(“Content-Disposition”,“attachment; fileName = 文件名.文件类型”); 这个响应头告诉浏览器,这是需要下载的。而attachment表示附件,也就是下载的一个文件。fileName=后面表示下载的文件名。 完成上面的两个步骤,下载文件是没问题了。但是我们要下载的文件是中文名的话,会发现下载无法正确显示出正确的中文名。 原因是在响应头中,不能包含有中文的字符,只能包含ASCII码。 文件下载示例:

代码语言:javascript复制
public class DownloadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取要下载的文件名
        String downloadFileName = "宇航员.jpg";
        //读取要下载的文件内容(通过ServletContext对象可以读取)
        ServletContext servletContext = getServletContext();
        //获取要下载的文件类型
        String mimeType = servletContext.getMimeType("/file/"   downloadFileName);
        System.out.println("下载的文件类型: "   mimeType);
        //在回传前,通过响应头告诉客户端返回的数据类型
        resp.setContentType(mimeType);
        //还要告诉客户端收到的数据是用于下载使用(还是使用响应头)
/*        Content-Disposition 响应头,表示收到的数据怎么处理
          attachment 表示附件,表示下载使用
          filename   表示指定下载的文件名*/
        //把中文名进行UTF-8编码操作
        String str = "attachment; fileName="   URLEncoder.encode("宇航员.jpg","UTF-8");
        resp.setHeader("Content-Disposition",str);
        InputStream resourceAsStream = servletContext.getResourceAsStream("file/"   downloadFileName);
        //获取响应输出流
        OutputStream outputStream = resp.getOutputStream();
        //把下载的文件内容回传给客户端
        //读取输入流中全部的数据,复制给输出流,输出给客户端
        IOUtils.copy(resourceAsStream,outputStream);
    }
}

三、附件中文名乱码的解决方案:

方案一:URLEncoder解决IE和谷歌浏览器中的附件中文名问题

如果客户端浏览器是IE浏览器或者是谷歌浏览器,我们需要使用URLEncoder类先对中文名进行UTF-8的编码操作。 因为IE浏览器和谷歌浏览器收到含有编码的字符串后会以UTF-8字符集进行解码显示。

代码语言:javascript复制
        //把中文名进行UTF-8编码操作
        String str = "attachment; fileName="   URLEncoder.encode("宇航员.jpg","UTF-8");
        resp.setHeader("Content-Disposition",str);

方案二:BASE64编解码解决火狐浏览器的附件中文名问题

如果客户端浏览器是火狐浏览器,那么我们需要对中文名进行BASE64的编码操作。

BASE64编解码操作:

代码语言:javascript复制
 public static void main(String[] args) throws Exception {
        String content = "这是需要Base64编码的内容";
        // 创建一个Base64编码器
        BASE64Encoder base64Encoder = new BASE64Encoder();
        // 执行Base64编码操作
        String encodedString = base64Encoder.encode(content.getBytes("UTF-8"));

        System.out.println( encodedString );
        // 创建Base64解码器
        BASE64Decoder base64Decoder = new BASE64Decoder();
        // 解码操作
        byte[] bytes = base64Decoder.decodeBuffer(encodedString);

        String str = new String(bytes, "UTF-8");

        System.out.println(str);
    }

因为火狐浏览器使用的是BASE64的编解码方式还原响应中的汉字,所以需要使用BASE64Encoder类进行编码操作。 注:BASE64Encoder类在高版本的JDK中已经被抛弃使用了。所以用这个类慎用!

总结以上两种解决方案

我们只需要通过判断请求头中User-Agent这个请求头携带过来的浏览器信息即可判断出是什么浏览器。 如下:

代码语言:javascript复制
 if (req.getHeader("User-Agent").contains("Firefox")) {
            // 如果是火狐浏览器使用Base64编码
            resp.setHeader("Content-Disposition", "attachment; filename==?UTF-8?B?"   new BASE64Encoder().encode("中文.jpg".getBytes("UTF-8"))   "?=");
        } else {
            // 如果不是火狐,是IE或谷歌,使用URL编码操作
            resp.setHeader("Content-Disposition", "attachment; filename="   URLEncoder.encode("中文.jpg", "UTF-8"));
        }

0 人点赞