在Android設(shè)備上搭建Web服務(wù)器的方法
一般而言,Android 應(yīng)用在請(qǐng)求數(shù)據(jù)時(shí)都是以 Get 或 Post 等方式向遠(yuǎn)程服務(wù)器發(fā)起請(qǐng)求,那你有沒(méi)有想過(guò)其實(shí)我們也可以在 Android 設(shè)備上搭建一個(gè)小型 Web 服務(wù)器,并且實(shí)現(xiàn)常規(guī)的下載圖片、下載文件、提交表單等功能呢?
下面要介紹的就是如何在 Android 設(shè)備上搭建一個(gè) Web 服務(wù)器,這個(gè) Web 服務(wù)器的功能有如下幾點(diǎn):
- 接受客戶端文件上傳、下載文件
- 動(dòng)態(tài) Http API,像 Java 的 Servlet 一樣寫(xiě)接口
- 部署靜態(tài)網(wǎng)站,例如純Html,支持 JS、CSS、Image 分離
- 部署動(dòng)態(tài)網(wǎng)站
這需要依賴一個(gè)開(kāi)源庫(kù)來(lái)實(shí)現(xiàn):AndServer
AndServer 類似于 Apache 和 Tomcat,支持在同個(gè)局域網(wǎng)下的設(shè)備能夠以常規(guī)的網(wǎng)絡(luò)請(qǐng)求方式來(lái)向 Web 服務(wù)器請(qǐng)求數(shù)據(jù),只要指明 Web 服務(wù)器的 IP 地址和端口號(hào)即可
那么,這個(gè) Web 服務(wù)器的用途有哪些呢?
說(shuō)下我現(xiàn)在遇到的一個(gè)需求吧!需要實(shí)現(xiàn)兩臺(tái)設(shè)備(Android 或 ios 設(shè)備)在無(wú)網(wǎng)絡(luò)情況下進(jìn)行數(shù)據(jù)交流。本來(lái)是打算讓設(shè)備之間的交流通道以 Wifi 來(lái)鏈接,即某一臺(tái)設(shè)備連上另一臺(tái)設(shè)備的 Wiif 熱點(diǎn),這樣兩者之間就建立起了一條“通道”,之后通過(guò)建立 Socket 連接來(lái)獲取輸入輸出流,通過(guò)輸入輸出流來(lái)交換數(shù)據(jù)??墒沁@樣就需要處理好在高并發(fā)情況下的數(shù)據(jù)同步和解析問(wèn)題,比較麻煩,而通過(guò) AndServer 就可以直接套用項(xiàng)目已有的網(wǎng)絡(luò)請(qǐng)求框架,直接以網(wǎng)絡(luò)請(qǐng)求的方式來(lái)交流數(shù)據(jù),而服務(wù)端也較好的處理了并發(fā)問(wèn)題
Gradle 遠(yuǎn)程依賴
implementation 'com.yanzhenjie:andserver:1.1.3'
搭建服務(wù)器
搭建服務(wù)器的方式很簡(jiǎn)單,支持鏈?zhǔn)秸{(diào)用。指明服務(wù)器在本機(jī)的 IP 地址上監(jiān)聽(tīng),并指定端口號(hào)為 1995 ,并開(kāi)放了三個(gè)接口分別用于:下載文件、下載圖片、Post表單
AndServer server = AndServer.serverBuilder()
.inetAddress(NetUtils.getLocalIPAddress()) //服務(wù)器要監(jiān)聽(tīng)的網(wǎng)絡(luò)地址
.port(Constants.PORT_SERVER) //服務(wù)器要監(jiān)聽(tīng)的端口
.timeout(10, TimeUnit.SECONDS) //Socket超時(shí)時(shí)間
.registerHandler(Constants.GET_FILE, new DownloadFileHandler()) //注冊(cè)一個(gè)文件下載接口
.registerHandler(Constants.GET_IMAGE, new DownloadImageHandler()) //注冊(cè)一個(gè)圖片下載接口
.registerHandler(Constants.POST_JSON, new JsonHandler()) //注冊(cè)一個(gè)Post Json接口
.filter(new HttpCacheFilter()) //開(kāi)啟緩存支持
.listener(new Server.ServerListener() { //服務(wù)器監(jiān)聽(tīng)接口
@Override
public void onStarted() {
String hostAddress = server.getInetAddress().getHostAddress();
Log.e(TAG, "onStarted : " + hostAddress);
ServerPresenter.onServerStarted(ServerService.this, hostAddress);
}
@Override
public void onStopped() {
Log.e(TAG, "onStopped");
ServerPresenter.onServerStopped(ServerService.this);
}
@Override
public void onError(Exception e) {
Log.e(TAG, "onError : " + e.getMessage());
ServerPresenter.onServerError(ServerService.this, e.getMessage());
}
})
.build();
開(kāi)啟服務(wù)器
server.startup();
停止服務(wù)器
server.shutdown();
接口處理器
在注冊(cè)接口時(shí),除了指明開(kāi)放出來(lái)的 Url 地址外,還需要指明相應(yīng)的處理器,專門(mén)用于處理該接口的請(qǐng)求操作
開(kāi)放出來(lái)的三個(gè)接口分別對(duì)應(yīng)于三個(gè)地址
public class Constants {
//服務(wù)端接口的端口號(hào)
public static final int PORT_SERVER = 1995;
public static final String GET_FILE = "/file";
public static final String GET_IMAGE = "/image";
public static final String POST_JSON = "/json";
}
··· .registerHandler(Constants.GET_FILE, new DownloadFileHandler()) //注冊(cè)一個(gè)文件下載接口 .registerHandler(Constants.GET_IMAGE, new DownloadImageHandler()) //注冊(cè)一個(gè)圖片下載接口 .registerHandler(Constants.POST_JSON, new JsonHandler()) //注冊(cè)一個(gè)Post Json接口 ···
例如,假設(shè)設(shè)備的 IP 地址是:192.168.0.101 ,那么在訪問(wèn) http://192.168.0.101:1995/file 接口時(shí),請(qǐng)求操作就會(huì)由 DownloadFileHandler 來(lái)處理
下載文件
DownloadFileHandler 實(shí)現(xiàn)了 RequestHandler 接口,在 handle 方法中可以獲取到請(qǐng)求頭,表單數(shù)據(jù)這些信息,,通過(guò)注解聲明支持 Get 方式調(diào)用,在此直接返回一個(gè)文本文件用于下載
/**
* 作者:leavesC
* 時(shí)間:2018/4/5 16:30
* 描述:https://github.com/leavesC/AndroidServer
*/
public class DownloadFileHandler implements RequestHandler {
@RequestMapping(method = {RequestMethod.GET})
@Override
public void handle(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) throws HttpException, IOException {
File file = createFile();
HttpEntity httpEntity = new FileEntity(file, ContentType.create(getMimeType(file.getAbsolutePath()), Charset.defaultCharset()));
httpResponse.setHeader("Content-Disposition", "attachment;filename=File.txt");
httpResponse.setStatusCode(200);
httpResponse.setEntity(httpEntity);
}
private File createFile() {
File file = null;
OutputStream outputStream = null;
try {
file = File.createTempFile("File", ".txt", MainApplication.get().getCacheDir());
outputStream = new FileOutputStream(file);
outputStream.write("leavesC,這是一段測(cè)試文本".getBytes());
} catch (IOException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.flush();
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return file;
}
}
這里直接在瀏覽器中訪問(wèn)接口(要和 Android Web服務(wù)器運(yùn)行在同個(gè)局域網(wǎng)下),可以直接下載到文件

下載圖片
類似的,下載圖片的接口處理器 DownloadImageHandler 可以如下設(shè)計(jì),在 handle 方法中返回應(yīng)用的圖標(biāo)
/**
* 作者:leavesC
* 時(shí)間:2018/4/5 16:30
* 描述:https://github.com/leavesC/AndroidServer
*/
public class DownloadImageHandler extends SimpleRequestHandler {
private File file = new File(Environment.getExternalStorageDirectory(), "leavesC.jpg");
@RequestMapping(method = {RequestMethod.GET})
@Override
protected View handle(HttpRequest request) throws HttpException, IOException {
writeToSdCard();
HttpEntity httpEntity = new FileEntity(file, ContentType.create(getMimeType(file.getAbsolutePath()), Charset.defaultCharset()));
return new View(200, httpEntity);
}
private void writeToSdCard() throws IOException {
if (!file.exists()) {
synchronized (DownloadImageHandler.class) {
if (!file.exists()) {
boolean b = file.createNewFile();
if (!b) {
throw new IOException("What broken cell phone.");
}
Bitmap bitmap = BitmapFactory.decodeResource(MainApplication.get().getResources(), R.mipmap.ic_launcher_round);
OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
outputStream.flush();
outputStream.close();
}
}
}
}
}
}
}

Post表單
這里需要將注解值改為 RequestMethod.POST,通過(guò) HttpRequestParser.getContentFromBody(httpRequest) 函數(shù)可以獲取到表單數(shù)據(jù),這里直接檢測(cè)表單數(shù)據(jù)是否為 Json 字符串,是的話則為之多添加一個(gè)屬性 :"state" 作為返回值,否則返回只包含屬性 “state” 的 Json 字符串
/**
* 作者:leavesC
* 時(shí)間:2018/4/5 16:30
* 描述:https://github.com/leavesC/AndroidServer
*/
public class JsonHandler implements RequestHandler {
@RequestMapping(method = {RequestMethod.POST})
@Override
public void handle(HttpRequest httpRequest, HttpResponse httpResponse, HttpContext httpContext) throws HttpException, IOException {
String content = HttpRequestParser.getContentFromBody(httpRequest);
JSONObject jsonObject = null;
try {
jsonObject = new JSONObject(content);
} catch (JSONException e) {
e.printStackTrace();
}
if (jsonObject == null) {
jsonObject = new JSONObject();
}
try {
jsonObject.put("state", "success");
} catch (JSONException e) {
e.printStackTrace();
}
StringEntity stringEntity = new StringEntity(jsonObject.toString(), "utf-8");
httpResponse.setStatusCode(200);
httpResponse.setEntity(stringEntity);
}
}
這里在 Postman 這個(gè)工具上進(jìn)行 Post 操作

以上三個(gè)例子都是在電腦端調(diào)用的,這和在手機(jī)端調(diào)用是同個(gè)效果的
基本的操作就介紹到這里,再具體的內(nèi)容可以看示例代碼:AndroidServer
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android實(shí)現(xiàn)原生鎖屏頁(yè)面音樂(lè)控制
這篇文章主要介紹了Android實(shí)現(xiàn)原生鎖屏頁(yè)面音樂(lè)控制,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
Android 帶有彈出收縮動(dòng)畫(huà)的扇形菜單實(shí)例
本篇文章主要介紹了Android 帶有彈出收縮動(dòng)畫(huà)的扇形菜單實(shí)例,具有一定的參考價(jià)值,有興趣的可以了解一下2017-06-06
Android webview加載https鏈接錯(cuò)誤或無(wú)響應(yīng)的解決
這篇文章主要介紹了Android webview加載https鏈接錯(cuò)誤或無(wú)響應(yīng)的解決,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android實(shí)現(xiàn)自定義ImageView的圓角矩形圖片效果
android顯示圓角矩形的圖片其原理就是首先獲取到圖片的Bitmap,然后進(jìn)行裁剪對(duì)應(yīng)的圓角矩形的bitmap,然后在onDraw()進(jìn)行繪制圓角矩形圖片輸出2018-05-05
android實(shí)現(xiàn)簡(jiǎn)單圓弧效果
這篇文章主要為大家詳細(xì)介紹了android實(shí)現(xiàn)簡(jiǎn)單圓弧效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-08-08
Flutter開(kāi)發(fā)技巧ListView去除水波紋方法示例
這篇文章主要為大家介紹了Flutter開(kāi)發(fā)技巧ListView去除水波紋方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
android隱式意圖激活自定義界面和系統(tǒng)應(yīng)用界面的實(shí)例
下面小編就為大家?guī)?lái)一篇android隱式意圖激活自定義界面和系統(tǒng)應(yīng)用界面的實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-06-06

