第一部分:文件的上傳
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();