JAVA EE-文件上傳

JAVA EE-文件上傳

應該相信,自己是生活的戰勝者。 —— 雨果

文件下載

首先我們複習一下文件下載的內容

靜態下載
public class AServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
            //1 準備工作
                //設置content-type
            response.setContentType(getServletContext().getMimeType("xxx.zip"));
                //添加響應頭 content-disposition
            response.setHeader("Content-Disposition", "attachment;filename=apache-tomcat-6.0.35.zip");  
            //2 獲得輸入流
            InputStream is
              = getServletContext().getResourceAsStream("/WEB-INF/apache-tomcat-6.0.35.zip");
            //3 獲得輸出流
            OutputStream os = response.getOutputStream();
            //4 兩個流對接
            IOUtils.copy(is, os);

    }

}
根據用戶的選擇來獲取下載

JSP文件:

 <body>
    <a href="/day12-download/AServlet" >點擊下載</a><br>
    <a href="/day12-download/BServlet?name=apache-tomcat-6.0.35.zip" >apache-tomcat-6.0.35.zip</a><br>
    <a href="/day12-download/BServlet?name=激活軟件_v10.0.0.exe" >激活軟件_v10.0.0.exe</a><br>
  </body>

業務處理的Servlet

public class BServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //1 獲得參數,拿到用戶需要下載的文件名稱
        String fileName = request.getParameter("name");
        fileName = new String(fileName.getBytes("ISO-8859-1"),"UTF-8");
        //2 準備工作
        //設置content-type
        response.setContentType(getServletContext().getMimeType(fileName));
            //添加響應頭 content-disposition
        response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(fileName, "UTF-8")); 
        //2 獲得輸入流
        InputStream is
          = getServletContext().getResourceAsStream("/WEB-INF/"+fileName);
        //3 獲得輸出流
        OutputStream os = response.getOutputStream();
        //4 兩個流對接
        IOUtils.copy(is, os);
        //關閉輸出流
        is.close();
        os.close();
    }

}

下載的亂碼問題

客戶端的超連接中如果包含了中文,會出現get請求方式亂碼問題

            <a href="${pageContext.request.contextPath}/download?filename=天空.mp3">下載王非天空.mp3</a>
                    String filename = request.getParameter("name"); // yog.rar / 她說.mp3
                    byte[] b = filename.getBytes("ISO-8859-1");
                    filename = new String(b,"UTF-8");
                    實際上Get提交時包含中文亂碼的解決。

如果下載文件名稱中出現了中文亂碼問題

            <a href="${pageContext.request.contextPath}/download?filename=天空.mp3">下載王非天空.mp3</a>
                    String filename = request.getParameter("name"); // yog.rar / 她說.mp3
                    byte[] b = filename.getBytes("ISO-8859-1");
                    filename = new String(b,"UTF-8");
                    實際上Get提交時包含中文亂碼的解決。

文件上傳

  • 爲什麼使用文件上傳?

    • 例如社交網站需要提供用戶照片.
    • 很多企業內部,商品網站維護時需要上傳一些文件
    • 郵箱需要上傳附件….
  • 文件上傳的操作

    • 請求方式必須是post
    • 需要使用組件
    • 表單必須設置encType=”multipart/form-data”
    • 上傳文件的input 中,name屬性必須要填寫,不然不會上傳.

這樣一來,通過request對象,獲取InputStream,可以將瀏覽器提交的所有請求正文讀取到.

文件上傳需要的插件

    commons-fileupload 它是常用的一個文件上傳工具

    使用時要導入兩個jar包
        commons-fileupload-1.2.1.jar
        commons-io-1.4.jar

一個上傳的瀏覽器端代碼

  <body>
    <!-- 
    1.文件上傳,表單必須是post提交
    2.文件上傳,還需要在表單上加上enctype屬性(提交請求正文的類型)
            *application/x-www-form-urlencoded(默認取值,普通提交)
            *multipart/form-data(多段式提交)
    3.  文件上傳,使用<input type="file" name="photo" /> 標籤,並且必須有name屬性
     -->
    <form action="/day12-upload/BServlet"  method="post" encType="multipart/form-data"  > 
        用戶名:<input type="text" name="name" /><br>
        個人近照:<input type="file" name="photo" /><br>
        <input type="submit" value="上傳"  />
    </form>
  </body>

下面演示如何使用第三方的jar包來優化文件上傳處理

public class BServlet extends HttpServlet {
    //使用文件上傳工具類(第三方)
    // 導包  => commons-fileupload-1.2.1.jar
    //     => commons-io-1.4.jar

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

        // 1 創建配置工廠
        DiskFileItemFactory factory = new DiskFileItemFactory();

        //2 根據配置工廠創建解析請求中文件上傳內容的解析器
        ServletFileUpload upload = new ServletFileUpload(factory);

        //3 判斷當前請求是否是多段式提交
        if(!upload.isMultipartContent(request)){
            //普通表單提交
            throw new RuntimeException("不是多段式提交!");
        }

        try {
        //4 解析request對象
            List<FileItem>  list = upload.parseRequest(request);
            if(list!=null){
                for(FileItem item : list){
                    //判斷當前上傳段是普通字段,還是文件上傳
                    if(!item.isFormField()){//文件上傳段
                        String fName = item.getFieldName();

                        InputStream is = item.getInputStream();//獲得文件上傳段中,文件的流

                        FileOutputStream fos = new FileOutputStream("d://upload/xxx.jpg");

                        IOUtils.copy(is, fos);

                        fos.close();

                    }else{//普通字段段
                        String name = item.getFieldName();
                        String value = item.getString();

                        System.out.println(name+"==>"+value);

                    }

                }
            }

        } catch (FileUploadException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


    }

}

文件上傳段與普通表單段的區別如下
這裏寫圖片描述

fileupload工具類詳解

public class CServlet extends HttpServlet {
    //fileupload 工具類使用詳解
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    //1 創建配置工廠=> 有參的構造可以 直接設置下面兩個配置
        DiskFileItemFactory factory  = new DiskFileItemFactory();
    //1.1 設置文件上傳臨時目錄 => 默認位置 => tomcat/temp
        factory.setRepository(new File("d:/temp"));
    //1.2 設置文件寫入硬盤的緩衝區大小=>默認值=>10k
        factory.setSizeThreshold(10240);
    //2 根據配置工廠創建解析器(解析request對象)
        ServletFileUpload upload = new ServletFileUpload(factory);
    //2.1 判斷當前請求是否是多段式提交
        upload.isMultipartContent(request);
    //2.2 設置多段中每段 段頭 在解析時,使用什麼碼錶解碼 => 當段頭中出現中文時,一定要調用該方式指定段頭碼錶
        upload.setHeaderEncoding("UTF-8");
    //2.3 設置文件最大上傳大小 (單位:字節)
        upload.setSizeMax(1024*1024*10); //單次請求,總上傳大小限制  10兆
        upload.setFileSizeMax(1024*1024);// 每個文件上傳段,大小限制 1兆
        List<FileItem> list = null;
        try {
            //2.4 解析request,將每個分段中的內容封裝到FileItem中
            list = upload.parseRequest(request);
        } catch (FileUploadException e) {
            e.printStackTrace();
        }
        if(list!=null){
            for(FileItem item : list){
            //3.1 item 判斷當前分段是否是普通表單段
                    boolean flag = item.isFormField();
                    //普通段
                    //3.2獲得 表單提交的鍵.(input元素,name屬性的值)
                    String fname = item.getFieldName();
                    //3.3 返回文件名稱
                    String  name = item.getName();
                    //3.4 獲得文件上傳中的正文
                    //item.getInputStream();
                    //3.5 以字符串形式返回段體中的內容 注意:文件上傳段不建議使用該方法. 
                    String content= item.getString();
                    //3.6  刪除上傳的臨時文件
                    item.delete();
                    System.out.println("是否是普通表單提交:"+flag+",表單提交的鍵:"+fname+",文件名稱:"+name+",文件內容:"+content);
            }

        }
    }

}

關於亂碼問題的研究
當上傳的文件名中有中文時,如果碼錶不當就會造成亂碼問題的產生。

public class DServlet extends HttpServlet {
    //上傳文件名稱是中文,亂碼問題
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 1 創建配置工廠
                DiskFileItemFactory factory = new DiskFileItemFactory();
        //2 根據配置工廠創建解析請求中文件上傳內容的解析器
                ServletFileUpload upload = new ServletFileUpload(factory);

            //解決文件名稱中文亂碼
                upload.setHeaderEncoding("UTF-8");
                //3 判斷當前請求是否是多段式提交
                if(!upload.isMultipartContent(request)){
                    //普通表單提交
                    throw new RuntimeException("不是多段式提交!");
                }

                try {
                //4 解析request對象
                    List<FileItem>  list = upload.parseRequest(request);
                    if(list!=null){
                        for(FileItem item : list){
                            //判斷當前上傳段是普通字段,還是文件上傳
                            if(!item.isFormField()){//文件上傳段

                                String fileName = item.getName();

                                System.out.println(fileName);
                            }
                        }
                    }

                } catch (FileUploadException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

    }

}

設置上傳文件的最大大小

public class FServlet extends HttpServlet {

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // 1 創建配置工廠
        DiskFileItemFactory factory = new DiskFileItemFactory();
//2 根據配置工廠創建解析請求中文件上傳內容的解析器
        ServletFileUpload upload = new ServletFileUpload(factory);
        //設置文件上傳大小限制
        upload.setFileSizeMax(1024);

        try {
            upload.parseRequest(request);
        } catch (FileUploadException e) {
            e.printStackTrace();
            throw new RuntimeException("文件大小不能超過1kb!");
        }
}

}
        可以設置上傳文件大小,如果超過設置大小.將會拋出異常(默認沒有最大值)
            void setFileSizeMax(long fileSizeMax) 設置單個文件上傳大小 
            void  setSizeMax(long sizeMax) 設置總文件上傳大小 

如何實現保存的文件名不會重複

public class GServlet extends HttpServlet {
    //如果將文件全部保存 => 保證文件名稱不能重複
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 1 創建配置工廠
        DiskFileItemFactory factory = new DiskFileItemFactory();

        //2 根據配置工廠創建解析請求中文件上傳內容的解析器
        ServletFileUpload upload = new ServletFileUpload(factory);

        //3 判斷當前請求是否是多段式提交
        if(!upload.isMultipartContent(request)){
            //普通表單提交
            throw new RuntimeException("不是多段式提交!");
        }

        try {
        //4 解析request對象
            List<FileItem>  list = upload.parseRequest(request);
            if(list!=null){
                for(FileItem item : list){
                    //判斷當前上傳段是普通字段,還是文件上傳
                    if(!item.isFormField()){//文件上傳段
                        String fName = item.getFieldName();

                        InputStream is = item.getInputStream();//獲得文件上傳段中,文件的流

                        //保存之前,生成文件名稱( 保證永遠不重複)
                        //生成隨機字符串即可
                        String fileName = UUID.randomUUID().toString();

                        FileOutputStream fos = new FileOutputStream("d:/upload/"+fileName);

                        IOUtils.copy(is, fos);

                        fos.close();

                    }
                }
            }

        } catch (FileUploadException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



    }

}

如何防止同一個目錄之下上傳文件數量過多?

public class HServlet extends HttpServlet {
    //如何將上傳文件分目錄保存
    // 使用登錄用戶的用戶名 來創建不同的文件夾. 每個用戶上傳的文件就放到自己的文件夾中
    // 按照日期分目錄=> d:/upload/2015/08/24/
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // 1 創建配置工廠
        DiskFileItemFactory factory = new DiskFileItemFactory();

        //2 根據配置工廠創建解析請求中文件上傳內容的解析器
        ServletFileUpload upload = new ServletFileUpload(factory);

        //3 判斷當前請求是否是多段式提交
        if(!upload.isMultipartContent(request)){
            //普通表單提交
            throw new RuntimeException("不是多段式提交!");
        }

        try {
        //4 解析request對象
            List<FileItem>  list = upload.parseRequest(request);
            if(list!=null){
                for(FileItem item : list){
                    //判斷當前上傳段是普通字段,還是文件上傳
                    if(!item.isFormField()){//文件上傳段
                        String fName = item.getFieldName();

                        InputStream is = item.getInputStream();//獲得文件上傳段中,文件的流

                        // 生成日期目錄
                        //1 獲得當前日期=>目錄結構 的 路徑
                        SimpleDateFormat format = new SimpleDateFormat("/yyyy/MM/dd/");
                        String datepath = format.format( new Date()); //    /2015/08/24/
                        //拼接完整保存目錄路徑
                        String wholePath = "d:/upload"+datepath;// d:/upload/2015/08/24/

                        //確保文件夾存在
                        File directory = new File(wholePath);
                        if(!directory.exists()){//如果文件夾結構不存在
                            directory.mkdirs(); //創建文件夾結構
                        }

                        //保存之前,生成文件名稱( 保證永遠不重複)
                        //生成隨機字符串即可
                        String fileName = UUID.randomUUID().toString();

                        FileOutputStream fos = new FileOutputStream(wholePath+fileName);

                        IOUtils.copy(is, fos);

                        fos.close();

                    }
                }
            }

        } catch (FileUploadException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }



    }

}
發佈了36 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章