我正在构建我的第一个即时消息应用程序。使用各种教程(The New Boston; Head First Java)我已经成功实现了一个可以在另一个之间发送接收/消息的工作客户端服务器。
我现在希望添加一些稍微高级的功能,例如允许我添加朋友的联系人列表,查看我的朋友何时在线/离线。我试图避免第三方API(例如Smack),因为我希望学习基础知识。遗憾的是,我所阅读的在线教程并不仅仅是设置基本的双方客户端 - 服务器模型。
我的问题是:如何实现链接到我的下面的Server.java和Client.java的基本联系人列表?
非常感谢您的帮助。
Server.java:
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.Date;//timestamp functionality
public class Server extends JFrame{ //inherits from JFrame
//1. Instance Variables
private JTextField userText; //where messages are typed
private JTextArea chatWindow; //where messages are displayed
private String fullTimeStamp = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date());
//fullTimeStamp - MM = months; mm = minutes; HH = 24-hour clock
//setting up the streams
private ObjectOutputStream output; //messages being sent by user
private ObjectInputStream input; //messages being received by user;
private ServerSocket server;
private Socket connection; //Socket = sets up connection between one computer and another.
//2. Constructor (GUI)
public Server(){
super("Mick's Instant Messenger [SERVER]"); //window title
userText = new JTextField();
userText.setEditable(false); //you cannot type anything, unless you are connected to someone else
userText.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
sendMessage(event.getActionCommand());
userText.setText(""); //Resets editable text field after you send message
}
}
);
add(userText, BorderLayout.SOUTH);//places user text input (JTextArea) field at bottom
chatWindow = new JTextArea(15,30); //displays conversation
add(new JScrollPane(chatWindow));
chatWindow.setLineWrap(true); //wraps lines when they outgrow the panel width
chatWindow.setWrapStyleWord(true); //ensures that above line wrap occurs at word end
setSize(400,320);
setVisible(true); //set visible on screen
}
//3.Setup and Run the Server
public void StartRunning(){
try{
server = new ServerSocket(6789, 100);
//Client connects at Port # 6789
//100 = QueueLength - the backlog of clients who can wait at port #6789 to connect to the Server
//while(true) ... means this while loop is going to run forever
while(true){
try{
waitForConnection();
setupStreams();
whileChatting(); //allows messages to pass back and forth through streams
}catch(EOFException eofException){
//connect and have conversation
//Display timestamp for disconnection
showMessage("\n\n" + fullTimeStamp);
showMessage("\nConnection terminated by SERVER! "); //displays end of stream/connection
}finally{
closeCrap();
}
}
}catch(IOException ioException){
ioException.printStackTrace(); //Displays info where there's an error!
}
}
//4. wait for connection method, then display connection info
private void waitForConnection() throws IOException{
showMessage("\n SERVER : Waiting for user(s) to connect... \n "); //tells user Server is waiting for a connection
connection = server.accept();
//socket "connection" will accept connections. Creates a socket for each new connection.
showMessage("Connected with " +connection.getInetAddress().getHostName()); //displays IP address and hostname
}
//5. setup streams method.. get streams to send and receive data
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
//creates pathway to allow connection to whichever computer the 'connnection' socket created.
output.flush(); //clears data that gets left over in buffer when you try to connect to someone else. Flushes it over to the other person.
input = new ObjectInputStream(connection.getInputStream());
//no flush here, because you cannot flush someone else's stream
showMessage("\n Streams are now setup! \n");
}
//6. during conversation method
private void whileChatting() throws IOException{
//Display timestamp for connection
showMessage("\n" + fullTimeStamp);
String message = "You are now connected! \n ";
sendMessage(message);
ableToType(true); //will allow user to type into text box after a connection
String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
do{
try{
message = (String) input.readObject(); //read incoming message as a String and store in 'message' variable.
showMessage("\n" + message);//displays each message you receive on a new line
}catch(ClassNotFoundException classNotFoundException){
showMessage("/n I don't know what object the user has sent!");
}
//***broken by timestamp?***
}while(!message.equalsIgnoreCase("CLIENT " + "[" + timeStamp + "]" + ": " + "END")); //allows conversation until Client enters "END"
}
//7. Close Crap method - close streams and sockets after you are finished chatting
private void closeCrap(){
showMessage("\n\n Closing connections... \n");
ableToType(false);
try{
output.close(); //close your stream to other users
input.close(); //close incoming streams
connection.close(); //close the socket
}catch(IOException ioException){
ioException.printStackTrace();
}
}
//8. send message method - send message to client
private void sendMessage(String message){
try{
//writeObject method is built into Java.
String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
output.writeObject("SERVER" + " [" + timeStamp + "]" + ": " + message);
showMessage("\nSERVER" + " [" + timeStamp + "]" + ": " + message); //shows the ouput message in our conversation window
output.flush();
}catch(IOException ioException){
chatWindow.append("ERROR: Unable to send message!");
}
}
//9. updates chatWindow - instead of creating entirely new GUI each time
private void showMessage(final String text){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
chatWindow.setEditable(false); //disallows text editing in chatWindow
chatWindow.append(text); //appends text, which was passed in from above
}
}
);
}
//10. Lets user type
private void ableToType(final boolean tof){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
userText.setEditable(tof); //passes in 'true'
}
}
);
}
}
Client.java:
import java.io.*;
import java.net.*;
import java.awt.*;
import java.awt.event.*;
import java.util.Date; //timestamp functionality
import javax.swing.*;
public class Client extends JFrame { //inherits from JFrame
//1. Creating instance variables
private JTextField userText; //where user inputs text
private JTextArea chatWindow; //where messages are displayed
private String fullTimeStamp = new java.text.SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(new Date());
//fullTimeStamp - MM = months; mm = minutes; HH = 24-hour cloc
private ObjectOutputStream output; //output from Client to Server
private ObjectInputStream input; //messages received from Server
private String message ="";
private String serverIP;
private Socket connection;
//2. Constructor (GUI)
public Client(String host){ //host=IP address of server
super("Mick's Instant Messenger [CLIENT]");
serverIP = host; //placed here to allow access to private String ServerIP
userText = new JTextField();
userText.setEditable(false);
userText.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent event){
sendMessage(event.getActionCommand()); //For this to work, must build sendData Method
userText.setText(""); //resets userText back to blank, after message has been sent to allow new message(s)
}
}
);
add(userText, BorderLayout.SOUTH);
chatWindow = new JTextArea();
add(new JScrollPane(chatWindow), BorderLayout.CENTER); //allows you to scroll up and down when text outgrows chatWindow
chatWindow.setLineWrap(true); //wraps lines when they outgrow the panel width
chatWindow.setWrapStyleWord(true); //ensures that above line wrap occurs at word end
setSize(400,320);
setVisible(true);
}
//3. startRunning method
public void startRunning(){
try{
connectToServer(); //unlike Server, no need to wait for connections. This connects to one specific Server.
setupStreams();
whileChatting();
}catch(EOFException eofException){
//Display timestamp for disconnection
showMessage("\n\n" + fullTimeStamp);
showMessage("\nConnection terminated by CLIENT! ");
}catch(IOException ioException){
ioException.printStackTrace();
}finally{
closeCrap();
}
}
//4. Connect to Server
private void connectToServer() throws IOException{
showMessage(" \n Attempting connection to SERVER... \n");
connection = new Socket(InetAddress.getByName(serverIP), 6789);//Server IP can be added later
showMessage(" Connected to: " +connection.getInetAddress().getHostName() ); //displays IP Address of Server
}
//5. Setup streams to send and receive messages
private void setupStreams() throws IOException{
output = new ObjectOutputStream(connection.getOutputStream());
output.flush();
input = new ObjectInputStream(connection.getInputStream());
showMessage("\n Streams are now setup! \n");
}
//6. While chatting method
private void whileChatting() throws IOException{
//Display timestamp for connection
showMessage("\n" + fullTimeStamp);
ableToType(true);
String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
do{
try{
message = (String) input.readObject(); //read input, treat as String, store in message variable
showMessage("\n" + message);
}catch(ClassNotFoundException classNotfoundException){
showMessage("\n I don't know that object type");
}
//***broken by timestamp?***
}while(!message.equalsIgnoreCase("SERVER " + "[" + timeStamp + "]" + ": " + "END")); //Conversation happens until Server inputs 'End'
}
//7. Close the streams and sockets
private void closeCrap(){
showMessage("\n\nClosing streams and sockets...");
ableToType(false);//disable typing feature when closing streams and sockets
try{
output.close();
input.close();
connection.close();
}catch(IOException ioException){
ioException.printStackTrace(); //show error messages or exceptions
}
}
//8. Send Messages to Server
private void sendMessage(String message){
try{
String timeStamp = new java.text.SimpleDateFormat("HH:mm:ss").format(new Date());//timestamp
output.writeObject("CLIENT" + " [" + timeStamp + "]" + ": " + message);
output.flush();
showMessage("\nCLIENT" + " [" + timeStamp + "]" + ": " + message);
}catch(IOException ioexception){
chatWindow.append("\n Error: Message not sent!");
}
}
//9.change/update chatWindow
private void showMessage(final String m){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
chatWindow.setEditable(false); //disallows text editing in chatWindow
chatWindow.append(m); //appends text, which was passed in from above
}
}
);
}
//10. Lets user type
private void ableToType(final boolean tof){
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
userText.setEditable(tof); //passes in 'true'
}
}
);
}
}
答案 0 :(得分:1)
我认为你想要一个持久的联系人列表而不是一个会话。因此,一种解决方案是根据用户名创建帐户并关联id:
示例您的朋友使用名称Fred登录IM,如果这是一个新名称,请将其保存到某处(例如文本文件或简单数据库)
如果您随后将Fred添加为联系人,则需要单独的文本文件或数据库表来保存每个用户的联系人详细信息。您将要做的就是将Fred的ID与您自己的ID联系起来。
然后,当您下次进入IM时,服务器应该从保存的任何地方显示您的联系人列表
答案 1 :(得分:1)
创建文件并存储最近的在线用户,方法是将他们映射到他们聊天的用户。假设Fred正在与X
和Y
聊天,所以从下次Fred登录时,他会看到X
和Y
已被添加到他的联系人列表中,他应该可以选择在将来删除或阻止它们。 X
和Y
也是如此。