在进行聊天之前呢,我们在前文的基础上还要再增加一个查询聊天记录的action,这里我们直接在UserAction这个类中自定义loadRecord方法,如下:
其中getChatRecords方法已经在UserService类中实现了并且是按照时间,用户排序的。接受sid,rid参数,发送者以及接受者。这些参数在上一篇文章中已经有过定义了,所以这里我们直接使用。
/**
* 获取聊天记录
* @return 返回json
*/
public String loadRecords(){
Map<Integer,Object> result = userService.getChatRecords(sid,rid);
data.put("code",200);
data.put("info","获取聊天记录成功");
data.put("data",result);
return SUCCESS;
}
修改P2PChatRoom程序
- 在onOpen方法中获取登录信息,向所有在线用户广播当前用户上线
- 根据ws连接参数判断用户是否请求与其他在线用户连接
- 如何发送在线列表(在前面的文章中已经解决了)
- 用户聊天匹配以及下线广播
完整程序如下(完备版):
package cn.zipple.ws;
import cn.zipple.dao.impl.UserDaoImpl;
import cn.zipple.encoder.ServerEncoder;
import cn.zipple.entity.ChatRecord;
import cn.zipple.entity.User;
import cn.zipple.service.UserService;
import cn.zipple.util.Log;
import javax.servlet.http.HttpSession;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* Created by zipple on 2017/11/14.
* 点对点聊天室
*/
@ServerEndpoint(value ="/chatRoom/{username}",configurator=HttpSessionWSHelper.class,encoders = {ServerEncoder.class})
//@ServerEndpoint(value ="/chatRoom",configurator=HttpSessionWSHelper.class)
public class P2PChatRoom {
private Session session;//本身的ws session
private HttpSession httpSession;//对应的 httpSession
private static CopyOnWriteArraySet<P2PChatRoom> P2PChatRoomSet = new CopyOnWriteArraySet<>();//保证线程安全
private Session targetSession;//目标session
private String targetName;//目标name
private UserDaoImpl userDao;
public P2PChatRoom(){
Log.info("---------------启动webSocket P2PChatRoom聊天室-----------------------");
userDao =new UserService().getUserDao();
}
//初次连接初始化操作
private void init(Session session, EndpointConfig config){
this.setSession(session);
HttpSession httpSession= (HttpSession) config.getUserProperties().get(HttpSession.class.getName());
this.setHttpSession(httpSession);
}
//与用户配对
private void connect2Users(String username,User self){
boolean flag =false;
for (P2PChatRoom p2pChatRoom: P2PChatRoomSet){
User user = (User) p2pChatRoom.getHttpSession().getAttribute("user");
if (user.getName().equals(username)){
targetName=username;//必须要在能连接会话的时候赋值
targetSession=p2pChatRoom.getSession();//获取目标对象的Session
//同时给对方也连接本身的target
p2pChatRoom.setTargetSession(session);
p2pChatRoom.setTargetName(self.getName());
flag=true;
break;
}
}
if (flag){
ChatRecord sysSelf= new ChatRecord(new User("系统","000",0),self.getId(),"*连接"+targetName+"成功");
ChatRecord sysTarget= new ChatRecord(new User("系统","000",0),self.getId(),self.getName()+"请求与您通话!");//不等待对方同意
try {
session.getBasicRemote().sendObject(sysSelf);
targetSession.getBasicRemote().sendObject(sysTarget);
} catch (Exception e) {
e.printStackTrace();
}
Log.info("会话连接成功");
}else{
ChatRecord sysSelf= new ChatRecord(new User("系统","000",0),self.getId(),"连接失败.对方不在线");
try {
session.getBasicRemote().sendObject(sysSelf);
} catch (Exception e) {
e.printStackTrace();
}
Log.info("会话连接失败");
}
}
/**
* 将消息发送给所有人
* @param msg 消息
*/
public void send2All(String msg) throws IOException, EncodeException {
ChatRecord chatRecord= new ChatRecord(new User("系统","000",0),0,msg);
//发送在线列表
for (P2PChatRoom p2pChatRoom: P2PChatRoomSet){
p2pChatRoom.getSession().getBasicRemote().sendObject(chatRecord);
}
}
/**
* 发送在线列表
* @throws IOException IO异常
* @throws EncodeException 编码器异常
*/
private void sendOnlineUsers() throws IOException, EncodeException {
//当有新用户连接服务器时,将在线列表发送给所有在线用户
Log.info("发送在线列表");
Set<User> userSet =new HashSet<>();
for (P2PChatRoom p2pChatRoom: P2PChatRoomSet){
User temp = (User) p2pChatRoom.getHttpSession().getAttribute("user");
if (temp!=null){
temp.setChatRecords(null);//不需要加载聊天记录----否则会引起死循环解析
userSet.add(temp);
}
}
//发送在线列表
for (P2PChatRoom p2pChatRoom: P2PChatRoomSet){
p2pChatRoom.getSession().getBasicRemote().sendObject(userSet);
}
}
@OnOpen
public void onOpen(@PathParam("username")String username, Session session, EndpointConfig config){
try {
Log.info("正在连接服务器.....,username:"+username);
init(session,config);
P2PChatRoomSet.add(this);
Log.info("服务器当前连接数:"+P2PChatRoomSet.size());
User self = (User)httpSession.getAttribute("user");
Log.info("ws自己对应的httpSession:"+self.getName());
send2All(self.getName()+"上线");
if (username!=null&&!username.equals("null")){
connect2Users(username,self);
sendOnlineUsers();
}else{
Log.info("*连接服务器成功");
//发送在线列表
sendOnlineUsers();
}
}catch (Exception e){
e.printStackTrace();
}
}
@OnMessage
public void onMessage(Session session, String msg){
User self = (User)httpSession.getAttribute("user");
if (targetName==null||targetSession==null){
//未选择私聊的连接者
Log.info("未选择私聊的连接者:"+self.getName()+" 消息将转发给自己");
ChatRecord me = new ChatRecord(self,self.getId(),msg);
try {
session.getBasicRemote().sendObject(me);
} catch (Exception e) {
e.printStackTrace();
}
}else{
Log.info("服务器收到来自"+self.getName()+"转发给"+targetName+"的信息:"+msg);
User target = userDao.getUserByUsername(targetName);
ChatRecord chats = new ChatRecord(self,target.getId(),msg);
userDao.save(chats);//保存聊天记录----是不是应该发送出去后再保存
try {
if (targetSession.isOpen()){
targetSession.getBasicRemote().sendObject(chats);
}else{
session.getBasicRemote().sendObject(new ChatRecord(new User("系统","000",0),0,"对方已下线"));
}
// session.getBasicRemote().sendObject(chats);不用发送给自己
}catch (Exception e){
e.printStackTrace();
}
}
}
@OnError
public void onError(Session session, Throwable throwable){
User user = (User)httpSession.getAttribute("user");
if (user!=null){
Log.info("用户:"+user.getName()+" 连接异常. throwable:"+throwable.getMessage());
}else{
Log.info("session:"+session.getId()+"连接异常. throwable:"+throwable.getMessage());
}
}
@OnClose
public void onClose(Session session, CloseReason reason){
try {
User user = (User)httpSession.getAttribute("user");
P2PChatRoomSet.remove(this);//会不会remove 两次
if (user!=null){
Log.info(user.getName()+"断开连接,原因:"+reason.getReasonPhrase());
//下线提醒
send2All(user.getName()+"下线");
//释放连接
}else{
Log.info("session:"+session.getId()+"断开连接,原因:"+reason.getReasonPhrase());
}
//发送在线列表
sendOnlineUsers();
}catch (Exception e){
e.printStackTrace();
}
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
public HttpSession getHttpSession() {
return httpSession;
}
public void setHttpSession(HttpSession httpSession) {
this.httpSession = httpSession;
}
public Session getTargetSession() {
return targetSession;
}
public void setTargetSession(Session targetSession) {
this.targetSession = targetSession;
}
public String getTargetName() {
return targetName;
}
public void setTargetName(String targetName) {
this.targetName = targetName;
}
public static CopyOnWriteArraySet<P2PChatRoom> getP2PChatRoomSet() {
return P2PChatRoomSet;
}
public static void setP2PChatRoomSet(CopyOnWriteArraySet<P2PChatRoom> p2PChatRoomSet) {
P2PChatRoomSet = p2PChatRoomSet;
}
public UserDaoImpl getUserDao() {
return userDao;
}
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}
}