在之前的文章中似忧,我們學(xué)習(xí)了如何建立一個(gè)DartVM服務(wù)器渣叛,在我對(duì)Flutter群分享時(shí)丈秩,有些群友會(huì)疑問盯捌,學(xué)習(xí)這個(gè)還不如學(xué)習(xí)golang,Dart服務(wù)器有什么用....等等蘑秽,我這里先說明一下饺著,就目前來說確實(shí)沒什么用箫攀,dart服務(wù)器運(yùn)行的是語言VM,而像java服務(wù)器運(yùn)行的是jvm幼衰,我們簡單來講一下什么是語言VM跟JVM靴跛,語言VM是專門針對(duì)某種語言去開發(fā),而JVM是一個(gè)字節(jié)碼VM渡嚣,這個(gè)字節(jié)碼VM是規(guī)定了一個(gè)規(guī)則梢睛,只要是遵守它的規(guī)則,無論你是什么語言都可以開發(fā)识椰,但前提是根據(jù)這個(gè)規(guī)則轉(zhuǎn)換為字節(jié)碼绝葡,所以說:JVM相對(duì)性能沒有語言VM要好,但適用范圍廣泛腹鹉,語言VM因?yàn)楦鶕?jù)該語言設(shè)計(jì)的藏畅,所以,是可以通過該語言完全的操控VM功咒,可以兩個(gè)類似的相比較愉阎,JVM跟語言VM就好比萬能驅(qū)動(dòng)與原配驅(qū)動(dòng),當(dāng)然這是類似的比較力奋,不用太較真榜旦!好了,巴拉巴拉景殷,說了一大堆章办,總結(jié):目前Flutter基于dart語言,學(xué)習(xí)DartVM開發(fā)有助于打好Dart基礎(chǔ)滨彻,基礎(chǔ)打好了藕届,開發(fā)Flutter的騷操作也就更多!同樣也適合走Dart web開發(fā)的同學(xué)
下面亭饵,如果你跟著仔細(xì)操作休偶,你將學(xué)會(huì)如何使用注解,使用反射獲取注解辜羊、通過反射調(diào)用方法踏兜。
1. 定義注解(dart叫元數(shù)據(jù))
在java中,如果自定義一個(gè)注解八秃,需要添加@Target作用域注解碱妆,@Retention注解類型注解,添加@interface,然后定義注解參數(shù)昔驱,那么現(xiàn)在告訴你疹尾,在dart都不用,我們只需要定義實(shí)體類一樣就可以了,代碼如下
class Controller{
final String path;
//構(gòu)造方法定義為編譯時(shí)常量
const Controller({this.path});
@override
String toString() =>'Controller';//這里是區(qū)別其它注解
}
要注意的是構(gòu)造方法需要添加一個(gè)const修飾,定義為編譯時(shí)常量纳本,然后下面就是使用
@Controller(path: '/user')
class UserController {
}
然后我們以Controller標(biāo)識(shí)過的作為該Controller的第一段請(qǐng)求路徑窍蓝,如果沒有path,就不定義path繁成,
接下來我們?cè)俣x一個(gè)@Request注解
class Request{
final String path;
final String method;
const Request({this.path,this.method});
@override
String toString() =>'Request';
}
上面定義了一個(gè)第二段請(qǐng)求路徑吓笙,跟一個(gè)請(qǐng)求方法,然后我們根據(jù)這個(gè)Request再弄Get跟Post的注解
class Get extends Request{
final String path;
const Get({this.path}) : super(path : path,method: 'GET');
@override
String toString() =>'Get';
}
class Post extends Request{
final String path;
const Post({this.path}) : super(path : path, method: 'POST');
@override
String toString() =>'Post';
}
可以看到Get跟Post注解都繼承了Request巾腕,傳遞了特定的請(qǐng)求方法
現(xiàn)在我們都準(zhǔn)備好了這些注解面睛,我們用這些注解寫一下請(qǐng)求
@Controller(path: '/user')
class UserController{
@Get(path: '/login')
void login(HttpRequest request) {
request.response
..statusCode = HttpStatus.ok
..writeln('LoginSuccess')
..close();
}
@Post(path: '/logout')
void logout(HttpRequest request){
request.response
..statusCode = HttpStatus.ok
..writeln('logoutSuccess')
..close();
}
@Request(path: '/delete', method: 'DELETE')
void editUser(HttpRequest request){
request.response
..statusCode = HttpStatus.ok
..writeln('DeleteSuccess')
..close();
}
}
好了請(qǐng)求寫完了,那么尊搬,我們?cè)趺慈リP(guān)聯(lián)這些注解呢侮穿,下面就要用到反射了!
2.使用反射解析注解類
dart里面含有一個(gè)鏡子包dart:mirrors毁嗦,這個(gè)包可以通過傳入的類亲茅,去解析元數(shù)據(jù)(即注解),并可以通過鏡子傳遞參數(shù)去調(diào)用方法狗准,為了統(tǒng)一管理這些Controller克锣,我們定義一個(gè)BaseController,讓處理請(qǐng)求的Controller都繼承這個(gè)類
//抽象類
abstract class BaseController{
}
上面這個(gè)方法是一個(gè)空方法腔长,我們不添加任何東西袭祟,然后讓UserController繼承這個(gè)類
@Controller(path: '/user')
class UserController extends BaseController{
@Get(path: '/login')
void login(HttpRequest request) {
request.response
..statusCode = HttpStatus.ok
..writeln('LoginSuccess')
..close();
}
@Post(path: '/logout')
void logout(HttpRequest request){
request.response
..statusCode = HttpStatus.ok
..writeln('logoutSuccess')
..close();
}
@Request(path: '/delete', method: 'DELETE')
void editUser(HttpRequest request){
request.response
..statusCode = HttpStatus.ok
..writeln('DeleteSuccess')
..close();
}
}
下面,我們導(dǎo)入鏡子包dart:mirrors捞附,新建一個(gè)ControllerManager巾乳,用來去管理Controller
import 'dart:mirrors';
import 'dart:io';
class ControllerManager{
static ControllerManager manager=new ControllerManager();
//該list用于判斷Controller是否已經(jīng)被添加
List<BaseController> controllers=[];
//這是一個(gè)map,對(duì)應(yīng)的是請(qǐng)求鏈接鸟召,跟對(duì)應(yīng)的controller信息
Map<String,ControllerInfo> urlToMirror=new Map();
//添加控制器
void addController(BaseController controller){
//判斷當(dāng)前是否已經(jīng)添加過控制器
if(!controllers.contains(controller)){
controllers.add(controller);
//添加map
urlToMirror.addAll(getRequestInfo(controller));
}
}
//該controllerManager處理請(qǐng)求的方法
void requestServer(HttpRequest request){
//當(dāng)前請(qǐng)求的路徑
String path=request.uri.toString();
//當(dāng)前請(qǐng)求的方法
String method=request.method;
//判斷map中是否包含該請(qǐng)求地址
if(urlToMirror.containsKey(path)){
ControllerInfo info=urlToMirror[path];
//獲取到該請(qǐng)求胆绊,傳遞路徑、請(qǐng)求方法跟請(qǐng)求
info.invoke(path, method, request);
}else{
//沒有該地址返回一個(gè)404
request.response
..statusCode=HttpStatus.notFound
..write('''{
"code": 404,
"msg": "鏈接不存在欧募!"
}''')
..close();
}
}
}
上面的思路是压状,在初始化時(shí),將所有的Controller都添加到map中以請(qǐng)求路徑為key去查找跟继,當(dāng)請(qǐng)求時(shí)种冬,請(qǐng)求地址在map中查找到,就為它處理請(qǐng)求舔糖,如果查找不到娱两,就給它丟一個(gè)404的信息,下面是ControllerInfo
class ControllerInfo{
//請(qǐng)求地址對(duì)應(yīng)Controller中的方法,Symbol包含方法標(biāo)識(shí)
final Map<String,Symbol> urlToMethod;
//該參數(shù)包含通過類初始化得到的實(shí)例鏡子金吗,可以通過該參數(shù)調(diào)用方法
final InstanceMirror instanceMirror;
//構(gòu)造方法
ControllerInfo(this.instanceMirror,this.urlToMethod);
//調(diào)用請(qǐng)求方法
void invoke(String url,String method,HttpRequest request){
//判斷是否該請(qǐng)求地址是對(duì)應(yīng)的請(qǐng)求方法
if(urlToMethod.containsKey('$url#$method')){
//調(diào)用方法
instanceMirror.invoke(urlToMethod['$url#$method'], [request]);
}else {
//請(qǐng)求方法不對(duì)十兢,返回一個(gè)錯(cuò)誤
request.response
..statusCode=HttpStatus.methodNotAllowed
..write('''{
"code": 405,
"msg": "請(qǐng)求出錯(cuò)趣竣!"
}''')
..close();
}
}
}
主要的是Symbol、InstanceMirror這兩個(gè)類纪挎,通過instanceMirror.invoke(Symbol,[傳遞的參數(shù)]),就能調(diào)用對(duì)應(yīng)的方法了
我們?cè)贑ontrollerManager中還有一個(gè)添加Controller到map的方法getRequestInfo(controller)沒有介紹跟匆,這個(gè)就是獲取InstanceMirror跟Symbol的關(guān)鍵异袄,下面介紹獲取InstanceMirror跟Symbol
//傳遞一個(gè)Controller進(jìn)去
Map<String,ControllerInfo> getRequestInfo(BaseController controller) {
// 實(shí)際返回的Map
Map<String,ControllerInfo> info=new Map();
//請(qǐng)求地址對(duì)應(yīng)的方法
Map<String,Symbol> urlToMethod=new Map();
// 獲取Controller實(shí)例的鏡子
InstanceMirror im = reflect(controller);
//獲取Controller運(yùn)行時(shí)類型的鏡子
ClassMirror classMirror = im.type;
//請(qǐng)求的根路徑
List<String> path = [];
//該Controller的所有接收的請(qǐng)求地址
List<String> urlList=[];
//獲取元數(shù)據(jù),就是獲取@Controller(path: xxx)中的xxx
classMirror.metadata.forEach((medate) {
path.add(medate.reflectee.path);
});
//獲取該類的所有方法
classMirror.declarations.forEach((symbol, declarationMirror) {
//將自身的構(gòu)造方法剔除
if (symbol.toString() != classMirror.simpleName.toString()) {
//獲取方法的元數(shù)據(jù),就是@Get(path: path)
declarationMirror.metadata.forEach((medate) {
//請(qǐng)求的地址
String requestPath = path.join() + medate.reflectee.path;
//請(qǐng)求的類型
String method = medate.reflectee.method;
// print('請(qǐng)求地址為:$requestPath,請(qǐng)求方法為:$method');
//添加到請(qǐng)求地址集合
urlList.add(requestPath);
//添加到請(qǐng)求地址對(duì)應(yīng)方法的集合
urlToMethod.putIfAbsent('$requestPath#$method', ()=>symbol);
}
);
}
});
//實(shí)例化一個(gè)Controller信息
ControllerInfo controllerInfo=new ControllerInfo(im, urlToMethod);
//循環(huán)添加到實(shí)際需要的Map玛臂,對(duì)應(yīng)請(qǐng)求地址根ControllerInfo信息
urlList.forEach((url){
info.putIfAbsent(url, ()=>controllerInfo);
});
//返回需要的map
return info;
}
上面的注釋已經(jīng)寫的很明細(xì)了烤蜕,如果不清楚,我再講解下:
- reflect(controller) >>>> InstanceMirror(含有Controller的實(shí)例迹冤,可調(diào)用方法)
- InstanceMirror.type >>>> ClassMirror(為了獲取類的注解)
- classMirror. metadata >>>>> 獲取類的元數(shù)據(jù)
- classMirror.declarations >>>> (symbol, declarationMirror) 獲取該類的所有方法名(用于調(diào)用方法)讽营,鏡子(用于獲取元數(shù)據(jù))
- declarationMirror.metadata >>>> 獲取方法的元數(shù)據(jù)
好了,基本上講完泡徙,然后我們?nèi)ナ褂迷揅ontrollerManager
3. 使用ControllerManager
首先我們需要在運(yùn)行服務(wù)器之前橱鹏,將我們需要的Controller添加到ControllerManager中(這個(gè)比較笨的方法,如果有大佬知道怎么自動(dòng)去掃描Controller添加到ControllerManager堪藐,請(qǐng)告知小弟莉兰,謝謝!)
//添加控制器
ControllerManager.manager.addController(new UserController());
然后將我們之前的 handleMessage(request)方法替換為
//....
ControllerManager.manager.requestServer(request);
//....
當(dāng)所有操作完成之后,我們休息一會(huì)礁竞,然后點(diǎn)擊綠色按鈕糖荒,啟動(dòng)我們的服務(wù)器,并輸入http://localhost:8080/user/login
見證奇跡模捂!
可以看到捶朵,我們成功的利用注解處理請(qǐng)求!
今天的內(nèi)容基本上是這些了狂男,如果你仔細(xì)學(xué)習(xí)了該文章综看,對(duì)于Flutter開發(fā)也可以使用注解去登陸,去請(qǐng)求數(shù)據(jù)岖食,好了寓搬,謝謝!我們明天見县耽!
如果想繼續(xù)學(xué)習(xí)DartVM服務(wù)器開發(fā)句喷,請(qǐng)關(guān)注我,學(xué)習(xí)更多騷操作兔毙!