Web 基礎(chǔ)26 文件上傳概述及其入門(mén)案例

1.1 文件上傳概述

  • 文件上傳
    • 用戶將本地文件通過(guò)網(wǎng)絡(luò)上傳至服務(wù)器的過(guò)程
  • 應(yīng)用場(chǎng)景
    • 相親網(wǎng)站的照片上傳
    • 招聘網(wǎng)站的簡(jiǎn)歷上傳
  • 文件上傳的技術(shù)
名稱 描述
jspSmartUpload 應(yīng)用在jsp上的文件上傳和文件下載的組件
fileupload 應(yīng)用在java上的文件上傳技術(shù)干发,由Apache開(kāi)源組織提供
servlet3.0 提供了文件上傳的技術(shù)
Struts 提供了文件上傳的技術(shù)
  • 文件上傳的條件
    • 需要有一個(gè)表單
    • 表單的method屬性的值必須設(shè)置為post
    • 表單的enctype屬性的值需要設(shè)置為multipart/form-data
    • 表單需要有一個(gè)input標(biāo)簽
      • input標(biāo)簽type屬性的值需要設(shè)置為file
      • input標(biāo)簽需要有name屬性和值

1.2 JSP編寫(xiě)

  • 一些屬性的注釋
    • enctype:encode type 編碼類型:屬性規(guī)定了發(fā)送服務(wù)器之前如何對(duì)表單數(shù)據(jù)進(jìn)行編碼
    • application/x-www-form-urlencoded %WE%RT 默認(rèn)對(duì)表單數(shù)據(jù)進(jìn)行url編碼,不能用于文件上傳
    • multipart/form-data:表單數(shù)據(jù)有多個(gè)部分組成:既有文本數(shù)據(jù),還有文件,圖片這些二進(jìn)制數(shù)據(jù)設(shè)置之后,瀏覽器會(huì)將文件以二進(jìn)制的方式上傳,可以實(shí)現(xiàn)多種類型的文
      件上傳
<%@ 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>Insert title here</title>
</head>
<body>
    <h1>文件上傳</h1>
    
    <form action="${pageContext.request.contextPath}/UploadServlet" method="post" enctype="multipart/form-data">
        文件信息:<input type="text" name="info"/>
        <br />
        用戶名:<input type="text" name="username"/>
        <br />
        文件:<input type="file" name="file01" />
        <br />
        文件2:<input type="file" name="file02" />
        <br />
        <input type="submit" value="上傳"/>
    </form>
</body>
</html>

1.3 Servlet的編寫(xiě)

  • 編寫(xiě)流程
    • 創(chuàng)建一個(gè)磁盤(pán)文件的工廠對(duì)象
    • 創(chuàng)建文件上傳的核心對(duì)象
    • 通過(guò)核心對(duì)象解析請(qǐng)求對(duì)象得到一個(gè)集合對(duì)象,他里面包含所有的表單項(xiàng)對(duì)象
    • 遍歷這個(gè)集合對(duì)象,得到每一個(gè)表單項(xiàng),判斷他是否是普通表單項(xiàng)
    • 如果是普通的表單項(xiàng),獲取他的name和value的值
    • 如果不是,創(chuàng)建IO流傳輸
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //獲取表單所提交的數(shù)據(jù)
        //創(chuàng)建磁盤(pán)文件的工廠對(duì)象
        DiskFileItemFactory dfif = new DiskFileItemFactory();
        //創(chuàng)建文件上傳的核心對(duì)象
        ServletFileUpload upload = new ServletFileUpload(dfif);
        //解析請(qǐng)求對(duì)象臊旭,獲取表單所提交的數(shù)據(jù)
        List<FileItem> items = null;
        try {
            items = upload.parseRequest(request);
        } catch (FileUploadException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        //遍歷集合對(duì)象
        if(items != null) {
            for (FileItem fileItem : items) {
                //判斷表單項(xiàng)是否是普通的表單項(xiàng)
                if(fileItem.isFormField()) {
                    //確定是普通的表單項(xiàng)
                    //獲取普通表單項(xiàng)name屬性的值
                    String fieldName = fileItem.getFieldName();
                    //獲取普通表單項(xiàng)value屬性的值
                    String fieldValue = fileItem.getString("UTF-8");
                    System.out.println(fieldName + "=" + fieldValue);
                }
                else {
                    //文件上傳的表單項(xiàng)
                    //獲取文件名稱
                    String fileName = fileItem.getName();
                    //獲取文件的內(nèi)容
                    InputStream is = fileItem.getInputStream();
                    /*byte[] bys = new byte[1024];
                    int len = 0;
                    while((len = is.read(bys)) != -1) {
                        System.out.println(new String(bys,0,len));
                    }*/
                    
                    String realPath = getServletContext().getRealPath("/file");
                    File file = new File(realPath);
                    if(!file.exists()) {
                        //目錄不存在,則要?jiǎng)?chuàng)建
                        file.mkdirs();
                    }
                    //創(chuàng)建輸出流對(duì)象
                    OutputStream os = new FileOutputStream(realPath + "/" + fileName);
                    byte[] bys = new byte[1024];
                    int len = 0;
                    while((len = is.read(bys)) != -1) {
                        os.write(bys, 0, len);
                    }
                    
                    os.close();
                    
                }
        
            }
        }
    }

1.4 DiskFileItemFactory的常用API

方法 描述
void setSizeThreshold(int sizeThreshold) 設(shè)置緩沖區(qū)大小
void setRepository(java.io.File repository) 設(shè)置臨時(shí)目錄
DiskFileItemFactory dfif = new DiskFileItemFactory();
// 設(shè)置緩沖區(qū)大小
dfif.setSizeThreshold(1024 * 1024 * 6);// 6M
// 設(shè)置臨時(shí)目錄
String tempPath = getServletContext().getRealPath("/temp");
File temp = new File(tempPath);
if (!temp.exists()) {
    temp.mkdirs();
}

dfif.setRepository(temp);

  • 注意:
    • 如果上傳的文件不是很大,先走緩沖區(qū)
    • 如果上傳文件比較大,超過(guò)緩沖區(qū)的大小,就不走緩沖區(qū)了,他會(huì)把文件先上傳到臨時(shí)目錄中,再把臨時(shí)目錄中的臨時(shí)文件復(fù)制到file目錄中
    • 需要把整個(gè)文件上傳工作完成之后才把臨時(shí)文件復(fù)制到我們指定的File目錄中
    • 需要先把Tomcat關(guān)掉才能手動(dòng)刪掉temp里面的文件
    • 臨時(shí)文件臨時(shí)目錄的作用 是做一些續(xù)傳的操作

1.5 ServletFileUpload的常用API

方法 描述
static boolean isMultipartContent(javax.servlet.http.HttpServletRequest request) 用來(lái)判斷表單 link-tap的屬性值是否是mutipart 是返回ture 否則返回 false
public void setFileSizeMax(long fileSizeMax) 設(shè)置一個(gè)請(qǐng)求中單個(gè)文件的大小
public void setSizeMax(long sizeMax) 設(shè)置一個(gè)請(qǐng)求中所有文件的總大小
boolean flag = ServletFileUpload.isMultipartContent(request);
if (!flag) {
    request.setAttribute("msg", "表單提交數(shù)據(jù)的方式錯(cuò)誤晌缘!");
    request.getRequestDispatcher("/upload.jsp").forward(request,
            response);
    return;
}

ServletFileUpload upload = new ServletFileUpload(dfif);
// 設(shè)置文件的大小
upload.setFileSizeMax(1024 * 1024 * 40);//40M
// 設(shè)置請(qǐng)求中所有文件的總大小
upload.setSizeMax(1024 * 1024 * 40);//40M
  • 注意:
    • 工廠對(duì)象既可以通過(guò)構(gòu)造方法傳遞,也可以通過(guò)他所對(duì)應(yīng)的set方法傳遞

1.7 FileItem的常用API

方法 描述
long getSize() 獲取表單上傳文件的大小
void delete() 刪除臨時(shí)文件
void write(java.io.File file) 直接寫(xiě)一個(gè)文件

1.8 上傳Servlet 改寫(xiě)

protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
            // 判斷表單提交數(shù)據(jù)的方式是否正確
            boolean flag = ServletFileUpload.isMultipartContent(request);
            if (!flag) {
                request.setAttribute("msg", "表單提交數(shù)據(jù)的方式錯(cuò)誤饰豺!");
                request.getRequestDispatcher("/upload.jsp").forward(request,
                        response);
                return;
            }
    
            // 實(shí)現(xiàn)文件上傳的功能
            DiskFileItemFactory dfif = new DiskFileItemFactory();
            // 設(shè)置緩沖區(qū)大小
            dfif.setSizeThreshold(1024 * 1024 * 6);// 6M
            // 設(shè)置臨時(shí)目錄
            String tempPath = getServletContext().getRealPath("/temp");
            File temp = new File(tempPath);
            if (!temp.exists()) {
                temp.mkdirs();
            }
    
            dfif.setRepository(temp);
    
            ServletFileUpload upload = new ServletFileUpload(dfif);
            // 設(shè)置文件的大小
            // upload.setFileSizeMax(1024 * 1024 * 40);//40M
            // 設(shè)置請(qǐng)求中所有文件的總大小
            // upload.setSizeMax(1024 * 1024 * 40);//40M
            List<FileItem> items = null;
            try {
                items = upload.parseRequest(request);
            } catch (FileUploadException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (items != null) {
                for (FileItem fileItem : items) {
                    if (fileItem.isFormField()) {
                        String fieldName = fileItem.getFieldName();
                        String fieldValue = fileItem.getString("UTF-8");
                        System.out.println(fieldName + "=" + fieldValue);
                    } else {
                        //獲取表單上傳文件的大小
                        long size = fileItem.getSize();
                        if(size > 0) {
                            String fileName = fileItem.getName();
                            /*InputStream is = fileItem.getInputStream();
                            String realPath = getServletContext().getRealPath("/file");
                            File file = new File(realPath);
                            if (!file.exists()) {
                                file.mkdirs();
                            }
        
                            OutputStream os = new FileOutputStream(realPath + "/" + fileName);
                            byte[] bys = new byte[1024];
                            int len = 0;
                            while ((len = is.read(bys)) != -1) {
                                os.write(bys, 0, len);
                            }
                            //關(guān)閉輸入流亿鲜,刪除臨時(shí)文件需要
                            is.close();
                            os.close();*/
                            String realPath = getServletContext().getRealPath("/file");
                            File file = new File(realPath);
                            if (!file.exists()) {
                                file.mkdirs();
                            }
                            //File uploadFile = new File(file,fileName);
                            try {
                                fileItem.write(new File(file,fileName));
                            } catch (Exception e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
        
                        }
                    }
                    //刪除臨時(shí)文件
                    fileItem.delete();
                }
    
            }

    }



最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市冤吨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饶套,老刑警劉巖漩蟆,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異妓蛮,居然都是意外死亡怠李,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)蛤克,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)捺癞,“玉大人,你說(shuō)我怎么就攤上這事构挤∷杞椋” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵筋现,是天一觀的道長(zhǎng)唐础。 經(jīng)常有香客問(wèn)我箱歧,道長(zhǎng),這世上最難降的妖魔是什么一膨? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任呀邢,我火速辦了婚禮,結(jié)果婚禮上豹绪,老公的妹妹穿的比我還像新娘价淌。我一直安慰自己,他們只是感情好瞒津,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布输钩。 她就那樣靜靜地躺著,像睡著了一般仲智。 火紅的嫁衣襯著肌膚如雪买乃。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,754評(píng)論 1 307
  • 那天钓辆,我揣著相機(jī)與錄音剪验,去河邊找鬼。 笑死前联,一個(gè)胖子當(dāng)著我的面吹牛功戚,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播似嗤,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼啸臀,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了烁落?” 一聲冷哼從身側(cè)響起乘粒,我...
    開(kāi)封第一講書(shū)人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎伤塌,沒(méi)想到半個(gè)月后灯萍,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡每聪,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年旦棉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片药薯。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡绑洛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出童本,到底是詐尸還是另有隱情真屯,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布巾陕,位于F島的核電站讨跟,受9級(jí)特大地震影響纪他,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜晾匠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一茶袒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凉馆,春花似錦薪寓、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至嗦董,卻和暖如春母谎,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背京革。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工奇唤, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人匹摇。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓咬扇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親廊勃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子懈贺,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355