Flutter书架管理插件shelf_plus的使用

Flutter书架管理插件shelf_plus的使用

概述

Shelf Plus 是一个用于服务器端开发的质量提升插件,基于 Shelf 平台。它提供了快速启动应用程序的能力,并且与 Shelf 生态系统完全兼容。Shelf Plus 包含了零配置初始化、内置热重载以及强大的路由增强功能。

快速开始

简单示例

import 'package:shelf_plus/shelf_plus.dart';

void main() => shelfRun(init);

Handler init() {
  var app = Router().plus;

  app.get('/', () => 'Hello World!');

  return app.call;
}

路由增强 (Router Plus)

基本用法

var app = Router().plus;

app.use(middleware());

app.get('/text', () => 'I am a text');

app.get('/html/<name>', (Request request, String name) => '<h1>Hello $name</h1>',
    use: typeByExtension('html'));

app.get('/file', () => File('path/to/file.zip'));

app.get('/person', () => Person(name: 'John', age: 42));

处理返回值 (ResponseHandler)

Shelf Plus 提供了一个强大的 ResponseHandler 机制,可以处理多种类型的返回值:

返回类型 使用场景
String 响应文本(text/plain)
Uint8List, Stream<List<int>> 响应二进制数据(application/octet-stream)
Map<String, dynamic>, List<dynamic> 响应 JSON 数据(application/json)
任何具有 toJson() 方法的类 序列化支持
File 响应文件内容
WebSocketSession 创建 WebSocket 连接
Handler 处理 Shelf 中间件或处理器

示例代码

import 'dart:io';
import 'package:shelf_plus/shelf_plus.dart';

void main() => shelfRun(init);

Handler init() {
  var app = Router().plus;

  app.get('/text', () => 'a text');
  app.get('/binary', () => File('data.zip').openRead());
  app.get('/json', () => {'name': 'John', 'age': 42});
  app.get('/class', () => Person('Theo'));
  app.get('/list-of-classes', () => [Person('Theo'), Person('Bob')]);
  app.get('/iterables', () => [1, 10, 100].where((n) => n > 9));
  app.get('/handler', () => typeByExtension('html') >> '<h1>Hello</h1>');
  app.get('/file', () => File('thesis.pdf'));
  app.get('/websocket', () => WebSocketSession(
        onOpen: (ws) => ws.send('Hello!'),
        onMessage: (ws, data) => ws.send('You sent me: $data'),
        onClose: (ws) => ws.send('Bye!'),
      ));

  return app.call;
}

class Person {
  final String name;

  Person(this.name);

  Map<String, dynamic> toJson() => {'name': name};
}

中间件 (Middleware)

使用中间件

var app = Router().plus;

app.use(middlewareA); // 应用于所有路由

// 应用于单个路由
app.get('/request1', () => 'response', use: middlewareB);

// 组合中间件
app.get('/request2', () => 'response', use: middlewareB + middlewareC);

在请求处理器中动态应用中间件

app.get('/request/<value>', (Request request, String value) {
  return middleware(value) >> 'response';
});

请求体处理 (Request Body Handling)

解析请求体

app.post('/text', (Request request) async {
  var text = await request.body.asString;
  return 'You send me: $text';
});

app.post('/json', (Request request) async {
  var person = Person.fromJson(await request.body.asJson);
  return 'You send me: ${person.name}';
});

自定义访问器 (Custom Accessors)

extension PersonAccessor on RequestBodyAccessor {
  Future<Person> get asPerson async => Person.fromJson(await asJson);
}

app.post('/person', (Request request) async {
  var person = await request.body.asPerson;
  return 'You send me: ${person.name}';
});

Shelf Run

启动服务器

import 'package:shelf_plus/shelf_plus.dart';

void main() => shelfRun(init);

Handler init() {
  return (Request request) => Response.ok('Hello!');
}

自定义配置

void main() => shelfRun(init, defaultBindPort: 3000);

多线程支持

import 'dart:isolate';
import 'package:shelf_plus/shelf_plus.dart';

void main() {
  const numberOfIsolates = 8;

  for (var i = 0; i < numberOfIsolates - 1; i++) {
    Isolate.spawn(spawnServer, null, debugName: i.toString()); // isolate 0..7
  }
  spawnServer(null); // use main isolate as the 8th isolate
}

void spawnServer(_) => shelfRun(init, defaultShared: true);

Handler init() {
  var app = Router().plus;

  app.get('/', () async {
    await Future.delayed(Duration(milliseconds: 500)); // simulate load
    return 'Hello from isolate: ${Isolate.current.debugName}';
  });

  return app.call;
}

示例

启用 CORS

import 'package:shelf_cors_headers/shelf_cors_headers.dart';
import 'package:shelf_plus/shelf_plus.dart';

void main() => shelfRun(init);

Handler init() {
  final router = Router().plus;

  router.get('/', () => {'data': 'This API is CORS enabled.'});

  return corsHeaders() >> router.call;
}

REST 服务

import 'dart:io';
import 'package:shelf_plus/shelf_plus.dart';
import 'person.dart';

void main() => shelfRun(init);

final data = <Person>[
  Person(firstName: 'John', lastName: 'Doe', age: 42),
  Person(firstName: 'Jane', lastName: 'Doe', age: 43),
];

Handler init() {
  var app = Router().plus;

  app.get('/', () => File('frontend/page.html'));
  app.get('/person', () => data);
  app.get('/person/<id>', (Request request, String id) => data.where((person) => person.id == id));
  app.post('/person', (Request request) async {
    var newPerson = await request.body.as(Person.fromJson);
    data.add(newPerson);
    return {'ok': 'true', 'person': newPerson.toJson()};
  });
  app.put('/person/<id>', (Request request, String id) async {
    data.removeWhere((person) => person.id == id);
    var person = await request.body.as(Person.fromJson);
    person.id = id;
    data.add(person);
    return {'ok': 'true'};
  });
  app.delete('/person/<id>', (Request request, String id) {
    data.removeWhere((person) => person.id == id);
    return {'ok': 'true'};
  });

  return app.call;
}

WebSocket 聊天服务器

import 'dart:io';
import 'package:shelf_plus/shelf_plus.dart';

void main() => shelfRun(init);

Handler init() {
  var app = Router().plus;

  app.get('/', () => File('public/html_client.html'));

  var users = <WebSocketSession>[];

  app.get('/ws', () => WebSocketSession(
        onOpen: (ws) {
          users.add(ws);
          users.where((user) => user != ws).forEach((user) => user.send('A new user joined the chat.'));
        },
        onClose: (ws) {
          users.remove(ws);
          for (var user in users) {
            user.send('A user has left.');
          }
        },
        onMessage: (ws, dynamic data) {
          for (var user in users) {
            user.send(data);
          }
        },
      ));

  return app.call;
}

通过以上内容,您可以快速上手并充分利用 shelf_plus 插件的强大功能来构建高效的服务端应用。

1 回复

更多关于Flutter书架管理插件shelf_plus的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html


当然,下面是一个关于如何使用Flutter书架管理插件shelf_plus的示例代码案例。这个插件假设是用来管理书籍的添加、删除和展示等基本功能。请注意,shelf_plus是一个假设的插件名称,实际中你可能需要找到一个真实存在的插件或自己实现这些功能。

首先,确保你的Flutter项目中已经添加了shelf_plus插件。你可以在pubspec.yaml文件中添加依赖项:

dependencies:
  flutter:
    sdk: flutter
  shelf_plus: ^x.y.z  # 替换为实际的版本号

然后运行flutter pub get来安装依赖。

接下来是一个简单的Flutter应用示例,展示如何使用shelf_plus插件来管理书架上的书籍。

main.dart

import 'package:flutter/material.dart';
import 'package:shelf_plus/shelf_plus.dart';  // 假设这是插件的导入路径

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Shelf Management',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ShelfManagerScreen(),
    );
  }
}

class ShelfManagerScreen extends StatefulWidget {
  @override
  _ShelfManagerScreenState createState() => _ShelfManagerScreenState();
}

class _ShelfManagerScreenState extends State<ShelfManagerScreen> {
  final ShelfPlusController _shelfController = ShelfPlusController();
  final TextEditingController _titleController = TextEditingController();

  @override
  void initState() {
    super.initState();
    // 初始化书架数据,可以从本地存储或远程服务器加载
    _shelfController.initialize();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Book Shelf Manager'),
      ),
      body: Padding(
        padding: const EdgeInsets.all(8.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            TextField(
              controller: _titleController,
              decoration: InputDecoration(labelText: 'Book Title'),
            ),
            SizedBox(height: 16),
            ElevatedButton(
              onPressed: () async {
                // 添加书籍到书架
                String title = _titleController.text;
                if (title.isNotEmpty) {
                  await _shelfController.addBook(title);
                  _titleController.clear();
                  setState(() {});  // 刷新UI以显示新书
                } else {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Book title cannot be empty')),
                  );
                }
              },
              child: Text('Add Book'),
            ),
            SizedBox(height: 16),
            Expanded(
              child: ListView.builder(
                itemCount: _shelfController.bookCount,
                itemBuilder: (context, index) {
                  Book book = _shelfController.getBookAtIndex(index);
                  return Dismissible(
                    key: Key(book.id),
                    onDismissed: (direction) async {
                      // 从书架中删除书籍
                      await _shelfController.removeBook(book.id);
                      setState(() {});  // 刷新UI以删除书籍
                    },
                    background: Container(color: Colors.red, alignment: Alignment.centerRight, child: Icon(Icons.delete)),
                    child: ListTile(
                      title: Text(book.title),
                    ),
                  );
                },
              ),
            ),
          ],
        ),
      ),
    );
  }
}

// 假设的Book类
class Book {
  String id;
  String title;

  Book({required this.id, required this.title});
}

// 假设的ShelfPlusController类
class ShelfPlusController {
  List<Book> _books = [];
  int _nextId = 1;

  // 初始化书架数据
  Future<void> initialize() async {
    // 这里可以从本地存储或远程服务器加载数据
    // 示例:_books = await fetchBooksFromLocalStorage();
  }

  // 添加书籍到书架
  Future<void> addBook(String title) async {
    String id = 'book_$_nextId';
    _nextId++;
    _books.add(Book(id: id, title: title));
    // 这里可以保存数据到本地存储或远程服务器
    // 示例:await saveBookToLocalStorage(Book(id: id, title: title));
  }

  // 从书架中删除书籍
  Future<void> removeBook(String id) async {
    _books.removeWhere((book) => book.id == id);
    // 这里可以删除数据从本地存储或远程服务器
    // 示例:await deleteBookFromLocalStorage(id);
  }

  // 获取书架上的书籍数量
  int get bookCount => _books.length;

  // 根据索引获取书籍
  Book getBookAtIndex(int index) {
    return _books[index];
  }
}

在这个示例中,我们创建了一个简单的Flutter应用,它使用了一个假设的ShelfPlusController类来管理书架上的书籍。用户可以在输入框中输入书籍标题,然后点击“Add Book”按钮将书籍添加到书架。书架上的每本书籍都可以通过滑动来删除。

请注意,这个示例中的ShelfPlusController类和Book类都是假设的,实际中你可能需要根据你的具体需求和插件API来实现这些功能。此外,数据持久化(如保存到本地存储或远程服务器)的部分也需要根据你的具体需求来实现。

回到顶部
AI 助手
你好,我是IT营的 AI 助手
您可以尝试点击下方的快捷入口开启体验!