[原创]hava基础巩固之Java实现文件上传_Tomcat, WebLogic及J2EE讨论区_Weblogic技术|Tuxedo技术|中间件技术|Oracle论坛|JAVA论坛|Linux/Unix技术|hadoop论坛_联动北方技术论坛  
网站首页 | 关于我们 | 服务中心 | 经验交流 | 公司荣誉 | 成功案例 | 合作伙伴 | 联系我们 |
联动北方-国内领先的云技术服务提供商
»  游客             当前位置:  论坛首页 »  自由讨论区 »  Tomcat, WebLogic及J2EE讨论区 »
总帖数
3
每页帖数
101/1页1
返回列表
0
发起投票  发起投票 发新帖子
查看: 2485 | 回复: 2   主题: [原创]hava基础巩固之Java实现文件上传        下一篇 
heli.jia
注册用户
等级:少校
经验:874
发帖:21
精华:0
注册:1970-1-1
状态:离线
发送短消息息给heli.jia 加好友    发送短消息息给heli.jia 发消息
发表于: IP:您无权察看 2016-3-30 16:36:43 | [全部帖] [楼主帖] 楼主

对于文件上传,浏览器在上传的过程中是将文件以流的形式提交到服务器端的,如果直接使用Servlet获取上传文件的输入流然后再解析里面的请求参数是比较麻烦,所以一般选择采用apache的开源工具common-fileupload这个文件上传组件。这个common-fileupload上传组件的jar包可以去apache官网上面下载,也可以在struts的lib文件夹下面找到,struts上传的功能就是基于这个实现的。common-fileupload是依赖于common-io这个包的,所以还需要下载这个包。

如下两个jar包:

jar包.png


接下来就是实现文件上传

1.先写两个jsp页面,作为上传页面(upload.jsp)和消息提示页面(message.jsp),如下代码所示:

upload.jsp:

<%@ page language="java" pageEncoding="UTF-8"%>

<!DOCTYPE HTML>

<html>

  <head>

    <title>文件上传</title>

  </head>

  

  <body>

    <form action="${pageContext.request.contextPath}/servlet/UploadHandleServlet" enctype="multipart/form-data" method="post">

        上传用户:<input type="text" name="username"><br/>

        上传文件1:<input type="file" name="file1"><br/>

        上传文件2:<input type="file" name="file2"><br/>

        <input type="submit" value="提交">

    </form>

  </body>

</html>


message.jsp:

<%@ page language="java" pageEncoding="UTF-8"%>

<!DOCTYPE HTML>

<html>

  <head>

    <title>消息提示</title>

  </head>

  

  <body>

        ${message}

  </body>

</html>


2.处理文件上传的severlet(uploadhandleseverlet)代码如下:

package me.gacl.web.controller;


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 UploadHandleServlet extends HttpServlet {


    public void doGet(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:\a\b\1.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("/message.jsp").forward(request, response);

    }


    public void doPost(HttpServletRequest request, HttpServletResponse response)

            throws ServletException, IOException {


        doGet(request, response);

    }

}


3.在web.xml文件中注册uploadhandleseverlet

<servlet>

    <servlet-name>UploadHandleServlet</servlet-name>

    <servlet-class>me.gacl.web.controller.UploadHandleServlet</servlet-class>

</servlet>


<servlet-mapping>

    <servlet-name>UploadHandleServlet</servlet-name>

    <url-pattern>/servlet/UploadHandleServlet</url-pattern>

</servlet-mapping>


文件上传成功后,保存在WEB-INF下的upload目录里。


4.文件上传需要注意的一些细节:

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

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

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

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

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

所以对severlet进行改进后的代码如下:

package me.gacl.web.controller;


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

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();

                    //设置工厂的缓冲区的大小,当上传的文件大小超过缓冲区的大小时,就会生成一个临时文件存放到指定的临时目录当中。

                    factory.setSizeThreshold(1024*100);//设置缓冲区的大小为100KB,如果不指定,那么缓冲区的大小默认是10KB

                    //设置上传时生成的临时文件的保存目录

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

                           

                        }

                    });

                     //解决上传文件名的中文乱码

                    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:\a\b\1.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);

    }

    

     

    private String makeFileName(String filename){  //2.jpg

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

        return UUID.randomUUID().toString() + "_" + filename;

    }

    

     

    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;  //upload\2\3  upload\3\5

        //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);

    }

}









赞(0)    操作        顶端 
arcona
注册用户
等级:少校
经验:1100
发帖:10
精华:0
注册:2015-6-1
状态:离线
发送短消息息给arcona 加好友    发送短消息息给arcona 发消息
发表于: IP:您无权察看 2016-4-14 9:12:27 | [全部帖] [楼主帖] 2  楼

很强大,感谢分享~



赞(0)    操作        顶端 
ruiyu.yu
注册用户
等级:少尉
经验:331
发帖:15
精华:0
注册:1970-1-1
状态:离线
发送短消息息给ruiyu.yu 加好友    发送短消息息给ruiyu.yu 发消息
发表于: IP:您无权察看 2016-10-21 17:18:20 | [全部帖] [楼主帖] 3  楼

学习了。



赞(0)    操作        顶端 
总帖数
3
每页帖数
101/1页1
返回列表
发新帖子
请输入验证码: 点击刷新验证码
您需要登录后才可以回帖 登录 | 注册
技术讨论