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
  • 相关阅读:
    【BZOJ 4581】【Usaco2016 Open】Field Reduction
    【BZOJ 4582】【Usaco2016 Open】Diamond Collector
    【BZOJ 4580】【Usaco2016 Open】248
    【BZOJ 3754】Tree之最小方差树
    【51Nod 1501】【算法马拉松 19D】石头剪刀布威力加强版
    【51Nod 1622】【算法马拉松 19C】集合对
    【51Nod 1616】【算法马拉松 19B】最小集合
    【51Nod 1674】【算法马拉松 19A】区间的价值 V2
    【BZOJ 2541】【Vijos 1366】【CTSC 2000】冰原探险
    【BZOJ 1065】【Vijos 1826】【NOI 2008】奥运物流
  • 原文地址:https://www.cnblogs.com/jiangbei/p/6705861.html
Copyright © 2011-2022 走看看