1.介绍
这一节我们来学习一下资源控制器ResourceController
2. 什么是资源控制器?
可以从名字看出,这个控制器是用来管理资源的,也就是上一节中介绍了控制器B,也可以称为端点的控制器,可以用以下图来描述:
Controller处理,那么会不会出现该控制器会不断的实例化,导致性能出现问题呢?
3. Recyclable
我们在查看源码的时候,可以看到ResourceController继承 Controller并实现了Recyclable,这个 Recyclable就是能让Controller实现在处理完请求后,进行回收,等待下次请求时不用重新实例化,它主要实现了 recycledState和restore
BoundController的一个实体,那么这个实体哪个地方耗时,导致需要循环再用呢?我们进一步看源码
4.请求方法
目前Aqueduct框架支持下面的注解请求方法,并且支持 0-4的请求路径
-
Operation('请求方法') -
Operation.get -
Operation.put -
Operation.post -
Operation.delete
我们来把之前的获取文章接口使用ResourceController实现看看,新建文件 article_controller,然后添加以下代码
class ArticleController extends ResourceController { ArticleController(this.context); final ManagedContext context; @Operation.get() //获取文章列表 FutureOr<Response> getArticle() async {//查询文章,并根据createDate进行排序 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 { //定义路由、请求链接等,在启动期间调用 return Router(notFoundHandler: (request) async { //当出现请求不到接口的时候,返回下面内容给客户端 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
上面代码就完成了请求文章列表的接口,让我们来请求一下http://localhost:8080/article
class ArticleController extends ResourceController { ArticleController(this.context); final ManagedContext context; @Operation.get() //获取文章列表 FutureOr<Response> getArticle() async {//查询文章,并根据createDate进行排序 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();//插入一条数据 final result = await context.insertObject<Article>(article); return Result.data(result); } @Operation.get('id')//查询单个文章 Future<Response> getArticleById(@Bind.path('id') int id) async {//根据id查询一条数据 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);//更新一条数据 final result = await query.updateOne();// final article = await query.fetchOne(); if (result != null) { return Result.data(result); } else { return Result.errorMsg("更新失败,数据不存在"); } } @Operation.delete('id')//删除一篇文章 Future<Response> deleteArticleById(@Bind.path('id') int id) async { final query = Query<Article>(context)..where((a) => a.id).equalTo(id);//删除一条数据 final result = await query.delete(); if (result != null && result == 1) { return Result.successMsg("删除成功"); } else { return Result.errorMsg("删除失败,数据不存在"); } }}
以上就是文章的增删查改,有兴趣的朋友可以CV看看效果,下面我们来学习一下在代码中出现的@Bind
5.请求绑定
目前Aqueduct框架支持下面的注解请求绑定
-
Bind.path绑定路径
具体使用:
@Operation.get('id')//查询单个文章 Future<Response> getArticleById(@Bind.path('id') int id) async {//根据id查询一条数据 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(); } }
对应请求:http://localhost:8080/article/1
-
Bind.query绑定Url查询参数
具体使用:
@Operation.get() //获取文章列表或一篇文章 FutureOr<Response> getArticle({@Bind.query('id') int id}) async {//使用中括号表示参数可选 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 {//查询文章,并根据createDate进行排序 final query = Query<Article>(context) ..sortBy((e) => e.createDate, QuerySortOrder.ascending); final List<Article> articles = await query.fetch(); return Result.data(articles); } }
对应请求:http://localhost:8080/article?id=1
-
Bind.header绑定请求头
具体使用:
class ArticleController extends ResourceController { ArticleController(this.context); final ManagedContext context; @Bind.header("token") String token;//@Bind注解可以在局部变量使用,根据传入的key获取对应的值//...}
-
Bind.body绑定请求体(需要注意,获取的内容为json形式传递的数据)具体使用:
@Operation.post() //添加一篇文章 FutureOr<Response> insertArticle( @Bind.body(ignore: ["createData"]) Article article) async {//这里可以直接转为实体,但需要注意的是@Bind.body里的参数含义如下//ignore表示忽略哪些字段//reject表示拒绝接收哪些字段//require表示哪些字段必须有//啥都不填表示参数如果不传则为空 article.createDate = DateTime.now();//插入一条数据 final result = await context.insertObject<Article>(article); return Result.data(result); }
6.ResourceController全局参数
当某个控制器需要获取或设置全局参数时,框架提供以下参数:
-
Request request可获取请求信息 -
Mapget pathVariables可获取路径 -
List acceptedContentTypes可设置接收的内容类型 -
ContentType responseContentType可设置响应的内容类型
7.生命周期
很多时候,一个请求的到来,通常伴随者控制器的生命周期,下面是ResourceController的生命周期
FutureOr<RequestOrResponse> willProcessRequest(Request req)//在处理请求之前调用,如果返回Response类型,则终止后续处理void willDecodeRequestBody(RequestBody body)//在解码请求体之前调用void didDecodeRequestBody(RequestBody body)//在解码请求体之后调用,如果没有请求体,则不执行FutureOr<RequestOrResponse> handle(Request request)//该方法继承自Controller,无需处理
以上就是这一节的所有内容,如果小伙伴们觉得有收获,不妨点一下点⬇️在看,让我能看到你跟我一起学习Dart服务器,也是对我写作的一种肯定🙏!