kotlin和vertx和mongo写的一个服务器验证登陆功能(很简陋)
包结构长这个样子:
server包:(服务器相关配置)
HttpServer:用ver.x创建了一个http服务器,把接收到的req请求传入RPCRequest中;
RPCRequest:解析请求body内容,把信息保存为M(类名) A(方法名) P(参数),同时还拥有invoke()方法,根据m、a、p的数据用反射调用方法。
RPCResponse:没写,用来保存响应信息的。
Manager包:(将所有需要被远程调用的方法保存到内容中,加快调用时遍历查询方法的响应速度)
MethodManager:里面声明一个HashMap,value是KFunction<*>保存所有被@RPC1注解的方法,同时有addAllMethod()方法,用来保存当前类所有带@RPC1注解的方法。
ControllerManager:用HashMap保存所有Controller类,value是KClass<*>,init中需要手动put添加controller类。
Service包:(提供业务方法,供调用)
LoginService:提供业务解决逻辑的方法
Mongo包:(数据持久层,与数据库打交道,应该写成Dao层的)
UserDao:用户集合的数据库操作。
(2017.7.27更新)
Log包:
Loggin:封装了日志的信息
controller包:
LoginController:请求响应被调用的方法
2018.7.27更新:
原来的版本有几个缺陷:
①没有使用vert.x的mongo,而使用了原生mongo的jdbc;
②对数据库的查询没有实现异步。
①刚开始使用了原生mongodb的jar包和mongoclient对象,但是这种方式没有用到vertx的异步,所以改为 io.vertx.ext.mongo.MongoClient 这个jar包。但是没有删除原来原生的mongodb包,就造成了一个bug。会在执行 val mongoClient = MongoClient.createNonShared(Main.vertx, config) 这条语句的时候报错:clusterListener can not be null。 删除原生mongodb的jar包就可以了。
②改成了vertx的mongo方式就是为了查询数据库的时候使用异步来提高查询效率。刚开始还是不理解kotlin中的异步写法。
异步就是当前程序正在执行,使用回调执行了另外一段代码,如果当前程序执行完了,就会结束,不会得到另一端代码的结果,如:
1 /* 2 * 查找指定用户名和密码的用户 3 * */ 4 fun findUser(userName:String,pwd:String):String?{ 5 val query=JsonObject().put("name",userName).put("pwd",pwd) 6 var user?=null 7 mongoClient.find("jtest",query,{res-> 8 if (res.succeeded()){ 9 val result=res.result()[0] 10 if (!result.isEmpty){ 11 user=User(result.getString("name"),result.getString("pwd")) 12 } 13 } 14 }) 15 return user 16 }
上面的写法是错误的,因为vertx的mongo的find()方法使用了异步写法,在异步的方法块里面对外面的变量赋值,外面是接收不到的。
正确的写法应该是回调来接收结果。java中想要使用回调onDone需要写一个接口如Active,然后把这个接口作为参数传入方法,重写onDone来对结果进行处理。
而kotlin中的回调不需要重新写一个接口。它可以直接把过程作为对象传入参数,如下:onDone是一个类型为(参数为User,返回值为Void的过程)。可以看到findUser方法的结尾调用了onDone,并把保存后的user作为参数传递进去了。调用findUser方法的时候,我们就可以使用lambda表达式写出对传入onDone的参数user对象的处理。
1 /* 2 * 查找指定用户名和密码的用户 3 * */ 4 fun findUser(userName:String,pwd:String, onDone:(User?) -> Unit){ 5 val query=JsonObject().put("name",userName).put("pwd",pwd) 6 mongoClient.find("jtest",query,{res-> 7 var user:User?=null 8 if (res.succeeded()){ 9 val result=res.result()[0] 10 if (!result.isEmpty){ 11 user=User(result.getString("name"),result.getString("pwd")) 12 } 13 } 14 onDone.invoke(user) 15 }) 16 }
val userDao = UserDao() val user = userDao.findUser(userName, pwd) { user -> if (user == null) { var resp = "用户名或密码输入错误!!" println(resp) } else { var resp = "登陆成功!" println(resp) }
}
2018.7.27的再次更新:
加了注册功能,封装了一些方法,看起来更简洁了一些。对kotlin的异步有了更深的了解,回调函数可以传递,如下:
1 fun login(Param:JsonObject,onDone:(JsonObject)->Unit){ 2 LoginService().login(Param, {req-> 3 val request=req 4 onDone(req) 5 }) 6 } 7 8 //可以写成如下: 9 10 fun login(Param:JsonObject,onDone:(JsonObject)->Unit){ 11 LoginService().login(Param, onDone) 12 }
此外,如果反射要调用的函数里有回调,那么只需要先声明一个变量保存这个回调函数,再传入参数即可:
//回调函数 val call: (JsonObject) -> Unit = {response-> resp=response onDone(resp!!) } //得到类的引用M KClass<*> 类型 var M = Main.ins.controllerManager.controllers.get(actions[0]) //得到方法的引用A KFunction<*> 类型 var A = M?.methods?.get(actions[1]) //反射,这里把回调函数作为参数传入,不能直接把大括号写在里面 A?.javaMethod?.invoke(conIns, JsonObject(),call)