0.前言
上面兩篇文章,
講解了網(wǎng)絡(luò)中浙炼,底層的數(shù)據(jù)傳輸?shù)脑恚⊿ocket)本文則著重講解實(shí)際情況中份氧,我們?nèi)绾问褂肑ava進(jìn)行數(shù)據(jù)的傳輸(上傳、下載等)
若想要了解“類(lèi)”等其他主要知識(shí)弯屈,可以去看前面的文章
由于最終目的是要開(kāi)發(fā)安卓app蜗帜,
因此這里使用的IDE是AS(Android Studio)
(不會(huì)使用的可以參考下面這篇文章中的例子)
《[Java]開(kāi)發(fā)安卓,你得掌握的Java知識(shí)2》
1.準(zhǔn)備工作
在讀本文前资厉,你需要做好以下準(zhǔn)備:
- (1)要配置好apache服務(wù)器
- (2)電腦中配置了php钮糖,可以寫(xiě)php代碼
- (3)大致了解前后端交互
- (4)可以的話,最好去了解一下html的表單<form>
- 推薦新手使用wampserver 64酌住,
它集成了php店归、apache、MYSQL數(shù)據(jù)庫(kù)- 直接安裝酪我、運(yùn)行wampserver 64消痛,就可以免去配置php、apache的復(fù)雜操作都哭。
2.基礎(chǔ)知識(shí)講解
URL的一些奧秘
- url就是我們?cè)诘刂窓谳斎氲木W(wǎng)址
一般我們可能只會(huì)注意到www.xxx.com這部分秩伞,
后面的內(nèi)容,外行人可能以為是亂碼- 其實(shí)欺矫,url的每一個(gè)部分都有它對(duì)應(yīng)的意思纱新,只是我們未必能知道而已
www.xxx.com這部分叫域名,其實(shí)是與ip地址有映射關(guān)系的字符串穆趴,我們>訪問(wèn)的所有網(wǎng)頁(yè)脸爱,其實(shí)都是接入網(wǎng)絡(luò)中的某臺(tái)計(jì)算機(jī)中的內(nèi)容(這些計(jì)算機(jī)一般叫做服務(wù)器)
域名后面的那些用斜杠隔開(kāi)的,其實(shí)是對(duì)應(yīng)的文件夾未妹,我們?cè)L問(wèn)的網(wǎng)頁(yè)簿废,就是ip地址所指向的計(jì)算機(jī)中空入,某個(gè)指定文件夾下面的某個(gè)html文件(當(dāng)然可能是jsp什么的)
如果看到有?name=jack&age=12之類(lèi)的格式,其實(shí)就是向?qū)?yīng)的文件傳參數(shù)族檬,實(shí)際上就是在說(shuō):
name = jack , age = 12
把這兩個(gè)參數(shù)傳過(guò)去
比如這一點(diǎn)可以在微博中有一定作用
- is_hot=1表示按照微博的火熱程度來(lái)排序
如果改成is_all=1歪赢,那么就會(huì)按照時(shí)間排序,這一點(diǎn)十分有用
Get與Post
- get與post是兩種傳遞數(shù)據(jù)的方式单料,他們最主要的區(qū)別在于:
get:
①傳遞的數(shù)據(jù)會(huì)出現(xiàn)在地址欄中(就是上面所說(shuō)的?name=jack&age=12)
②傳遞的數(shù)據(jù)不能太多
③由于數(shù)據(jù)會(huì)出現(xiàn)在地址欄埋凯,因此不安全
④雖然不安全,但是我們可以通過(guò)修改地址欄的參數(shù)傳遞扫尖,來(lái)改變一些東西(比如上面微博的那個(gè)例子is_all與is_hot)post:
①傳遞的數(shù)據(jù)不會(huì)出現(xiàn)在地址欄中
②由于數(shù)據(jù)不會(huì)出現(xiàn)在地址欄递鹉,因此安全
③可以一次傳遞大量數(shù)據(jù)
④代碼編寫(xiě)比get方法略微復(fù)雜一點(diǎn)
PHP簡(jiǎn)單語(yǔ)法:
變量的定義:
$name = "jack"
輸出/返回內(nèi)容:
echo $name;
或者echo "jack"
等變量的獲取:
$age = $_GET["age"];
注意:
這里的GET表示是用GET方法傳遞數(shù)據(jù)藏斩,因此要用$_GET來(lái)獲取穿過(guò)來(lái)的數(shù)據(jù)
"age"是傳遞數(shù)據(jù)的時(shí)候指定的名字躏结,如果是用html傳遞的話,就是寫(xiě)在標(biāo)簽中的name(這個(gè)name是標(biāo)簽的一個(gè)參數(shù))
<input type="text" name="age">
3.具體實(shí)現(xiàn)方法
本文會(huì)wampserver64來(lái)使用php狰域、apache服務(wù)器
第一步
先寫(xiě)一個(gè)php文件媳拴,來(lái)作為接受、返回?cái)?shù)據(jù)
<?php
$name = $_POST["fname"];
$age = $_POST["age"];
echo $name." ".$age."歲";
?>
- 簡(jiǎn)單來(lái)說(shuō)就是定義了兩個(gè)變量
age
然后返回
$name $age歲
第二步
把這個(gè)php文件放在wamp64\www下面
www是wampserver這個(gè)集成軟件的根目錄
默認(rèn)的apache服務(wù)器的根目錄在htdocs
第三步
在java程序中書(shū)寫(xiě)傳遞數(shù)據(jù)的函數(shù)
(我知道代碼很長(zhǎng)很?chē)樔苏桌溃a后面會(huì)有逐句分析)
public static void post() throws IOException {
//1.創(chuàng)建URL對(duì)象
URL url = new URL("http://127.0.0.1/AndroidTest/test1.5.php");
//2.創(chuàng)建HttpURLConnection對(duì)象
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
//3.設(shè)置請(qǐng)求方式為post
connection.setRequestMethod("POST");
//設(shè)置有輸出流(說(shuō)明需要上傳屈溉,默認(rèn)值為false)
connection.setDoOutput(true);
//設(shè)置輸入流,默認(rèn)為true(服務(wù)器肯定會(huì)返回?cái)?shù)據(jù)
connection.setDoInput(true);
//4.準(zhǔn)備上傳的數(shù)據(jù)
String data = "fname=jack&age=12";
//5.開(kāi)始上傳 要得到輸出流對(duì)象(不斷向服務(wù)器輸出)
OutputStream os = connection.getOutputStream();
//data是字符串抬探,要轉(zhuǎn)換為字節(jié)
os.write(data.getBytes());
os.flush();//寫(xiě)完了
//6,接收服務(wù)器端返回的數(shù)據(jù)
InputStream is = connection.getInputStream();
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf)) != -1) {
System.out.println(new String(buf,0,len));
}
}
POST請(qǐng)求方式
首先子巾,我們實(shí)際用java在網(wǎng)絡(luò)中傳遞數(shù)據(jù),不會(huì)像之前那樣直接用Socket小压,原因是:
Socket有局限性线梗,我們只能在Socket中放ip地址和端口,但是
無(wú)法讓socket知道訪問(wèn)該ip地址中的哪個(gè)文件所以我們用的是封裝了Socket的URL類(lèi)來(lái)實(shí)現(xiàn)數(shù)據(jù)傳遞怠益,
URL的構(gòu)造參數(shù)中放的是欲訪問(wèn)的網(wǎng)址使用HTTPURLConnection的原因是要設(shè)置請(qǐng)求方式和輸出流
因?yàn)?strong>請(qǐng)求方式默認(rèn)為GET仪搔,所以post才需要設(shè)置請(qǐng)求方式String data就是想要發(fā)送給指定文件的內(nèi)容,雖然是post方式蜻牢,但是也是要按照類(lèi)似get方式來(lái)寫(xiě)(只是開(kāi)頭沒(méi)有?)
輸出流用的是字節(jié)流OutputStream烤咧,
getBytes()可以將字符串變?yōu)樽止?jié)數(shù)組讀取返回的內(nèi)容用的是InputStream,InputStream后面幾行都是常規(guī)操作抢呆,如果不熟悉的可以去看之前的文章:
《[Java]開(kāi)發(fā)安卓煮嫌,你得掌握的Java知識(shí)9》
執(zhí)行結(jié)果:(要找一個(gè)main函數(shù)調(diào)用post())
GET請(qǐng)求方式
java代碼差不多(要簡(jiǎn)單一些):
public static void getParams() throws IOException {
String path = "http://127.0.0.1/AndroidTest/test.php?fname=jack&age=12";
URL url = new URL(path);
//1.5.指明請(qǐng)求方式,默認(rèn)為get
//2.獲取連接的對(duì)象(URLConnection封裝了socket抱虐,socket可以做的昌阿,URLConnection都可以做)
URLConnection connection = url.openConnection();
//接受服務(wù)器端的數(shù)據(jù)
InputStream is = connection.getInputStream();
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf)) != -1) {
System.out.println(new String(buf,0,len));
}
}
主要區(qū)別在于:
將要傳遞的數(shù)據(jù)放到了path中,不需要額外傳數(shù)據(jù)
不需要去設(shè)置請(qǐng)求方式
php文件中的 _POST要改為_(kāi)GET
傳遞文件
public static void getImage() throws IOException {
//URL
URL url = new URL("http://localhost/1.jpg");
//獲取與服務(wù)器連接的對(duì)象
URLConnection connection = url.openConnection();
//讀取下載的內(nèi)容 - 獲取輸入流
InputStream is = connection.getInputStream();
//創(chuàng)建文件保存的位置,路徑自己定義
String desPath ="D:\\AndroidStudioProjects\\AndroidCourse\\JavaCourse1Day1\\course1day1\\src\\main\\java\\course1day14\\1.jpg";
FileOutputStream fos = new FileOutputStream(desPath);
//具體的下載操作
byte[] buf = new byte[1024];
int len;
while ((len = is.read(buf)) != -1) {
fos.write(buf,0,len);
}
}
- URL宝泵、URLConnection的操作和上面的POST、GET一樣
-下面的InputStream到最后的while那部分代碼轩娶,
就是經(jīng)典的文件的拷貝儿奶,先用InputStream讀取文件到緩存,再用FileOutputStream將文件從緩存中讀出
只不過(guò)這次是從服務(wù)器中把文件拷貝到本地
- byte[]是字節(jié)數(shù)組鳄抒,新手可能沒(méi)見(jiàn)過(guò)闯捎,它的目的就是在讀取文件時(shí),找一個(gè)地方放你要讀取到的東西的一部分许溅,然后將這次讀到的內(nèi)容寫(xiě)到硬盤(pán)中瓤鼻,要反復(fù)多次這樣的操作,直至將整個(gè)文件拷貝完
(當(dāng)然贤重,每次讀寫(xiě)的單位還是一個(gè)字節(jié)茬祷,只是字節(jié)數(shù)組能一次性放下1024個(gè)字節(jié)而已)
4.總結(jié)
(1)本文講解了實(shí)際情況中,如何實(shí)現(xiàn)網(wǎng)絡(luò)中的數(shù)據(jù)傳遞并蝗,比起使用底層的socket進(jìn)行交互祭犯,封裝好的URL更加方便
(2)雖然訪問(wèn)服務(wù)器可以使用URL這種封裝好的類(lèi),但是數(shù)據(jù)的讀寫(xiě)依然要使用InputStream和OutputStream這些類(lèi)滚停,因此即使看起來(lái)很復(fù)雜沃粗,也有必要多多熟悉字節(jié)、字符輸入輸出流的使用方法