Java网络编程:登录界面 登录验证 以及登录成功的好友界面
引言
这部分我们就开始设计这个山寨版的qq了,首先最开始的就是需要一个登录界面,当输入的用户名密码正确之后,就跳转到登录成功的界面,我们这里登录成功之后设计的是显示该用户好友界面,这一串我认为是一个整体,所以就放在了一起来写,可能会造成本文比较长。
首先我们来看一下登录界面
登录界面
我们设计的登录界面如图所示
分析界面
这个界面可以分为三个大的部分,北部的一张图片,qq2003全新体验Q人类,中部的QQ号码,手机号码和Email登录部分,以及下面的三个按钮,中间的QQ号码Label,号码输入框,清除号码按钮,QQ密码Label,密码输入框,忘记密码Label,以及隐身登录,记住密码Checkbox,加上申请密码保护按钮,这九个可以用一个3×3的网络布局来做
而QQ号码,手机号码和Email登录这三个可以切换的Label可以用JTabbedPane
界面编程
首先北部组件的那张图片可以是一个JLabel,然后把图片作为参数传入即可
jLabel = new JLabel(new ImageIcon("image/tou.gif"));
然后将其加入到JFrame的北部
this.add(jLabel, "North");
然后南部组件的三个按钮可以是将三个JButton放在一个JPanel里
jPanel = new JPanel();
jPanelButton1 = new JButton(new ImageIcon("image/denglu.gif"));
jPanelButton1.addActionListener(this);
jPanelButton2 = new JButton(new ImageIcon("image/quxiao.gif"));
jPanelButton3 = new JButton(new ImageIcon("image/xiangdao.gif"));
jPanel.add(jPanelButton1);
jPanel.add(jPanelButton2);
jPanel.add(jPanelButton3);
this.add(jPanel, "South");
中部的组件比较复杂,主要要实现可以切换标签页
首先我们把3×3网格里的东西做出来
jPanel1 = new JPanel(new GridLayout(3, 3));
jPanel1_JLabel1 = new JLabel("QQ号码", JLabel.CENTER);
jPanel1_JLabel2 = new JLabel("QQ密码", JLabel.CENTER);
jPanel1_JLabel3 = new JLabel("忘记密码");
jPanel1_JLabel4 = new JLabel("申请密码保护");
jPanel1_JButton = new JButton(new ImageIcon("image/clear.gif"));
jPanel1_UserNameField = new JTextField();
jPanel1_PasswordField = new JPasswordField();
jPanel1_CheckBox1 = new JCheckBox("隐身登录");
jPanel1_CheckBox2 = new JCheckBox("记住密码");
jPanel1.add(jPanel1_JLabel1);
jPanel1.add(jPanel1_UserNameField);
jPanel1.add(jPanel1_JButton);
jPanel1.add(jPanel1_JLabel2);
jPanel1.add(jPanel1_PasswordField);
jPanel1.add(jPanel1_JLabel3);
jPanel1.add(jPanel1_CheckBox1);
jPanel1.add(jPanel1_CheckBox2);
jPanel1.add(jPanel1_JLabel4);
然后我们除了QQ号码这个标签页已经做好了之外(jPanel1),我们把后面两个标签页(手机号码和Email相应的标签页也做好)
jPanel2 = new JPanel();
jPanel3 = new JPanel();
最后我们创建一个JTabbedPane把这三个JPanel放进去即可
jTabbedPane = new JTabbedPane();
jTabbedPane.add("QQ号码", jPanel1);
jTabbedPane.add("手机号码", jPanel2);
jTabbedPane.add("Email", jPanel3);
this.add(jTabbedPane, "Center");
至此登录界面就做好了,接下来就是QQ好友界面
QQ好友界面
我们设计的QQ好友界面如下图所示
分析界面
这个界面大概可以分为三个部分,最上面的我的好友,可以是一个Button,连着中间的好友列表,好友列表要实现向下拉的功能,可以用一个JScrollPane实现,最下面是两个Button,可以放在一个2×1的网格布局里
//用于放我的好友这个界面的东西,布局为BorderLayout
friendPanel1=new JPanel(new BorderLayout());
//用于显示好友列表
friendPanel2=new JPanel(new GridLayout(50, 1, 4, 4));
//用于放陌生人、黑名单按钮
friendPanel3=new JPanel(new GridLayout(2,1));
//将我的好友按钮放入friendPanel1
friendPanel_Button1=new JButton("我的好友");
friendPanel1.add(friendPanel_Button1,"North");
//将好友列表放入friendPanel1
//给好友列表初始化,用一个JLabel数组放好友列表,每一个好友是一个JLabel
JLabel[] friendsList;
friendsList=new JLabel[50];
for (int i = 0; i < friendsList.length; i++) {
friendsList[i]=new JLabel(i+1+"",new ImageIcon("image/mm.jpg"),JLabel.LEFT);
//将每个JLabel放入friendPanel2
friendPanel2.add(friendsList[i]);
}
//将friendPanel2放入JScrollPane
friendPanel_jScrollPane=new JScrollPane(friendPanel2);
//将好友列表也就是JScrollPane放入friendPanel1
friendPanel1.add(friendPanel_jScrollPane,"Center");
//将南部的两个按钮放入friendPanel1
friendPanel_Button2=new JButton("陌生人");
friendPanel_Button3=new JButton("黑名单");
friendPanel3.add(friendPanel_Button2);
friendPanel3.add(friendPanel_Button3);
friendPanel1.add(friendPanel3,"South");
陌生人界面
另外我们想实现的是当点击陌生人按钮时能切换到陌生人界面
如何才能实现呢,一个简单的方式就是我们仿照好友界面也要定义这么多的组件
//用于放陌生人这个界面的东西,布局为BorderLayout
msrPanel1=new JPanel(new BorderLayout());
首先北部现在变为了两个按钮的网格部分的Panel
msrPanel3=new JPanel(new GridLayout(2,1));
//将这个Panel放入msrPanel1
msrPanel_Button1=new JButton("我的好友");
msrPanel_Button2=new JButton("陌生人");
msrPanel3.add(msrPanel_Button1);
msrPanel3.add(msrPanel_Button2);
msrPanel1.add(msrPanel3,"North");
中部依旧是一个JScrollPane用于显示陌生人列表
msrPanel2=new JPanel(new GridLayout(20, 1, 4, 4));
JLabel[] msrList=new JLabel[20];
for (int i = 0; i < msrList.length; i++) {
msrList[i]=new JLabel(i+1+"",new ImageIcon("image/mm.jpg"),JLabel.LEFT);
msrPanel2.add(msrList[i]);
}
msrPanel_jScrollPane=new JScrollPane(msrPanel2);
msrPanel1.add(msrPanel_jScrollPane,"Center");
最后是南部的一个黑名单按钮
msrPanel_Button3=new JButton("黑名单");
msrPanel1.add(msrPanel_Button3,"South");
到这里为止我们遇到了一个困难,就是如何在这两个界面中来回切换呢
这里我们要将JFrame本身的布局设置为CardLayout
cl=new CardLayout();
this.setLayout(cl);
然后将我的好友,陌生人加入到这个卡片布局中
this.add(friendPanel1,"1");
this.add(msrPanel1,"2");
然后我们要在我的好友界面监听陌生人这个按钮,当按下的时候我们切换到陌生人界面
也要在陌生人界面中监听我的好友这个按钮,当按下时我们切换到我的好友界面
if (e.getSource()==friendPanel_Button2) {
cl.show(this.getContentPane(), "2");
}
if (e.getSource()==msrPanel_Button1) {
cl.show(this.getContentPane(), "1");
}
实现鼠标放在好友上面异色显示
也是用到鼠标的监听事件,Entered事件Exited事件
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
JLabel jLabel=(JLabel) e.getSource();
jLabel.setForeground(Color.red);
}
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
JLabel jLabel=(JLabel) e.getSource();
jLabel.setForeground(Color.black);
}
登录验证
接下来我们要实现登录界面输入用户名和密码,通过验证用户名和密码来达到用户登录验证的功能,所以我们需要一个服务器端来做这件事情。
首先是服务器的界面,服务器端的界面设计如下,我们仅仅需要通过GUI开启和关闭服务器即可
服务器界面
分析界面
界面的设计代码也很简单,就是用一个JPanel把两个button给装起来即可,然后再构造函数中去初始化这些组件
JPanel jPanel;
JButton jButton1, jButton2;
public MyServerFrame() {
jPanel = new JPanel();
jButton1 = new JButton("启动服务器");
jButton1.addActionListener(this);
jButton2 = new JButton("关闭服务器");
jPanel.add(jButton1);
jPanel.add(jButton2);
this.add(jPanel);
this.setSize(300, 200);
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setVisible(true);
}
服务器GUI中的button添加监听事件
jButton1.addActionListener(this);
public void actionPerformed(ActionEvent e) {
if (e.getSource()==jButton1) {
new MyQQServer();
}
}
服务器的GUI设计好了,那么接下来我们真正的来编写服务器端的代码,客户端要向服务器端发送用户名和密码信息,这里服务器和客户端的通信通过对象流的方式传递对象信息,所以首先我们得有对象流传送对象信息的先备知识,这里穿插一下这个知识的讲解
对象流
服务器端接收
public class MyServer {
public MyServer()
{
System.out.println("在3456端口监听,,");
ServerSocket ss=new ServerSocket(3456);
Socket s=ss.accept();
//以对象流的形式读取
ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
User u=(User)ois.readObject();
//输出
System.out.println(u.getName()+u.getPass());
}
}
客户端发送
public class MyClient {
public MyClient()
{
Socket s=new Socket("127.0.0.1",3456);
//通过ObjectOutputStream给服务器传送对象
ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
User u=new User();
u.setName("桑阳");
u.setPass("123");
oos.writeObject(u);
}
}
其中User类我们在服务器和客户端中都要建立,那么我们选择建立在一个名叫common的包中,该类要实现序列化接口
User类
public class User implements java.io.Serializable{
private String name;
private String pass;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPass() {
return pass;
}
public void setPass(String pass) {
this.pass = pass;
}
}
有了对象流的概念之后,我们就可以真正的来编写用户验证的代码了
登录验证
用户验证的逻辑就是在登录界面点击了登录按钮,要将用户名框中的信息和密码框中的信息组成一个User类,用对象流的方法传递到服务器端,进行验证。所以首先需要响应按钮的点击事件
响应登录点击事件
响应登录点击事件的逻辑就是,点击了登录按钮,会去新建一个QQClientUser类,该类中有一个验证用户的方法,而该方法实际上会去调用QQClientConServer类中的sendLoginInfoToServer。
public class QqClientUser {
public boolean checkUser(User u)
{
return new QqClientConServer().sendLoginInfoToServer(u);
}
}
在QQClientConServer中我们建立与服务器的连接,在我们把用户对象发送到服务器之后,就开始等待服务器端发回来的结果,结果由信息类型表示,当信息类型为1的时候,表示验证通过,这里我们需要定义一个信息类型类MessageType.class,由于这个也是客户端和服务器端要公用的,所以也放在common包下,注意这个是个接口
public interface MessageType {
public String message_success="1";
public String message_failure="2";
public String message_common_message="3";
public String message_require_friendOnline="4";
public String message_return_friendOnline="5";
}
然后需要建立message类,用于创建服务器和客户端之间传送的对象
public class Message implements Serializable {
private String mesType;
private String sender;
private String getter;
private String content;
private String sentTime;
//一大堆set、get方法
}
于是在服务端验证,如果用户密码正确,就返回messageType为1
if (user.getPasswdString().equals("123456")) {
message.setMesType("1");
oosStream.writeObject(message);
//单开一个线程,让该线程与一个客户端保持通信
ServerToClientThread serverToClientThread=new ServerToClientThread(socket);
ManageClientThread.addClientThread(user.getUserID(), serverToClientThread);
serverToClientThread.start();
//并通知所有的其他用户
serverToClientThread.notifyOther(user.getUserID());
}else {
message.setMesType("2");
oosStream.writeObject(message);
socket.close();
}
public class QqClientConServer {
//发送第一次请求
public boolean sendLoginInfoToServer(Object o)
{
boolean b=false;
Socket s=new Socket("127.0.0.1", 9999);
ObjectOutputStream oos=new ObjectOutputStream(s.getOutputStream());
oos.writeObject(o);
ObjectInputStream ois=new ObjectInputStream(s.getInputStream());
Message ms=(Message)ois.readObject();
if(ms.getMesType().equals("1"))
{
b=true;
}
return b;
}
}
public void actionPerformed(ActionEvent arg0) {
//如果用户点击登录
if(arg0.getSource()==jp1_jb1)
{
QqClientUser qqClientUser=new QqClientUser();
User u=new User();
u.setUserId(jp2_jtf.getText().trim()); //trim是出去开始或结尾的空格
u.setPasswd(new String(jp2_jpf.getPassword()));
if(qqClientUser.checkUser(u))
{
new QqFriendList();
//关闭掉登录界面
this.dispose();
}else{
JOptionPane.showMessageDialog(this, "用户名密码错误");
}
}
}
服务器端
public class MyQQServer {
public MyQQServer(){
ServerSocket ss=new ServerSocket(9999);
while (true) {
Socket socket=ss.accept();
//接收客户端发来的信息
ObjectInputStream oiStream=new ObjectInputStream(socket.getInputStream());
User user=(User) oiStream.readObject();
System.out.println("接收到用户名:"+user.getUserID()+"密码:"+user.getPasswdString());
Message message=new Message();
ObjectOutputStream oosStream=new ObjectOutputStream(socket.getOutputStream());
if (user.getPasswdString().equals("123456")) {
message.setMesType("1");
oosStream.writeObject(message);
//单开一个线程,让该线程与一个客户端保持通信
ServerToClientThread serverToClientThread=new ServerToClientThread(socket);
ManageClientThread.addClientThread(user.getUserID(), serverToClientThread);
serverToClientThread.start();
//并通知所有的其他用户
serverToClientThread.notifyOther(user.getUserID());
}else {
message.setMesType("2");
oosStream.writeObject(message);
socket.close();
}
System.out.println("服务器启动完毕");
}
}