我这里只显示需要添加的代码,其余代码与韩老师写的一样。

这里用户1发短信给用户2

大体思路:1.在服务器接收用户1输入信息ObjectInputStream的时候有两个分支(if-else),

第一,如果在线程池里用户2不存在,就把输入信息保存在concurrentHashMap

第二,如果线程池里存在用户2,就把输入信息通过ObjectOutputStream.WriteObject发给客户端。

2.在服务器,用户2发送登录成功MessageType给客户端的时候,同时把用户1的信息也发出去,通过message.setContent()。

建议自己在想一下,因为很简单,具体代码如下:

1.设定属性.private static ConcurrentHashMap<String, ArrayList<Message>>ofLineDb = new ConcurrentHashMap<>();

2.写方法用来保存内容

public static void dbmessage(String userId,Message message1){

if (!ManageClientThread.getHm().containsKey(userId)){

ArrayList<Message> messages1 = new ArrayList<>();

messages1.add(message1); ofLineDb.put(userId,messages1);

}

3.服务器对收到的信息进行分流
else if (o1.getMesType().equals(MessageType.MESSAGE_COMM_MES.getNum())){//把客户端私聊的内容保存在dbmessage方法里的ConcurrentHashMap里if (!ManageClientThread.getHm().containsKey(o1.getGetter())) {o1.setContent("\n"+o1.getSender()+"发消息说"+o1.getContent());QQserver.dbmessage(o1.getGetter(), o1);}//传递给客户端,通过需要收到的用户id找到socketServerConnectClientThread getserverconnectclietnthread = ManageClientThread.getserverconnectclietnthread(o1.getGetter());ObjectOutputStream objectOutputStream = new ObjectOutputStream(getserverconnectclietnthread.getSocket().getOutputStream());objectOutputStream.writeObject(o1);  }

4.在服务器,当用户2登入时,从数组里取出用户1的信息打包过去。

if (ofLineDb.get(o1.getUserId())!=null){ArrayList<Message> messages = ofLineDb.get(o1.getUserId());Iterator<Message> iterator = messages.iterator();while (iterator.hasNext()) {Message next = iterator.next();message.setContent(next.getContent());}
}

5.客户端里输出

if (ManageClientConnectiServerThread.getccst(message.getGetter())==null){System.out.println(message.getGetter()+"用户已经离线");}else
{ System.out.println(senderId+"对"+getterId+"说"+content);}

服务器端的:


public class ServerConnectClientThread extends Thread{private Socket socket;private String userId;//连接到服务端的用户idpublic ServerConnectClientThread(Socket socket, String userId) {this.socket = socket;this.userId = userId;}@Overridepublic void run() {//这里线程处于rum的状态,可以发送/接送消息while(true){System.out.println("服务端和客户端"+userId+"保持通信,读取数据...");try {ObjectInputStream objectInputStream = new ObjectInputStream(socket.getInputStream());Object o = objectInputStream.readObject();Message o1 = (Message) o;
//                后面会使用message
//                根据message的类型,做相应的业务处理if (o1.getMesType().equals(MessageType.MESSAGE_GET_ONLINEFRIEND.getNum())){//客户端要在先用户列表/*在线用户列表形式100 200*/System.out.println(o1.getSender()+"要在线用户列表");String onlineUser = ManageClientThread.getOnlineUser();//返回message//构建一个message对象,返回给客户端Message message = new Message();message.setMesType(MessageType.MESSAGE_RET_ONLINEFRIEND.getNum());message.setContent(onlineUser);message.setGetter(message.getSender());//返回给客户端ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());objectOutputStream.writeObject(message);} else if (o1.getMesType().equals(MessageType.MESSAGE_CLIENT_EXIT.getNum())) {//如果客户端退出把socket退出System.out.println(o1.getSender()+"退出");//将这个客户端对应线程,从集合中删除ManageClientThread.removeServerConnectClientThread(o1.getSender());socket.close();//关闭链接//退出线程break;} else if (o1.getMesType().equals(MessageType.MESSAGE_COMM_MES.getNum())){//把客户端私聊的内容保存在dbmessage方法里的ConcurrentHashMap里if (!ManageClientThread.getHm().containsKey(o1.getGetter())) {o1.setContent("\n"+o1.getSender()+"发消息说"+o1.getContent());QQserver.dbmessage(o1.getGetter(), o1);}else {//传递给需要收到的用户idServerConnectClientThread getserverconnectclietnthread = ManageClientThread.getserverconnectclietnthread(o1.getGetter());ObjectOutputStream objectOutputStream = new ObjectOutputStream(getserverconnectclietnthread.getSocket().getOutputStream());objectOutputStream.writeObject(o1);}//如果,提示客户不在线,通过保存到数据库达到离线留言}else if (o1.getMesType().equals(MessageType.MESSAGE_TO_ALL_MES.getNum())){HashMap<String, ServerConnectClientThread> hm = ManageClientThread.getHm();Iterator<String> iterator = hm.keySet().iterator();while (iterator.hasNext()) {String next = iterator.next();//取出在线用户idif (!(next.equals(o1.getSender()))){//进行转发messageObjectOutputStream objectOutputStream =new ObjectOutputStream(hm.get(next).getSocket().getOutputStream());objectOutputStream.writeObject(o1);}}  hm.remove(o1.getSender());}else if (o1.getMesType().equals(MessageType.FILE_TO_ONE_MES.getNum())){ServerConnectClientThread getserverconnectclietnthread =ManageClientThread.getserverconnectclietnthread(o1.getGetter());Socket socket = getserverconnectclietnthread.getSocket();ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());objectOutputStream.writeObject(o1);}else {System.out.println("其他类型的message,暂时不处理");}} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}}public Socket getSocket() {return socket;}
}

public class QQserver {//ConcurrentHashMap,线程安全的HashMap,多线程下是阿暖的private ServerSocket ss =null;//创建一个集合,存放多个用户,如果是这些用户登入就认为是合法的private static HashMap<String,User> validUsers = new HashMap<>();private static ConcurrentHashMap<String, ArrayList<Message>>ofLineDb = new ConcurrentHashMap<>();public static ConcurrentHashMap<String, ArrayList<Message>> getOfLineDb() {return ofLineDb;}public static void setOfLineDb(ConcurrentHashMap<String, ArrayList<Message>> ofLineDb) {QQserver.ofLineDb = ofLineDb;}static {//在静态代码块,初始化validUsers//validUsers.put("100",new User("100","123456"));validUsers.put("200",new User("200","123456"));validUsers.put("300",new User("300","123456"));validUsers.put("至尊宝",new User("至尊宝","123456"));validUsers.put("铺地老祖",new User("菩提老祖","123456"));}public static void dbmessage(String userId,Message message1){if (!ManageClientThread.getHm().containsKey(userId)){ArrayList<Message> messages1 = new ArrayList<>();messages1.add(message1);ofLineDb.put(userId,messages1);}}private boolean checkUser(String userId,String passwd){System.out.println("准备登入");User user = validUsers.get(userId);if (user==null){//说明userId没有存在validUsers的key中return false;}if (!user.getPasswd().equals(passwd)){//userId正确,但是密码错误return false;}return true;}public QQserver()  {System.out.println("服务端在9999端口监听。。。");try {//启动推送新闻的线程new Thread(new SendNewsToALLService()).start();ss = new ServerSocket(9999);while(true) {//监听是循环的一直监听的,当合某个客户端建立链接后,会继续监听,如果没有客户端服务器会阻塞在这里//因此whileSocket accept = ss.accept();//如果没有客户端链接,就会阻塞//得到socket关联的对象输入流ObjectInputStream objectInputStream = new ObjectInputStream(accept.getInputStream());ObjectOutputStream objectOutputStream = new ObjectOutputStream(accept.getOutputStream());Object o = objectInputStream.readObject();//得到socket冠梁的对象输出流User o1 = (User) o;//创建一个Message对象,准备回复客户端Message message = new Message();//验证if (checkUser(o1.getUserId(),o1.getPasswd())){//登录通过//登录成功message.setMesType(MessageType.MESSAGE_LOGIN_SUCCEED.getNum());//将Message对象回复//封装私聊内容发送给客户端if (ofLineDb.get(o1.getUserId())!=null){ArrayList<Message> messages = ofLineDb.get(o1.getUserId());Iterator<Message> iterator = messages.iterator();while (iterator.hasNext()) {Message next = iterator.next();message.setContent(next.getContent());}}objectOutputStream.writeObject(message);//创建一个线程,和客户端进行链接ServerConnectClientThread serverConnectClientThread = new ServerConnectClientThread(accept, o1.getUserId());serverConnectClientThread.start();//把该线程对象,放入到一个集合中,进行管理,//写DBManageClientThread.addClentThread(o1.getUserId(), serverConnectClientThread);}else {//登录失败]System.out.println("用户id="+ o1.getUserId()+"验证失败");message.setMesType(MessageType.MESSAGE_LOGIN_FAIL.getNum());objectOutputStream.writeObject(message);accept.close();}}} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}finally {//如果服务器退出了while,说明服务器端不在监听,因此关闭ServerSockettry {ss.close();} catch (IOException e) {e.printStackTrace();}}}
}

客户端的:


public class MessageClientService {/**** @param content  内容* @param senderId  发送用户id* @param getterId  接收用户id*/public static  void sendMessageToOne(String content,String senderId,String getterId){//构建messageMessage message = new Message();message.setSender(senderId);message.setGetter(getterId);message.setContent(content);message.setMesType(MessageType.MESSAGE_COMM_MES.getNum());//设置消息类型message.setSendTime(new Date().toString());//发送时间设置到message对象if (ManageClientConnectiServerThread.getccst(message.getGetter())==null){System.out.println(message.getGetter()+"用户已经离线");}else{ System.out.println(senderId+"对"+getterId+"说"+content);}//发送给服务端try {ClientConnectServerThread getccst = ManageClientConnectiServerThread.getccst(senderId);Socket socket = getccst.getSocket();ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());objectOutputStream.writeObject(message);} catch (IOException e) {e.printStackTrace();}}public static void sendMessageToAll(String content,String senderId){Message message = new Message();message.setSender(senderId);message.setContent(content);message.setMesType(MessageType.MESSAGE_TO_ALL_MES.getNum());//设置消息类型群发message.setSendTime(new Date().toString());//发送时间设置到message对象System.out.println(senderId+"对大家说"+content);//发送给服务端try {ClientConnectServerThread getccst = ManageClientConnectiServerThread.getccst(senderId);Socket socket = getccst.getSocket();ObjectOutputStream objectOutputStream = new ObjectOutputStream(socket.getOutputStream());objectOutputStream.writeObject(message);} catch (IOException e) {e.printStackTrace();}}}

效果:

登入100,发短信

登入200发短信

韩顺平30天javaQQ通信作业扩展-完成离线提醒及接收接收相关推荐

  1. 尚硅谷Java数据结构和java算法,韩顺平数据结构和算法课后作业01

    尚硅谷Java数据结构和java算法,韩顺平数据结构和算法课后作业第一题 要求: 1)在前面的基础上,将稀疏数组保存到磁盘上,比如map.data 2) 恢复原来的数组时,读取map.data进行恢复 ...

  2. 适合有编程基础的人看的《韩顺平零基础30天学java》笔记(P104~P129)

    写在最前边: 研究生一枚,为后端实习和未来工作打基础.无意间发现韩顺平老师的课程,细心细致,讲课和吴恩达老师一样,都是保姆式讲解,各种基础知识都会补充,爱了. 韩顺平老师课程地址:https://ww ...

  3. 观韩顺平的《0基础30天学会Java》后感

    万丈高楼平地起,在韩老师的带领下你的筑基期肯定很强,日后成仙指日可待. 开门先说重点:一定要加韩老师微信要资料!一定要加韩老师微信要资料!一定要加韩老师微信要资料!,重要的事情说三遍,千万不要去官网下 ...

  4. 韩顺平集合课后作业Homework06.java探讨

    看了韩顺平老师的视频获益匪浅,但是这里有点不太懂,希望会的大神能帮助解答一下.第二次输出前的:set.add(new Person(1001,"CC"));为啥能add进HashS ...

  5. 韩顺平Java:qq项目离线发送接收消息/文件扩展

    思路:1.在服务端创建一个ConcurrentHashMap线程安全的集合用来存储离线用户的消息和文件,为了实现每个用户可以保存多条离线消息,我们在键值对value中采用ArrayList来保存多条m ...

  6. servletjsp入门.....韩顺平笔记

    u 背景知识介绍 J2EE的13种技术 java->servlet->jsp [技术总是有一个演变过程] zip粘贴到word设置 u 回顾一下我们现有的技术 java 基础(面向对象,集 ...

  7. 韩顺平的php东方航空_韩顺平php视频教程

    韩顺平php从入门到精通视频教程是由知名的讲师韩顺平制作讲解的一套php基础入门教程,也是自学PHP必备的一系列教程.包含了php开山篇.html介绍.html运行原理.网上支付平台开发实例.XML编 ...

  8. 韩顺平主讲PHP从入门到精通掌握网站核心技术

    本视频教程为传智播客讲师韩顺平讲解 视频目录如下: 下载地址:百度网盘 0讲 PHP开山篇 1讲 html介绍 html运行原理① 2讲 html运行原理② html文件基本结构 html元素和属性 ...

  9. Java基础易忘重点内容笔记【附B站韩顺平老师课程链接】

    B站课程链接:https://www.bilibili.com/video/BV1fh411y7R8?spm_id_from=333.999.0.0 1. 文档注释 用于对Java方法的注释,可据此生 ...

最新文章

  1. php手机底部菜单,html5手机web页面底部菜单
  2. 【Linux】一步一步学Linux——split命令(59)
  3. github 如何设置项目的语言显示
  4. 【OCR技术系列之五】自然场景文本检测技术综述(CTPN, SegLink, EAST)
  5. python3 windows console 输出乱码问题
  6. 计算机的关机键,怎么让电脑按关机键后不关机?让电脑主机上关机键失效的方法...
  7. [vb]SendMessageA函数
  8. ubuntu jdk tomcat mysql_linux-ubuntu tomcat jdk 及 mysql 安装配置
  9. 用word怎么做c语言框图作业,在Word中绘制简单C语言流程图精.docx
  10. VB程序设计教程(第四版) 龚沛曾
  11. 如何使用工时表软件跟踪时间和成本?
  12. 【建议收藏】手把手教你画一个项目的技术架构图
  13. 163邮箱如何注册呢?
  14. python爬取网课答案_高校邦网络数据采集与Python爬虫【带实验】网课答案
  15. ASP.NET网站部署详细步骤
  16. 04_python爬虫爬取超星回放
  17. javaweb_util_excel模板横向纵向循环
  18. opencv实现matlab的median()函数
  19. 检测ip是否为中国php,PHP判断IP是中国IP还是外国IP
  20. 有趣且重要的JS知识合集(18)浏览器实现前端录音功能

热门文章

  1. DBeaver安装完成使用时下载驱动报错的问题--网络原因
  2. 自尊宣言—个人力量的源泉
  3. HuaPu在学:机器学习——sklearn【决策树】
  4. 键盘1左边的符号叫什么 mysql_~!#$%^*这些符号怎么读? 当然是用英语(键盘特殊符号小结)...
  5. 除非……否则……在命题公式中的翻译(符号化)
  6. 湖北松滋历史上十二大李氏家族
  7. 阿里云视频点播-记录
  8. iOS URLWithString返回为空nil的解决方案
  9. Python向上取整和向下取整
  10. 华三路由追踪命令 tracert详解