DartVM服務(wù)器開發(fā)(第六天)--利用注解處理請(qǐng)求

在之前的文章中似忧,我們學(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)用方法踏兜。


image

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
見證奇跡模捂!

成功.png

可以看到捶朵,我們成功的利用注解處理請(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í)更多騷操作兔毙!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末唾琼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子澎剥,更是在濱河造成了極大的恐慌锡溯,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異祭饭,居然都是意外死亡芜茵,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門倡蝙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來九串,“玉大人,你說我怎么就攤上這事寺鸥≈砼ィ” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵胆建,是天一觀的道長烤低。 經(jīng)常有香客問我,道長笆载,這世上最難降的妖魔是什么扑馁? 我笑而不...
    開封第一講書人閱讀 56,648評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮凉驻,結(jié)果婚禮上檐蚜,老公的妹妹穿的比我還像新娘。我一直安慰自己沿侈,他們只是感情好闯第,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,770評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著缀拭,像睡著了一般咳短。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上蛛淋,一...
    開封第一講書人閱讀 49,950評(píng)論 1 291
  • 那天咙好,我揣著相機(jī)與錄音,去河邊找鬼褐荷。 笑死勾效,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的叛甫。 我是一名探鬼主播层宫,決...
    沈念sama閱讀 39,090評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼其监!你這毒婦竟也來了萌腿?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤抖苦,失蹤者是張志新(化名)和其女友劉穎毁菱,沒想到半個(gè)月后米死,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡贮庞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,592評(píng)論 2 327
  • 正文 我和宋清朗相戀三年峦筒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片窗慎。...
    茶點(diǎn)故事閱讀 38,724評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡物喷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出捉邢,到底是詐尸還是另有隱情脯丝,我是刑警寧澤商膊,帶...
    沈念sama閱讀 34,409評(píng)論 4 333
  • 正文 年R本政府宣布伏伐,位于F島的核電站,受9級(jí)特大地震影響晕拆,放射性物質(zhì)發(fā)生泄漏藐翎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,052評(píng)論 3 316
  • 文/蒙蒙 一实幕、第九天 我趴在偏房一處隱蔽的房頂上張望吝镣。 院中可真熱鬧,春花似錦昆庇、人聲如沸末贾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽拱撵。三九已至,卻和暖如春表蝙,著一層夾襖步出監(jiān)牢的瞬間拴测,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評(píng)論 1 266
  • 我被黑心中介騙來泰國打工府蛇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留集索,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,503評(píng)論 2 361
  • 正文 我出身青樓汇跨,卻偏偏與公主長得像务荆,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子穷遂,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,627評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理蛹含,服務(wù)發(fā)現(xiàn),斷路器塞颁,智...
    卡卡羅2017閱讀 134,637評(píng)論 18 139
  • Spring Web MVC Spring Web MVC 是包含在 Spring 框架中的 Web 框架浦箱,建立于...
    Hsinwong閱讀 22,363評(píng)論 1 92
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,778評(píng)論 6 342
  • 醒在2017的除夕 太陽強(qiáng)烈 老公溫柔 人類和植物一樣幸福 鞭炮和紅包一樣四起 產(chǎn)品里開始有群吵架 竊喜 偏見產(chǎn)生...
    掌門_艾老師閱讀 157評(píng)論 0 2
  • 2017.12.4-12.5 給倩楠的幾個(gè)建議: 1吸耿、加幾支有顏色的筆(但最多三色);2酷窥、下筆放慢速度咽安,比平常至少...
    企業(yè)煉金師閱讀 261評(píng)論 0 0