java如何保存聊天记录?

在写一个javaweb程序的聊天模块碰到一个问题。
聊天中双方的聊天记录如何保存呢?
之前做过类似bbs留言一样的功能,由于留言或者私信量少,留一条就往数据库里存一条也没觉得不妥;可聊天如何存聊天记录呢,总不能全存数据库吧!
以文本日志的方式存记录也感觉不好,记录存到客户端还可以类似qq记录那样每两个用户之间的会话记录成一个文件,可我的目的是把聊天记录存放到服务端,这样的话每两个不同用户间的会话就存一个文件也太多了。
可用文件保存的话,如果用户当前不在线给他发的消息如何记录已读未读,从而方便下次登录的时候把消息推送给他呢?
希望有这方便经验的道友不吝赐教,感激不尽!

3个回答

个人观点:
聊天记录存储到库中,至于存多少,记录生命期是多少,什么时候删除等系统设计上考虑下!
如何记录已读未读,这是状态问题!一般CS是双向通信的,而BS可使用轮询模拟双向通信,或者直接使用websocket进行通信,当web端读取到信息时应答服务器。

pandahii
pandahii 回复sin_404: 文本保存是可以记录状态的,只是在读取和写入时带格式,如XML,JSON等!
2 年多之前 回复
pandahii
pandahii 回复sin_404: 这个web前段做的!!!你这个enter是可以在前段进行不抓事件的!!!!
2 年多之前 回复
sin_404
sin_404 //用enter键直接发送了,兄弟是怎么换行的,一路空格吗? 先存库,然后定期把数据转移到文本里保存也考虑过,就是想问一下有没有高效的方法
2 年多之前 回复
sin_404
sin_404 我是指在用文本保存记录的时候不好记录已读未读,用数据库记录是知道的。聊天记录保存到库中,每发一条数据就往库里存一条记录吗?
2 年多之前 回复

用jsp的application+数据库 进行用户信息交互比较合理

kdksz
kdksz 回复sin_404: 如果双方都在线的话可以不用考虑保存问题 直接输出到页面 如果是对方不在线 可以考虑存数据库
2 年多之前 回复
kdksz
kdksz 回复sin_404: 如果双方都在线的话可以不用考虑保存问题 直接输出到页面
2 年多之前 回复
sin_404
sin_404 我的问题不在于如何进行信息交互,而是交互的记录如何保存
2 年多之前 回复

这个你真可以参考一下腾讯qq的做法,因为qq面向的用户众多,所以他是如果是qq会员的话就会把聊天记录以一个xml文件的形式保存在服务器中,
而普通用户是只存在客户端的。所以你要结合你现在做的聊天应用的用户数而做出合适的选择,如果不是太多的话,全部以文件的形式保存在服务器
也占用不了多少空间,而且你也可以比如做个定时更新,定时清除1个月或3个月以前的聊天记录,这样也可以达到减轻服务器压力。

xiaomage1314
人称小马哥 回复sin_404: 在xml里加个标记元,比方说加个type元素为0的时候,表示这条消息未读
2 年多之前 回复
sin_404
sin_404 请问如果把记录存到xml里,qq是如何实现把用户未读的消息在用户下次登录的时候发送给用户呢?
2 年多之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
抄袭、复制答案,以达到刷声望分或其他目的的行为,在CSDN问答是严格禁止的,一经发现立刻封号。是时候展现真正的技术了!
其他相关推荐
后台(java)如何将聊天信息保存至数据库
前面app的im都是用的环信的,这两天得到需求将im的聊天信息保存到数据库,聊天信息有图片,也有对图片的评论,有时候只有纯文字记录。这个改怎么保存。如何一个接口完成保存任务。希望大家提提自己的想法。谢谢诶
JAVA,GUI聊天功能,只做到发送信息和聊天记录,但是聊天记录不知道为什么不能不能查看
public class Demo_GUIChat extends JFrame { /** * */ private static final long serialVersionUID = 1L; private TextField tf; private Button send; private Button log; private Button clear; private Button shake; private TextArea viewText; private TextArea sendText; private DatagramSocket socket; private BufferedWriter bw; public Demo_GUIChat(){ init(); southPanel(); centerPanel(); event(); } private void event() { this.addWindowFocusListener(new WindowAdapter() { @Override public void windowOpened(WindowEvent e) { try { socket.close(); bw.close(); } catch (IOException e1) { e1.printStackTrace(); } System.exit(0); } }); send.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { try { send(); } catch (Exception e) { e.printStackTrace(); } } }); log.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { try { logFile(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } } }); } private void logFile() throws IOException { bw.flush(); //刷新缓冲区 FileInputStream fis = new FileInputStream("config.txt"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); //在内存中创建缓冲区 int len; byte[] arr = new byte[8192]; while((len = fis.read(arr)) != -1) { baos.write(arr,0,len); } String str = baos.toString(); //将内存中的内容转换成字符串 viewText.setText(str); fis.close(); } private void send() throws IOException { String message = sendText.getText(); //获取发送区域的内容 String ip = tf.getText(); //获取IP地址 DatagramPacket packet = new DatagramPacket(message.getBytes(), message.getBytes().length, InetAddress.getByName(ip), 1213); socket.send(packet); //发送数据 String time = getCurrentTime(); String str = time + "\r\n" + message + "\r\n\r\n"; //alt +shift +l 抽取局部变量 viewText.append(str); //将信息添加到显示区域中 bw.write(str); //将信息写到数据库中 sendText.setText(""); } private String getCurrentTime() { Date d = new Date(); //创建当前日期对象 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(d); //将时间格式化 } private void centerPanel() { Panel center = new Panel(); viewText = new TextArea(); sendText = new TextArea(5,1); center.setLayout(new BorderLayout()); //设置为边界布局管理器 center.add(sendText,BorderLayout.SOUTH); center.add(viewText,BorderLayout.CENTER); viewText.setEditable(false); viewText.setBackground(Color.WHITE); sendText.setFont(new Font("zzz",Font.PLAIN,15)); viewText.setFont(new Font("zzz",Font.PLAIN,15)); this.add(center,BorderLayout.CENTER); } private void southPanel() { Panel south = new Panel(); tf = new TextField(15); tf.setText("127.0.0.1"); send = new Button("发送"); log = new Button("记录"); clear = new Button("清除"); shake = new Button("震动"); System.out.println(shake.getLabel()); south.add(tf); south.add(send); south.add(log); south.add(clear); south.add(shake); this.add(south,BorderLayout.SOUTH); } public void init() { this.setLocation(500,50); this.setSize(400,600); new Reveive().start(); try { socket = new DatagramSocket(); bw = new BufferedWriter(new FileWriter("config.txt",true)); //需要在尾部追加 所以加上true } catch (Exception e) { e.printStackTrace(); } this.setVisible(true); this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); } private class Reveive extends Thread{ //接收和发送需要同时执行,所以 public void run() { try { DatagramSocket socket = new DatagramSocket(1213); DatagramPacket packet = new DatagramPacket(new byte[8192], 8192); while(true) { socket.receive(packet); //接收信息 byte[] arr = packet.getData(); //获取字节数据 int len = packet.getLength(); //获取有效的字节数据 String message = new String(arr,0,len); //转换成字符串 String time = getCurrentTime(); //获取当前时间 String ip = packet.getAddress().getHostAddress(); //获取ip地址 String str = time + " " + ip + "对我说:\r\n" + message + "\r\n\r\n"; viewText.append(str); bw.write(str); } } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) throws Exception { new Demo_GUIChat(); } }
Java如何设计数据库记录到对象的映射的
Java如何设计数据库记录到对象的映射的,datamapper和recordactive又扮演了什么角色? 刚刚和同事聊天,同事是工作近十年的HTML5前端工程师,对Java后端也有很深造诣。我是入坑不久的菜鸟。今天我在浏览MyBatis源码时,问道:“如何才能简单快速读取MyBatis源码?” 同事回答我说:“首先,带着问题去看,然后根据Java的设计模式,去理解源码的实现和设计。”之后他和我谈到数据库记录到对象的映射,告诉我Datamapper和recordactive是很好的两种可以用于关系映射的架构设计。 我在网上搜了一下,没有看到太有用的信息,希望大神能解答一下。多谢。
Java 网络编程 聊天软件和发送文件
package ch09; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import javax.swing.*; public class Server extends JFrame implements ActionListener,Runnable{ JTextArea showArea = new JTextArea(); //聊天区域 JLabel lb1 = new JLabel("连接的端口"); //端口栏便签 JTextField tf1 = new JTextField(); //端口栏 JTextField tf2 = new JTextField(); //发送栏 JButton link = new JButton("开启"); //连接按钮 JButton send = new JButton("发送"); JScrollPane JSPane = new JScrollPane(showArea); JPanel pan1 = new JPanel(); JPanel pan2 = new JPanel(); JMenuBar menuBar = new JMenuBar(); //菜单栏 JMenu menuFile = new JMenu("文件"); //菜单 JMenuItem sentFile = new JMenuItem("发送文件"); //菜单项 JMenuItem select = new JMenuItem("历史记录"); JMenuItem exit = new JMenuItem("退出"); //菜单项 Thread thread = null; Thread thread2 = null; Thread thread3 = null; ServerSocket serverSocket; Socket connectToClient; DataInputStream dis; DataOutputStream dos; public Server(){ this.setTitle("聊天小工具"); initialize(); this.setBounds(100,100,650,350); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); } public void initialize(){ tf1.setText("5500"); tf1.setEditable(false); tf1.setColumns(8); send.setEnabled(false); tf2.setEnabled(false); pan1.add(lb1); pan1.add(tf1); pan1.add(link); tf2.setColumns(40); pan2.add(tf2); pan2.add(send); menuFile.add(sentFile); //添加文件菜单项 menuFile.add(select); menuFile.add(exit); //添加删除菜单项 menuBar.add(menuFile); //添加菜单栏菜单 this.setJMenuBar(menuBar); //窗框设置菜单栏 this.add(pan1,BorderLayout.NORTH); this.add(JSPane,BorderLayout.CENTER); this.add(pan2,BorderLayout.SOUTH); tf2.addActionListener(this); exit.addActionListener(this); send.addActionListener(this); link.addActionListener(this); sentFile.addActionListener(this); thread3 = new Thread(this,"触发客户端"); thread3.start(); } public void actionPerformed(ActionEvent e){ try{ if(e.getSource()==sentFile){ thread2 = new Thread(this,"文件"); thread2.setPriority(Thread.MIN_PRIORITY); thread2.start(); } else if(e.getSource()==link){ thread = new Thread(this,"信息"); thread.setPriority(Thread.MAX_PRIORITY); thread.start(); tf2.setEnabled(true); send.setEnabled(true); } else if(e.getSource()==exit){ System.exit(0); } else{ String s = tf2.getText(); if(s.length()>0){ dos.writeUTF(s); showArea.append("我说:"+tf2.getText()+"\n"); tf2.setText(null); } } } catch(IOException el){ showArea.append("你的消息:"+tf2.getText()+"未能发送出去\n"); } } public void run() { try{ if(Thread.currentThread()==thread3){ try{ serverSocket = new ServerSocket(Integer.parseInt(tf1.getText())); showArea.append("正在等待对话请求\n"); connectToClient = serverSocket.accept(); showArea.append("连接成功,请说话\n"); dis = new DataInputStream(connectToClient.getInputStream()); dos = new DataOutputStream(connectToClient.getOutputStream()); } catch(IOException el){ showArea.append("对不起,不能创建服务器\n"); tf2.setEnabled(false); send.setEnabled(false); } } else if(Thread.currentThread()==thread){ while(true){ showArea.append("对方说:"+dis.readUTF()+"\n"); Thread.sleep(1000); } } else{ JFileChooser chooser = new JFileChooser(); String target; if(chooser.showOpenDialog(null)==JFileChooser.APPROVE_OPTION){ target = chooser.getSelectedFile().toString(); FileInputStream fis = new FileInputStream(target); byte[] buffer = new byte[1024]; int len; while(((len=fis.read(buffer))>0)){ dos.write(buffer,0,len); } fis.close(); } } } catch(IOException el){} catch(InterruptedException e){} } public static void main(String[] args) { new Server(); } } 客户端 package ch09; import java.awt.*; import java.awt.event.*; import java.io.*; import java.net.*; import javax.swing.*; public class Client extends JFrame implements Runnable,ActionListener{ String ip; JTextArea showArea = new JTextArea(); //聊天区域 JLabel lb1 = new JLabel("连接的端口"); //端口栏便签 JLabel lb2 = new JLabel("连接的服务器IP"); JTextField tf1 = new JTextField(); //端口栏 JTextField tf2 = new JTextField(); JTextField tf3 = new JTextField(); //发送栏 JButton link = new JButton("连接"); //连接按钮 JButton send = new JButton("发送"); JScrollPane JSPane = new JScrollPane(showArea); JPanel pan1 = new JPanel(); JPanel pan2 = new JPanel(); JMenuBar menuBar = new JMenuBar(); //菜单栏 JMenu menuFile = new JMenu("文件"); //菜单 JMenuItem sentFile = new JMenuItem("发送文件"); //菜单项 JMenuItem select = new JMenuItem("历史记录"); JMenuItem exit = new JMenuItem("退出"); //菜单项 Thread thread = null; Thread thread2 = null; Socket connectToServer; DataInputStream dis; DataOutputStream dos; public Client(){ } public Client(String IP){ this.ip = IP; this.setTitle("客户端"); initialize(); this.setBounds(100,100,650,350); this.setVisible(true); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); try{ connectToServer = new Socket(tf2.getText(),Integer.parseInt(tf1.getText())); dis = new DataInputStream(connectToServer.getInputStream()); dos = new DataOutputStream(connectToServer.getOutputStream()); showArea.append("连接成功,请说话\n"); } catch(IOException el){ showArea.append("对不起,未能连接服务器\n"); tf3.setEnabled(false); send.setEnabled(false); } } public void initialize(){ tf1.setText("5500"); tf2.setText(ip); tf1.setEditable(false); tf2.setEditable(false); tf1.setColumns(8); tf2.setColumns(8); send.setEnabled(false); tf3.setEnabled(false); pan1.add(lb1); pan1.add(tf1); pan1.add(lb2); pan1.add(tf2); pan1.add(link); tf3.setColumns(40); pan2.add(tf3); pan2.add(send); menuFile.add(sentFile); //添加文件菜单项 menuFile.add(select); menuFile.add(exit); //添加删除菜单项 menuBar.add(menuFile); //添加菜单栏菜单 this.setJMenuBar(menuBar); //窗框设置菜单栏 this.add(pan1,BorderLayout.NORTH); this.add(JSPane,BorderLayout.CENTER); this.add(pan2,BorderLayout.SOUTH); tf3.addActionListener(this); exit.addActionListener(this); send.addActionListener(this); link.addActionListener(this); sentFile.addActionListener(this); } public void actionPerformed(ActionEvent e){ try{ if(e.getSource()==sentFile){ thread2 = new Thread(this,"文件"); thread2.setPriority(Thread.MIN_PRIORITY); thread2.start(); } else if(e.getSource()==link){ thread = new Thread(this,"信息"); thread.setPriority(Thread.MIN_PRIORITY); thread.start(); tf3.setEnabled(true); send.setEnabled(true); } else if(e.getSource()==exit){ System.exit(0); } else{ String s = tf3.getText(); if(s.length()>0){ dos.writeUTF(s); dos.flush(); showArea.append("我说:"+tf3.getText()+"\n"); tf3.setText(null); } } } catch(IOException el){ showArea.append("你的消息:"+tf3.getText()+"未能发送出去\n"); } } public void run() { try{ if(Thread.currentThread()==thread){ while(true){ showArea.append("对方说:"+dis.readUTF()+"\n"); Thread.sleep(1000); } } else{ JFileChooser chooser = new JFileChooser(); String source; if(chooser.showSaveDialog(null)==JFileChooser.APPROVE_OPTION){ source = chooser.getSelectedFile().toString(); FileOutputStream fos = new FileOutputStream(source); byte[] buffer = new byte[1024]; int len; while(((len=dis.read(buffer))>0)){ fos.write(buffer,0,len); } // dis.close(); fos.flush(); fos.close(); } } } catch(IOException el){} catch(InterruptedException e){} } } 问题一 为什么当我发送消息后,就不能发送文件了 问题二 为什么只能发送一次文件,当我再次发送就会变成0字节
JAVA聊天室服务器端线程的识别
我做的基于JAVA的有界面的聊天室。注册界面单击注册需要连接服务器去向数据库中插入记录并返回账号。如:![图片说明](https://img-ask.csdn.net/upload/201505/27/1432706833_447699.jpg)点击注册,会执行我标记的那块代码(序列化输出流向服务器发送数据及接受结果) 登陆界面点击登陆需要连接数据库后台验证数据,如:![图片说明](https://img-ask.csdn.net/upload/201505/27/1432707027_141677.jpg) 现在的问题是:在服务器端有两个线程分别用来处理这个两个请求的。如:![图片说明](https://img-ask.csdn.net/upload/201505/27/1432707188_998040.jpg)但是每次区别不了请求,都是处理注册请求的连接。。怎样区别啊
websocket 读写数据库 java
用websocket 进行聊天时,需要将聊天记录存到数据库,然而每次在@open或@Onmessage调用外部类读写数据库时报错, 都是报空指针,在读数据的那个接口 java.lang.NullPointerException
java开发聊天系统的问题(毕业设计)
我打算用Java编写一个类似QQ的软件,包括PC的客户端,网站,服务器端,同时还有手机的wap网站和java版,我已经设计了一段时间,现开始从底层编写代码,用Hibernate和Spring对MySQL数据库的表和操作进行封装;通讯采用队列的方式,无论是服务器还是客户端,有收发两个队列进行控制,发送和接收的都是Message对象。登陆之后有一个tcp连接始终与服务器保持连接,直到离线或退出,其余的消息采用UDP的方式进行通讯,我将客户端的请求都封装在不同的Request类中,比如OnlineRequest,服务器端的回复都封装在不同的但相对应的Response的类中,比如OnlineResponse,同时有处理相应Request和Response的类,比如OnlineRequestMgr,OnlineResponseMgr等,Request和Response分别是不同的抽象类,但都继承自Message接口,通讯类Communication负责初始化TCP连接和收发UDP包,将UDP包中的Message放入相应的队列。一般来说Request由Response对其进行确认,但对于特殊情况,比如由服务器直接发起的Response,比如被添加好友时的确认信息,需要有一个MessageACK类来对其确认。这些协议的加载和处理都是动态的,只要有相应的class文件就可以自动加载并处理,这样可扩充性就比较好。在安全方面,我想的是在用户建立TCP连接后,先将用户的IP地址和TCP端口号记录下来,然后再根据之后发送的UDP包:LoginRequest,将UDP端口也记录下来,这样就完成了用户ID与IP地址,TCP,UDP端口的绑定,服务器将拒绝为同一个ID但其余信息不同的主机提供服务。目前底层的设计和代码编写就到这里,我想问的问题是:我的思路有没有比较严重的问题,目前聊天系统的整体架构是什么?我编写的协议的思路是否正确,可行?我感觉服务器端的压力会比较大,主要是接受连接,解析Request和查询数据库,有没有提高效率的方法?如果网站需要用到这些底层组件,应该怎么复用,采用EJB吗?Hibernate是轻量级的数据库持久层框架,能承受多少压力?对于聊天系统应该考虑的安全问题,有什么好的建议?Java对于开发语音和视频的支持怎么样,能否达到QQ的水平?另外要说明的是我并非开发商用软件,编写这个软件的目的是为了学习,本人还是在校学生,对Java很感兴趣^_^。希望大家不吝赐教
关于Java socket 聊天程序中如何把线程1的文本传到其他线程中
服务器端的代码: package 实验室项目一; import java.io.DataInputStream; import java.io.DataOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.io.IOException; import java.net.InetAddress; public class Server { public static void main(String[] args) { try { //1.创建一个服务器端Socket,即ServerSocket,指定绑定的端口,并监听此端口 ServerSocket serverSocket=new ServerSocket(10086); Socket socket=null; //记录客户端的数量 int count=0; System.out.println("***服务器即将启动,等待客户端的连接***"); //循环监听等待客户端的连接 while(true){ //调用accept()方法开始监听,等待客户端的连接 socket=serverSocket.accept(); //创建一个新的线程 ServerThread serverThread=new ServerThread(socket); //启动线程 serverThread.start(); count++;//统计客户端的数量 System.out.println("客户端的数量:"+count); InetAddress address=socket.getInetAddress(); System.out.println("当前客户端的IP:"+address.getHostAddress()); } } catch (IOException e) { e.printStackTrace(); } } } package 实验室项目一; /** * 服务器线程处理类 */ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.net.Socket; public class ServerThread extends Thread { // 和本线程相关的Socket Socket socket = null; public ServerThread(Socket socket) { this.socket = socket; } //线程执行的操作,响应客户端的请求 public void run(){ String msg;//客户端的消息 DataInputStream is=null; DataOutputStream os=null; try { //获取输入流,并读取客户端信息 is = new DataInputStream(socket.getInputStream()); msg=is.readUTF(); //获取输出流,响应客户端的请求 os = new DataOutputStream(socket.getOutputStream()); os.writeUTF(msg);//注意 啊,写到这儿不知道怎么把数据传到其他的线程中 } catch (IOException e) { e.printStackTrace(); }finally{ //关闭资源 try { if(is!=null) is.close(); if(socket!=null) socket.close(); } catch (IOException e) { e.printStackTrace(); } } } }
一个不连接数据库的聊天室的设计
1.用户登录 2.在线用户列表显示 3.用户群聊 4.单独与某一个用户聊 5.消息日志 点聊天记录要会显示在聊天内容中,希望解释详细些,代码简单些,新手。 ![图片](https://img-ask.csdn.net/upload/201612/23/1482497840_528500.jpg)![图片](https://img-ask.csdn.net/upload/201612/23/1482498056_124548.png)
Java Web开发中 application使用的问题
老师要我们用Myeclipse做一个网页聊天的东西,大概就是在网页中有两个文本框,一个大的文本框显示聊天的记录,下面一个小的文本框用来输入文字,旁边有一个button,点一下就可以发送了。求教,还有代码...谢谢!
swing开发的基于XMPP的聊天客户端spark的聊天界面的问题
spark im客户端的二次开发,想让聊天记录中,接收的消息在左侧,发送的消息在右侧,然后给消息添加气泡。已知显示窗口是org.jivesoftware.spark.ui包下的TranscriptWindow.java类,但是在里面重写paintComponent(Graphics g)了方法,还是没有效果![图片说明](https://img-ask.csdn.net/upload/201709/06/1504685791_32297.png)
求一个极光推送JavaWeb应用开发聊天功能的例子
最近在学习极光推送聊天功能开发https://docs.jiguang.cn/jmessage/client/im__sdk_j_s__v2/_ _但是官方给的文档较为简单,不够详细,求各路大神指点。 我是要把这个聊天功能整合到我自己的一个OA项目中,实现实时信息收发的功能和聊天记录查询(极光IM的Web SDK中包含了这些功能),就是找不到方向下手。_
netty 聊天服务 服务器存的通道Channel 怎么绑定客户端用户登录账户的id;
/** * 当有客户端连接时记录客户通道 * @param ctx * @throws Exception */ @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { Channel channel = ctx.channel();//获得客户端通道 channels.add(channel);//添加到通道队列 } 怎么在客户端启动和服务端建立连接的时候保存chaennl和客户端用户登录的id
网络聊天室的相关问题
刚学web编程,老师让写一个网络聊天室,发现诸多问题无法解决,在此询问诸位大神,万望搭救兄弟一把。 1.当A发送消息时,在他自己的页面中可以刷出自己的聊天信息来,B的页面没有显示,只有当B也发送一条信息后,A的聊天信息才会连同自己的一起显示。这是怎么回事?怎么解决? 2.怎么使得滚动条每发送一条信息就自动滚到最下方? 3.我用的是textarea显示聊天记录,怎么能显示用户的头像呢?(用户头像存储在了数据库中,在用户表里) 4.好友列表是用JSP写的,怎么能实时显示在线用户,即有人登陆即出现在好友列表中,有人下线即从好友列表中消失? 万望大神搭救。以下是聊天页面的代码: ``` <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ page import=" javax.servlet.http.HttpServletRequest"%> <%@ page import=" javax.servlet.http.HttpServletResponse"%> <%@ page import=" javax.servlet.http.HttpSession"%> <%@ page import=" java.util.Date" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <style> #div2{ position:absolute; top:10px; bottom:140px; left:10px; right:10px; width:95%; background:#F0F0F0; } #div1{ position:absolute; bottom:10px; width:95%; height:100px; margin:0; } #text{ margin:0; width:84%; padding:0; height:100px; float:left; } #text2{ margin:0; width:100%; height:100%; } #button{ margin:0; width:15%; padding:0; height:100px; float:right; } </style> <script type="text/javascript"> function check(){ if(document.getElementById("text").value.length==0){ document.getElementById("text").value="聊天记录不能为空"; return false; } else{ localtion.reload(); return true; } } </script> </head> <body> <% request.setCharacterEncoding("UTF-8"); String chat=request.getParameter("text"); String chats=(String)application.getAttribute("chat"); if(chat!=null){ chat=new String(chat.getBytes("ISO-8859-1"),"UTF-8"); String username; HttpSession session1=request.getSession(); if(session1.getAttribute("username")!=null){ username=(String)session1.getAttribute("username"); } else username="游客"; Date d=new Date(); chat=username+" "+d.toLocaleString()+"\r\n"+chat; if(chats==null) chats=chat; else chats=chats+"\r\n"+"\r\n"+chat; } if(chats!=null) application.setAttribute("chat", chats);%> <div id="div2"><textarea id="text2" ><%out.println(application.getAttribute("chat"));%></textarea></div> <form name="form1" id="form1" method="get" action="chatting.jsp" onsubmit="return check()"> <div id="div1"> <div><textarea rows="6" cols="10" id="text" name="text"></textarea></div> <div><input type="submit" id="button" name="button" value="发言"></div> </div> </form> </body> </html> ```
新登录的用户名怎么判断是否和已登录的用户名重名?
用户1、用户2、用户3、用户4依次登录,再登录用户2怎么判断是否重名 ![图片说明](https://img-ask.csdn.net/upload/202002/13/1581566962_929174.png) ![图片说明](https://img-ask.csdn.net/upload/202002/13/1581566977_484440.png) ``` package Pack; import java.awt.event.*; import java.io.*; import java.net.*; import java.text.*; import java.util.*; import javax.swing.*; import javax.swing.event.*; public class Test { private JFrame jf = null; private JTextField CastIPTxtFiled = new JTextField("228.9.6.8");// 组播IP地址文本框 private JTextField portTxtFiled = new JTextField("8000");// 端口地址文本框 private JTextField nameField = new JTextField("用户");// 用户名文本框 private JTextArea receiveMesArea = new JTextArea();// 接收消息文本域 private JTextArea sendMesArea = new JTextArea();// 发送消息文本域 private JButton startChatBtn = new JButton("开始聊天");// 按钮 private JButton stopChatBtn = new JButton("断开聊天"); private JButton quitBtn = new JButton("退出"); private JButton saveBtn = new JButton("保存"); private JButton cleaBtn = new JButton("清空"); private JButton sendBtn = new JButton("发送"); private JRadioButton groupchatBtn = new JRadioButton("群聊");// 单选按钮 private JRadioButton privatechatBtn = new JRadioButton("私聊"); private ButtonGroup btg = new ButtonGroup(); private JList<String> jlist = new JList<String>();// 列表框 private DefaultListModel<String> dlm = new DefaultListModel<String>();// 用dlm向jlist动态增删用户 private JScrollPane jScrollPane1 = new JScrollPane(receiveMesArea);// 滚动窗口 private JScrollPane jScrollPane2 = new JScrollPane(sendMesArea); private JScrollPane jScrollPane3 = new JScrollPane(jlist); private BroadCast broadCast = null; boolean broadCastIsDisable = true; boolean chitchat = true;// 判断是群聊还是私聊 public void InitFrame() { jf = new JFrame("组播聊天室"); jf.setLayout(null); jf.setSize(650, 530); jf.setLocationRelativeTo(null);// 在屏幕中居中显示 jf.setResizable(false);// 不可调整窗口大小 jf.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);// 标题栏关闭按钮失效 JLabel nameJLabel = new JLabel("用户名"); nameJLabel.setBounds(30, 80, 60, 20); jf.add(nameJLabel); nameField.setBounds(80, 80, 100, 20); jf.add(nameField); JLabel portTxtJLabel = new JLabel("端口地址"); portTxtJLabel.setBounds(300, 20, 60, 20); jf.add(portTxtJLabel); portTxtFiled.setBounds(360, 20, 100, 20); jf.add(portTxtFiled); JLabel CastIPTxtJLabel = new JLabel("组播IP地址"); CastIPTxtJLabel.setBounds(10, 20, 90, 20); jf.add(CastIPTxtJLabel); CastIPTxtFiled.setBounds(80, 20, 100, 20); jf.add(CastIPTxtFiled); startChatBtn.setBounds(220, 80, 100, 20); stopChatBtn.setBounds(360, 80, 100, 20); jf.add(startChatBtn); jf.add(stopChatBtn); JLabel receiveJLabel = new JLabel("接收消息"); receiveJLabel.setBounds(20, 140, 100, 20); jScrollPane1.setBounds(20, 160, 460, 130); jScrollPane1.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); jf.add(jScrollPane1); jf.add(receiveJLabel); JLabel sendJLabel = new JLabel("发送消息"); sendJLabel.setBounds(20, 300, 100, 20); jScrollPane2.setBounds(20, 320, 460, 100); jScrollPane2.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); jf.add(jScrollPane2); jf.add(sendJLabel); jlist.setModel(dlm); jScrollPane3.setBorder(BorderFactory.createTitledBorder("在线用户列表")); jScrollPane3.setBounds(500, 20, 120, 430); jScrollPane3.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); jf.add(jScrollPane3); quitBtn.setBounds(20, 460, 100, 20); // 退出 jf.add(quitBtn); saveBtn.setBounds(140, 460, 100, 20); // 保存 jf.add(saveBtn); cleaBtn.setBounds(260, 460, 100, 20);// 清空 jf.add(cleaBtn); sendBtn.setBounds(380, 460, 100, 20); // 发送 jf.add(sendBtn); groupchatBtn.setBounds(120, 120, 100, 20); jf.add(groupchatBtn); privatechatBtn.setBounds(320, 120, 100, 20); jf.add(privatechatBtn); btg.add(groupchatBtn); btg.add(privatechatBtn); groupchatBtn.setSelected(true); jf.setVisible(true); // 显示窗口 BtnFalse(); Object1(); receiveMesArea.setEditable(false);// 接收消息文本域不能被编辑 sendBtn.setMnemonic(KeyEvent.VK_ENTER); // 给sendBtn设置快捷键(Alt+Enter) broadCast = new BroadCast(Integer.parseInt(portTxtFiled.getText()), CastIPTxtFiled.getText(), nameField.getText()); startChatBtn.addActionListener(new ButtonAction()); stopChatBtn.addActionListener(new ButtonAction()); groupchatBtn.addActionListener(new ButtonAction()); privatechatBtn.addActionListener(new ButtonAction()); quitBtn.addActionListener(new ButtonAction()); saveBtn.addActionListener(new ButtonAction()); cleaBtn.addActionListener(new ButtonAction()); sendBtn.addActionListener(new ButtonAction()); jlist.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { Object2(); } }); } public class ButtonAction implements ActionListener { public void actionPerformed(ActionEvent e) { if (e.getSource().equals(startChatBtn)) { jf.setTitle("当前用户:" + nameField.getText()); startChatBtn.setEnabled(false); BtnTrue(); Object2(); broadCastIsDisable = false; StartChat(); } else if (e.getSource().equals(stopChatBtn)) { jf.setTitle("组播聊天室"); startChatBtn.setEnabled(true); BtnFalse(); Object1(); broadCastIsDisable = true; broadCast.StopChat(); // 用户下线 } else if (e.getSource().equals(groupchatBtn)) { chitchat = true; Object2(); } else if (e.getSource().equals(privatechatBtn)) { chitchat = false; Object2(); } else if (e.getSource().equals(quitBtn)) { if (broadCastIsDisable == false) { broadCast.StopChat(); } System.exit(0); } else if (e.getSource().equals(saveBtn)) { try { SaveScreen(); Object2(); } catch (IOException e1) { e1.printStackTrace(); } } else if (e.getSource().equals(cleaBtn)) { ClearScreen(); Object2(); } else if (e.getSource().equals(sendBtn)) { if (sendMesArea.getText().equals("")) { JOptionPane.showMessageDialog(jf, "请输入需要发送的消息", "提示!!!", JOptionPane.ERROR_MESSAGE); } else { SendMessage(); sendMesArea.setText(null);// 按发送按钮,立即将发送消息文本域内容清空 } Object2(); } } } public void Object1() { nameField.requestFocusInWindow();// 将nameField设置为焦点 nameField.selectAll(); startChatBtn.getRootPane().setDefaultButton(startChatBtn);// 将startChatBtn设置为焦点,按回车相当于鼠标单击 } public void Object2() { sendMesArea.requestFocusInWindow(); } public void BtnTrue() {// 按钮可点击 stopChatBtn.setEnabled(true); sendBtn.setEnabled(true); groupchatBtn.setEnabled(true); privatechatBtn.setEnabled(true); } public void BtnFalse() {// 按钮不可点击 stopChatBtn.setEnabled(false); sendBtn.setEnabled(false); groupchatBtn.setEnabled(false); privatechatBtn.setEnabled(false); } public void StartChat() { // 用户上线开始聊天 String port = portTxtFiled.getText(); String castIp = portTxtFiled.getText(); if (!castIp.equals("") && !port.equals("")) { broadCast = new BroadCast(Integer.parseInt(portTxtFiled.getText()), CastIPTxtFiled.getText(), nameField.getText()); broadCast.start(); // 启动线程 } } public void SendMessage() { if (chitchat == true) { broadCast.SendMessage(sendMesArea.getText().toString()); } else { broadCast.SendMessage("@" + jlist.getSelectedValue() + "#" + sendMesArea.getText().toString()); } } public void SaveScreen() throws IOException { broadCast.SaveScreen(); } public void ClearScreen() { broadCast.ClearScreen(); } public static void main(String[] args) { Test client = new Test(); client.InitFrame(); } public class BroadCast extends Thread { public int port = 0; // 端口地址 String Ip = ""; // 组播IP地址 String name = ""; // 用户名 MulticastSocket multicastSocket = null; boolean StopThread = false; static final char FLAG_CHAT = '#'; static final char FLAG_PM_USER = '@'; static final char FLAG_PM_TEXT = '#'; static final char FLAG_ONLINE = '$'; static final char FLAG_OFFLINE = '&'; static final char FLAG_REQ_ONLINE = '*'; static final char FLAG_ALREADY_ONLINE = '+'; public BroadCast(int port, String Ip, String name) { this.port = port; this.Ip = Ip; this.name = name; } public void SocketSend(String data) // 发送组播消息 { try { byte[] buf = data.getBytes(); DatagramPacket datagramPacket1 = new DatagramPacket(buf, buf.length); InetAddress address = InetAddress.getByName(Ip); datagramPacket1.setAddress(address); datagramPacket1.setPort(port); multicastSocket.send(datagramPacket1); } catch (IOException e) { e.printStackTrace(); } } public void SendMessage(String message) // 发送组播消息 { SocketSend(FLAG_CHAT + this.name + ":" + message); // '#' + this.name + ":" + message } public void SendUserOnline() // 发送用户上线消息 { SocketSend(FLAG_ONLINE + this.name); // '$' + this.name } public void SendUserOffline() // 发送用户下线消息 { SocketSend(FLAG_OFFLINE + this.name); // '&' + this.name } public void ReqOnlineUser() // 请求在线用户 { SocketSend(String.valueOf(FLAG_REQ_ONLINE)); // '*' 请求在线用户 } public void SendAlreadyOnline() // 当前在线用户 { SocketSend(FLAG_ALREADY_ONLINE + this.name); // '+' + this.name } public void StopChat() { SendUserOffline(); // 发送用户下线消息 StopThread = true; // 用户下线 while (StopThread == true) { dlm.removeAllElements(); } } public void PrintMessageWT(String message) // 带时间的消息 { receiveMesArea.append("[" + GetSystemTime() + "] "); receiveMesArea.append(message); receiveMesArea.append("\n"); receiveMesArea.setCaretPosition(receiveMesArea.getText().length()); } public void SaveScreen() throws IOException { // 保存聊天记录 String msg = receiveMesArea.getText(); FileOutputStream Note = new FileOutputStream(this.name + "的聊天记录.txt"); PrintMessageWT("聊天记录保存地址:" + System.getProperty("user.dir") + "\\" + this.name + "的聊天记录.txt"); Note.write(msg.getBytes()); Note.close(); } public void ClearScreen() { receiveMesArea.setText(""); // 清空接收消息文本域内容 } public String GetSystemTime() { SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss"); // 获取当前时间(格式yyyy-MM-dd HH:mm:ss) return sdf.format(new Date()); // 返回当前时间 } public void run() { // 启动线程 try { InetAddress address = InetAddress.getByName(Ip); multicastSocket = new MulticastSocket(this.port); multicastSocket.joinGroup(address); SendUserOnline(); // 发送用户上线消息 ReqOnlineUser(); // 请求在线用户 while (!StopThread) { byte[] buf = new byte[1024]; DatagramPacket datagramPacket = new DatagramPacket(buf, buf.length); if (multicastSocket.isClosed() == false) { multicastSocket.receive(datagramPacket); String string_MS = new String(datagramPacket.getData(), 0, datagramPacket.getLength()); switch (string_MS.charAt(0)) { case (FLAG_ONLINE): // '$' string_MS = string_MS.substring(1, string_MS.length()); // 去掉第一个字符,获取用户名 // dlm.addElement(string_MS); PrintMessageWT("系统提示:" + string_MS + " 上线!"); break; case (FLAG_OFFLINE): // '&' string_MS = string_MS.substring(1, string_MS.length()); dlm.removeElement(string_MS); PrintMessageWT("系统提示:" + string_MS + " 下线!"); break; case (FLAG_REQ_ONLINE): // '*' SendAlreadyOnline(); break; case (FLAG_ALREADY_ONLINE): // '+' string_MS = string_MS.substring(1, string_MS.length()); boolean notfound = true; for (int i = 0; i < dlm.size(); i++) { if (dlm.get(i).equals(string_MS)) { notfound = false; break; } } if (notfound == true) { if (nameField.getText().equals(string_MS)) { JOptionPane.showMessageDialog(jf, "欢迎加入组播聊天室!!!", "提示!!!", JOptionPane.INFORMATION_MESSAGE); } dlm.addElement(string_MS); // receiveMesArea.append("新加入用户:" + string_MS + "\n"); // receiveMesArea.append("目前总人數:" + String.valueOf(dlm.size()) + "\n"); } int max = dlm.size(), min = 0; int ran = (int) (Math.random() * (max - min) + min); jlist.setSelectedIndex(ran); } boolean IsPM1 = false, IsPM2 = false;// 判断是否为私聊,默认不是 int num1 = 0, num2 = 0; if (string_MS.charAt(0) == FLAG_CHAT) {// '#' 判断第一个字符是否相等 string_MS = string_MS.substring(1, string_MS.length());// 去掉第一个字符 for (int i = 0; i < string_MS.length(); i++) {// 私聊,判断@和#在哪个位置,获取姓名 if (string_MS.charAt(i) == FLAG_PM_USER) { // '@' num1 = i + 1; IsPM1 = true;// 是私聊 } if (string_MS.charAt(i) == FLAG_PM_TEXT) { // '#' num2 = i; } } String Chat_UserName = string_MS.substring(num1, num2++);// 获取私聊对象的姓名 if (IsPM1 == true) {// 是私聊 String PM_SenderName = string_MS.substring(0, num1 - 2);// 获取私聊对象的姓名 if (this.name.equals(Chat_UserName)) {// 是和我私聊 PrintMessageWT("私聊消息--> " + PM_SenderName + "@我:" + string_MS.substring(num2, string_MS.length())); } else if (this.name.equals(PM_SenderName)) {// 自己发私聊消息 PrintMessageWT("私聊消息--> " + "我@" + Chat_UserName + ":" + string_MS.substring(num2, string_MS.length())); } else {// 不是和我私聊 IsPM2 = true; } } if (IsPM1 == false && IsPM2 == false) { // 不是私聊 PrintMessageWT(string_MS); } } } } } catch (Exception e) { e.printStackTrace(); } try { multicastSocket.close(); } catch (Exception e) { e.printStackTrace(); } StopThread = false; } } } ```
多人聊天器求大神代码!
1. 对功能的规定 分必选项和任选项,其中,必选项是必须完成的,属于项目答辩的入口条件,所有人都要做,未完成者取消答辩资格; 任选项不是入口条件,但每完成一项都会加分,对于完成了必选项的同学,尽可能地多完成一些任选项,以期获得更高的答辩成绩。 如果所有项(包括必选和任选)都完成,那么功能分就是满分。 如果设计思路、界面效果、代码组织等方面有个性(或和别人的不同),则获得附加分。 1.1 服务器功能 1.1.1配置文件 属性:任选 描述:服务器的配置从配置文件中获取,内容包括服务器地址(服务器IP 和 port),具体格式如下: SERVER_IP = 192.168.1.11 PORT = 12012 注意:具体IP和port以本地为准 1.1.2账户文件 属性:必选 描述:客户端注册的用户名和密码需要服务器保存。必须完成下列所有情况: ●内容为用户名和用户密码列表; ●必须用文本形式; ●用户注册用户名重复,需要提示重新选择用户名 ●用户登录时用户名重复,需要提示重新选择用户名 ●用户名密码输入错误,应该提示。给3次连续错误机会,超过3次退出。 1.1.3支持多客户端 属性:必选 描述:基于tcp协议的客户端服务器通讯,服务器采用多线程支持多个客户端连接。 1.1.4业务功能 属性:必选 描述:群聊,单聊 1.1.5链表记录会话连接 属性:必选 描述:服务端使用链表记录当前客户端的会话连接,多个线程访问同一个链表,采用互斥锁来控制。 链表包含下列信息:客户端的ip地址、连接时间,用户名。 1.1.6链表记录动态维护 属性:任选 描述:服务端能够动态维护链表记录;服务器有命令供查询显示。 1.1 客户端功能 1.2.1注册 属性:必选 描述:客户端提供注册用户名,密码功能,用户名密码通过网络传输到服务器认证(用户名不可重复),认证通过后写入账户文件。 1.2.2登陆(认证) 属性:必选 描述:服务器和客户端增加用户密码登陆机制,包含如下流程: ●客户端把接受的用户名密码发送至服务器; ●服务器启动后从配置文件中读取用户信息形成数据表,根据此来验证密码。验证后返回认证结果给客户端(不可一个用户名同时登录) ●如果认证正确,服务器开始接受客户端的命令;认证错误重新认证(3次登陆错误退出) 1.3心跳机制 属性:必选 描述:客户端与服务端之间使用心跳机制,必须完成下列所有情况: ●客户端定时向服务端发送一个数据包(心跳包,内容不限,3秒间隔),证明自己活着; ●服务端显示来自某个IP地址客户端的心跳包; 1.4心跳异常 属性:任选 描述:服务器超过一定的时间没有收到客户端的心跳包(3秒间隔),连续5个包没有接收到则说明客户端出现问题,必须做出如下的处理: ●记录状况; ●断开连接; 1.5聊天功能 属性:必选 描述:两客户端之间能够直接文字通信(类似于QQ聊天), ●能够查询在线列表,具体信息从服务器的链表记录获得; ●可以和别的客户端聊天,发数据采用“用户名后面加数据”方式; 1.6日志文件 属性:任选 描述:服务端通过一个日志文件记录所有客户端连接、命令执行、断开信息(时间,IP地址,执行的命令,心跳包超时等)。 例如:“客户端连接时间 客户端IP地址 客户端的命令 数据包类型(就是上面1.6的data_type) 客户端发送的信息 ”。 2.对性能的规定 本系统在设计方面本着方便、实用的宗旨,性能方面应遵循如下原则: ●执行效率(时间): 软件运行应该尽量高效;避免没有必要的循环处理、重复处理; ●资源损耗(空间):设计尽量节约资源(内存、数组、链表等);不用的资源要及时释放; ●初始化: 变量、数组、内存块、链表节点(其next要置NULL)等都要初始化; ●健壮性:不能出现野指针、内存泄露、数组越界访问等等: ◎申请内存之后,应该立即检查指针值是否为NULL;动态内存的申请与释放必须配对,防止内存泄漏。释放了内存之后,立即将指针设置为NULL,防止产生“野指针”; ◎函数的入参必须进行有效性判断;用户输入、函数返回值(如果用到的话)都要判断; ◎switch-case一定要有default;if-else if等后要有else,除非if满足后返回或退出; ◎数组的下标不要发生“多1”或者“少1”操作。 3.对排版的规定 ●缩进要对齐; ●长行拆分; ●二元操作符的前后应当加空格,包括如下操作符: 赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如"="、"+=" ">="、"<="、"+"、"*"、"%"、"&&"、"||"、"<<", "^" 等; ●空行: ◎结构体 声明之后、每个函数定义结束之后都要加1行空行; ◎逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔; ◎一行代码只做一件事情; ◎"if"、"for"、"while"、"do"等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加 "{ }"; 4.对可维护性的规定 对可维护性的最终要求:别人能够轻松上手你的代码。 ●结构清晰: ◎模块化:对界面(显示)、菜单管理、逻辑管理、文件操作等等代码要独立,必须多个.java文件; ◎封装:一个函数只做一件事,函数功能要单一;一个函数不能超过50行; 避免重复、冗余代码; ◎代码块清晰。 ●变量命名规范,变量名应该具有自明性: ◎常量,枚举和宏定义命名 常量名,宏和枚举值由全大写字母组成,单词间通过下划线来界定; ◎函数的命名: 使用"动词"或者"动词+名词"(动宾词组)的形式,由一个或多个单词组成且以小写字母开头,以后每个单词的首字母必须大写 ◎变量的命名与定义 应当使用"名词"或者"形容词+名词",由一个或多个单词组成且以小写字母开头,以后每个单词之间用下划线隔开。 ●注释充分:变量、函数(包括参数、返回值)、代码功能块、一些复杂算法……等都需要 清晰明了地说明; 5.对个性的规定 把项目做出个性出来。下列各项中有和比人不同之处、或很有创意,即可认为有个性。独立设计的软件,一般都会出现一些个性。参考、抄袭不会出现个性。 ●设计思路:包括软件的整体架构、功能块的设计思路、函数封装等等; ●功能实现:从用户的角度,使用上发现与众不同的地方; ●其它方面;
java web 不使用session 判断用户在线的问题
我现在有个页面有一个聊天功能,类似于QQ那样的,现在要显示我的好友的登录 状态,不让能用session,我怎么能够判断用户是否在线呢? 我的想法是在数据库存一个字段,用来记录用户登录状态,但是这样的话有个问题, 就是当用户正常退出、关闭浏览器、清空缓存的时候都是退出操作,我怎么能判断推出了呢?求大神指教!
JAVA Socket服务器与客户端互发信息,只能收发第一条?
收到第一条之后再发送第二条,客户端会出现IO异常,客户端代码如下: Socket s1; DataInputStream dis = null; DataOutputStream dos = null; public void Accept(int port) { try{ s1 = new Socket("127.0.0.1", port); dis = new DataInputStream(s1.getInputStream()); while (true) { //时间 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //把聊天记录设置为 之前的+现在的 MessageArea.setText(MessageArea.getText()+ "对方 "+df.format(System.currentTimeMillis())+"\n" +dis.readUTF()+"\n"); } } catch(ConnectException e) { MessageArea.setText(MessageArea.getText()+"网络连接失败!"); } catch(IOException e) { MessageArea.setText(MessageArea.getText()+"AcceptIO异常!"); } } public void Send() { try{ dos = new DataOutputStream(s1.getOutputStream()); dos.writeUTF(Message.getText()); dos.flush(); //时间 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); MessageArea.setText(MessageArea.getText()+ "我 "+df.format(System.currentTimeMillis())+"\n" +Message.getText()+"\n"); Message.setText(null); }catch(ConnectException e) { MessageArea.setText(MessageArea.getText()+"网络连接失败!"); }catch(IOException e) { MessageArea.setText(MessageArea.getText()+"SendIO异常!"); } } }
多人聊天器,求大神发源代码!初来乍到,小弟实在不是很懂,望大神指教!在线等大神!
1. 对功能的规定 分必选项和任选项,其中,必选项是必须完成的,属于项目答辩的入口条件,所有人都要做,未完成者取消答辩资格; 任选项不是入口条件,但每完成一项都会加分,对于完成了必选项的同学,尽可能地多完成一些任选项,以期获得更高的答辩成绩。 如果所有项(包括必选和任选)都完成,那么功能分就是满分。 如果设计思路、界面效果、代码组织等方面有个性(或和别人的不同),则获得附加分。 1.1 服务器功能 1.1.1配置文件 属性:任选 描述:服务器的配置从配置文件中获取,内容包括服务器地址(服务器IP 和 port),具体格式如下: SERVER_IP = 192.168.1.11 PORT = 12012 注意:具体IP和port以本地为准 1.1.2账户文件 属性:必选 描述:客户端注册的用户名和密码需要服务器保存。必须完成下列所有情况: ●内容为用户名和用户密码列表; ●必须用文本形式; ●用户注册用户名重复,需要提示重新选择用户名 ●用户登录时用户名重复,需要提示重新选择用户名 ●用户名密码输入错误,应该提示。给3次连续错误机会,超过3次退出。 1.1.3支持多客户端 属性:必选 描述:基于tcp协议的客户端服务器通讯,服务器采用多线程支持多个客户端连接。 1.1.4业务功能 属性:必选 描述:群聊,单聊 1.1.5链表记录会话连接 属性:必选 描述:服务端使用链表记录当前客户端的会话连接,多个线程访问同一个链表,采用互斥锁来控制。 链表包含下列信息:客户端的ip地址、连接时间,用户名。 1.1.6链表记录动态维护 属性:任选 描述:服务端能够动态维护链表记录;服务器有命令供查询显示。 1.1 客户端功能 1.2.1注册 属性:必选 描述:客户端提供注册用户名,密码功能,用户名密码通过网络传输到服务器认证(用户名不可重复),认证通过后写入账户文件。 1.2.2登陆(认证) 属性:必选 描述:服务器和客户端增加用户密码登陆机制,包含如下流程: ●客户端把接受的用户名密码发送至服务器; ●服务器启动后从配置文件中读取用户信息形成数据表,根据此来验证密码。验证后返回认证结果给客户端(不可一个用户名同时登录) ●如果认证正确,服务器开始接受客户端的命令;认证错误重新认证(3次登陆错误退出) 1.3心跳机制 属性:必选 描述:客户端与服务端之间使用心跳机制,必须完成下列所有情况: ●客户端定时向服务端发送一个数据包(心跳包,内容不限,3秒间隔),证明自己活着; ●服务端显示来自某个IP地址客户端的心跳包; 1.4心跳异常 属性:任选 描述:服务器超过一定的时间没有收到客户端的心跳包(3秒间隔),连续5个包没有接收到则说明客户端出现问题,必须做出如下的处理: ●记录状况; ●断开连接; 1.5聊天功能 属性:必选 描述:两客户端之间能够直接文字通信(类似于QQ聊天), ●能够查询在线列表,具体信息从服务器的链表记录获得; ●可以和别的客户端聊天,发数据采用“用户名后面加数据”方式; 1.6日志文件 属性:任选 描述:服务端通过一个日志文件记录所有客户端连接、命令执行、断开信息(时间,IP地址,执行的命令,心跳包超时等)。 例如:“客户端连接时间 客户端IP地址 客户端的命令 数据包类型(就是上面1.6的data_type) 客户端发送的信息 ”。 2.对性能的规定 本系统在设计方面本着方便、实用的宗旨,性能方面应遵循如下原则: ●执行效率(时间): 软件运行应该尽量高效;避免没有必要的循环处理、重复处理; ●资源损耗(空间):设计尽量节约资源(内存、数组、链表等);不用的资源要及时释放; ●初始化: 变量、数组、内存块、链表节点(其next要置NULL)等都要初始化; ●健壮性:不能出现野指针、内存泄露、数组越界访问等等: ◎申请内存之后,应该立即检查指针值是否为NULL;动态内存的申请与释放必须配对,防止内存泄漏。释放了内存之后,立即将指针设置为NULL,防止产生“野指针”; ◎函数的入参必须进行有效性判断;用户输入、函数返回值(如果用到的话)都要判断; ◎switch-case一定要有default;if-else if等后要有else,除非if满足后返回或退出; ◎数组的下标不要发生“多1”或者“少1”操作。 3.对排版的规定 ●缩进要对齐; ●长行拆分; ●二元操作符的前后应当加空格,包括如下操作符: 赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如"="、"+=" ">="、"<="、"+"、"*"、"%"、"&&"、"||"、"<<", "^" 等; ●空行: ◎结构体 声明之后、每个函数定义结束之后都要加1行空行; ◎逻揖上密切相关的语句之间不加空行,其它地方应加空行分隔; ◎一行代码只做一件事情; ◎"if"、"for"、"while"、"do"等语句自占一行,执行语句不得紧跟其后。不论执行语句有多少都要加 "{ }"; 4.对可维护性的规定 对可维护性的最终要求:别人能够轻松上手你的代码。 ●结构清晰: ◎模块化:对界面(显示)、菜单管理、逻辑管理、文件操作等等代码要独立,必须多个.java文件; ◎封装:一个函数只做一件事,函数功能要单一;一个函数不能超过50行; 避免重复、冗余代码; ◎代码块清晰。 ●变量命名规范,变量名应该具有自明性: ◎常量,枚举和宏定义命名 常量名,宏和枚举值由全大写字母组成,单词间通过下划线来界定; ◎函数的命名: 使用"动词"或者"动词+名词"(动宾词组)的形式,由一个或多个单词组成且以小写字母开头,以后每个单词的首字母必须大写 ◎变量的命名与定义 应当使用"名词"或者"形容词+名词",由一个或多个单词组成且以小写字母开头,以后每个单词之间用下划线隔开。 ●注释充分:变量、函数(包括参数、返回值)、代码功能块、一些复杂算法……等都需要 清晰明了地说明; 5.对个性的规定 把项目做出个性出来。下列各项中有和比人不同之处、或很有创意,即可认为有个性。独立设计的软件,一般都会出现一些个性。参考、抄袭不会出现个性。 ●设计思路:包括软件的整体架构、功能块的设计思路、函数封装等等; ●功能实现:从用户的角度,使用上发现与众不同的地方; ●其它方面;
大学四年自学走来,这些私藏的实用工具/学习网站我贡献出来了
大学四年,看课本是不可能一直看课本的了,对于学习,特别是自学,善于搜索网上的一些资源来辅助,还是非常有必要的,下面我就把这几年私藏的各种资源,网站贡献出来给你们。主要有:电子书搜索、实用工具、在线视频学习网站、非视频学习网站、软件下载、面试/求职必备网站。 注意:文中提到的所有资源,文末我都给你整理好了,你们只管拿去,如果觉得不错,转发、分享就是最大的支持了。 一、电子书搜索 对于大部分程序员...
【JSON解析】浅谈JSONObject的使用
简介 在程序开发过程中,在参数传递,函数返回值等方面,越来越多的使用JSON。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,同时也易于机器解析和生成、易于理解、阅读和撰写,而且Json采用完全独立于语言的文本格式,这使得Json成为理想的数据交换语言。 JSON建构于两种结构: “名称/值”对的集合(A Collection of name/va...
程序员请照顾好自己,周末病魔差点一套带走我。
程序员在一个周末的时间,得了重病,差点当场去世,还好及时挽救回来了。
卸载 x 雷某度!GitHub 标星 1.5w+,从此我只用这款全能高速下载工具!
作者 | Rocky0429 来源 | Python空间 大家好,我是 Rocky0429,一个喜欢在网上收集各种资源的蒟蒻… 网上资源眼花缭乱,下载的方式也同样千奇百怪,比如 BT 下载,磁力链接,网盘资源等等等等,下个资源可真不容易,不一样的方式要用不同的下载软件,因此某比较有名的 x 雷和某度网盘成了我经常使用的工具。 作为一个没有钱的穷鬼,某度网盘几十 kb 的下载速度让我...
只因接了一个电话,程序员被骗 30 万!
今天想给大家说一个刚刚发生在我身边的一起真实的诈骗经历,我的朋友因此被骗走30万。注:为了保护当事人隐私,部分情节进行了修改。1平安夜突来的电话开始以为就像普通的诈骗一样,想办法让你把钱...
我一个37岁的程序员朋友
周末了,人一旦没有点事情干,心里就瞎想,而且跟几个老男人坐在一起,更容易瞎想,我自己现在也是 30 岁了,也是无时无刻在担心自己的职业生涯,担心丢掉工作没有收入,担心身体机能下降,担心突...
python自动下载图片
近日闲来无事,总有一种无形的力量萦绕在朕身边,让朕精神涣散,昏昏欲睡。 可是,像朕这么有职业操守的社畜怎么能在上班期间睡瞌睡呢,我不禁陷入了沉思。。。。 突然旁边的IOS同事问:‘嘿,兄弟,我发现一个网站的图片很有意思啊,能不能帮我保存下来提升我的开发灵感?’ 作为一个坚强的社畜怎么能说自己不行呢,当时朕就不假思索的答应:‘oh, It’s simple. Wait for me for a ...
一名大专同学的四个问题
【前言】   收到一封来信,赶上各种事情拖了几日,利用今天要放下工作的时机,做个回复。   2020年到了,就以这一封信,作为开年标志吧。 【正文】   您好,我是一名现在有很多困惑的大二学生。有一些问题想要向您请教。   先说一下我的基本情况,高考失利,不想复读,来到广州一所大专读计算机应用技术专业。学校是偏艺术类的,计算机专业没有实验室更不用说工作室了。而且学校的学风也不好。但我很想在计算机领...
复习一周,京东+百度一面,不小心都拿了Offer
京东和百度一面都问了啥,面试官百般刁难,可惜我全会。
Java 14 都快来了,为什么还有这么多人固守Java 8?
从Java 9开始,Java版本的发布就让人眼花缭乱了。每隔6个月,都会冒出一个新版本出来,Java 10 , Java 11, Java 12, Java 13, 到2020年3月份,...
达摩院十大科技趋势发布:2020 非同小可!
【CSDN编者按】1月2日,阿里巴巴发布《达摩院2020十大科技趋势》,十大科技趋势分别是:人工智能从感知智能向认知智能演进;计算存储一体化突破AI算力瓶颈;工业互联网的超融合;机器间大规模协作成为可能;模块化降低芯片设计门槛;规模化生产级区块链应用将走入大众;量子计算进入攻坚期;新材料推动半导体器件革新;保护数据隐私的AI技术将加速落地;云成为IT技术创新的中心 。 新的画卷,正在徐徐展开。...
轻松搭建基于 SpringBoot + Vue 的 Web 商城应用
首先介绍下在本文出现的几个比较重要的概念: 函数计算(Function Compute): 函数计算是一个事件驱动的服务,通过函数计算,用户无需管理服务器等运行情况,只需编写代码并上传。函数计算准备计算资源,并以弹性伸缩的方式运行用户代码,而用户只需根据实际代码运行所消耗的资源进行付费。Fun: Fun 是一个用于支持 Serverless 应用部署的工具,能帮助您便捷地管理函数计算、API ...
讲真,这两个IDE插件,可以让你写出质量杠杠的代码
周末躺在床上看《拯救大兵瑞恩》 周末在闲逛的时候,发现了两个优秀的 IDE 插件,据说可以提高代码的质量,我就安装了一下,试了试以后发现,确实很不错,就推荐给大家。 01、Alibaba Java 代码规范插件 《阿里巴巴 Java 开发手册》,相信大家都不会感到陌生,其 IDEA 插件的下载次数据说达到了 80 万次,我今天又贡献了一次。嘿嘿。 该项目的插件地址: https://github....
Python+OpenCV实时图像处理
目录 1、导入库文件 2、设计GUI 3、调用摄像头 4、实时图像处理 4.1、阈值二值化 4.2、边缘检测 4.3、轮廓检测 4.4、高斯滤波 4.5、色彩转换 4.6、调节对比度 5、退出系统 初学OpenCV图像处理的小伙伴肯定对什么高斯函数、滤波处理、阈值二值化等特性非常头疼,这里给各位分享一个小项目,可通过摄像头实时动态查看各类图像处理的特点,也可对各位调参、测试...
2020年一线城市程序员工资大调查
人才需求 一线城市共发布岗位38115个,招聘120827人。 其中 beijing 22805 guangzhou 25081 shanghai 39614 shenzhen 33327 工资分布 2020年中国一线城市程序员的平均工资为16285元,工资中位数为14583元,其中95%的人的工资位于5000到20000元之间。 和往年数据比较: yea...
为什么猝死的都是程序员,基本上不见产品经理猝死呢?
相信大家时不时听到程序员猝死的消息,但是基本上听不到产品经理猝死的消息,这是为什么呢? 我们先百度搜一下:程序员猝死,出现将近700多万条搜索结果: 搜索一下:产品经理猝死,只有400万条的搜索结果,从搜索结果数量上来看,程序员猝死的搜索结果就比产品经理猝死的搜索结果高了一倍,而且从下图可以看到,首页里面的五条搜索结果,其实只有两条才是符合条件。 所以程序员猝死的概率真的比产品经理大,并不是错...
害怕面试被问HashMap?这一篇就搞定了!
声明:本文以jdk1.8为主! 搞定HashMap 作为一个Java从业者,面试的时候肯定会被问到过HashMap,因为对于HashMap来说,可以说是Java集合中的精髓了,如果你觉得自己对它掌握的还不够好,我想今天这篇文章会非常适合你,至少,看了今天这篇文章,以后不怕面试被问HashMap了 其实在我学习HashMap的过程中,我个人觉得HashMap还是挺复杂的,如果真的想把它搞得明明白...
毕业5年,我问遍了身边的大佬,总结了他们的学习方法
我问了身边10个大佬,总结了他们的学习方法,原来成功都是有迹可循的。
python爬取百部电影数据,我分析出了一个残酷的真相
2019年就这么匆匆过去了,就在前几天国家电影局发布了2019年中国电影市场数据,数据显示去年总票房为642.66亿元,同比增长5.4%;国产电影总票房411.75亿元,同比增长8.65%,市场占比 64.07%;城市院线观影人次17.27亿,同比增长0.64%。 看上去似乎是一片大好对不对?不过作为一名严谨求实的数据分析师,我从官方数据中看出了一点端倪:国产票房增幅都已经高达8.65%了,为什...
推荐10个堪称神器的学习网站
每天都会收到很多读者的私信,问我:“二哥,有什么推荐的学习网站吗?最近很浮躁,手头的一些网站都看烦了,想看看二哥这里有什么新鲜货。” 今天一早做了个恶梦,梦到被老板辞退了。虽然说在我们公司,只有我辞退老板的份,没有老板辞退我这一说,但是还是被吓得 4 点多都起来了。(主要是因为我掌握着公司所有的核心源码,哈哈哈) 既然 4 点多起来,就得好好利用起来。于是我就挑选了 10 个堪称神器的学习网站,推...
这些软件太强了,Windows必装!尤其程序员!
Windows可谓是大多数人的生产力工具,集娱乐办公于一体,虽然在程序员这个群体中都说苹果是信仰,但是大部分不都是从Windows过来的,而且现在依然有很多的程序员用Windows。 所以,今天我就把我私藏的Windows必装的软件分享给大家,如果有一个你没有用过甚至没有听过,那你就赚了????,这可都是提升你幸福感的高效率生产力工具哦! 走起!???? NO、1 ScreenToGif 屏幕,摄像头和白板...
阿里面试,面试官没想到一个ArrayList,我都能跟他扯半小时
我是真的没想到,面试官会这样问我ArrayList。
曾经优秀的人,怎么就突然不优秀了。
职场上有很多辛酸事,很多合伙人出局的故事,很多技术骨干被裁员的故事。说来模板都类似,曾经是名校毕业,曾经是优秀员工,曾经被领导表扬,曾经业绩突出,然而突然有一天,因为种种原因,被裁员了,...
大学四年因为知道了这32个网站,我成了别人眼中的大神!
依稀记得,毕业那天,我们导员发给我毕业证的时候对我说“你可是咱们系的风云人物啊”,哎呀,别提当时多开心啦????,嗯,我们导员是所有导员中最帅的一个,真的???? 不过,导员说的是实话,很多人都叫我大神的,为啥,因为我知道这32个网站啊,你说强不强????,这次是绝对的干货,看好啦,走起来! PS:每个网站都是学计算机混互联网必须知道的,真的牛杯,我就不过多介绍了,大家自行探索,觉得没用的,尽管留言吐槽吧???? 社...
良心推荐,我珍藏的一些Chrome插件
上次搬家的时候,发了一个朋友圈,附带的照片中不小心暴露了自己的 Chrome 浏览器插件之多,于是就有小伙伴评论说分享一下我觉得还不错的浏览器插件。 我下面就把我日常工作和学习中经常用到的一些 Chrome 浏览器插件分享给大家,随便一个都能提高你的“生活品质”和工作效率。 Markdown Here Markdown Here 可以让你更愉快的写邮件,由于支持 Markdown 直接转电子邮...
【程序人生】程序员接私活常用平台汇总
00. 目录 文章目录00. 目录01. 前言02. 程序员客栈03. 码市04. 猪八戒网05. 开源众包06. 智城外包网07. 实现网08. 猿急送09. 人人开发10. 开发邦11. 电鸭社区12. 快码13. 英选14. Upwork15. Freelancer16. Dribbble17. Remoteok18. Toptal19. AngelList20. Topcoder21. ...
看完这篇HTTP,跟面试官扯皮就没问题了
我是一名程序员,我的主要编程语言是 Java,我更是一名 Web 开发人员,所以我必须要了解 HTTP,所以本篇文章就来带你从 HTTP 入门到进阶,看完让你有一种恍然大悟、醍醐灌顶的感觉。 最初在有网络之前,我们的电脑都是单机的,单机系统是孤立的,我还记得 05 年前那会儿家里有个电脑,想打电脑游戏还得两个人在一个电脑上玩儿,及其不方便。我就想为什么家里人不让上网,我的同学 xxx 家里有网,每...
史上最全的IDEA快捷键总结
现在Idea成了主流开发工具,这篇博客对其使用的快捷键做了总结,希望对大家的开发工作有所帮助。
阿里程序员写了一个新手都写不出的低级bug,被骂惨了。
这种新手都不会范的错,居然被一个工作好几年的小伙子写出来,差点被当场开除了。
谁是华为扫地僧?
是的,华为也有扫地僧!2020年2月11-12日,“养在深闺人不知”的华为2012实验室扫地僧们,将在华为开发者大会2020(Cloud)上,和大家见面。到时,你可以和扫地僧们,吃一个洋...
立即提问