JavaWeb - 文件的上傳鸯两,核心API的使用闷旧,文件下載,注解(jdk的注解甩卓、自定義注解)

轉(zhuǎn)載請(qǐng)注明出處:http://www.reibang.com/p/9719cbc8f164

第一部分:文件的上傳

1鸠匀、什么是文件的上傳

1.1 把本地的文件存儲(chǔ)到服務(wù)器上,這個(gè)過(guò)程稱為文件的上傳逾柿。比如,網(wǎng)盤(pán)宅此、qq空間

1.2 實(shí)現(xiàn)文件的上傳
(1)jspSmartUpload:應(yīng)用在jsp的模型一
= 適于嵌入執(zhí)行上傳下載操作的JSP文件中

(2)fileUpload:應(yīng)用在jsp的模型二(mvc)
= FileUpload 是 Apache commons下面的一個(gè)子項(xiàng)目
= 組件FileUpload依賴于Commons IO組件
= 導(dǎo)入jar包(有兩個(gè)jar包)

(3)要想使用第三方的技術(shù)實(shí)現(xiàn)文件的上傳机错,首先導(dǎo)入jar包

1.3 要想使用文件的上傳,滿足三個(gè)要求
第一個(gè)要求:表單父腕,提交方式是post
    = get提交方式:地址欄會(huì)攜帶數(shù)據(jù)弱匪,get大小有限制

第二個(gè)要求:在表單里面有文件上傳項(xiàng),必須有name屬性 <input type="file" name="filename"/>

第三個(gè)要求:在form里面璧亮,設(shè)置一個(gè)屬性值 enctype萧诫,設(shè)置為multipart/form-data

2、使用代碼實(shí)現(xiàn)文件的上傳

2.1 文件上傳代碼實(shí)現(xiàn)的步驟(固定)
第一步:創(chuàng)建磁盤(pán)文件項(xiàng)工廠
= new DiskFileItemFactory();
第二步:創(chuàng)建核心上傳類
= new ServletFileUpload(FileItemFactory fileItemFactory);
第三步:使用核心上傳類解析request對(duì)象
= parseRequest(javax.servlet.http.HttpServletRequest request)
= 返回的List集合枝嘶,集合里面有多個(gè)FileItem帘饶,List<FileItem>
第四步:遍歷list集合,得到每個(gè)FileItem
第五步:判斷是普通輸入項(xiàng)還是文件上傳項(xiàng)
= boolean isFormField()
第六步:如果是普通輸入項(xiàng)得到值群扶;如果是文件上傳項(xiàng)編寫(xiě)上傳的代碼
= 普輸入項(xiàng)
== getFieldName():得到普通輸入項(xiàng)name的屬性的值
== getString():得到普通輸入項(xiàng)里面輸入的值
= 文件上傳項(xiàng)
== 得到通過(guò)表單提交過(guò)了的文件的輸入流及刻,getInputStream()
== 創(chuàng)建輸出流镀裤,把文件的輸入流寫(xiě)到服務(wù)器的一個(gè)文件中

3、核心api的使用

3.1 DiskFileItemFactory:磁盤(pán)文件項(xiàng)工廠
(1)構(gòu)造方法
= DiskFileItemFactory(int sizeThreshold, java.io.File repository)
== 有兩個(gè)參數(shù):
== 第一個(gè)參數(shù)設(shè)置上傳文件的緩沖區(qū)的大薪煞埂暑劝;
== 第二個(gè)參數(shù)是如果上傳文件超出了緩沖區(qū),產(chǎn)生臨時(shí)文件颗搂,設(shè)置臨時(shí)文件路徑

= DiskFileItemFactory()
== setSizeThreshold(int sizeThreshold):設(shè)置上傳文件的緩沖區(qū)的大小
== setRepository(java.io.File repository):設(shè)置臨時(shí)文件路徑


3.2 ServletFileUpload:核心上傳類
(1)構(gòu)造方法
= ServletFileUpload(FileItemFactory fileItemFactory)

(2)普通方法
= parseRequest(javax.servlet.http.HttpServletRequest request):解析request對(duì)象
返回List集合担猛,集合里面每個(gè)部分是FileItem

= setHeaderEncoding(java.lang.String encoding):設(shè)置上傳文件名稱的編碼

= setFileSizeMax(long fileSizeMax):設(shè)置單個(gè)上傳文件的大小

= setSizeMax(long sizeMax):設(shè)置上傳文件的總大小


3.3 FileItem:文件項(xiàng)
(1)普通方法
= boolean isFormField():判斷是否是普通輸入項(xiàng),返回boolean丢氢,如果返回true是普通輸入項(xiàng)

= getFieldName():得到普通輸入項(xiàng)name的屬性值

= getString():得到普通輸入項(xiàng)輸入的值
= getString(java.lang.String encoding):輸入的值有中文傅联,設(shè)置編碼

= getName():得到上傳文件的名稱。在某些瀏覽器里面得到帶路徑的名稱卖丸,截取操作

= getInputStream():得到表單提交的文件的輸入流

= delete():刪除臨時(shí)文件

4纺且、練習(xí):js控制多文件的上傳

4.1 需求描述
(1)在上傳表單里面,有兩個(gè)按鈕稍浆,一個(gè)是上傳载碌,一個(gè)是增加
(2)點(diǎn)擊增加按鈕時(shí)候,增加一個(gè)文件上傳項(xiàng)和刪除按鈕
(3)點(diǎn)擊刪除按鈕時(shí)候衅枫,刪除一行內(nèi)容
(4)點(diǎn)擊上傳按鈕時(shí)候嫁艇,把當(dāng)前文件上傳到服務(wù)器

4.2 使用js增加一行和刪除一行
(1)代碼
    //增加一行
    function addFile() {
        //得到div
        var div1 = document.getElementById("div1");
        div1.innerHTML += "<div><input type='file' name='filename'/><input type='button' value='刪除' onclick='del1(this);'/></div>";
    }
    
    //刪除一行
    function del1(who) {
        //因?yàn)橐獎(jiǎng)h除文件上傳項(xiàng)和刪除按鈕,這兩個(gè)內(nèi)容都在div里面弦撩,刪除div就可以了
        //得到當(dāng)前點(diǎn)擊的刪除按鈕所在的div
        var div = who.parentNode;
        //刪除div步咪,使用dom里面的方法 removeChild(),不能自己刪除自己益楼,通過(guò)父標(biāo)簽刪除
        //得到要?jiǎng)h除div的父標(biāo)簽
        var div1 = div.parentNode;
        div1.removeChild(div);
    }

4.3 使用button提交表單
(1)代碼
    //提交表單猾漫,實(shí)現(xiàn)上傳(使用button提交的表單)
    function uploadfile() {
        //得到form標(biāo)簽
        var form1 = document.getElementById("form1");
        form1.submit();
    }

5、文件上傳問(wèn)題的解決

5.1 文件重名的問(wèn)題
(1)如果上傳了多個(gè)項(xiàng)目名稱的文件感凤,最后一次上傳的文件悯周,把之后的文件給覆蓋了。

5.2 解決方法
(1)在上傳的文件名稱里面陪竿,添加一個(gè)隨機(jī)的唯一的字符串禽翼,保證每個(gè)文件名稱都是唯一的一個(gè)值
(2)生成一個(gè)隨機(jī)的唯一的值
第一種方式:使用毫秒數(shù)實(shí)現(xiàn)
第二種方式:使用UUID工具類實(shí)現(xiàn)
(3)代碼
    //在文件名稱里面添加隨機(jī)的唯一的值
    String uuid = UUID.randomUUID().toString();
    //uuid_filename
    filename = uuid+"_"+filename;

第二部分:文件的下載

1、什么是文件的下載

1.1 把服務(wù)器上文件保存到本地硬盤(pán)族跛,這個(gè)過(guò)程稱為文件的下載

1.2 文件下載的實(shí)現(xiàn)方式:有兩種實(shí)現(xiàn)方式
第一種方式:使用超鏈接實(shí)現(xiàn)文件的下載 
(1)如果要下載的文件是圖片格式闰挡,直接在瀏覽器里面打開(kāi);如果下載的是zip格式的文件礁哄,才會(huì)
提示下載长酗。最終:無(wú)論什么格式都是一下載方式打開(kāi)。

第二種方式:通過(guò)代碼實(shí)現(xiàn)文件的下載
(1)實(shí)現(xiàn)的步驟
第一步:設(shè)置要下載文件的MIME類型姐仅,設(shè)置頭信息 Content-Disposition刻盐,無(wú)論是什么格式,都是以下載方式打開(kāi)
第二步:從服務(wù)器上得到要下載的文件的輸入流
第三步:創(chuàng)建輸出流劳翰,通過(guò)輸出流把文件寫(xiě)到瀏覽器
第四步:流對(duì)接敦锌,關(guān)閉流

2、代碼實(shí)現(xiàn)文件的下載

2.1 實(shí)現(xiàn)的步驟
第一步:設(shè)置要下載文件的MIME類型佳簸,設(shè)置頭信息 Content-Disposition乙墙,無(wú)論是什么格式,都是以下載方式打開(kāi)
= 設(shè)置mime類型
    //設(shè)置要下載文件的mime類型
    String type = getServletContext().getMimeType(filename);
    //設(shè)置mime類型
    response.setContentType(type);
= 設(shè)置頭信息
    response.setHeader("Content-Disposition", "attachment;filename="+filename);

第二步:從服務(wù)器上得到要下載的文件的輸入流
    //得到要下載文件的輸入流
    InputStream in = new FileInputStream(path);

第三步:創(chuàng)建輸出流生均,通過(guò)輸出流把文件寫(xiě)到瀏覽器
    OutputStream out = response.getOutputStream();

第四步:流對(duì)接听想,關(guān)閉流


2.2 下載文件名稱包含中文的亂碼問(wèn)題解決
(1)不同的瀏覽器有不同的編碼,ie瀏覽器采用的url編碼马胧,火狐采用base64編碼
(2)區(qū)分不同的瀏覽器
= 在請(qǐng)求頭 User-Agent汉买,得到當(dāng)前請(qǐng)求的瀏覽器的類型
(3)代碼
    //得到當(dāng)前請(qǐng)求的瀏覽器類型 ,使用頭 User-Agent
    String agent = request.getHeader("User-Agent");
    if(agent.contains("Firefox")) {//如果是火狐瀏覽器
        //base64編碼
        filename = "=?UTF-8?B?"+
                new BASE64Encoder().encode(filename.getBytes("utf-8"))+"?=";
    } else {
        //url編碼
        filename = URLEncoder.encode(filename, "UTF-8");
    }

第三部分:注解

1佩脊、什么是注解

1.1 是jdk5.0的新特性
(1)jdk5.0很多新特性:泛型蛙粘、自動(dòng)拆裝箱、增強(qiáng)for循環(huán)威彰、可變參數(shù)出牧、枚舉..

1.2 注解不是注釋
(1)注釋:給程序員看的
(2)注解:給程序看的
(3)注解就是代碼里面的特殊標(biāo)記,主要功能替代配置文件
其實(shí)就是代碼里的特殊標(biāo)記, 它用于替代配置文件歇盼,
也就是說(shuō)舔痕,傳統(tǒng)方式通過(guò)配置文件告訴類如何運(yùn)行,
有了注解技術(shù)后豹缀,開(kāi)發(fā)人員可以通過(guò)注解告訴類如何運(yùn)行伯复。
在Java技術(shù)里注解的典型應(yīng)用是:可以通過(guò)反射技術(shù)去得到類里面的注解,以決定怎么去運(yùn)行類邢笙。

1.3 寫(xiě)法
(1) @注解的名稱
(2)可以使用在方法上面边翼,也可以是類上面

2、jdk里面的三個(gè)注解

(1) @Override: 限定重寫(xiě)父類方法, 該注解只能用于方法

(2) @SuppressWarnings: 抑制編譯器警告.
= @SuppressWarnings("all")
= 不影響程序的運(yùn)行

(3) @Deprecated: 用于表示某個(gè)程序元素(類, 方法等)已過(guò)時(shí)
= 不影響程序的運(yùn)行

3鸣剪、自定義注解

3.1 定義的方式:使用關(guān)鍵字 @interface 注解名稱
(1) @interface MyAnno { }

3.2 聲明注解的屬性
(1)類型 屬性的名稱();
@interface MyAnno {
    //定義屬性
    String aa();    
    int bb();
}

3.3 如果定義屬性類型是Date類型,報(bào)錯(cuò)
Invalid type Date for the annotation attribute MyAnno.date; 
only primitive type, String, Class, annotation, enumeration are permitted 
or 1-dimensional arrays thereof

(1)屬性允許的類型:基本數(shù)據(jù)類型丈积、string筐骇、Class、注解江滨、枚舉铛纬,一維數(shù)組
(2)代碼
//自定義注解
@interface MyAnno {
    //定義屬性
    String aa();    
    int bb();
    
    //定義Date類型
//  Date date();
    
    //定義Class類型
    Class clazz();
    
    //定義注解
    anno ann();
    
    //定義枚舉類型
    Color c();
    
    //定義一維數(shù)組
    String[] arr();
}

(3)使用自定義注解
@MyAnno(aa="qq",bb=1,clazz=TestAnno01.class,ann=@anno,c=Color.RED,arr={"aa","bb"})

3.4 特殊屬性value
(1)如果把屬性的名稱寫(xiě)成value,在使用這個(gè)注解的時(shí)候value可以省略不寫(xiě)

3.5 元注解
(1)修飾注解的注解
@Retention:修飾注解使用范圍唬滑,自定義一個(gè)注解告唆,在默認(rèn)的情況下是源代碼階段
    RetentionPolicy.CLASS: 編譯器將把注解記錄在 class 文件中. 當(dāng)運(yùn)行 Java 程序時(shí), JVM 不會(huì)保留注解. 這是默認(rèn)值
    RetentionPolicy.RUNTIME:編譯器將把注釋記錄在 class 文件中. 當(dāng)運(yùn)行 Java 程序時(shí), JVM 會(huì)保留注解. 程序可以通過(guò)反射獲取該注釋
    RetentionPolicy.SOURCE: 編譯器直接丟棄這種策略的注釋

    @Retention(RetentionPolicy.RUNTIME)

@Target:指定注解用于修飾類的哪個(gè)成員. 
    @Target 包含了一個(gè)名為  value棺弊,類型為ElementType的成員變量。 
    @Target({ElementType.METHOD,ElementType.PARAMETER})

@Documented: 用于指定被該元 Annotation 修飾的 Annotation 類將被 javadoc 工具提取成文檔.

@Inherited: 被它修飾的 Annotation 將具有繼承性.
    如果某個(gè)類使用了被 @Inherited 修飾的 Annotation, 則其子類將自動(dòng)具有該注解

4擒悬、使用反射+注解完成兩個(gè)練習(xí)

4.1 使用反射+注解實(shí)現(xiàn)模擬單元測(cè)試的效果
(1)什么是單元測(cè)試 junit
= 測(cè)試一個(gè)類中的方法模她,使用注解方式進(jìn)行操作 @Test
= 在要測(cè)試方法上面添加注解 @Test,選擇要測(cè)試的方法懂牧,點(diǎn)擊右鍵 run as ---> junit  test
= 運(yùn)行之后侈净,在工具里面出現(xiàn)一個(gè)JUNIT,有一個(gè)綠色的條僧凤,表示測(cè)試通過(guò)了
= 運(yùn)行之后畜侦,在工具里面出現(xiàn)一個(gè)JUNIT,如果有紅棕色條躯保,表示測(cè)試失敗
= 在方法上面有 @Test注解旋膳,這個(gè)方法就可以運(yùn)行
= @Ignore :當(dāng)前的方法不參與單元測(cè)試

(2)實(shí)現(xiàn)的步驟
 * 1、得到要測(cè)試方法所在類的Class
 *  = 有三種方式
 *  第一種:類名.class
 *  第二種:對(duì)象.getClass()
 *  第三種:Class.forName("包類路徑")
 * 2途事、得到類中的所有的方法
 *  Method[] getMethods()  验懊,返回方法的數(shù)組
 * 3、遍歷數(shù)組盯孙,得到類中的每個(gè)方法
 * 4鲁森、判斷方法上面是否有注解
 *  boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 
 *  = 參數(shù):注解的Class
 * 5、如果有注解振惰,讓方法執(zhí)行
 *  invoke(Object obj, Object... args) 
 *  = 第一個(gè)參數(shù)是類實(shí)例歌溉;第二個(gè)參數(shù)執(zhí)行方法里面的參數(shù)

(3)自定義的注解,在默認(rèn)情況下作用范圍是源代碼階段骑晶,使用元注解設(shè)置的作用范圍

(4)代碼
    //得到要測(cè)試方法所在類的Class
    Class clazz = TestJunit02.class;
    //得到類中的所有的方法
    Method[] methos = clazz.getMethods();
    //遍歷數(shù)組痛垛,得到每個(gè)方法
    for (Method m : methos) {
        //判斷方法上面是否有注解
        //自定義注解,在默認(rèn)情況下作用在源代碼階段
        //使用元注解修飾注解的作用范圍  @Retention(RetentionPolicy.RUNTIME)
        boolean flag = m.isAnnotationPresent(MyTest.class);
        //如果有注解桶蛔,讓方法執(zhí)行
        if(flag) {
            //方法執(zhí)行 invoke()
            try {
                m.invoke(clazz.newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            } 
        }
    }


4.2 使用反射獲取注解里面的屬性值
(1)使用傳統(tǒng)方式實(shí)現(xiàn)jdbc操作

(2)使用反射實(shí)現(xiàn)jdbc的操作

(3)實(shí)現(xiàn)的步驟
第一步:創(chuàng)建注解匙头,注解定義數(shù)據(jù)庫(kù)操作信息的屬性
第二步:得到類的Class,得到帶注解的方法
    = Method getMethod(String name, Class<?>... parameterTypes) 
    == 第一個(gè)參數(shù)方法名稱仔雷,第二個(gè)參數(shù)方法里面參數(shù)列表
第三步:得到方法上面的注解
    = <T extends Annotation> T  getAnnotation(Class<T> annotationClass)  
第四步:得到注解里面的屬性的值

= 自定義的注解蹂析,在默認(rèn)情況下作用范圍是源代碼階段,使用元注解設(shè)置的作用范圍

(4)核心的代碼
    //得到Class
    Class clazz = TestJDBC02.class;
    //得到方法
    Method method = clazz.getMethod("testSelect");

    //得到方法上面的注解
    JdbcInfo info = method.getAnnotation(JdbcInfo.class);
    //得到注解里面的屬性的值
    String drivername = info.drivername();
    String url = info.url();
    String username = info.username();
    String password = info.password();
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末碟婆,一起剝皮案震驚了整個(gè)濱河市电抚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌竖共,老刑警劉巖蝙叛,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異公给,居然都是意外死亡借帘,警方通過(guò)查閱死者的電腦和手機(jī)蜘渣,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)肺然,“玉大人蔫缸,你說(shuō)我怎么就攤上這事≌玻” “怎么了捂龄?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)加叁。 經(jīng)常有香客問(wèn)我倦沧,道長(zhǎng),這世上最難降的妖魔是什么它匕? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任展融,我火速辦了婚禮,結(jié)果婚禮上豫柬,老公的妹妹穿的比我還像新娘告希。我一直安慰自己,他們只是感情好烧给,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布燕偶。 她就那樣靜靜地躺著,像睡著了一般础嫡。 火紅的嫁衣襯著肌膚如雪指么。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天榴鼎,我揣著相機(jī)與錄音伯诬,去河邊找鬼。 笑死巫财,一個(gè)胖子當(dāng)著我的面吹牛盗似,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播平项,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼赫舒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了闽瓢?” 一聲冷哼從身側(cè)響起号阿,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎鸳粉,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體园担,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡届谈,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年枯夜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖旁理,靈堂內(nèi)的尸體忽然破棺而出吵取,到底是詐尸還是另有隱情,我是刑警寧澤垄琐,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響征讲,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜橡娄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一诗箍、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧挽唉,春花似錦滤祖、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至塑顺,卻和暖如春汤求,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背茬暇。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工首昔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人糙俗。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓勒奇,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親巧骚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子赊颠,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344