虽然标题是有点浮夸,但的确实现了部分功能
有时候要用 android 当服务器去进行数据传输, 如局域网的文件传输功能, 这些用 http 服务去做是比较好的选择. 既然要用到 http 服务, 那使用 NanoHttpd 是最好的选择之一, 只有一个文件但可以完成很多 http 服务的功能. 但使用 NanoHttpd 的时候会有很多的不便, 例如我们每次都要对 uri 进行分析, 这样就使得代码臃肿, 请求的方法过多的话, 那看上去就会一脸懵, 大大的降低代码可读性.
对于使用 NanoHttpd 的各种不便, 然后就二次封装了下, 就出了我个人认为是 android 界的 spring-boot 的 http 服务框架 (有点傻的想法).
是不是有点像 spring 的风格, 代码瞬间就简洁了. 整个人瞬间愉悦起来.
是根据 NanoHttpd 二次开发, 主要使用了注解反射来实现 url 的映射, 代码也不多, 轻量级, 以下是关键代码
/**
* 解析注解文件
*
* @param session
* @param file_name
* @return
*/
private Response responseData(IHTTPSession session, String file_name) {
Response response;
Object[] objects = null;
try {
Map < String,
java.lang.reflect.Method > methods = FHttpManager.getFHttpManager().getMethods();
java.lang.reflect.Method method = methods.get(file_name);
if (method != null) {
method.setAccessible(true); //允许修改反射属性
Class cla = method.getDeclaringClass(); //获取该方法所在的类
Object obj = cla.newInstance(); //实例化类
Class < ?>[] parameterTypes = method.getParameterTypes(); //获得方法所有参数的类型
if (parameterTypes.length > 0) {
objects = new Object[parameterTypes.length];
Map < String,
String > sessionMap = session.getParms(); //获取请求参数
Annotation[][] parameterAnnotations = method.getParameterAnnotations(); //获取方法参数里的注解
for (int i = 0; i < parameterAnnotations.length; i++) {
if (parameterTypes[i] == IHTTPSession.class) {
objects[i] = session;
} else if (parameterTypes[i] == Map.class) {
objects[i] = sessionMap;
} else {
Annotation parameterAnnotation = parameterAnnotations[i][0]; //获取参数中的第一个注解。所以每个参数只能只有一个注解
if (parameterAnnotation.annotationType() == RequestBody.class) { //返回对象
byte[] buf = new byte[(int)((HTTPSession) session).getBodySize()];
session.getInputStream().read(buf, 0, buf.length);
objects[i] = new Gson().fromJson(new String(buf), parameterTypes[I]);
} else if (parameterAnnotation.annotationType() == RequestParam.class) { //返回指定param
objects[i] = dataConversion(parameterTypes[i], sessionMap, (RequestParam) parameterAnnotation);
}
}
}
}
response = responseBody(method.getReturnType(), method.invoke(obj, objects), method.isAnnotationPresent(ResponseBody.class));
} else {
response = newFixedLengthResponse(Response.Status.NOT_FOUND, NanoHTTPD.MIME_PLAINTEXT, file_name + " Not Found");
}
} catch(Exception e) {
response = newFixedLengthResponse(Response.Status.INTERNAL_ERROR, NanoHTTPD.MIME_PLAINTEXT, e.getMessage());
}
return response;
}
这是根据 NanoHttpd 二次开发的一个轻量级, 使用简单, 功能比较强大的一个 http 服务框架. 可以实现:
注解 | 含义 |
---|---|
@RequestBody | 方法里的属性注解, 使用该注解可指定以对象返回 主要用于处理 json 请求 |
@RequestParam("") | 方法里的属性注解, 使用该注解可指定 param 值返回 主要用于处理 get,post 的请求 |
@RequestMapping("") | 方法注解, 使用该注解是映射 url , 把 url 指定到对应的方法中处理数据 |
@ResponseBody | 方法注解, 使用该方法可以对象返回经过处理吐出 json 数据返回给客户端 |
以上注解的使用可看前面的图片
compile 'cn.hotapk:fhttpserver:0.2.0'
android:name="android.permission.INTERNET" />
android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
fHttpManager = FHttpManager.init(this, UserController.class);
fHttpManager.setPort(9999);
...
UserController.class 是进行 url 映射的类, 可添加多个这样的类
public class UserController {
@RequestMapping("userls")
public NanoHTTPD.Response getUserLs() {
return setResponse("user列表");
}
@ResponseBody
@RequestMapping("getuser")
public UserBean getUser() {
return new UserBean("admin", "admin");
}
...
fHttpManager.startServer();
NanoHTTPD.Response response = NanoHTTPD.newChunkedResponse(NanoHTTPD.Response.Status.OK, "application/octet-stream", inputStream); //这代表任意的二进制数据传输。
response.addHeader("Accept-Ranges", "bytes");
response.addHeader("Content-Disposition", "attachment; filename=" + "test.java") //可以这里返回文件名称
/**
* 文件上传
*
* @param session
* @param fileDir 保存文件的目录
* @param parm 上传文件的参数
* @return
*/
public static boolean uploadFile(NanoHTTPD.IHTTPSession session, String fileDir, String parm) {
Map < String,
String > files = new HashMap < >();
try {
session.parseBody(files);
Map < String,
String > parms = session.getParms();
return FFileUtils.copyFileTo(files.get(parm), fileDir + "/" + parms.get(parm));
} catch(IOException e) {
e.printStackTrace();
} catch(NanoHTTPD.ResponseException e) {
e.printStackTrace();
}
return false;
}
该框架默认打开 index.html 文件, 如果不希望用这文件名可如下修改
fHttpManager.setIndexName(" ")
默认使用 8080 端口, 浏览器访问 http://xxx.xx.xx.xx:8080 即可
这块就不出详细 demo 了 可以到我另外一个项目查看 这是一个 android 调试数据库的神器
这方面就不讲了, 主要使用注解反射实现, 其它也没什么的了
FHttpServer
以上是 FHttpServer 框架的全部内容, 谢谢观看, 欢迎使用. 同时希望各位在使用中遇到什么问题或建议可以用以下联系方式进行反馈
github 地址 (感兴趣的话,不妨点赞支持下)
来源: https://juejin.im/post/5a3094c86fb9a0451b0487aa