在 Android 设备上搭建 Web 服务器
在 Android 设备上搭建 Web 服务器
叶志陈已关注
12018.04.11 00:20:05字数 1,018阅读 10,291
一般而言,Android 应用在请求数据时都是以 Get 或 Post 等方式向远程服务器发起请求,那你有没有想过其实我们也可以在 Android 设备上搭建一个小型 Web 服务器,并且实现常规的下载图片、下载文件、提交表单等功能呢?
下面要介绍的就是如何在 Android 设备上搭建一个 Web 服务器,这个 Web 服务器的功能有如下几点:
- 接受客户端文件上传、下载文件
- 动态 Http API,像 Java 的 Servlet 一样写接口
- 部署静态网站,例如纯Html,支持 JS、CSS、Image 分离
- 部署动态网站
这需要依赖一个开源库来实现:AndServer
AndServer 类似于 Apache 和 Tomcat,支持在同个局域网下的设备能够以常规的网络请求方式来向 Web 服务器请求数据,只要指明 Web 服务器的 IP 地址和端口号即可
那么,这个 Web 服务器的用途有哪些呢?
说下我现在遇到的一个需求吧!需要实现两台设备(Android 或 ios 设备)在无网络情况下进行数据交流。本来是打算让设备之间的交流通道以 Wifi 来链接,即某一台设备连上另一台设备的 Wiif 热点,这样两者之间就建立起了一条“通道”,之后通过建立 Socket 连接来获取输入输出流,通过输入输出流来交换数据。可是这样就需要处理好在高并发情况下的数据同步和解析问题,比较麻烦,而通过 AndServer 就可以直接套用项目已有的网络请求框架,直接以网络请求的方式来交流数据,而服务端也较好的处理了并发问题
Gradle 远程依赖
implementation 'com.yanzhenjie:andserver:1.1.3'
搭建服务器
搭建服务器的方式很简单,支持链式调用。指明服务器在本机的 IP 地址上监听,并指定端口号为 1995 ,并开放了三个接口分别用于:下载文件、下载图片、Post表单
AndServer server = AndServer.serverBuilder().inetAddress(NetUtils.getLocalIPAddress()) //服务器要监听的网络地址.port(Constants.PORT_SERVER) //服务器要监听的端口.timeout(10, TimeUnit.SECONDS) //Socket超时时间.registerHandler(Constants.GET_FILE, new DownloadFileHandler()) //注册一个文件下载接口.registerHandler(Constants.GET_IMAGE, new DownloadImageHandler()) //注册一个图片下载接口.registerHandler(Constants.POST_JSON, new JsonHandler()) //注册一个Post Json接口.filter(new HttpCacheFilter()) //开启缓存支持.listener(new Server.ServerListener() { //服务器监听接口@Overridepublic void onStarted() {String hostAddress = server.getInetAddress().getHostAddress();Log.e(TAG, "onStarted : " + hostAddress);ServerPresenter.onServerStarted(ServerService.this, hostAddress);}@Overridepublic void onStopped() {Log.e(TAG, "onStopped");ServerPresenter.onServerStopped(ServerService.this);}@Overridepublic void onError(Exception e) {Log.e(TAG, "onError : " + e.getMessage());ServerPresenter.onServerError(ServerService.this, e.getMessage());}}).build();
开启服务器
server.startup();
停止服务器
server.shutdown();
接口处理器
在注册接口时,除了指明开放出来的 Url 地址外,还需要指明相应的处理器,专门用于处理该接口的请求操作
开放出来的三个接口分别对应于三个地址
public class Constants {//服务端接口的端口号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()) //注册一个文件下载接口.registerHandler(Constants.GET_IMAGE, new DownloadImageHandler()) //注册一个图片下载接口.registerHandler(Constants.POST_JSON, new JsonHandler()) //注册一个Post Json接口···
例如,假设设备的 IP 地址是:192.168.0.101 ,那么在访问 http://192.168.0.101:1995/file 接口时,请求操作就会由 DownloadFileHandler 来处理
下载文件
DownloadFileHandler 实现了 RequestHandler 接口,在 handle 方法中可以获取到请求头,表单数据这些信息,,通过注解声明支持 Get 方式调用,在此直接返回一个文本文件用于下载
/*** 作者:leavesC* 时间:2018/4/5 16:30* 描述:https://github.com/leavesC/AndroidServer* https://www.jianshu.com/u/9df45b87cfdf*/
public class DownloadFileHandler implements RequestHandler {@RequestMapping(method = {RequestMethod.GET})@Overridepublic 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,这是一段测试文本".getBytes());} catch (IOException e) {e.printStackTrace();} finally {if (outputStream != null) {try {outputStream.flush();outputStream.close();} catch (IOException e) {e.printStackTrace();}}}return file;}}
这里直接在浏览器中访问接口(要和 Android Web服务器运行在同个局域网下),可以直接下载到文件
下载图片
类似的,下载图片的接口处理器 DownloadImageHandler 可以如下设计,在 handle 方法中返回应用的图标
/*** 作者:leavesC* 时间:2018/4/5 16:30* 描述:https://github.com/leavesC/AndroidServer* https://www.jianshu.com/u/9df45b87cfdf*/
public class DownloadImageHandler extends SimpleRequestHandler {private File file = new File(Environment.getExternalStorageDirectory(), "leavesC.jpg");@RequestMapping(method = {RequestMethod.GET})@Overrideprotected 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,通过 HttpRequestParser.getContentFromBody(httpRequest)
函数可以获取到表单数据,这里直接检测表单数据是否为 Json 字符串,是的话则为之多添加一个属性 :"state" 作为返回值,否则返回只包含属性 “state” 的 Json 字符串
/*** 作者:leavesC* 时间:2018/4/5 16:30* 描述:https://github.com/leavesC/AndroidServer* https://www.jianshu.com/u/9df45b87cfdf*/
public class JsonHandler implements RequestHandler {@RequestMapping(method = {RequestMethod.POST})@Overridepublic 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 这个工具上进行 Post 操作
以上三个例子都是在电脑端调用的,这和在手机端调用是同个效果的
基本的操作就介绍到这里,再具体的内容可以看示例代码:AndroidServer
欢迎关注我的简书账号:叶应是叶
95人点赞
Android 解析
"哈,希望可以得到一份鼓励,让我喝杯咖啡"
赞赏支持还没有人赞赏,支持一下
叶志陈https://github.com/leavesC
总资产513 (约37.90元)共写了20.0W字获得2,658个赞共1,211个粉丝
已关注
全部评论15只看作者
按时间倒序
按时间正序
昨日d书生
15楼 2019.10.12 09:19
发现同一个局域网下 是可以的 用外网就无法访问呢?
赞 回复
帅气的昵称呢啊吧
14楼 2019.04.16 14:45
楼主你好,我跑了下你的demo,能下载文件和传json数据,但是图片看不到.而且工程一直在报这个java.net.SocketTimeoutException: Read timed out错误,不知道是哪里的问题,请指教
赞 回复
遇见_ca39
13楼 2019.01.04 11:03
看了看楼主的源码,知道文件上专是用fileUpload来实现的,但是里面的FileItemFactory该怎么实现?谢谢
赞 回复
諾言_cfbf
12楼 2018.11.16 11:50
在JsonHandler类中 String content = HttpRequestParser.getContentFromBody(httpRequest); 得到的content 附带这种数据 ----------------------------958044966615931359259061-- 怎么去掉
赞 回复
前年的邂逅_Jerry
11楼 2018.11.08 09:21
为什么mp4文件不能在iOS手机上在线播放?安卓上是可以的.
赞 回复
前年的邂逅_Jerry
2018.11.08 09:21
@GetMapping("/get/video/{isLock}/{fileName}")
public ResponseBody getVideo(@PathVariable(name = "isLock") int isLock, @PathVariable(name = "fileName") String fileName) {
Logger.i(TAG, "getVideo isLock:" + isLock + ", fileName:" + fileName);
String path;
if (isLock == LOCK_VEDIO) {
path = COLLISION_VIDEO_DIR;
} else {
path = FONT_VIDEO_DIR;
}
String filePath = TextUtils.concat(path, fileName).toString();
File file = new File(filePath);
return new FileBody(file);
}
回复
添加新评论
一页书啊
10楼 2018.04.27 23:13
请问用这个库可以实现两个手机的长连接吗,就是客户端手机可以一直从服务端手机接收数据
赞 回复
熊猫仙
9楼 2018.04.27 14:38
准备用xamarin的绑定库引入这个jar包,但是一开始就报错无数,不知道该如何入手,希望自己能坚持搞下去,也希望有同样兴趣的人一起研究。
赞 回复
Cosecant
8楼 2018.04.27 08:28
可能ObjectBox的数据浏览的网页页面就是类似于这种功能
赞 回复
JethroHuang
7楼 2018.04.26 15:05
就是linux deploy
赞 回复
JethroHuang
6楼 2018.04.26 15:04
还是喜欢把Android弄成centos这样的发行版,然后想怎么写怎么写,想用php就用php,想用python就用python,想用JAVA就用java
在 Android 设备上搭建 Web 服务器相关推荐
- centos+7虚拟机web服务器,CentOS7上搭建WEB服务器
mysql 安装 直接yum install mysql-server是不可以的 1 wget http://repo.mysql.com/mysql-community-release-el7-5. ...
- mac搭建网站服务器,Mac上搭建Web服务器--Apache
局域网搭建 Web 服务器测试环境,因为Mac OS X 自带了 Apache 和 PHP 环境,我们只需要简单的启动它就行了. 1.命令:sudo apachectl start Apache服务器 ...
- 在自己的电脑上搭建web服务器和FTP在同一局域网如何被其他机器访问
一.搭建web服务器 1.首先在开始屏幕中打开"搜索",输入"控制面板",并打开; .在控制面板窗口中,找到"程序",点击, 3.在打开的& ...
- 在VMware上搭建web服务器
1.创建角色 开始–>管理工具–>服务器–>服务器管理器–>角色–>右击,选择添加角色–>web服务器II–>安装 2.web服务器网站的配置 开始–> ...
- 在Rayeager px2上搭建web服务器anmpp
2019独角兽企业重金招聘Python工程师标准>>> 1.使用root工具获取root权限. 2.安装anmpp.apk http://www.anmpp.net 3.下载anmp ...
- Linux上部署web服务器并发布web项目
近在学习如何在linux上搭建web服务器来发布web项目,由于本人是linux新手,所以中间入了不少坑,搞了好久才搞出点成果. 以下是具体的详细步骤以及我对此做的一些总结和个人的一些见解,希望对跟我 ...
- 安卓Termux搭建web服务器【公网远程手机Android服务器】
文章目录 概述 1.搭建apache 2.安装cpolar内网穿透 3.公网访问配置 4.固定公网地址 5.添加站点 转载自cpolar极点云的文章:[手机建站]Termux+Cpolar内网穿透,搭 ...
- 废旧Android手机搭建个人服务器:ksweb搭建Web服务器+Termux、Ngrok实现内网穿透
写在前面: 本篇博客介绍利用废旧手机搭建一个服务器,可以放自己的网页搭建网站 之前闲着没事,低价买了个虚拟主机,放了自己的静态网页,搭建了个人博客引导网站,后来虚拟主机被打死,凑巧了解到相关知识,于是 ...
- gnuradio android手机,如何搭配USRP在安卓设备上搭建GNU Radio
原标题:如何搭配USRP在安卓设备上搭建GNU Radio 在这篇文章中,我们会使用安卓设备通过USB连接USRP.所以就需要USRP B2xx(B200, B210, 或者是 B200mini),这 ...
最新文章
- shell脚本自动化部署服务
- 转载:逻辑思维提升表达
- python学习笔记8--socket编程
- css中标签显示模式、块元素、行内元素、行内块元素、显示模式转换
- echarts formatter_牛X!用 Echarts 打造一个轮播图!
- JavaScript如何实现字符串拼接操作
- 转数组_Java中IO必杀技-文件转字节数组
- 听了那么多语音识别,你知道它的发展史吗?
- 重庆大学c语言程序设计基础,c语言程序设计基础黄文胜
- 机房搬迁的一般步骤方案
- 谈谈架构 -- architect
- sql 字段逗号分割
- Spring Kafka 之 @KafkaListener 单条或批量处理消息
- 【C语言】街区最短路径问题解题思路
- RuntimeError: Could not find GCC executable.
- 融资租赁系统-覆盖业务全场景数据服务
- 已解决:Traceback (most recent call last): File “d:\python3.6\lib\runpy.py“,
- 程序员一定会有35岁危机吗?三分天注定,七分靠打拼
- 安卓终端神器Termux (后面还有Termux常用的快捷键,妥妥干货分享,记得点赞收藏哦!)
- 使用Jest进行React单元测试