Java 静态ObjectOutputStream引用在客户端代码中不起作用
制作一个聊天应用程序,我最近将它从Swing移植到JavaFX。我遇到了使用ObjectOutputStream引用的问题 在Client.java文件中,底部的toServer引用返回null。我认为将toServer设置为静态将允许我访问代码中任何位置的指针。只是不知道我做错了什么 我收到java.lang.NullPointerException 位于Client.sendMessageToServer(Client.java:130) 如果您有任何意见,我将不胜感激,谢谢Java 静态ObjectOutputStream引用在客户端代码中不起作用,java,javafx,objectoutputstream,Java,Javafx,Objectoutputstream,制作一个聊天应用程序,我最近将它从Swing移植到JavaFX。我遇到了使用ObjectOutputStream引用的问题 在Client.java文件中,底部的toServer引用返回null。我认为将toServer设置为静态将允许我访问代码中任何位置的指针。只是不知道我做错了什么 我收到java.lang.NullPointerException 位于Client.sendMessageToServer(Client.java:130) 如果您有任何意见,我将不胜感激,谢谢
Main.java
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import java.io.IOException;
/**
* @author Sergey
* Date: 11/22/13 Time: 9:10 PM
*/
public class Main extends Application
{
private Stage primaryStage;
private BorderPane rootLayout;
/**
* this code creates a borderpane with a menubar at the top, the purpose is of
* this is to nest the chat client into the borderpane's centre location
*/
@Override
public void start( Stage primaryStage )
{
this.primaryStage = primaryStage;
this.primaryStage.setTitle( "chatninjas client" );
try
{
// load the menubar layout from the fxml file
FXMLLoader loader = new FXMLLoader( Client.class.getResource( "ninjamenu.fxml" ) );
rootLayout = ( BorderPane ) loader.load();
Scene scene = new Scene( rootLayout );
primaryStage.setScene( scene );
primaryStage.show();
}
catch( Exception ex )
{
// Exception gets thrown if the fxml file could not be loaded
ex.printStackTrace();
}
showChatRoom();
}
/**
* Shows the chat room area that will be nested into the centre of the borderpane above
*/
public void showChatRoom()
{
try
{
// Load the fxml file and set into the center of the main layout
FXMLLoader loader = new FXMLLoader( Client.class.getResource( "ninja.fxml" ) );
AnchorPane overviewPage = ( AnchorPane ) loader.load();
rootLayout.setCenter( overviewPage );
}
catch( IOException e )
{
// Exception gets thrown if the fxml file could not be loaded
e.printStackTrace();
}
}
/**
* Returns the main stage.
*
* @return
*/
public Stage getPrimaryStage()
{
return primaryStage;
}
public static void main( String[] args )
{
launch( args );
}
}
NinjaController.java
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import java.net.URL;
import java.util.ResourceBundle;
public class NinjaController implements Initializable
{
@FXML // fx:id="userOutput"
static protected TextArea userOutput = null;
@FXML // fx:id="userInput"
static protected TextField userInput = null;
@FXML // fx:id="sendButton"
static protected Button sendButton = null;
@FXML
ResourceBundle resources = null;
@FXML
URL location = null;
@Override
public void initialize( URL fxmlFileLocation, ResourceBundle resources )
{
this.resources = resources;
this.location = fxmlFileLocation;
System.out.println( "about to show the resources var: " + resources );
System.out.println( "about to show the fxmlFileLocation var: " + fxmlFileLocation );
userInput.setOnAction( new EventHandler<ActionEvent>()
{
@Override
public void handle( javafx.event.ActionEvent actionEvent )
{
Client.sendMessageToServer( constructMessageFromFXMLuserInput() );
userInput.setText( "" );
System.out.println( "send via enter key" );
}
});
sendButton.setOnAction( new EventHandler<javafx.event.ActionEvent>()
{
@Override
public void handle( javafx.event.ActionEvent actionEvent )
{
Client.sendMessageToServer( constructMessageFromFXMLuserInput() );
userInput.setText( "" );
System.out.println( "sent via send button" );
}
} );
}
/* dont think i need this anymore
public void onEnter()
{
System.out.println( "user hit enter while mouse was focused in the textfield with this message: " + userInput.getText() );
}
*/
// returns a String trimmed of spaces
public static String retrieveTextFromFXMLuserInput()
{
return userInput.getText().trim();
}
// appends the incoming text area (userOut) with an inbound message
public static void sendMessageToFXMLuserOutput( Message incomingMessage )
{
userOutput.appendText( incomingMessage.getMsgBody() + "\n" );
}
public static Message constructMessageFromFXMLuserInput()
{
// if the userInput field is empty, don't even bother sending the message
if( retrieveTextFromFXMLuserInput().equals( "" ))
{
System.out.println( "message is empty, didnt send anything" );
return null;
}
return new Message( retrieveTextFromFXMLuserInput(),
null, // font entry
null, // font entry
"bob" /*getUserName()*/ );
}
}
Client.java:
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Date;
import static java.text.DateFormat.MEDIUM;
import static java.text.DateFormat.getTimeInstance;
public class Client
{
/*
These are the user set preferences, the userName will be set by the user
when the Client loads.
*/
private static String userName; // this field will be changed when user is prompted for a name
private static int fontSize = 12;
// Object IO streams
private static ObjectOutputStream toServer;
private ObjectInputStream fromServer;
/*
Plan to update the port selection to use a showInputDialog that will request a user
specified port and url of the server to connect to.
Like the other showInputDialogs, this will have a server address and port preset.
*/
private static final int port = 4000;
String date;
boolean connected;
// static Font myFont = new Font( fontType, Font.BOLD, fontSize ); // testing the font functionality // works!
Message wantToSend;
public Client() throws IOException
{
String hostname = "localhost";
Socket socket = new Socket( hostname, port );
// prompt the user for an alias using JOptionPane.showInputDialog
userName = "bob"; //getName(); // getName needs to be rewritten, it used the old JFrames approach, needs to use the new css approach
toServer = new ObjectOutputStream( socket.getOutputStream() );
fromServer = new ObjectInputStream( socket.getInputStream() );
// send the username to the server for "online list"
// ** feature is beta right now **
wantToSend = new Message( userName );
toServer.writeObject( wantToSend );
Message receiveMessage;
connected = true;
while( connected )
{
try
{
// make the date look pretty: 8:54:17 PM
date = getTimeInstance( MEDIUM ).format( new Date() );
receiveMessage = ( Message ) fromServer.readObject();
if( receiveMessage != null )
{
sendMessageToController( receiveMessage );
}
else
{
sendMessageToController( new Message( 1, ">>> Message from server == null <<< BUGCODE1001" ) );
}
}
catch( ClassNotFoundException e1 )
{
e1.printStackTrace();
}
}
}
/* _ _ _ _
| | | | ___ | | | |
__ _ ___ | |_ | |_ ___ _ __ ___ ( _ ) ___ ___ | |_ | |_ ___ _ __ ___
/ _` | / _ \ | __| | __| / _ \ | '__| / __| / _ \/\ / __| / _ \ | __| | __| / _ \ | '__| / __|
| (_| | | __/ | |_ | |_ | __/ | | \__ \ | (_> < \__ \ | __/ | |_ | |_ | __/ | | \__ \
\__, | \___| \__| \__| \___| |_| |___/ \___/\/ |___/ \___| \__| \__| \___| |_| |___/
__/ |
|___/
*/
/**
* Prompt for and return the desired screen name.
*/
// need to update this code with nicole's login screen functionality
/*
public String getName()
{
// the random generator is for testing purposes, i didn't want to keep having
// to type in usernames to test features
return ( String ) JOptionPane.showInputDialog(
null,
"Choose a name:",
"Screen name selection",
JOptionPane.PLAIN_MESSAGE,
null,
null,
"moose" + ( int ) ( Math.random() * ( 9999 - 1111 ) ) );
}
*/
public void sendMessageToController( Message sendThisToController )
{
System.out.println("--sending message to controller");
NinjaController.sendMessageToFXMLuserOutput( sendThisToController );
System.out.println("--message sent to controller");
}
static void sendMessageToServer( Message messageToSend )
{
try
{
if( ! ( messageToSend.getMsgBody().isEmpty() ) )
{
// sends wantToSend object to the server via ObjectOutputStream->OutputStream->Socket
toServer.writeObject( messageToSend ); // exception: java.lang.NullPointerException
//at Client.sendMessageToServer(Client.java:130)
print( "message sent to server" );
toServer.flush();
}
else if( messageToSend == null ) // this shouldn't ever happen BUGCODE1000
{
print( " >>> wantToSend is null .. this message is a bug BUGCODE1000 <<< " );
}
else;
}
catch( IOException ex )
{
System.err.println( ex );
}
}
// basic stdout print because System.out.println( "" )
public static void print( String printThisMessageToSystemOutPrintln )
{
System.out.println( printThisMessageToSystemOutPrintln );
}
}
Main.java
导入javafx.application.application;
导入javafx.fxml.fxmloader;
导入javafx.scene.scene;
导入javafx.scene.layout.ancorpane;
导入javafx.scene.layout.BorderPane;
导入javafx.stage.stage;
导入java.io.IOException;
/**
*@作者谢尔盖
*日期:2013年11月22日时间:晚上9:10
*/
公共类主扩展应用程序
{
私人阶段初级阶段;
私有边界布局;
/**
*这段代码创建了一个顶部带有菜单栏的边框窗格,目的是
*这是为了将聊天客户端嵌套到borderpane的中心位置
*/
@凌驾
公共无效开始(阶段primaryStage)
{
this.primaryStage=primaryStage;
this.primaryStage.setTitle(“聊天忍者客户端”);
尝试
{
//从fxml文件加载菜单栏布局
FXMLLoader=newFXMLLoader(Client.class.getResource(“ninjamenu.fxml”);
rootLayout=(BorderPane)loader.load();
场景=新场景(根布局);
初级阶段。场景(场景);
primaryStage.show();
}
捕获(例外情况除外)
{
//如果无法加载fxml文件,将引发异常
例如printStackTrace();
}
展示室();
}
/**
*显示将嵌套在上方边框窗格中心的聊天室区域
*/
公共聊天室()
{
尝试
{
//加载fxml文件并设置到主布局的中心
FXMLLoader=newFXMLLoader(Client.class.getResource(“ninja.fxml”);
AnchorPane概览页面=(AnchorPane)loader.load();
rootLayout.setCenter(概览页面);
}
捕获(IOE异常)
{
//如果无法加载fxml文件,将引发异常
e、 printStackTrace();
}
}
/**
*返回主阶段。
*
*@返回
*/
公共阶段getPrimaryStage()
{
返回初级阶段;
}
公共静态void main(字符串[]args)
{
发射(args);
}
}
NinjaController.java
导入javafx.event.ActionEvent;
导入javafx.event.EventHandler;
导入javafx.fxml.fxml;
导入javafx.fxml.Initializable;
导入javafx.scene.control.Button;
导入javafx.scene.control.TextArea;
导入javafx.scene.control.TextField;
导入java.net.URL;
导入java.util.ResourceBundle;
公共类NinjaController实现可初始化
{
@FXML//fx:id=“userOutput”
静态受保护的TextArea userOutput=null;
@FXML//fx:id=“userInput”
静态保护的TextField userInput=null;
@FXML//fx:id=“sendButton”
静态保护按钮sendButton=null;
@FXML
ResourceBundle resources=null;
@FXML
URL位置=空;
@凌驾
公共void初始化(URL fxmlFileLocation,ResourceBundle资源)
{
这就是资源=资源;
this.location=fxmlFileLocation;
System.out.println(“即将显示资源变量:“+resources”);
System.out.println(“即将显示fxmlFileLocation变量:”+fxmlFileLocation);
setOnAction(新的EventHandler()
{
@凌驾
公共无效句柄(javafx.event.ActionEvent)
{
sendMessageToServer(constructMessageFromFXMLuserInput());
userInput.setText(“”);
System.out.println(“通过回车键发送”);
}
});
setOnAction(新的EventHandler()
{
@凌驾
公共无效句柄(javafx.event.ActionEvent)
{
sendMessageToServer(constructMessageFromFXMLuserInput());
userInput.setText(“”);
System.out.println(“通过发送按钮发送”);