最近在研究vue,想写点案例,最后决定写一个比较常用的聊天室。再次记录一下,方便日后查阅。前端用vue构建,后端使用java websocket
关于websocket的好处这里不在赘述,直接贴代码
package webSocketDemo.web;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArraySet;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/wb")
public class socketWeb {
public static int Count = 0;
public Session session;
public String name;
public static CopyOnWriteArraySet<socketWeb> listAll = new CopyOnWriteArraySet<socketWeb>();
@OnOpen
public void onOpen(Session session){
Map<String, List<String>> map= session.getRequestParameterMap();
if(map.size()>0){
List <String>list=map.get("name");
if(null!=list&&list.size()>0){
String name=list.get(0);
if(null!=name&&name.length()>0){
if(!haveName(name)){
this.name=name;
this.session=session;
listAll.add(this);
Count++;
System.out.println("有客户端连接成功");
sendList( session);
}else{
send(session,"sys_have");
}
}
}
}
System.out.println(map.get("name"));
System.out.println(map);
}
@OnClose
public void onClose(Session session){
listAll.remove(this);
Count--;
sendList( session);
}
@OnError
public void onError(Session session, Throwable error) {
listAll.remove(this);
Count--;
sendList( session);
}
public static void send(Session session, String msg){
try {
session.getBasicRemote().sendText(msg);
} catch (IOException e) {
e.printStackTrace();
}
}
@OnMessage
public void onMessage(String message,Session session){
System.out.println("有人骂你"+message); //####name####单挑
if(message.startsWith("##msg:")){
String[] s=message.substring(6,message.length()-1).split(":");
System.out.println("单聊");
if(s.length>1){
System.out.println(s[0]);
sendTo(s[0],"##msg:"+s[1]);
System.out.println(s[1]);
}
}else if(message.startsWith("##msgall:")){
System.out.println("群聊");
broadcast(session,"##msg:"+message);
}
}
@OnMessage
public void onMessage(ByteBuffer message,Session session){
System.out.println("有人骂你"+message);
/// broadcast(session,message);
}
public static boolean haveName(String name){
for(socketWeb sb: listAll){
if(name.equals(sb.name)){
return true;
}
}
return false;
}
public static List getList(){
List<String> list=new ArrayList<String>();
for (socketWeb item :listAll) {
list.add(item.name);
}
return list;
}
public static void sendList(Session session){
List<String> list=getList();
String str=String.valueOf(list);
broadcastAll("##list:"+str);
}
public static void broadcast(Session session,String msg){
for (socketWeb item :listAll) {
try {
synchronized (item.session) {
if (item.session!=session&&item.session.isOpen()) {
item.session.getBasicRemote().sendText(msg);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void broadcastAll(String msg){
for (socketWeb item :listAll) {
try {
synchronized (item.session) {
if (item.session.isOpen()) {
item.session.getBasicRemote().sendText(msg);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void sendTo(String name,String msg){
for (socketWeb item :listAll) {
try {
if(item.name.equals(name)){
synchronized (item.session) {
if (item.session.isOpen()) {
item.session.getBasicRemote().sendText(msg);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
注意这里使用到了两个包:javax.websocket-api-1.0.jar websocket必备 commons-io-1.4.jar IO操作必备
关于前端的代码这里贴出核心部分
<template>
<div>
<div class="stateInfo">
<input class="stateBt" type="text" v-model="userName">
<input class="stateBt" type="button" value="连接" @click="connect()">
<input class="stateBt" type="button" value="断开" @click="close()">
<select class="stateBt" v-model="selectedItem" placeholder="请选择对象" @change="changeObj($event)">
<option v-for="p in userList" :key="p" >{{p}}</option>
</select>
</div>
<div ref="cont" class="content">
<div class="pp" v-for="(a,index) in msgs" :key="index" >
<div class="p1" v-if="a.kind==1" >{{a.data}}</div>
<div class="p2" v-else-if="a.kind==2">{{a.data}}</div>
</div>
</div>
<div class="put">
<input type="text" class="inputa" v-model="info" ><input class="stateBt" type='button' value="发送" @click="send()">
</div>
</div>
</template>
<script>
export default {
props:[
'wz',
'col'
],
name: "aa",
data(){
return {
msgs:[{data:"我是模拟信息2",kind:1},{data:"我是模拟信息2",kind:1}],
socket:null,
info:"hellow",
userName:"userName",
selectedItem:"all",
userList:["all"]
}
},
methods:{
send:function(){
if(null!=this.socket&&this.socket.readyState==1){
if(this.selectedItem=="all"){
this.socket.send("##msgall:"+this.info);
this.msgs.push({data:this.info,kind:2});
this.$refs.cont.scrollTop = this.$refs.cont.scrollHeight
}else{
this.socket.send("##msg:"+this.selectedItem+":"+this.info);
this.msgs.push({data:this.info,kind:2});
this.$refs.cont.scrollTop = this.$refs.cont.scrollHeight
}
}else{
this.$notify({
title: '请先连接网络',
type: 'success',
message: '请先连接网络后在发送消息',
duration: 3000
})
}
},
connect:function(){
var me=this;
if(this.userName.length>0){
this.socket=new WebSocket("ws://localhost:8080/webSocketDemo/wb?name="+this.userName);
this.socket.onmessage=function(e){
if(e.data.startsWith("##list:")){
var strm=(e.data.substring(8,e.data.length-1)).split(",");
console.log(strm);
me.userList=["all"].concat(strm);
}else if(e.data.startsWith("##msg:")){
me.msgs.push({data:e.data,kind:1});
me.$refs.cont.scrollTop = me.$refs.cont.scrollHeight
}
}
}else{
this.$notify({
title: '请先输入用户名',
type: 'success',
message: '请先输入用户名,再连接',
duration: 3000
})
}
},
close:function(){
this.socket.close();
},
changeObj:function(obj){
}
},
directives:{
// 注册一个局部的自定义指令 v-focus
oo:{
// 指令的定义
inserted: function (ea) {
// 聚焦元素
ea.focus();
ea.style.background="orange";
}
}
}
}
</script>
<style>
*{
margin: 0;
padding: 0;
border: 0;
}
.stateInfo{
width:60%;
height: auto;
margin: 0 auto;
background: peachpuff;
border-radius: 5px;
}
.stateBt{
width:80px;
border-radius: 5px;
background: mintcream;
color:#008000;
height:30px;
}
.content{
width:60%;
height:300px;
background: papayawhip;
overflow-y: scroll;
margin: 0 auto;
}
.put{
width:60%;
height: auto;
background: peachpuff;
border-radius: 5px;
margin: 0 auto;
}
.inputa{
width:60%;
height:30px;
background:mintcream;
border: 2px solid orange;
border-radius: 5px;
}
.pp{
width:100%;
height:21px;
}
.p1{
width:100%;
height:21px;
color:deeppink;
text-align: left;
font-size:28px;
font-family: kaiti;
margin: 10px;
}
.p2{
width:100%;
height:21px;
color:green;
text-align:right;
font-size:28px;
font-family: kaiti;
}
body{
background: snow;
}
</style>
当然这是初级版的,页面有点low,有需要的可以自己完善下。原码上传了,有需要可以点击下载