• java web(四)文件上传与下载


     一、文件上传原理

      1、在TCP/IP中,最早出现的文件上传机制是FTP ,它是将文件由客户端发送到服务器的标准机制;但是在jsp使用过程中不能使用FTP方法上传文件,这是由jsp运行机制所决定。  

      通过为表单元素设置 method="post" enctype="multipart/form-data" 属性 ,让表单提交的数据以二进制编码的方式提交,在接受此请求的Servlet中用二进制流来获取内容,就可以取得上传文件的内容,从而实现文件的上传。

      2、表单enctype属相

        1>application/x-www-form-urlencoded

        默认编码方式,只处理表单域里的value属性值,采用这种编码方式的表单域中的值处理成URL编码方式。

        2>multipart/form-data

        这种编码方式的表单会以二进制流的方式处理表单数据,  这种编码方式会把文件域指定的文件内容也封装到请求参数中。

        3>text/plain

        这种方式主要适用于直接通过表单发送邮件的方式。

    二、SmartUpload上传组件的使用

      SmartUpload组件使用简单,可以轻松的实现上传文件类型的限制,也可以轻易地取得上传文件的名称、后缀、大小。  使用该组件需要导入jar包,我用的是 jspsmartupload.jar。

     1、上传单个文件

    upload.htm

    <html>
      <head>
      <title>文件上传</title>
      </head>
    <body>
      <form action="upload.jsp" method="post" enctype="multipart/form-data">
        请选择文件:<input type="file" name="pic">
        <input type="submit" value="上传">
      </form>
    </body>
    </html>

    upload.jsp

    <%@ page contentType="text/html" pageEncoding="utf-8"%>
    <%@ page import="com.jspsmart.upload.*"%>
    <html>
    <head>
    <title>文件上传2</title>
    </head>
    <body>
    <%
    SmartUpload smart=new SmartUpload();
    smart.initialize(pageContext);
    smart.upload();
    smart.save("upload");
    %>
    </body>
    </html>

    这里要注意在jsp页面引入导入jar包中的类文件:上面是com.jspsmart.upload.*,为什么这样写,可以用360压缩打开jar包文件如下:

    upload表示上传文件的保存文件夹,该文件夹要在跟目录手动建立。上传结果如下:

    2、混合表单

      如果要上传文件,表单必须封装,但是表单使用了enctype 封装后其他非文件类的表单控件无法通过request内置对象取得,此时必须通过SmartUpload类的getRequest()方法取得全部请求参数。

    upload2.htm

    <html>
    <head>
    <title>文件上传</title>
    </head>
    <body>
    <form action="upload2.jsp" method="post" enctype="multipart/form-data">
    姓名:<input type="text" name="uname"><br>
    照片:<input type="file" name="pic"><br>
    <input type="submit" value="上传">
    <input type="reset" value="重置">
    </form>
    </body>
    </html>

    upload2.jsp

    <%@ page contentType="text/html" pageEncoding="utf-8"%>
    <%@ page import="com.jspsmart.upload.*"%>
    <html>
    <head>
    <title>文件上传2</title>
    </head>
    <body>
    <%
    SmartUpload smart=new SmartUpload();    //实例化SmartUpload上传组件
    smart.initialize(pageContext);          //初始化上传操作
    smart.upload();                  //上传准备
    String name=smart.getRequest().getParameter("uname");  //接受请求参数
    smart.save("upload");              //将上传文件保存在upload文件夹中
    %>
    <h2>姓名:<%=name%></h2>
    <h2>request=:<%=request.getParameter("uname")%></h2>
    </body>
    </html>

    3、为上传文件自动命名

        主要为了防止重名情况下发生覆盖文件。以下例子中文件命名采用 IP地址+时间戳+三位随机数

    upload3.htm

    <html>
    <head>
    <title>文件上传</title>
    </head>
    <body>
    <form action="upload3.jsp" method="post" enctype="multipart/form-data">
    姓名:<input type="text" name="uname"><br>
    照片:<input type="file" name="pic"><br>
    <input type="submit" value="上传">
    <input type="reset" value="重置">
    </form>
    </body>
    </html>

    upload3.jsp

    <%@ page contentType="text/html" pageEncoding="utf-8"%>
    <%@ page import="com.jspsmart.upload.*"%>
    <%@ page import="kk.upload3.IPTimeStamp"%>
    <html>
    <head>
    <title>文件上传3</title>
    </head>
    <body>
    <%
    request.setCharacterEncoding("utf-8");
    //实例化SmartUpload上传组件
    SmartUpload smart=new SmartUpload();
    //初始化上传操作
    smart.initialize(pageContext);
    //上传准备
    smart.upload();
    //接受请求参数
    String name=smart.getRequest().getParameter("uname");

    IPTimeStamp its=new IPTimeStamp(request.getRemoteAddr());
    //取得文件后缀名
    String ext=smart.getFiles().getFile(0).getFileExt();
    //拼凑文件名称
    String fileName=its.getIPTimeRand()+"."+ext;
    System.out.println("文件名称及后缀==>"+fileName);
    //保存文件

    smart.getFiles().getFile(0).saveAs(getServletContext().getRealPath("/")
    +"upload"+java.io.File.separator+fileName);

    //./表示当前目录;../表示源文件所在目录的上一级目录;../../表示源文件所在目录的上上级目录,以此类推
    %>

    <%=getServletContext().getRealPath("/")+"upload"+java.io.File.separator+fileName %>
    <h2>姓名:<%=name%></h2>

    <img src="./upload/<%=fileName%>">
    </body>
    </html>

    IPTimeStamp.java

    package kk.upload3;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Random;
    public class IPTimeStamp{

    private SimpleDateFormat sdf=null;
    private String ip=null;

    public IPTimeStamp(){

    }
    public IPTimeStamp(String ip){
    this.ip=ip;
    //System.out.println("ip="+ip);
    }

    //得到IP地址+时间戳+三位随机数
    public String getIPTimeRand(){

    StringBuffer buf=new StringBuffer();
    if(this.ip!=null){
    /*
    * 进行拆分操作
    * 在java中 代表转义字符 等,而 \ 代表一个反斜杠 而.代表一个元字符
    * 要表示一个.就需要用 要用.
    * 所以"\." 在实际编译中 就代表 .
    * */
    String s[]=this.ip.split("\.");
    for(int i=0;i<s.length;i++){

    //不够三位数字补0
    buf.append(this.addZero(s[i],3));
    }
    }
    //取得时间戳
    buf.append(this.getTimeStamp());
    Random r=new Random();
    for(int i=0;i<3;i++){

    buf.append(r.nextInt(10));
    }
    System.out.println("文件前缀==>"+buf.toString());
    return buf.toString();
    }

    private String addZero(String str,int len){

    StringBuffer s=new StringBuffer();
    s.append(str);
    while(s.length()<len){
    s.insert(0,"0");
    }
    //System.out.println(s);
    return s.toString();
    }

    public String getDate(){
    this.sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    return this.sdf.format(new Date());
    }

    public String getTimeStamp(){
    this.sdf=new SimpleDateFormat("yyyyMMddHHmmssSSS");
    return this.sdf.format(new Date());
    }

    }

    运行结果:

    问题:限制文件上传类型?

    比如验证上传文件后缀的合法性:

    //表示只允许后缀为jpg/gif的文件上传。

    if(smart.getFiles().getFile(0).getFileName().matches("^\w+\.(jpg|gif)$")){

    }

    4、批量上传

    对upload3.jsp文件进行如下更改,其他的都不用改变,

    <%@ page contentType="text/html" pageEncoding="utf-8"%>
    <%@ page import="com.jspsmart.upload.*"%>
    <%@ page import="kk.upload3.IPTimeStamp"%>
    <html>
    <head>
    <title>文件上传3</title>
    </head>
    <body>
    <%
    request.setCharacterEncoding("utf-8");
    SmartUpload smart=new SmartUpload();
    smart.initialize(pageContext);
    smart.upload();
    String name=smart.getRequest().getParameter("uname");
    IPTimeStamp its=new IPTimeStamp(request.getRemoteAddr());
    for(int x=0;x<smart.getFiles().getCount();x++){
    String ext=smart.getFiles().getFile(x).getFileExt();
    String fileName=its.getIPTimeRand()+"."+ext;
    smart.getFiles().getFile(x).saveAs(getServletContext().getRealPath("/")
    +"upload"+java.io.File.separator+fileName);
    }

    %>

    </body>
    </html>

    获得上传文件数量:smart.getFiles().getCount()。

    三、FileUpload上传组件的使用

    1、接收上传内容

      FileUpload的具体上传操作与SmartUpload相比有着很高的复杂度;FileUpload上传基本步骤如下:

      <1>创建磁盘工厂:DiskFileItemFactory factory=new DiskFileItemFactory();

      <2>创建处理工具:ServletFileUpload upload=new ServletFileUpload(factory);

      <3>设置上传文件大小:upload.setFileSizeMax(3145728);

      <4>接收全部内容:List<FileItem> items=upload.parseRequest(request);

      由于FileUpload会将所有上传的内容(包括文件和普通参数)一起接收,所以要依次判断每一次上传的内容是文件还是普通文本。在使用FileUpload接收时所有提交的内容都会通过upload.parseRequest()方法返回,然后在使用Iterator依次取出每一个提交内容。

    fileUpload.htm

    <html>
    <head>
    <title>文件上传</title>
    </head>
    <body>
    <form action="fileUpload.jsp" method="post" enctype="multipart/form-data">
    姓名:<input type="text" name="uname"><br>
    照片:<input type="file" name="pic"><br>
          <input type="submit" value="上传">
          <input type="reset" value="重置">
    </form>
    </body>
    </html>

    fileUpload.jsp

    <%@ page contentType="text/html" pageEncoding="utf-8"%>
    <%@ page import="java.util.*"%>
    <%@ page import="org.apache.commons.fileupload.disk.*"%>
    <%@ page import="org.apache.commons.fileupload.servlet.*"%>
    <%@ page import="org.apache.commons.fileupload.*"%>
    <html>
    <head>
    <title>文件上传2</title>
    </head>
    <body>
    <%

     DiskFileItemFactory factory=new DiskFileItemFactory();   //创建磁盘工厂
     ServletFileUpload upload=new ServletFileUpload(factory);  //创建处理工具
     upload.setFileSizeMax(3145728);   //设置最大上传大小为3MB

    upload.setHeaderEncoding("UTF-8");    //解决上传文件名的中文乱码

     List<FileItem> items=upload.parseRequest(request);    //接受全部内容
     Iterator<FileItem> iter=items.iterator(); //将全部的内容变成Iterator实例
     while(iter.hasNext()){
      FileItem item=iter.next(); //取出每一个上传的文件
      String fieldName=item.getFieldName(); //取得表单控件的名称
    %>
      
      <ul>
      <h4>表单控件名:<%=fieldName%>--><%=item.isFormField()%></h4>

    <%
      if(!item.isFormField()){  //不是普通的文本文件,是上传文件
       String fileName=item.getName(); //获取上传文件的文件名
       String contentType=item.getContentType();  //获得文件类型
       long sizeInBytes=item.getSize(); //获得文件的大小

    %>

       <li>上传文件名:<%=fileName%></li>
       <li>上传文件类型:<%=contentType%></li>
       <li>上传文件大小:<%=sizeInBytes%></li>

    <%

      }else{
       String value=item.getString();

    %>

       <li>普通参数:<%=value%></li>

    <%
      }
    %>
       </ul>

    <%
     }
     
    %>
    </body>
    </html>

      使用FileUpload组件接收完全部的数据后,所有的文件都保存在List集合中,所以需要Iterator来取出每一个数据,但由于其中包含普通的文本数据和上传的文件,每一个上传的内容都是用FileItem类对象表示,所以当时用迭代器取出每一个FileItem对象时就可以使用FileItem类中的isFormField()方法来判断当前操作的内容是普通的文本还是上传的文件,如果是上传的文件则将文件的内容依次取出;如果是普通的文本则直接通过getString()方法取得具体信息; 程序运行结果如下图:

    问题:乱码,我使用的是utf-8编码,保存jsp文件的时候也是将文件另存为utf-8编码,但是姓名如果输入中文就会显示乱码;

     2、以上所有的文件上传都是htm+jsp完成的,所有的Java代码都是写在jsp文件中,下面将使用jsp+Servlet完成文件上传。

    fileUpload2.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>
    <title>文件上传</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>

    <body>
    <h1>文件上传实例</h1>
    <form method="post" action="${pageContext.request.contextPath}/FileUpload/UploadServlet" enctype="multipart/form-data">
    上传用户:<input type="text" name="username" />
    <br/><br/>
    上传文件1:<input type="file" name="file1" />
    <br/><br/>
    上传文件2:<input type="file" name="file2" />
    <br/><br/>
    <input type="submit" value="上传" />
    </form>
    </body>
    </html>

    fileMessage2.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>文件上传结果</title>
    </head>
    <body>
    <center>
    <h2>${message}</h2>
    </center>
    </body>
    </html>

    UploadServlet.java文件

    package kk.fileUpload;

    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.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;


    public class UploadServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {

    //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
    String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
    File file = new File(savePath);
    //判断上传文件的保存目录是否存在
    if (!file.exists() && !file.isDirectory()) {

    System.out.println(savePath+"目录不存在,需要创建");
    //创建目录
    file.mkdir();
    }

    //消息提示
    String message = "";
    try {
    //使用Apache文件上传组件处理文件上传步骤:
    //1、创建一个DiskFileItemFactory工厂
    DiskFileItemFactory factory = new DiskFileItemFactory();
    //2、创建一个文件上传解析器
    ServletFileUpload upload = new ServletFileUpload(factory);
    //解决上传文件名的中文乱码
    upload.setHeaderEncoding("UTF-8");
    //3、判断提交上来的数据是否是上传表单的数据
    if(!ServletFileUpload.isMultipartContent(request)){

    //按照传统方式获取数据
    return;
    }
    //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
    List<FileItem> list = upload.parseRequest(request);
    for(FileItem item : list){
    //如果fileitem中封装的是普通输入项的数据
    if(item.isFormField()){
    String name = item.getFieldName();
    //解决普通输入项的数据的中文乱码问题
    String value = item.getString("UTF-8");
    //value = new String(value.getBytes("iso8859-1"),"UTF-8");
    System.out.println(name + "=" + value);
    }else{
    //如果fileitem中封装的是上传文件
    //得到上传的文件名称,
    String filename = item.getName();
    System.out.println(filename);
    if(filename==null || filename.trim().equals("")){
    continue;
    }
    //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:a1.txt,而有些只是单纯的文件名,如:1.txt
    //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
    filename = filename.substring(filename.lastIndexOf("\")+1);
    //获取item中的上传文件的输入流
    InputStream in = item.getInputStream();
    //创建一个文件输出流
    FileOutputStream out = new FileOutputStream(savePath + "\" + filename);
    //创建一个缓冲区
    byte buffer[] = new byte[1024];
    //判断输入流中的数据是否已经读完的标识
    int len = 0;
    //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
    while((len=in.read(buffer))>0){
    //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\" + filename)当中
    out.write(buffer, 0, len);
    }
    //关闭输入流
    in.close();
    //关闭输出流
    out.close();
    //删除处理文件上传时生成的临时文件
    item.delete();
    message = "文件上传成功!";
    }
    }
    }catch (Exception e) {
    message= "文件上传失败!";
    e.printStackTrace();

    }
    request.setAttribute("message",message);
    request.getRequestDispatcher("/fileMessage2.jsp").forward(request, response);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws ServletException, IOException {

    doGet(req, resp);
    }
    }

     web.xml

    <?xml version="1.0" encoding="utf-8"?>

    <!--
    Licensed to the Apache Software Foundation (ASF) under one or more
    contributor license agreements. See the NOTICE file distributed with
    this work for additional information regarding copyright ownership.
    The ASF licenses this file to You under the Apache License, Version 2.0
    (the "License"); you may not use this file except in compliance with
    the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
    -->

    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
    version="2.5">

    <display-name>Welcome to Tomcat</display-name>

    <servlet>
    <servlet-name>Uploadf</servlet-name>
    <servlet-class>kk.fileUpload.UploadServlet</servlet-class>
    </servlet>

    <servlet-mapping>
    <servlet-name>Uploadf</servlet-name>
    <url-pattern>/FileUpload/UploadServlet</url-pattern>
    </servlet-mapping>

    </web-app>

      问题:从Java Web(一)开始一直使用手工在Tomcat安装目录webapps中创建,没有实用工具,所以在编写上面UploadServlet.java文件的时候提示找不到相应的jar包(commons-fileupload-1.3.2.jar/commons-io-2.5.jar/servlet-api.jar)。

      解决办法:

      classpath:.;%CATALINA_HOME%/lib/servlet-api.jar;%CATALINA_HOME%/lib/commons-io-2.5.jar;%CATALINA_HOME%/lib/commons-fileupload-1.3.2.jar;.;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar

      经过以上配置成功编译class类文件,然后将class文件放在classes文件夹中(注意按照打包的层级存放)。

    运行结果如下:

    四、文件上传小结

      上述的代码虽然可以成功将文件上传到服务器上面的指定目录当中,但是文件上传功能有许多需要注意的小细节问题:

        

      1、为保证服务器安全,上传文件应该放在外界无法直接访问的目录下,比如放于WEB-INF目录下。

      2、为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名。

      3、为防止一个目录下面出现太多文件,要使用hash算法打散存储。

      4、要限制上传文件的最大值。

      5、要限制上传文件的类型,在收到上传文件名时,判断后缀名是否合法。

    将java文件按照以上要求更改如下:

    package kk.upload3;

    import javax.servlet.http.HttpServlet;
    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.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;
    public class UploadHandleServlet extends HttpServlet{

    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    //得到上传文件的保存目录,将上传的文件存放于WEB-INF目录下,不允许外界直接访问,保证上传文件的安全
    String savePath = this.getServletContext().getRealPath("/WEB-INF/upload");
    //上传时生成的临时文件保存目录
    String tempPath = this.getServletContext().getRealPath("/WEB-INF/temp");
    File tmpFile = new File(tempPath);
    if (!tmpFile.exists()) {
    //创建临时目录
    tmpFile.mkdir();
    }

    //消息提示
    String message = "";
    try{
    //使用Apache文件上传组件处理文件上传步骤:

    //1、创建一个DiskFileItemFactory工厂
    DiskFileItemFactory factory = new DiskFileItemFactory();

    /*
    * 设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。
    * 设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB
    * */

    factory.setSizeThreshold(1024*100);
    //设置上传时生成的临时文件的保存目录
    factory.setRepository(tmpFile);
    //2、创建一个文件上传解析器
    ServletFileUpload upload = new ServletFileUpload(factory);
    //监听文件上传进度
    upload.setProgressListener(new ProgressListener(){

    public void update(long pBytesRead, long pContentLength, int arg2) {

    System.out.println("文件大小为:" + pContentLength + ",当前已处理:" + pBytesRead);
    /**
    * 文件大小为:14608,当前已处理:4096
    * 文件大小为:14608,当前已处理:7367
    * 文件大小为:14608,当前已处理:11419
    * 文件大小为:14608,当前已处理:14608
    */
    }
    });
    //解决上传文件名的中文乱码
    upload.setHeaderEncoding("UTF-8");
    //3、判断提交上来的数据是否是上传表单的数据
    if(!ServletFileUpload.isMultipartContent(request)){
    //按照传统方式获取数据
    return;
    }

    //设置上传单个文件的大小的最大值,目前是设置为1024*1024字节,也就是1MB
    upload.setFileSizeMax(1024*1024);
    //设置上传文件总量的最大值,最大值=同时上传的多个文件的大小的最大值的和,目前设置为10MB
    upload.setSizeMax(1024*1024*10);
    //4、使用ServletFileUpload解析器解析上传数据,解析结果返回的是一个List<FileItem>集合,每一个FileItem对应一个Form表单的输入项
    List<FileItem> list = upload.parseRequest(request);
    for(FileItem item : list){
    //如果fileitem中封装的是普通输入项的数据
    if(item.isFormField()){
    String name = item.getFieldName();
    //解决普通输入项的数据的中文乱码问题
    String value = item.getString("UTF-8");
    //value = new String(value.getBytes("iso8859-1"),"UTF-8");
    System.out.println(name + "=" + value);
    }else{
    //如果fileitem中封装的是上传文件
    //得到上传的文件名称,
    String filename = item.getName();
    System.out.println(filename);
    if(filename==null || filename.trim().equals("")){
    continue;
    }

    //注意:不同的浏览器提交的文件名是不一样的,有些浏览器提交上来的文件名是带有路径的,如: c:a1.txt,而有些只是单纯的文件名,如:1.txt
    //处理获取到的上传文件的文件名的路径部分,只保留文件名部分
    filename = filename.substring(filename.lastIndexOf("\")+1);
    //得到上传文件的扩展名
    String fileExtName = filename.substring(filename.lastIndexOf(".")+1);
    //如果需要限制上传的文件类型,那么可以通过文件的扩展名来判断上传的文件类型是否合法
    System.out.println("上传的文件的扩展名是:"+fileExtName);
    //获取item中的上传文件的输入流
    InputStream in = item.getInputStream();
    //得到文件保存的名称
    String saveFilename = makeFileName(filename);
    //得到文件的保存目录
    String realSavePath = makePath(saveFilename, savePath);
    //创建一个文件输出流
    FileOutputStream out = new FileOutputStream(realSavePath + "\" + saveFilename);
    //创建一个缓冲区
    byte buffer[] = new byte[1024];
    //判断输入流中的数据是否已经读完的标识
    int len = 0;
    //循环将输入流读入到缓冲区当中,(len=in.read(buffer))>0就表示in里面还有数据
    while((len=in.read(buffer))>0){
    //使用FileOutputStream输出流将缓冲区的数据写入到指定的目录(savePath + "\" + filename)当中
    out.write(buffer, 0, len);
    }
    //关闭输入流
    in.close();
    //关闭输出流
    out.close();
    //删除处理文件上传时生成的临时文件
    //item.delete();
    message = "文件上传成功!";
    }
    }
    }catch (FileUploadBase.FileSizeLimitExceededException e) {
    e.printStackTrace();
    request.setAttribute("message", "单个文件超出最大值!!!");
    request.getRequestDispatcher("/message.jsp").forward(request, response);
    return;
    }catch (FileUploadBase.SizeLimitExceededException e) {
    e.printStackTrace();
    request.setAttribute("message", "上传文件的总的大小超出限制的最大值!!!");
    request.getRequestDispatcher("/message.jsp").forward(request, response);
    return;
    }catch (Exception e) {
    message= "文件上传失败!";
    e.printStackTrace();
    }
    request.setAttribute("message",message);
    request.getRequestDispatcher("/message.jsp").forward(request, response);
    }

    /**
    * @Method: makeFileName
    * @Description: 生成上传文件的文件名,文件名以:uuid+"_"+文件的原始名称
    * @Anthor:kk
    * @param filename 文件的原始名称
    * @return uuid+"_"+文件的原始名称
    */
    private String makeFileName(String filename){ //2.jpg
    //为防止文件覆盖的现象发生,要为上传文件产生一个唯一的文件名
    return UUID.randomUUID().toString() + "_" + filename;
    }

    /**
    * 为防止一个目录下面出现太多文件,要使用hash算法打散存储
    * @Method: makePath
    * @Description:
    * @Anthor:kk
    *
    * @param filename 文件名,要根据文件名生成存储目录
    * @param savePath 文件存储路径
    * @return 新的存储目录
    */
    private String makePath(String filename,String savePath){
    //得到文件名的hashCode的值,得到的就是filename这个字符串对象在内存中的地址
    int hashcode = filename.hashCode();
    int dir1 = hashcode&0xf; //0--15
    int dir2 = (hashcode&0xf0)>>4; //0-15
    //构造新的保存目录
    String dir = savePath + "\" + dir1 + "\" + dir2; //upload23 upload35
    //File既可以代表文件也可以代表目录
    File file = new File(dir);
    //如果目录不存在
    if(!file.exists()){
    //创建目录
    file.mkdirs();
    }
    return dir;
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    doGet(request, response);
    }
    }

    运行结果如下:

     

     

     

     

    6、开发FileUpload组件的专属操作类

      经过以上FileUpload组件的基本操作学习,可以发现仍有诸多不便;

      1>无法像使用request.getParameter()方法那样准确地取得提交的参数;

      2>无法像使用request.getParameterValues()方法那样准确地取得一组提交的参数;

      3>所有的上传文件都要依次判断,才能分别保存,不能一次性批量保存;

      如要解决以上问题则需要自己进行代码的扩充,编写一个FileUpload操作的工具类----FileUploadTools(会用即可)。

    五、文件下载

      

  • 相关阅读:
    一个具体的例子学习Java volatile关键字
    JavaScript实现的水果忍者游戏,支持鼠标操作
    记录我开发工作中遇到HTTP跨域和OPTION请求的一个坑
    微信程序开发系列教程(四)使用微信API创建公众号自定义菜单
    微信程序开发系列教程(三)使用微信API给微信用户发文本消息
    Java实现 LeetCode 547 朋友圈(并查集?)
    Java实现 LeetCode 547 朋友圈(并查集?)
    Java实现 LeetCode 547 朋友圈(并查集?)
    Java实现 LeetCode 546 移除盒子(递归,vivo秋招)
    Java实现 LeetCode 546 移除盒子(递归,vivo秋招)
  • 原文地址:https://www.cnblogs.com/iamkk/p/5834332.html
Copyright © 2020-2023  润新知