Dart-Aqueduct框架開發(fā)(六)

上一篇

聲明:本文首發(fā)于微信訂閱號(hào):Dart客棧,微信后臺(tái)回復(fù)05166獲取本篇源碼
文章為原創(chuàng)藕夫,如需轉(zhuǎn)載請(qǐng)注明出處昌屉,并告知作者,謝謝福扬!

1.介紹

這一節(jié)我們來學(xué)習(xí)一下資源控制器ResourceController

2. 什么是資源控制器腕铸?

可以從名字看出,這個(gè)控制器是用來管理資源的铛碑,也就是上一節(jié)中介紹了控制器B狠裹,也可以稱為端點(diǎn)的控制器,可以用以下圖來描述:



從上圖可以得到的信息為汽烦,控制器可以處理多個(gè)請(qǐng)求路徑涛菠,并可返回不同的內(nèi)容,那么為什么它可以處理這么多個(gè)請(qǐng)求呢撇吞?如果多次請(qǐng)求讓Controller處理俗冻,那么會(huì)不會(huì)出現(xiàn)該控制器會(huì)不斷的實(shí)例化,導(dǎo)致性能出現(xiàn)問題呢牍颈?

3. Recyclable

我們?cè)诓榭丛创a的時(shí)候迄薄,可以看到ResourceController繼承Controller并實(shí)現(xiàn)了Recyclable,這個(gè)Recyclable就是能讓Controller實(shí)現(xiàn)在處理完請(qǐng)求后,進(jìn)行回收煮岁,等待下次請(qǐng)求時(shí)不用重新實(shí)例化讥蔽,它主要實(shí)現(xiàn)了recycledStaterestore



從源碼中可以看出,它保存了類名為BoundController的一個(gè)實(shí)體画机,那么這個(gè)實(shí)體哪個(gè)地方耗時(shí)冶伞,導(dǎo)致需要循環(huán)再用呢?我們進(jìn)一步看源碼

可以看到色罚,它的構(gòu)造方法一開始就調(diào)用了反射碰缔,大家應(yīng)該都知道,反射是比較耗時(shí)的戳护,如果每次請(qǐng)求一下都要反射一次的話金抡,那這個(gè)性能太低了瀑焦,所以需要循環(huán)使用,而歸功于上面的反射梗肝,可以使用元數(shù)據(jù)(注解)進(jìn)行對(duì)請(qǐng)求的處理

4.請(qǐng)求方法

目前Aqueduct框架支持下面的注解請(qǐng)求方法榛瓮,并且支持0-4的請(qǐng)求路徑

  • Operation('請(qǐng)求方法')
  • Operation.get
  • Operation.put
  • Operation.post
  • Operation.delete

我們來把之前的獲取文章接口使用ResourceController實(shí)現(xiàn)看看,新建文件article_controller,然后添加以下代碼

class ArticleController extends ResourceController {
  ArticleController(this.context);

  final ManagedContext context;

  @Operation.get() //獲取文章列表
  FutureOr<Response> getArticle() async {
//查詢文章巫击,并根據(jù)createDate進(jìn)行排序
    final query = Query<Article>(context)
      ..sortBy((e) => e.createData, QuerySortOrder.ascending);
    final List<Article> articles = await query.fetch();
    return Result.data(articles);
  }
}

然后把ArticleController鏈接到Router里面

  @override
  Controller get entryPoint {
    //定義路由禀晓、請(qǐng)求鏈接等,在啟動(dòng)期間調(diào)用
    return Router(notFoundHandler: (request) async {
      //當(dāng)出現(xiàn)請(qǐng)求不到接口的時(shí)候坝锰,返回下面內(nèi)容給客戶端
      await request.respond(Response.notFound()
        ..contentType = ContentType.json
        ..body = {
          'code': 404,
          'msg': 'not found',
          "data": null,
        });
      //打印日志
      logger.warning("${request.toDebugString()}");
    })
//new
      ..route('/article/[:id([0-9]+)]').link(
        () => ArticleController(context),
      );
//new

上面代碼就完成了請(qǐng)求文章列表的接口粹懒,讓我們來請(qǐng)求一下http://localhost:8080/article


可以看到,我們成功的拿到了數(shù)據(jù)顷级,下面凫乖,我們繼續(xù)添加文章的增刪改的接口

class ArticleController extends ResourceController {
  ArticleController(this.context);

  final ManagedContext context;

  @Operation.get() //獲取文章列表
  FutureOr<Response> getArticle() async {
//查詢文章,并根據(jù)createDate進(jìn)行排序
    final query = Query<Article>(context)
      ..sortBy((e) => e.createDate, QuerySortOrder.ascending);
    final List<Article> articles = await query.fetch();
    return Result.data(articles);
  }

  @Operation.post()//添加一篇文章
  FutureOr<Response> insertArticle(
      @Bind.body(ignore: ["createData"]) Article article) async {
    article.createDate = DateTime.now();
//插入一條數(shù)據(jù)
    final result = await context.insertObject<Article>(article);
    return Result.data(result);
  }

  @Operation.get('id')//查詢單個(gè)文章
  Future<Response> getArticleById(@Bind.path('id') int id) async {
//根據(jù)id查詢一條數(shù)據(jù)
    final query = Query<Article>(context)..where((a) => a.id).equalTo(id);
    final article = await query.fetchOne();
    if (article != null) {
      return Result.data(article);
    } else {
      return Result.successMsg();
    }
  }

  @Operation.put()//修改一篇文章
  Future<Response> updateArticleById(
      @Bind.body(ignore: ["createData"]) Article article) async {

    final query = Query<Article>(context)
      ..values.content = article.content
      ..where((a) => a.id).equalTo(article.id);
//更新一條數(shù)據(jù)
    final result = await query.updateOne();
//    final article = await query.fetchOne();
    if (result != null) {
      return Result.data(result);
    } else {
      return Result.errorMsg("更新失敗弓颈,數(shù)據(jù)不存在");
    }
  }

  @Operation.delete('id')//刪除一篇文章
  Future<Response> deleteArticleById(@Bind.path('id') int id) async {
    final query = Query<Article>(context)..where((a) => a.id).equalTo(id);
//刪除一條數(shù)據(jù)
    final result = await query.delete();
    if (result != null && result == 1) {
      return Result.successMsg("刪除成功");
    } else {
      return Result.errorMsg("刪除失敗帽芽,數(shù)據(jù)不存在");
    }
  }
}

以上就是文章的增刪查改,有興趣的朋友可以CV看看效果翔冀,下面我們來學(xué)習(xí)一下在代碼中出現(xiàn)的@Bind

5.請(qǐng)求綁定

目前Aqueduct框架支持下面的注解請(qǐng)求綁定

  • Bind.path 綁定路徑

具體使用:

  @Operation.get('id')//查詢單個(gè)文章
  Future<Response> getArticleById(@Bind.path('id') int id) async {
//根據(jù)id查詢一條數(shù)據(jù)
    final query = Query<Article>(context)..where((a) => a.id).equalTo(id);
    final article = await query.fetchOne();
    if (article != null) {
      return Result.data(article);
    } else {
      return Result.successMsg();
    }
  }

對(duì)應(yīng)請(qǐng)求:http://localhost:8080/article/1

  • Bind.query 綁定Url查詢參數(shù)

具體使用:

  @Operation.get() //獲取文章列表或一篇文章
  FutureOr<Response> getArticle({@Bind.query('id') int id}) async {//使用中括號(hào)表示參數(shù)可選
    if (id != null) {
//查詢一篇文章
      final query = Query<Article>(context)..where((a) => a.id).equalTo(id);
      final article = await query.fetchOne();
      if (article != null) {
        return Result.data(article);
      } else {
        return Result.successMsg();
      }
    } else {
//查詢文章导街,并根據(jù)createDate進(jìn)行排序
      final query = Query<Article>(context)
        ..sortBy((e) => e.createDate, QuerySortOrder.ascending);
      final List<Article> articles = await query.fetch();
      return Result.data(articles);
    }
  }

對(duì)應(yīng)請(qǐng)求:http://localhost:8080/article?id=1

  • Bind.header綁定請(qǐng)求頭

具體使用:

class ArticleController extends ResourceController {
  ArticleController(this.context);

  final ManagedContext context;

  @Bind.header("token")
  String token;//@Bind注解可以在局部變量使用,根據(jù)傳入的key獲取對(duì)應(yīng)的值

//...
}
image.png
  • Bind.body綁定請(qǐng)求體(需要注意纤子,獲取的內(nèi)容為json形式傳遞的數(shù)據(jù))
    具體使用:
  @Operation.post() //添加一篇文章
  FutureOr<Response> insertArticle(
      @Bind.body(ignore: ["createData"]) Article article) async {
//這里可以直接轉(zhuǎn)為實(shí)體搬瑰,但需要注意的是@Bind.body里的參數(shù)含義如下
//ignore表示忽略哪些字段
//reject表示拒絕接收哪些字段
//require表示哪些字段必須有
//啥都不填表示參數(shù)如果不傳則為空
    article.createDate = DateTime.now();
//插入一條數(shù)據(jù)
    final result = await context.insertObject<Article>(article);
    return Result.data(result);
  }

6.ResourceController全局參數(shù)

當(dāng)某個(gè)控制器需要獲取和設(shè)置全局參數(shù)時(shí),框架提供一下內(nèi)容:

  • Request request 可獲取請(qǐng)求信息
  • Map<String, String> get pathVariables 可獲取路徑
  • List<ContentType> acceptedContentTypes 可設(shè)置接收的內(nèi)容類型
  • ContentType responseContentType可設(shè)置響應(yīng)的內(nèi)容類型

7.生命周期

很多時(shí)候计福,一個(gè)請(qǐng)求的到來跌捆,通知伴隨者控制器的生命周期,下面是ResourceController的生命周期

FutureOr<RequestOrResponse> willProcessRequest(Request req)
//在處理請(qǐng)求之前調(diào)用象颖,如果返回Response類型佩厚,則終止后續(xù)處理

void willDecodeRequestBody(RequestBody body)
//在解碼請(qǐng)求體之前調(diào)用

void didDecodeRequestBody(RequestBody body)
//在解碼請(qǐng)求體之后調(diào)用,如果沒有請(qǐng)求體说订,則不執(zhí)行

FutureOr<RequestOrResponse> handle(Request request)
//該方法繼承自Controller,無需處理

以上就是這一節(jié)的所有內(nèi)容抄瓦,如果小伙伴們覺得有收獲,不妨點(diǎn)一下點(diǎn)個(gè)贊陶冷,讓我能看到你跟我一起學(xué)習(xí)Dart服務(wù)器钙姊,也是對(duì)我寫作的一種肯定??!

下一篇

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末埂伦,一起剝皮案震驚了整個(gè)濱河市煞额,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖膊毁,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件胀莹,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡婚温,警方通過查閱死者的電腦和手機(jī)描焰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來栅螟,“玉大人荆秦,你說我怎么就攤上這事×ν迹” “怎么了步绸?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長吃媒。 經(jīng)常有香客問我靡努,道長,這世上最難降的妖魔是什么晓折? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮兽泄,結(jié)果婚禮上漓概,老公的妹妹穿的比我還像新娘。我一直安慰自己病梢,他們只是感情好胃珍,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜓陌,像睡著了一般觅彰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钮热,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天填抬,我揣著相機(jī)與錄音,去河邊找鬼隧期。 笑死飒责,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的仆潮。 我是一名探鬼主播宏蛉,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼性置!你這毒婦竟也來了拾并?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎嗅义,沒想到半個(gè)月后屏歹,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芥喇,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年西采,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片继控。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡械馆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出武通,到底是詐尸還是另有隱情霹崎,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布冶忱,位于F島的核電站尾菇,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏囚枪。R本人自食惡果不足惜派诬,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望链沼。 院中可真熱鬧默赂,春花似錦、人聲如沸括勺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽疾捍。三九已至奈辰,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乱豆,已是汗流浹背奖恰。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留咙鞍,地道東北人房官。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像续滋,于是被迫代替她去往敵國和親翰守。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344