Flutter圈子DartVM服务器开发Flutter中文社区

DartVM服务器开发(第十七天)--Jaguar_websoc

2018-09-06  本文已影响135人  rhyme_lph

上一篇文章我们详细说明了如何使用JWT,今天,我们来使用websocket做一个简单的聊天室!那就开始吧!

1.定义消息

在开始建立webSocket之前,我们需要定义消息,如:发送人,发送时间,发送人id等..

import 'dart:convert';
class ChatMessageData {
  final String id;
  final String msg;
  final DateTime created;
  final String name;
  final int role;
  ChatMessageData(
    this.id,
    this.msg,
    this.name,
    this.role,
    this.created,
  );
  static ChatMessageData formMap(Map map) => ChatMessageData(
      map['id'],
      map['msg'],
      map['name'],
      map['role'],
      DateTime.fromMicrosecondsSinceEpoch(map['created']));

  Map toMap() => {
        "id": id,
        "msg": msg,
        "name": name,
        "role":role,
        "created": created.millisecondsSinceEpoch
      };
  String toJson() => jsonEncode(toMap());
  @override
  String toString() => toMap().toString();
}

我们这里定义了一个ChatMessageData,如果你想需要更多字段,可以再添加

2.添加消息订阅

//控制消息的发送
final pub = StreamController<ChatMessageData>();
//当pub调用add(data)方法,该sub的listen会监听到
final Stream<ChatMessageData> sub = pub.stream.asBroadcastStream();

3. 定义接口

这里我们定义两个接口,一个用于连接的接口,一个用于发送消息的接口

..post('/mini/login', (ctx) async{
      User user=await ctx.bodyAsJson(convert: User.forMap);
      String username = user.username;
      String password = user.password;
      if (username.isEmpty || password.isEmpty) {
        return Response.json(apiJson.errorMsgA(-1, '用户名或密码为空!').toMap());
      } else {
        User user = await userBean.findOneWhere(userBean.username.eq(username));
        if (user == null || user.password != password) {
          return Response.json(apiJson.errorMsgA(-2, '用户名或密码不正确!').toMap());
        } else {
          print('用户:$username登陆成功');
          return Response.json(apiJson.successA().toMap());
        }
      }
    })

连接接口

..ws(
      '/mini/connect',
      onConnect: (ctx, ws) {
        var subscription = sub.listen((ChatMessageData data) {
          print(data.toJson());
          ws.add(data.toJson());
        });
        ws.done.then((_) {
          print('用户已退出聊天房');
          subscription.cancel();
        });
        //连接上之后返回一条信息
        ws.add(new ChatMessageData('1', '欢迎登陆', '服务器', 1, DateTime.now()).toJson());
      },
      handler: (data) {
        //获取用户发送的消息
        ChatMessageData msg=ChatMessageData.formMap(json.decode(data));
        print(msg.toJson());
        //广播一条消息
        pub.add(msg);
      },
    )

ok,我们已经搭建好一个简单的聊天接口了,下面,我们使用Flutter简单的编辑一下客户端平台

4.Flutter建立一个简单的聊天室

这部分代码为Flutter下,可简单的编辑一个聊天室

mport 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(new FriendlychatApp());
}

final ThemeData kIOSTheme = new ThemeData(
  primarySwatch: Colors.orange,
  primaryColor: Colors.grey[100],
  primaryColorBrightness: Brightness.light,
);

final ThemeData kDefaultTheme = new ThemeData(
  primarySwatch: Colors.purple,
  accentColor: Colors.orangeAccent[400],
);

const String _name = "Your Name";

class FriendlychatApp extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
    return new MaterialApp(
      title: "Friendlychat",
      theme: defaultTargetPlatform == TargetPlatform.iOS
        ? kIOSTheme
        : kDefaultTheme,
      home: new ChatScreen(),
    );
  }
}

class ChatMessage extends StatelessWidget {
  ChatMessage({this.text, this.animationController});
  final String text;
  final AnimationController animationController;
  @override
  Widget build(BuildContext context) {
    return new SizeTransition(
      sizeFactor: new CurvedAnimation(
        parent: animationController,
        curve: Curves.easeOut
      ),
      axisAlignment: 0.0,
      child: new Container(
        margin: const EdgeInsets.symmetric(vertical: 10.0),
        child: new Row(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            new Container(
              margin: const EdgeInsets.only(right: 16.0),
              child: new CircleAvatar(child: new Text(_name[0])),
            ),
            new Expanded(
              child: new Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  new Text(_name, style: Theme.of(context).textTheme.subhead),
                  new Container(
                    margin: const EdgeInsets.only(top: 5.0),
                    child: new Text(text),
                  ),
                ],
              ),
            ),
          ],
        ),
      )
    );
  }
}

class ChatScreen extends StatefulWidget {
  @override
  State createState() => new ChatScreenState();
}

class ChatScreenState extends State<ChatScreen> with TickerProviderStateMixin {
  final List<ChatMessage> _messages = <ChatMessage>[];
  final TextEditingController _textController = new TextEditingController();
  bool _isComposing = false;

  void _handleSubmitted(String text) {
    _textController.clear();
    setState(() {
      _isComposing = false;
    });
    ChatMessage message = new ChatMessage(
      text: text,
      animationController: new AnimationController(
        duration: new Duration(milliseconds: 700),
        vsync: this,
      ),
    );
    setState(() {
      _messages.insert(0, message);
    });
    message.animationController.forward();
  }

  void dispose() {
    for (ChatMessage message in _messages)
      message.animationController.dispose();
    super.dispose();
  }

   Widget _buildTextComposer() {
    return new IconTheme(
      data: new IconThemeData(color: Theme.of(context).accentColor),
      child: new Container(
          margin: const EdgeInsets.symmetric(horizontal: 8.0),
          child: new Row(children: <Widget>[
            new Flexible(
              child: new TextField(
                controller: _textController,
                onChanged: (String text) {
                  setState(() {
                    _isComposing = text.length > 0;
                  });
                },
                onSubmitted: _handleSubmitted,
                decoration:
                    new InputDecoration.collapsed(hintText: "Send a message"),
              ),
            ),
            new Container(
                margin: new EdgeInsets.symmetric(horizontal: 4.0),
                child: Theme.of(context).platform == TargetPlatform.iOS
                    ? new CupertinoButton(
                        child: new Text("Send"),
                        onPressed: _isComposing
                            ? () => _handleSubmitted(_textController.text)
                            : null,
                      )
                    : new IconButton(
                        icon: new Icon(Icons.send),
                        onPressed: _isComposing
                            ? () => _handleSubmitted(_textController.text)
                            : null,
                      )),
          ]),
          decoration: Theme.of(context).platform == TargetPlatform.iOS
              ? new BoxDecoration(
                  border:
                      new Border(top: new BorderSide(color: Colors.grey[200])))
              : null),
    );
  }

  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("Friendlychat"),
        elevation:
            Theme.of(context).platform == TargetPlatform.iOS ? 0.0 : 4.0
      ),
      body: new Container(
        child: new Column(
          children: <Widget>[
          new Flexible(
            child: new ListView.builder(
              padding: new EdgeInsets.all(8.0),
              reverse: true,
              itemBuilder: (_, int index) => _messages[index],
              itemCount: _messages.length,
            )
          ),
          new Divider(height: 1.0),
          new Container(
            decoration: new BoxDecoration(
              color: Theme.of(context).cardColor),
            child: _buildTextComposer(),
          ),
         ]
       ),
       decoration: Theme.of(context).platform == TargetPlatform.iOS ? new BoxDecoration(border: new Border(top: new BorderSide(color: Colors.grey[200]))) : null),//new
   );
  }
}

上面就是简单的聊天界面,我们还有主要跟服务器交互的方法

WebSocket socket;
void login() {
    httpManager.post(
        url: 'http://192.168.1.101:8080/mini/login',
        body: json.encode({
          "username": "rhyme",
          "password": "123456",
        }),
        onSend: () {
//key为scaffold的key
          scaffoldKey?.currentState
              ?.showSnackBar(new SnackBar(content: Text('发送请求,连接服务器')));
        },
        onSuccess: (data) {
          WebSocket.connect('ws://192.168.1.101:8080/mini/connect')
              .then((socket) {
            this.socket = socket;
            socket.listen((data) {
//该方法接收服务器信息
              print(data);
              Map map = json.decode(data);
              ChatMessageData msg=ChatMessageData.formMap(map);
              if(msg.id!=widget.user.uuid){
                _handleGetMessage(msg);
              }
            });
            socket.done.then((e){
//当与服务器连接中断调用
              scaffoldKey.currentState.showSnackBar(new SnackBar(content: Text('连接服务器中断!')));
            });
          });
        },
        onError: (error) {
          print(error);
          scaffoldKey.currentState.showSnackBar(
              new SnackBar(content: Text('连接失败!${error.toString()}')));
        });
  }

我们发送消息给服务端

    socket.add(new ChatMessageData(widget.user.uuid, value, widget.user.userName, widget.user.role, DateTime.now()).toJson());

最后我们来尝试一下吧!


image.png
image.png

ok,我们是成功的!今天就到这里了,我们明天见!

如果想继续学习DartVM服务器开发,请关注我,学习更多骚操作!

上一篇下一篇

猜你喜欢

热点阅读