netty聊天室

package com.example.netty.chat.server;
import com.example.netty.chat.protocol.IMDecoder;
import com.example.netty.chat.protocol.IMEncoder;
import com.example.netty.chat.server.handler.HttpHandler;
import com.example.netty.chat.server.handler.SocketHandler;
import com.example.netty.chat.server.handler.WebSocktHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import lombok.extern.slf4j.Slf4j;
import java.io.IOException;
@Slf4j
public class ChatServer {

    private int port = 8080;

    public void start() {
        //主
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        //工作
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try {
            ServerBootstrap b = new ServerBootstrap();
            b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).option(ChannelOption.SO_BACKLOG, 1024)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {

                            ChannelPipeline pipeline = ch.pipeline();

                            /** 解析自定义协议 */
                            pipeline.addLast(new IMDecoder());
                            pipeline.addLast(new IMEncoder());
                            pipeline.addLast(new SocketHandler());

                            /** 解析Http请求 */
                            pipeline.addLast(new HttpServerCodec());
                            //主要是将同一个http请求或响应的多个消息对象变成一个 fullHttpRequest完整的消息对象
                            pipeline.addLast(new HttpObjectAggregator(64 * 1024));
                            //主要用于处理大数据流,比如一个1G大小的文件如果你直接传输肯定会撑暴jvm内存的 ,加上这个handler我们就不用考虑这个问题了
                            pipeline.addLast(new ChunkedWriteHandler());
                            pipeline.addLast(new HttpHandler());

                            /** 解析WebSocket请求 */
                            pipeline.addLast(new WebSocketServerProtocolHandler("/im"));
                            pipeline.addLast(new WebSocktHandler());

                        }
                    });
            ChannelFuture f = b.bind(this.port).sync();
            log.info("服务已启动,监听端口" + this.port);
            f.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            workerGroup.shutdownGracefully();
            bossGroup.shutdownGracefully();
        }
    }


    public static void main(String[] args) throws IOException {
        new ChatServer().start();
    }

}

 

package com.example.netty.chat.server.handler;

import com.example.netty.chat.processor.MsgProcessor;
import org.apache.log4j.Logger;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;


public class WebSocktHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {

    private static Logger LOG = Logger.getLogger(WebSocktHandler.class);

    private MsgProcessor processor = new MsgProcessor();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx,TextWebSocketFrame msg) throws Exception {
        System.out.println("---channelRead0"+msg.text());
        processor.sendMsg(ctx.channel(), msg.text());
        LOG.info("---channelRead0"+msg.text());
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception { // (2)
        Channel client = ctx.channel();
        String addr = processor.getAddress(client);
        LOG.info("WebSocket Client:" + addr + "加入");
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // (3)
        Channel client = ctx.channel();
        processor.logout(client);
        LOG.info("WebSocket Client:" + processor.getNickName(client) + "离开");
    }

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
        Channel client = ctx.channel();
        String addr = processor.getAddress(client);
        LOG.info("WebSocket Client:" + addr + "上线");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
        Channel client = ctx.channel();
        String addr = processor.getAddress(client);
        LOG.info("WebSocket Client:" + addr + "掉线");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
            throws Exception {
        Channel client = ctx.channel();
        String addr = processor.getAddress(client);
        LOG.info("WebSocket Client:" + addr + "异常");
        // 当出现异常就关闭连接
        cause.printStackTrace();
        ctx.close();
    }

}

 

 

package com.example.netty.chat.server.handler;

import io.netty.channel.*;
import io.netty.handler.codec.http.*;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.URL;

@Slf4j
public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest> {

//获取class路径
private URL baseURL = HttpHandler.class.getProtectionDomain().getCodeSource().getLocation();
private final String webroot = "static";

private File getResource(String fileName) throws Exception{
        String path = baseURL.toURI() + webroot + "/" + fileName;
        path = !path.contains("file:") ? path : path.substring(5);
        path = path.replaceAll("//", "/");
        return new File(path);
        }

@Override
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
        String uri = request.getUri();

        RandomAccessFile file = null;
        try{
        String page = uri.equals("/") ? "chat.html" : uri;
        file =	new RandomAccessFile(getResource(page), "r");
        }catch(Exception e){
        ctx.fireChannelRead(request.retain());
        return;
        }

        HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK);
        String contextType = "text/html;";
        if(uri.endsWith(".css")){
        contextType = "text/css;";
        }else if(uri.endsWith(".js")){
        contextType = "text/javascript;";
        }else if(uri.toLowerCase().matches("(jpg|png|gif)$")){
        String ext = uri.substring(uri.lastIndexOf("."));
        contextType = "image/" + ext;
        }
        response.headers().set(HttpHeaders.Names.CONTENT_TYPE, contextType + "charset=utf-8;");

        boolean keepAlive = HttpHeaders.isKeepAlive(request);

        if (keepAlive) {
        response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, file.length());
        response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        }
        ctx.write(response);

        ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));
//        ctx.write(new ChunkedNioFile(file.getChannel()));

        ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
        if (!keepAlive) {
        future.addListener(ChannelFutureListener.CLOSE);
        }

        file.close();
        }

@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
        throws Exception {
        Channel client = ctx.channel();
        log.info("Client:"+client.remoteAddress()+"异常");
        // 当出现异常就关闭连接
        cause.printStackTrace();
        ctx.close();
        }
 }

package com.example.netty.chat.server.handler;

import com.example.netty.chat.processor.MsgProcessor;
import com.example.netty.chat.protocol.IMMessage;
import org.apache.log4j.Logger;

import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;


public class SocketHandler extends SimpleChannelInboundHandler<IMMessage>{

    private static Logger LOG = Logger.getLogger(SocketHandler.class);

    private MsgProcessor processor = new MsgProcessor();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, IMMessage msg) throws Exception {
        processor.sendMsg(ctx.channel(), msg);
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        LOG.info(" 服务端 SocketHandler 创建...");
        super.handlerAdded(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { // (3)
        Channel client = ctx.channel();
        processor.logout(client);
        LOG.info("Socket Client:" + processor.getNickName(client) + "离开");
    }

    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception {
        LOG.info("channelInactive");
        super.channelInactive(ctx);
    }
    /**
     * tcp链路建立成功后调用
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        LOG.info("Socket Client: 有客户端连接:"+ processor.getAddress(ctx.channel()));
    }


    /**
     * 异常处理
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        LOG.info("Socket Client: 与客户端断开连接:"+cause.getMessage());
        cause.printStackTrace();
        ctx.close();
    }

}



 

 

package com.example.netty.chat.protocol;


/**
 * 自定义IM协议,Instant Messaging Protocol即时通信协议
 *
 */
public enum IMP {
    /** 系统消息 */
    SYSTEM("SYSTEM"),
    /** 登录指令 */
    LOGIN("LOGIN"),
    /** 登出指令 */
    LOGOUT("LOGOUT"),
    /** 聊天消息 */
    CHAT("CHAT"),
    /** 送鲜花 */
    FLOWER("FLOWER");

    private String name;

    public static boolean isIMP(String content){
        return content.matches("^\\[(SYSTEM|LOGIN|LOGIN|CHAT)\\]");
    }

    IMP(String name){
        this.name = name;
    }

    public String getName(){
        return this.name;
    }

    public String toString(){
        return this.name;
    }

}
 

 

package com.example.netty.chat.protocol;

import org.msgpack.annotation.Message;

/**
 * 自定义消息实体类
 *
 */
@Message
public class IMMessage{

    private String addr;        //IP地址及端口
    private String cmd;        //命令类型[LOGIN]或者[SYSTEM]或者[LOGOUT]
    private long time;        //命令发送时间
    private int online;        //当前在线人数
    private String sender;  //发送人
    private String receiver;    //接收人
    private String content;    //消息内容

    public IMMessage(){}

    public IMMessage(String cmd,long time,int online,String content){
        this.cmd = cmd;
        this.time = time;
        this.online = online;
        this.content = content;
    }
    public IMMessage(String cmd,long time,String sender){
        this.cmd = cmd;
        this.time = time;
        this.sender = sender;
    }
    public IMMessage(String cmd,long time,String sender,String content){
        this.cmd = cmd;
        this.time = time;
        this.sender = sender;
        this.content = content;
    }
    public String getCmd() {
        return cmd;
    }

    public void setCmd(String cmd) {
        this.cmd = cmd;
    }

    public long getTime() {
        return time;
    }
    public void setTime(long time) {
        this.time = time;
    }
    public int getOnline() {
        return online;
    }
    public void setOnline(int online) {
        this.online = online;
    }

    public String getSender() {
        return sender;
    }
    public void setSender(String sender) {
        this.sender = sender;
    }
    public String getReceiver() {
        return receiver;
    }
    public void setReceiver(String receiver) {
        this.receiver = receiver;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }

    public String getAddr() {
        return addr;
    }
    public void setAddr(String addr) {
        this.addr = addr;
    }
}
 

 

package com.example.netty.chat.protocol;

import org.msgpack.MessagePack;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;

/**
 * 自定义IM协议的编码器
 */
public class IMEncoder extends MessageToByteEncoder<IMMessage> {

    @Override
    protected void encode(ChannelHandlerContext ctx, IMMessage msg, ByteBuf out)
            throws Exception {
        out.writeBytes(new MessagePack().write(msg));
    }

    public String encode(IMMessage msg){
        if(null == msg){ return ""; }
        String prex = "[" + msg.getCmd() + "]" + "[" + msg.getTime() + "]";
        if(IMP.LOGIN.getName().equals(msg.getCmd()) ||
                IMP.CHAT.getName().equals(msg.getCmd()) ||
                IMP.FLOWER.getName().equals(msg.getCmd())){
            prex += ("[" + msg.getSender() + "]");
        }else if(IMP.SYSTEM.getName().equals(msg.getCmd())){
            prex += ("[" + msg.getOnline() + "]");
        }
        if(!(null == msg.getContent() || "".equals(msg.getContent()))){
            prex += (" - " + msg.getContent());
        }
        return prex;
    }

}
 

 

package  com.example.netty.chat.protocol;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;

import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.msgpack.MessagePack;
import org.msgpack.MessageTypeException;

/**
 * 自定义IM协议的编码器
 */
public class IMDecoder extends ByteToMessageDecoder {

    //解析IM写一下请求内容的正则
    private Pattern pattern = Pattern.compile("^\\[(.*)\\](\\s\\-\\s(.*))?");

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in,List<Object> out) throws Exception {
        try{
            //先获取可读字节数
            final int length = in.readableBytes();
            final byte[] array = new byte[length];
            String content = new String(array,in.readerIndex(),length);

            //空消息不解析
            if(!(null == content || "".equals(content.trim()))){
                if(!IMP.isIMP(content)){
                    ctx.channel().pipeline().remove(this);
                    return;
                }
            }

            in.getBytes(in.readerIndex(), array, 0, length);
            out.add(new MessagePack().read(array,IMMessage.class));
            in.clear();
        }catch(MessageTypeException e){
            ctx.channel().pipeline().remove(this);
        }
    }

    /**
     * 字符串解析成自定义即时通信协议
     * @param msg
     * @return
     */
    public IMMessage decode(String msg){
        if(null == msg || "".equals(msg.trim())){ return null; }
        try{
            Matcher m = pattern.matcher(msg);
            String header = "";
            String content = "";
            if(m.matches()){
                header = m.group(1);
                content = m.group(3);
            }

            String [] heards = header.split("\\]\\[");
            long time = 0;
            try{ time = Long.parseLong(heards[1]); } catch(Exception e){}
            String nickName = heards[2];
            //昵称最多十个字
            nickName = nickName.length() < 10 ? nickName : nickName.substring(0, 9);

            if(msg.startsWith("[" + IMP.LOGIN.getName() + "]")){
                return new IMMessage(heards[0],time,nickName);
            }else if(msg.startsWith("[" + IMP.CHAT.getName() + "]")){
                return new IMMessage(heards[0],time,nickName,content);
            }else if(msg.startsWith("[" + IMP.FLOWER.getName() + "]")){
                return new IMMessage(heards[0],time,nickName);
            }else{
                return null;
            }
        }catch(Exception e){
            e.printStackTrace();
            return null;
        }
    }
}
 

 

 

package com.example.netty.chat.processor;
import com.alibaba.fastjson.JSONObject;

import com.example.netty.chat.protocol.IMDecoder;
import com.example.netty.chat.protocol.IMEncoder;
import com.example.netty.chat.protocol.IMMessage;
import com.example.netty.chat.protocol.IMP;
import io.netty.channel.Channel;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.AttributeKey;
import io.netty.util.concurrent.GlobalEventExecutor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class MsgProcessor {

    //记录在线用户
    private static ChannelGroup onlineUsers = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    //定义一些扩展属性
    private final AttributeKey<String> NICK_NAME = AttributeKey.valueOf("nickName");
    private final AttributeKey<String> IP_ADDR = AttributeKey.valueOf("ipAddr");
    private final AttributeKey<JSONObject> ATTRS = AttributeKey.valueOf("attrs");

    //自定义解码器
    private IMDecoder decoder = new IMDecoder();
    //自定义编码器
    private IMEncoder encoder = new IMEncoder();

    /**
     * 获取用户昵称
     * @param client
     * @return
     */
    public String getNickName(Channel client){
        return client.attr(NICK_NAME).get();
    }
    /**
     * 获取用户远程IP地址
     * @param client
     * @return
     */
    public String getAddress(Channel client){
        return client.remoteAddress().toString().replaceFirst("/","");
    }

    /**
     * 获取扩展属性
     * @param client
     * @return
     */
    public JSONObject getAttrs(Channel client){
        try{
            return client.attr(ATTRS).get();
        }catch(Exception e){
            return null;
        }
    }

    /**
     * 获取扩展属性
     * @param client
     * @return
     */
    private void setAttrs(Channel client,String key,Object value){
        try{
            JSONObject json = client.attr(ATTRS).get();
            json.put(key, value);
            client.attr(ATTRS).set(json);
        }catch(Exception e){
            JSONObject json = new JSONObject();
            json.put(key, value);
            client.attr(ATTRS).set(json);
        }
    }

    /**
     * 登出通知
     * @param client
     */
    public void logout(Channel client){
        //如果nickName为null,没有遵从聊天协议的连接,表示未非法登录
        if(getNickName(client) == null){ return; }
        for (Channel channel : onlineUsers) {
            IMMessage request = new IMMessage(IMP.SYSTEM.getName(), sysTime(), onlineUsers.size(), getNickName(client) + "离开");
            String content = encoder.encode(request);
            channel.writeAndFlush(new TextWebSocketFrame(content));
        }
        onlineUsers.remove(client);
    }

    /**
     * 发送消息
     * @param client
     * @param msg
     */
    public void sendMsg(Channel client,IMMessage msg){

        sendMsg(client,encoder.encode(msg));
    }

    /**
     * 发送消息
     * @param client
     * @param msg
     */
    public void sendMsg(Channel client,String msg){
        IMMessage request = decoder.decode(msg);
        if(null == request){ return; }

        String addr = getAddress(client);

        if(request.getCmd().equals(IMP.LOGIN.getName())){
            client.attr(NICK_NAME).getAndSet(request.getSender());
            client.attr(IP_ADDR).getAndSet(addr);
            onlineUsers.add(client);

            for (Channel channel : onlineUsers) {
                if(channel != client){
                    request = new IMMessage(IMP.SYSTEM.getName(), sysTime(), onlineUsers.size(), getNickName(client) + "加入");
                }else{
                    request = new IMMessage(IMP.SYSTEM.getName(), sysTime(), onlineUsers.size(), "已与服务器建立连接!");
                }
                String content = encoder.encode(request);
                log.info("-----sendMsg");
                channel.writeAndFlush(new TextWebSocketFrame(content));
            }
        }else if(request.getCmd().equals(IMP.CHAT.getName())){
            for (Channel channel : onlineUsers) {
                if (channel == client) {
                    request.setSender("you");
                }else{
                    request.setSender(getNickName(client));
                }
                request.setTime(sysTime());
                String content = encoder.encode(request);
                channel.writeAndFlush(new TextWebSocketFrame(content));
            }
        }else if(request.getCmd().equals(IMP.FLOWER.getName())){
            JSONObject attrs = getAttrs(client);
            long currTime = sysTime();
            if(null != attrs){
                long lastTime = attrs.getLongValue("lastFlowerTime");
                //60秒之内不允许重复刷鲜花
                int secends = 10;
                long sub = currTime - lastTime;
                if(sub < 1000 * secends){
                    request.setSender("you");
                    request.setCmd(IMP.SYSTEM.getName());
                    request.setContent("您送鲜花太频繁," + (secends - Math.round(sub / 1000)) + "秒后再试");
                    String content = encoder.encode(request);
                    client.writeAndFlush(new TextWebSocketFrame(content));
                    return;
                }
            }

            //正常送花
            for (Channel channel : onlineUsers) {
                if (channel == client) {
                    request.setSender("you");
                    request.setContent("你给大家送了一波鲜花雨");
                    setAttrs(client, "lastFlowerTime", currTime);
                }else{
                    request.setSender(getNickName(client));
                    request.setContent(getNickName(client) + "送来一波鲜花雨");
                }
                request.setTime(sysTime());

                String content = encoder.encode(request);
                channel.writeAndFlush(new TextWebSocketFrame(content));
            }
        }
    }

    /**
     * 获取系统时间
     * @return
     */
    private Long sysTime(){
        return System.currentTimeMillis();
    }

}
 

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" name="viewport">
    <title>咕泡学院聊天室</title>
    <link rel="stylesheet" type="text/css" href="css/style.css" />
    <script type="text/javascript" src="/js/lib/jquery.min.js"></script>
    <script type="text/javascript" src="/js/lib/jquery.snowfall.js"></script>
    <script type="text/javascript" src="/js/chat.util.js"></script>
</head>

<body>
<div id="loginbox">
    <div style="width:300px;margin:200px auto;">
        欢迎进入咕泡学院WebSocket聊天室
        <br/>
        <br/>
        <input type="text" style="width:180px;" placeholder="进入前,请先输入昵称" id="nickname" name="nickname" />
        <input type="button" style="width:50px;" value="进入" onclick="CHAT.login();" />
        <div id="error-msg" style="color:red;"></div>
    </div>
</div>
<div id="chatbox" style="display: none;">
    <div style="background:#3d3d3d;height: 28px; width: 100%;font-size:12px;position: fixed;top: 0px;z-index: 999;">
        <div style="line-height: 28px;color:#fff;">
            <span style="text-align:left;margin-left:10px;">咕泡学院聊天室</span>
            <span style="float:right; margin-right:10px;">
                	<span>当前在线<span id="onlinecount">0</span>人</span> |
	                <span id="shownikcname">匿名</span> |
	                <a href="javascript:;" onclick="CHAT.logout()" style="color:#fff;">退出</a>
                </span>
        </div>
    </div>
    <div id="doc">
        <div id="chat">
            <div id="message" class="message">
                <div id="onlinemsg" style="background:#EFEFF4; font-size:12px; margin-top:40px; margin-left:10px; color:#666;">
                </div>
            </div>
            <form onsubmit="return false;">
                <div class="tool-box">
                    <div class="face-box" id="face-box"></div>
                    <span class="face" onclick="CHAT.openFace()" title="选择表情"></span>
                    <!--
                        <span class="img" id="tool-img-btn" title="发送图片"></span>
                        <span class="file" id="tool-file-btn" title="上传文件"></span>
                     -->
                    <span class="flower" onclick="CHAT.sendFlower()" title="送鲜花"></span>
                </div>
                <div class="input-box">
                    <div class="input" contenteditable="true" id="send-message"></div>
                    <div class="action">
                        <input class="button" type="button" id="mjr_send" onclick="CHAT.sendText()" value="发送"/>
                    </div>
                </div>
                <div class="copyright">咕泡学院&copy;版权所有</div>
            </form>
        </div>
    </div>
</div>
</body>

</html>
Date.prototype.format = function(format){
    var o = {
        "M+" : this.getMonth()+1, //月
        "d+" : this.getDate(), //日
        "h+" : this.getHours(), //时
        "m+" : this.getMinutes(), //分
        "s+" : this.getSeconds(), //秒
        "q+" : Math.floor((this.getMonth()+3)/3), //刻
        "S" : this.getMilliseconds() //毫秒
    }

    if(/(y+)/.test(format)) {
        format = format.replace(RegExp.$1, (this.getFullYear()+"").substr(4 - RegExp.$1.length));
    }

    for(var k in o) {
        if(new RegExp("("+ k +")").test(format)) {
            format = format.replace(RegExp.$1, RegExp.$1.length==1 ? o[k] : ("00"+ o[k]).substr((""+ o[k]).length));
        }
    }
    return format;
};

 var getStr1 =function(url) {
    var domain = url.split('/'); //以“/”进行分割

    if( domain[2] ) {

        domain = domain[2];

    } else {

        domain = ''; //如果url不正确就取空

    }
    return domain;
};
$(document).ready(function(){
     var host = getStr1(location.href);
    window.CHAT = {
        //保存服务器端WebSocket的请求地址
        serverAddr:"ws://" + host + "im",
        //保存用户输入的昵称
        nickname:null,
        //保存浏览器socket对象
        socket:null,
        //将滚动条设置到最顶部,以便能看到最新的消息
        scrollToBottom:function(){
            window.scrollTo(0, $("#onlinemsg")[0].scrollHeight);
        },
        //登录到聊天室
        login:function(){
            console.log("---login");
            $("#error-msg").empty();
            var _reg = /^\S{1,10}$/;
            var nickname = $("#nickname").val();
            if (nickname != "") {
                if (!(_reg.test($.trim(nickname)))) {
                    console.log("-----------昵称长度必须在10个字以内");
                    $('#error-msg').html("昵称长度必须在10个字以内");
                    return false;
                }
                $("#nickname").val('');
                $("#loginbox").hide();
                $("#chatbox").show();
                this.init(nickname);
            }else{
                $('#error-msg').html("先输入昵称才能进入聊天室");
                return false;
            }
            return false;
        },
        //退出登录
        logout:function(){
            location.reload();
        },
        //清空聊天记录
        clear:function(){
            CHAT.box.innerHTML = "";
        },
        //发送聊天消息
        sendText:function() {
            var message = $("#send-message");
            //去掉空格
            if(message.html().replace(/\s/ig,"") == ""){ return; }
            if (!window.WebSocket) { return; }
            if (CHAT.socket.readyState == WebSocket.OPEN) {
                var msg = ("[CHAT][" + new Date().getTime() + "]" + "[" + CHAT.nickname + "] - " + message.html().replace(/\n/ig,"<br/>"));
                CHAT.socket.send(msg);
                message.empty();
                message.focus();
            } else {
                alert("与服务器连接失败.");
            }
        },
        //发送鲜花
        sendFlower:function(){
            if (!window.WebSocket) { return; }
            if (CHAT.socket.readyState == WebSocket.OPEN) {
                var message = ("[FLOWER][" + new Date().getTime() + "]" + "[" + CHAT.nickname + "]");
                CHAT.socket.send(message);
                $("#send-message").focus();
            } else {
                alert("与服务器连接失败.");
            }
        },
        //选择表情
        selectFace:function(img){
            var faceBox = $("#face-box");
            faceBox.hide();
            faceBox.removeClass("open");
            var i = '<img src="' + img + '" />';
            $("#send-message").html($("#send-message").html() + i);
            $("#send-message").focus();
        },
        //打开表情弹窗
        openFace:function(e){
            var faceBox = $("#face-box");
            if(faceBox.hasClass("open")){
                faceBox.hide();
                faceBox.removeClass("open");
                return;
            }
            faceBox.addClass("open");
            faceBox.show();
            var box = '';
            for(var i = 1;i <= 130; i ++){
                var img = '/images/face/' + i + '.gif';
                box += '<span class="face-item" onclick="CHAT.selectFace(\'' + img + '\');">';
                box += '<img src="' + img + '"/>';
                box += '</span>';
            }
            faceBox.html(box);
        },
        //初始化聊天组件
        init:function(nickname){
            console.log("----init");
            var message = $("#send-message");
            //自动获取焦点
            message.focus();
            //按回车键自动发送
            message.keydown(function(e){
                if ((e.ctrlKey && e.which == 13) || e.which == 10) {
                    CHAT.sendText();
                }
            });

            CHAT.nickname = nickname;

            $("#shownikcname").html(nickname);


            //添加系统提示
            var addSystemTip = function(c){
                var html = "";
                html += '<div class="msg-system">';
                html += c;
                html += '</div>';
                var section = document.createElement('section');
                section.className = 'system J-mjrlinkWrap J-cutMsg';
                section.innerHTML = html;

                $("#onlinemsg").append(section);
            };
            //将消息添加到聊天面板
            var appendToPanel = function(message){
                var regx = /^\[(.*)\](\s\-\s(.*))?/g;
                var group = '',label = "",content = "",cmd="",time=0,name="";
                while(group = regx.exec(message)){
                    label = group[1];
                    content = group[3];
                }
                var labelArr = label.split("][");
                cmd = labelArr[0];
                time = labelArr[1];
                name = labelArr[2];

                if(cmd == "SYSTEM"){
                    var total = labelArr[2];
                    $("#onlinecount").html("" + total);
                    addSystemTip(content);
                }else if(cmd == "CHAT"){
                    var date = new Date(parseInt(time));
                    addSystemTip('<span class="time-label">' + date.format("hh:mm:ss") + '</span>');
                    var isme = (name == "you") ? true : false;
                    var contentDiv = '<div>' + content + '</div>';
                    var usernameDiv = '<span>' + name + '</span>';

                    var section = document.createElement('section');
                    if (isme) {
                        section.className = 'user';
                        section.innerHTML = contentDiv + usernameDiv;
                    } else {
                        section.className = 'service';
                        section.innerHTML = usernameDiv + contentDiv;
                    }
                    $("#onlinemsg").append(section);
                }else if(cmd == "FLOWER"){
                    addSystemTip(content);
                    //鲜花特效
                    $(document).snowfall('clear');
                    $(document).snowfall({
                        image:"/images/face/50.gif",
                        flakeCount:60,
                        minSize:20,
                        maxSize:40
                    });
                    window.flowerTimer = window.setTimeout(function(){
                        $(document).snowfall('clear');
                        window.clearTimeout(flowerTimer);
                    },5000);

                }
                //有新的消息过来以后,自动切到最底部
                CHAT.scrollToBottom();
            };


            if (!window.WebSocket) {
                window.WebSocket = window.MozWebSocket;
            }
            if (window.WebSocket) {
                CHAT.socket = new WebSocket(CHAT.serverAddr);
                // 收消息
                CHAT.socket.onmessage = function(e) {
                    console.log("----收消息");
                    appendToPanel(e.data);
                };
                CHAT.socket.onopen = function(e) {
                    CHAT.socket.send("[LOGIN][" + new Date().getTime() +"][" + nickname + "]");
                };
                CHAT.socket.onclose = function(e) {
                    appendToPanel("[SYSTEM][" + new Date().getTime() + "][0] - 服务器关闭,暂不能聊天!");
                };
            } else {
                alert("你的浏览器不支持 WebSocket!");
            }
        }
    };
});

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值