zoukankan      html  css  js  c++  java
  • JavaWeb基础—上传与下载

    1.上传(不能使用BaseServlet):
      上传的作用,略
      上传的要求(对表单和Servlet都有要求):
        1.必须使用表单,而不能是超链接,method="post" 文件明显不能get把参数带在后面
        2.必须使用多部件表单数据 enctype="multipart/form-data"
        3.表单中必须添加文件表单项 input type="file" name="xxx"

        4.凡是带文件的表单的所有(所有!)数据都不能用getParameter()方法获取,带了enctype
          就无法使用此方法,而是使用getInputStream() 返回整个请求体

      多部件表单的体:
        1.一个表单项一个部件
        2.一个部件中包含请求头、空行、请求体
        3.普通表单项:一个头 Content-Disposition name=“xxx” 即表单项的名字,体就是表单项的值
          文件表单项:包含两个头:Content-Disposition name=“xxx”,表单项名称,和一个filename="xxx"即文件名称
          Content-Type:上传文件的MIME类型

      commons-fileupload.jar包登场,他有一个io的依赖包
      它可以帮我们解析request中的数据,一个表单数据封装到一个items对象中,调用fileItems的方法即可
        上传三步:
        1.工厂 DiskFileItemFactory
        2.解析器 ServletFileUpload
        3.表单项 FileItem

      创建工厂 有构造器
      创建解析器 给一个工厂,就可以new
      得到表单项 使用解析器得到集合数据
      给一个request List<FileItem> FileItemList = sfu.parseRequest(request);

    给出一个小例子:

      JSP页面:

    <%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
    <%
    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 'form1.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>
       <form action="<c:url value='/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>
    </html>

    Servlet页面:

    package cn.itacast.servlet;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.List;
    
    import javax.servlet.ServletException;
    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.FileUploadException;
    import org.apache.commons.fileupload.disk.DiskFileItemFactory;
    import org.apache.commons.fileupload.servlet.ServletFileUpload;
    
    public class UploadServlet2 extends HttpServlet {
    
        public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
            request.setCharacterEncoding("utf-8");
            response.setContentType("text/html;charset=utf-8");
            //上传三步,步骤见笔记
            DiskFileItemFactory factory = new DiskFileItemFactory();
            ServletFileUpload sfu = new ServletFileUpload(factory);
            sfu.setFileSizeMax(100*1024);
            try{
                List<FileItem> FileItemList = sfu.parseRequest(request);
                FileItem f1 = FileItemList.get(0);
                FileItem f2 = FileItemList.get(1);
            
                System.out.println("普通表单项:"+f1.getFieldName()+"="+f1.getString("UTF-8"));
                System.out.println("文件表单项:");
                System.out.println("文件类型:"+f2.getContentType());
                File file = new File("F:/2.jpg");
                        f2.write(file);
            }catch(Exception e){
                e.printStackTrace();
            }
                    
            
        }
    }

      上传的细节:
        1.文件必须保存到WEB-INF下(当然C.D.E盘都可以,但强烈不建议),目的是为了不让浏览器直接访问

        2.文件名称相关:有的是绝对路径,需要进行切割(切割文件名过来),
        部分浏览器(IE6,遨游之类)这样

        Sting filename = f2.getName();
        int index = filename.lastIndexOf("\");
        if(index != -1){
        String filename1 = filename.subString(index+1);
        }

        3.乱码问题:文件的名称乱码等都交给FileUpload来处理,使用时告诉它编码,request.setCharaterEncoding("UTF-8");
        fileUpload会自动调用处理
        当然,解析器也提供了一个方法
        ServletFileUpload.setHeaderEncoding();内部的方法,优先级高

        4.处理重名问题,为每个文件名称添加前缀(UUID),处理重名问题
        filename = CommonUtils.uuid()+"_"+filename;使用客户的文件名称再加我们的不重复前缀

        5.目录打散问题:不能在一个文件夹下存放过多文件
        首字母打散:如文件名称叫abc.txt 则保存到B目录下,不存在则创建
        局限也明显,中文等的太多复杂
        时间打散:使用当前日期作为目录,一天一个文件夹
        局限性:有时候周末目录爆满,工作日空空如也
        哈希打散(推荐):任何对象都有一个hashCode()方法,得到一个INT值
        得到哈希值
        把Int值转换成十六进制
        获取十六进制的前两位用来生成目录
        目录为两层,例如文件名 1A2B3C 生成目录 1/A/文件名
        最多可以生成INT的范围,4字节32位,8位十六进制
        最多42亿
        局限性体现在人工不知道在哪,找起来麻烦,但计算机很清楚

        切割文件名->加UUID->得到文件名的哈希值->Integer.toHexString()
        ->使用String.cahrAt()拿出构建目录的目录名+root文件路径("/WEB-INF/files/") mkdirs
        6.上传文件大小限制:单个文件大小限制
        整个请求大小限制

         解析器有相关的方法:sfu.setFilesizeMax(100*1024);100KB
        必须放在解析之前
        如果超出限制,在解析时会抛出异常

        限制整个表单请求大小 sfu.setSizeMax();也是解析前执行
        7.缓存大小与临时目录
        1.缓存大小:超出多大才向硬盘保存,默认10KB
        2.向硬盘的什么目录保存
        DiskFileItemFactory(int sizeThreshold, File repository)
        使用此构造器,可以指定缓存与临时目录

    2.下载:下载就是客户端响应字节数据
      下载的要求:
        两个头一个流
        Content-Type (什么类型)
        Content-Dispositon (默认值是inline,浏览器能打开他就打开,图片,文字等)
        要弹下载框需要设置为 accathment;filename=xxx
        流就是要下载的文件数据

      下载的细节:
        显示在下载框的中文名称会出现乱码
        大部分主流浏览器都使用URL编码
        通用解决方案:frameName = new String(filename.getBytes(""),"");
        一个小工具类(此处略) filenameEncoding方法

      详细步骤:

    文件下载功能是web开发中经常使用到的功能,使用HttpServletResponse对象就可以实现文件的下载
    
    文件下载功能的实现思路:
    
      1.获取要下载的文件的绝对路径
    
      2.获取要下载的文件名
    
      3.设置content-disposition响应头控制浏览器以下载的形式打开文件
    
      4.获取要下载的文件输入流
    
      5.创建数据缓冲区
    
      6.通过response对象获取OutputStream流
    
      7.将FileInputStream流写入到buffer缓冲区
    
      8.使用OutputStream将缓冲区的数据输出到客户端浏览器

      借用苍狼大神的示例:

    package gacl.response.study;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.OutputStream;
    import java.io.PrintWriter;
    import java.net.URLEncoder;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    /**
     * @author gacl
     * 文件下载
     */
    public class ResponseDemo02 extends HttpServlet {
    
        public void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            downloadFileByOutputStream(response);//下载文件,通过OutputStream流
        }
    
        /**
         * 下载文件,通过OutputStream流
         * @param response
         * @throws FileNotFoundException
         * @throws IOException
         */
        private void downloadFileByOutputStream(HttpServletResponse response)
                throws FileNotFoundException, IOException {
            //1.获取要下载的文件的绝对路径
            String realPath = this.getServletContext().getRealPath("/download/1.JPG");
            //2.获取要下载的文件名
            String fileName = realPath.substring(realPath.lastIndexOf("\")+1);
            //3.设置content-disposition响应头控制浏览器以下载的形式打开文件
            response.setHeader("content-disposition", "attachment;filename="+fileName);
            //4.获取要下载的文件输入流
            InputStream in = new FileInputStream(realPath);
            int len = 0;
            //5.创建数据缓冲区
            byte[] buffer = new byte[1024];
            //6.通过response对象获取OutputStream流
            OutputStream out = response.getOutputStream();
            //7.将FileInputStream流写入到buffer缓冲区
            while ((len = in.read(buffer)) > 0) {
            //8.使用OutputStream将缓冲区的数据输出到客户端浏览器
                out.write(buffer,0,len);
            }
            in.close();
        }
    
        public void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            doGet(request, response);
        }
    }
    View Code
  • 相关阅读:
    Oracle的 listagg() WITHIN GROUP ()函数使用
    AJAX工作原理与缺点
    牛客网数据库SQL实战(此处只有答案,没有表内容)
    Jsp的四大作用域与九大对象
    eclipse的debug调试技巧
    浏览器与服务器交互
    eclipse图标含义
    不要在构造和析构函数中调用虚函数
    构造,析构 cpp
    2 c++对象被使用前要先被初始化
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6705861.html
Copyright © 2011-2022 走看看