河南工业大学课程设计课程设计名称:java qq聊天系统专业班级:学生姓名: xiaoyang学号:指导教师:王高平课程设计时间: 2016.7.7计科专业课程设计任务书说明:本表由指导教师填写,由教研室主任审核后下达给选题学生,装订在设计(论文)首页1 需求分析运用java语言实现一个qq聊天局域网系统,主要功能实现信息的相互交流,整个程序分三个大模块,第一个模块是服务器端的设计,第二个模块是客户端的实现,第三个模块是数据库连接的实现。
主要实现一个客户端发送串字符信息,另一端客户端能接受(在一个局域网下),同时建立了一个数据库(mysql),用于注册用户,同时存储用户的信息,以及找回密码要用到的密保问题答案。
2 概要设计主要类:JqqF类:主要是登录窗口Cell类:按钮类Findpassword.java:找回密码类Look:注册窗口Lookpassword.java:查看密码窗口Register.java:注册账号类JavaMysql.java:数据库类,连接数据库。
3 运行环境(软、硬件环境)Windows,64位pc机,jvm(java虚拟机)4 开发工具和编程语言Eclipse,java5 详细设计Server.java(实现一个小型的服务器)package ;import java.io.*;import .*;import java.util.*;public class Sever {boolean started = false;ServerSocket ss = null;List<Client> clients = new ArrayList<Client>();public static void main(String[] args) {new Sever().start();}public void start() {try {ss = new ServerSocket(9999);started = true;} catch (BindException e) {System.out.println("端口使用中....");System.out.println("请关掉相关程序并重新运行服务器!");System.exit(0);} catch (IOException e) {e.printStackTrace();}try {while (started) {Socket s = ss.accept();Client c = new Client(s);System.out.println("a client connected!");new Thread(c).start();clients.add(c);// dis.close();}} catch (IOException e) {e.printStackTrace();} finally {try {ss.close();} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}class Client implements Runnable {private Socket s;private DataInputStream dis = null;private DataOutputStream dos = null;private boolean bConnected = false;public Client(Socket s) {this.s = s;try {dis = new DataInputStream(s.getInputStream());dos = new DataOutputStream(s.getOutputStream());bConnected = true;} catch (IOException e) {e.printStackTrace();}}public void send(String str) {try {dos.writeUTF(str);} catch (IOException e) {clients.remove(this);System.out.println("对方退出了!我从List里面去掉了!");// e.printStackTrace();}}public void run() {//线程体try {while (bConnected) {String str = dis.readUTF();System.out.println(str);for (int i = 0; i < clients.size(); i++) {Client c = clients.get(i);c.send(str);}}} catch (EOFException e) {System.out.println("Client closed!");} catch (IOException e) {e.printStackTrace();} finally {try {if (dis != null)dis.close();if (dos != null)dos.close();if (s != null) {s.close();// s = null;}} catch (IOException e1) {e1.printStackTrace();}}}}}JqqF类:登录的窗口类package ;import java.awt.Color;import java.awt.Font;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JPasswordField;import javax.swing.JTextField;public class JqqF extends JFrame implements MouseListener { private static final long serialVersionUID = 1L;public static void main(String args[]) {JqqF f = new JqqF();}public static JTextField name = new JTextField(20);JLabel nameLab = new JLabel("输入qq号:");public static JPasswordField nam = new JPasswordField(20);JLabel nameLa = new JLabel("输入qq密码:");String path5 = "pic//x.png";// 背景图片ImageIcon background5 = new ImageIcon(path5);cell but = new cell(background5);Font fnt = new Font("Serief", Font.BOLD, 15);String path4 = "pic//l.png";ImageIcon background4 = new ImageIcon(path4);cell bt = new cell(background4);String path3 = "pic//b.png";ImageIcon background3 = new ImageIcon(path3);cell bt2 = new cell(background3);String path2 = "pic//qq3.png";ImageIcon background2 = new ImageIcon(path2);JLabel label2 = new JLabel(background2);public JqqF() {super("qq测试");this.setSize(500, 334);this.setLocation(300, 200);this.setVisible(true);String path = "pic//qq.png";// 背景图片ImageIcon background = new ImageIcon(path);// 把背景图片显示在一个标签里面JLabel label = new JLabel(background);label.setLayout(null);// 把标签的大小位置设置为图片刚好填充整个面板label.setBounds(0, 0, this.getWidth(), this.getHeight()); // 把内容窗格转化为JPanel,否则不能用方法setOpaque()来使内容窗格透明JPanel imagePanel = (JPanel) this.getContentPane(); imagePanel.setOpaque(false);// 把背景图片添加到分层窗格的最底层作为背景nameLab.setFont(fnt);nameLab.setForeground(Color.yellow);nameLa.setFont(fnt);nameLa.setForeground(Color.yellow);nameLab.setBounds(160, 120, 100, 30);bt.setBounds(360, 120, 72, 30);bt.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {register x = new register();}});name.setBounds(250, 120, 100, 30);nameLa.setBounds(160, 160, 100, 30);nam.setBounds(250, 160, 100, 30);bt2.setBounds(360, 160, 72, 30);bt2.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {new findpassword();}});// // nam.setColumns(20) ;label2.setBounds(65, 120, 88, 83);but.setBounds(185, 210, 147, 30);but.addMouseListener(this);label.add(nameLab);label.add(bt);label.add(bt2);label.add(nam);label.add(nameLa);label.add(label2);label.add(name);label.add(but);this.getLayeredPane().add(label, newInteger(Integer.MIN_VALUE));this.setResizable(false);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);// 让组件可见}public void mouseClicked(MouseEvent e) {char[] a = nam.getPassword();String s = new String(a);// System.out.print(s);String b = "1";Statement st = null;ResultSet rs = null;boolean t = false;boolean x = false;Connection con = null;String sql = "SELECT name,mibao,password FROM qq";try {con = new JavaMysql().connnecton();st = con.createStatement();rs = st.executeQuery(sql);} catch (ClassNotFoundException e2) {// TODO Auto-generated catch blocke2.printStackTrace();} catch (SQLException e2) {// TODO Auto-generated catch blocke2.printStackTrace();}try {while (rs.next()) {String qq = rs.getString("name");//匹配用户名String password1 = rs.getString("password");//匹配密码if (qq.equals(name.getText())) {t = true;if (password1.equals(nam.getText())) {x = true;}}}con.close();st.close();rs.close();} catch (SQLException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}if (t) {if (x) {JqqF2 f1 = new JqqF2();//好友列表在这里显示this.setVisible(false);//登录窗口消失f1.setVisible(true);//好友列表出现} else {new passworderror();}} else {new look();}}@Overridepublic void mousePressed(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseReleased(MouseEvent e) { // TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) { // TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) { // TODO Auto-generated method stub}};Passerror类:密码错误提示窗口package ;import javax.swing.JFrame;import javax.swing.JLabel;public class passworderror extends JFrame{JLabel b = new JLabel("密码错误");public passworderror(){this.add(b);this.setSize(100,100);this.setLocation(300, 500);this.setVisible(true);this.setResizable(false);}Findpassword类:找回密码类package ;import java.awt.Color;import java.awt.Font;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JTextField;public class findpassword extends JFrame {JLabel nameLab2 = new JLabel("密保问题:你的学号是多少");JTextField name3 = new JTextField(20);Font fnt = new Font("Serief", Font.BOLD, 15);cell but = new cell("确定");public findpassword() {this.setSize(500, 334);this.setLocation(300, 200);this.setVisible(true);this.setLayout(null);nameLab2.setFont(fnt);nameLab2.setForeground(Color.green);nameLab2.setBounds(140, 150, 200, 30);name3.setBounds(140, 180, 100, 30);this.add(name3);this.add(nameLab2);but.setBounds(160, 240, 147, 30);but.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {Statement st = null;ResultSet rs = null;boolean t = false;Connection con = null;String sql = "SELECT name,mibao,password FROM qq";//查找语句try {con = new JavaMysql().connnecton();st = con.createStatement();rs = st.executeQuery(sql);} catch (ClassNotFoundException e2) {// TODO Auto-generated catch blocke2.printStackTrace();} catch (SQLException e2) {// TODO Auto-generated catch blocke2.printStackTrace();}try {while (rs.next()) {String qqmibao = rs.getString("mibao");String name1 = rs.getString("name");String password1 = rs.getString("password");if (name3.getText().equals(qqmibao)&& name1.equals(.getText())) {//比较是否相等new lookpassword(password1);//如果和密保答案相等就输出t = true;break;}}if (t == false) {new look2password();}} catch (SQLException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}try {con.close();st.close();rs.close();} catch (SQLException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}});this.add(but);}}}Register类:注册新用户package ;import java.awt.Color;import java.awt.Font;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.SQLException;import java.sql.Statement;import javax.swing.ImageIcon;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JPanel;import javax.swing.JPasswordField;import javax.swing.JTextField;public class register extends JFrame implements MouseListener {JTextField name1 = new JTextField(20);JLabel nameLab = new JLabel("输入新qq号:");JPasswordField nam = new JPasswordField(20);JLabel nameLa = new JLabel("输入qq密码:");JLabel nameLab2 = new JLabel("密保问题:你的学号是多少");JTextField name3 = new JTextField(20);Font fnt = new Font("Serief", Font.BOLD, 15);// 背景图片cell but = new cell("确定");public register() {super("注册");this.setSize(500, 334);this.setLocation(300, 200);this.setVisible(true);String path = "pic//qq.png";// 背景图片ImageIcon background = new ImageIcon(path);// 把背景图片显示在一个标签里面JLabel label = new JLabel(background);label.setLayout(null);// 把标签的大小位置设置为图片刚好填充整个面板label.setBounds(0, 0, this.getWidth(), this.getHeight());// 把内容窗格转化为JPanel,否则不能用方法setOpaque()来使内容窗格透明JPanel imagePanel = (JPanel) this.getContentPane();imagePanel.setOpaque(false);nameLab.setFont(fnt);nameLab2.setFont(fnt);nameLab.setForeground(Color.yellow);nameLab2.setForeground(Color.green);nameLa.setFont(fnt);nameLa.setForeground(Color.yellow);nameLab.setBounds(140, 80, 100, 30);but.setBounds(160, 240, 147, 30);name1.setBounds(230, 80, 100, 30);nameLa.setBounds(140, 120, 100, 30);nam.setBounds(230, 120, 100, 30);nameLab2.setBounds(140, 150, 200, 30);name3.setBounds(140, 180, 100, 30);label.add(nameLab);label.add(but);label.add(nam);label.add(nameLa);label.add(nameLab2);label.add(name1);label.add(name3);but.addMouseListener(this);this.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE));this.setResizable(false);setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String args[]) {register f = new register();}@Overridepublic void mouseClicked(MouseEvent e) {String name = name1.getText();String mibao = name3.getText();String password = new String(nam.getPassword());PreparedStatement st = null;Connection con = null;String sql = "INSERT INTO qq(name,mibao,password) VALUES(?,?,?)";//预处理指令try {con = new JavaMysql().connnecton();st = con.prepareStatement(sql);} catch (ClassNotFoundException e2) {// TODO Auto-generated catch blocke2.printStackTrace();} catch (SQLException e2) {// TODO Auto-generated catch blocke2.printStackTrace();}try {st.setString(1, name);//向数据库输入账号st.setString(2, mibao);//密保答案st.setString(3, password);//向数据库输入密码st.executeUpdate();st.close();con.close();} catch (SQLException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}.setText("");JqqF.nam.setText("");this.setVisible(false);}@Overridepublic void mousePressed(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseReleased(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}}JqqF2类:好友列表package ;import java.awt.event.WindowAdapter ;import java.awt.event.MouseListener ;import java.awt.event.WindowEvent ;import java.awt.event.MouseEvent ;import java.awt.Color ;import javax.swing.JFrame ;import java.awt.event.ActionListener ;import java.awt.event.WindowEvent ;import java.awt.event.ActionEvent ;import java.awt.Color ;import java.awt.Container;import java.awt.GridLayout ;import java.awt.Font ;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import .Socket;import .UnknownHostException;import javax.swing.ImageIcon;import javax.swing.JFrame ;import javax.swing.JButton ;import javax.swing.JLabel ;import javax.swing.JSplitPane;import javax.swing.JTextArea ;import javax.swing.JPasswordField ;import javax.swing.JScrollPane ;import javax.swing.JPanel ;public class JqqF2 extends JFrame implements MouseListener { String path4 = "pic//m.png";// 背景图片ImageIcon background4 = new ImageIcon(path4);cell bt = new cell(background4);public JqqF2(){// 准备好了一个面板super.setLayout(null) ;super.setTitle("qq好友列表") ;this.setSize(500, 334);this.setLocation(300, 200);this.setVisible(true);String path = "pic//qq2.png";// 背景图片ImageIcon background = new ImageIcon(path);// 把背景图片显示在一个标签里面JLabel label = new JLabel(background);label.setLayout(null);// 把标签的大小位置设置为图片刚好填充整个面板label.setBounds(0,0,300, 140);// 把内容窗格转化为JPanel,否则不能用方法setOpaque()来使内容窗格透明 JPanel imagePanel = (JPanel) this.getContentPane();imagePanel.setOpaque(false);// 把背景图片添加到分层窗格的最底层作为背景String path2 = "pic//qq3.png";ImageIcon background2 = new ImageIcon(path2);// 把背景图片显示在一个标签里面JLabel label2 = new JLabel(background2);label2.setLayout(null);label2.setBounds(5, 10, 88, 83);String path3 = "pic//f.png";ImageIcon background3 = new ImageIcon(path3);// 把背景图片显示在一个标签里面JLabel label3 = new JLabel(background3);label3.setLayout(null);label3.setBounds(0, 140, 324, 22);JLabel name = new JLabel("冰河世纪(1174850659)");name.setForeground(Color.orange);name.setLayout(null);name.setBounds(97, 10, 180, 15);label.add(name);JLabel name2 = new JLabel("个性签名:坚持就是胜利");name2.setForeground(Color.GREEN);name2.setLayout(null);name2.setBounds(97, 60, 300, 15);label.add(name2);label.add(label2);this.add(label3);bt.addMouseListener(this);super.add(bt);bt.setBounds(0,162,325,60) ;this.setSize(300,550) ;this.setLocation(300,200) ;this.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE));setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);this.setResizable(false);}@Overridepublic void mouseClicked(MouseEvent e) {JqqF3 f1 =null;//提升作用域try {f1 = new JqqF3("吻柔哥(996059929)");//初始化聊天窗口} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}this.setVisible(true);f1.setVisible(true);}@Overridepublic void mousePressed(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseReleased(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}};JqqF3类:聊天窗口package ;import java.awt.Color;import java.awt.Font;import java.awt.event.MouseEvent;import java.awt.event.MouseListener;import java.io.DataInputStream;import java.io.DataOutputStream;import java.io.IOException;import .Socket;import .UnknownHostException;import javax.swing.ImageIcon;import javax.swing.JFrame;import javax.swing.JScrollPane;import javax.swing.JTextArea;public class JqqF3 extends JFrame implements MouseListener { String path4 = "pic//qq6.png";ImageIcon background4 = new ImageIcon(path4);cell cell2 = new cell(background4);static JTextArea j1 = new JTextArea(3, 20);static JTextArea j2 = new JTextArea(3, 20);Socket client = null;public JqqF3(String s) throws IOException {super(s);j1.setLineWrap(true);j2.setLineWrap(true);this.setLayout(null);j1.setBackground(Color.gray);j2.setBackground(Color.WHITE);JScrollPane scr1 = new JScrollPane(j1,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,//加入滚动条JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);JScrollPane scr2 = new JScrollPane(j2,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);scr1.setBounds(0, 0, 600, 600);scr2.setBounds(0, 600, 500, 60);cell2.setBounds(500, 600, 100, 60);cell2.addMouseListener(this);Font font = new Font("宋体", Font.BOLD, 15); // 创建一个字体以便其它调用j1.setFont(font);j1.setForeground(Color.blue);this.add(scr1);this.add(scr2);this.add(cell2);this.setSize(606, 694);this.setLocation(300, 200);this.setVisible(true);this.setResizable(false);client = new Socket("localhost", 9999);//初始化窗口时,客户端连接上new Thread(new Receive(client)).start();//开始一个新的进程用于接收}@Overridepublic void mouseClicked(MouseEvent e) {try {new Thread(new Send(client)).start();//开始一个线程用于发送信息} catch (IOException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}}@Overridepublic void mousePressed(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseReleased(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseEntered(MouseEvent e) {// TODO Auto-generated method stub}@Overridepublic void mouseExited(MouseEvent e) {// TODO Auto-generated method stub}}Send类:用于向服务器发送信息package ;import java.awt.Font;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.BufferedReader;import java.io.DataOutputStream;import java.io.;import java.io.;import java.io.IOException;import java.io.InputStreamReader;import .Socket;import java.text.DateFormat;import java.util.Date;public class Send implements Runnable {private BufferedReader console;//输入流private DataOutputStream dos;//输出流private boolean isRuning = true;public Send(Socket client) throws IOException {dos = new DataOutputStream(client.getOutputStream());//获得输出流}public void send() {DateFormat df = null;df = DateFormat.getDateTimeInstance();String s1 = df.format(new Date());//获得日期String s2 = JqqF3.j2.getText();String s3 = "冰河世纪(1174850659) " + s1;String s = s3 + ":" + "\n" + " " + s2;try {if (null != s && !s.equals("")) {dos.writeUTF(s);dos.flush();JqqF3.j2.setText("");//每发送完一个信息编辑框清空}} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}public void run() {//线程体{send();}}}Receive类:用于接收信息package ;import java.io.DataInputStream;import java.io.IOException;import .Socket;public class Receive implements Runnable {private DataInputStream dis;private boolean isRunning = true;public Receive(Socket client) {try {dis = new DataInputStream(client.getInputStream());//获得输入流} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();isRunning = false;}}public String receive() {String s = "";try {s = dis.readUTF();//读出字符串} catch (IOException e) {e.printStackTrace();isRunning = false;}return s;}@Overridepublic void run() {while (true) {JqqF3.j1.append(receive());//写到编辑框上JqqF3.j1.append("\n");}}}Cell:按钮类package ;import java.awt.Font;import javax.swing.ImageIcon;import javax.swing.JButton;public class cell extends JButton {private static final long serialVersionUID = 1L;public cell(ImageIcon img) {super(img);//传入一个图片类//Font fnt = new Font("Serief", Font.BOLD, 20);//设置字体此处没用//this.setFont(fnt);} // 加入事件public cell(String s) {super(s);//传入字符串参数Font fnt = new Font("Serief", Font.BOLD, 20);this.setFont(fnt);}}Look类:出现注册提示框package ;import javax.swing.JFrame;import javax.swing.JLabel;public class look extends JFrame {JLabel b = new JLabel("请注册");public look() {this.add(b);this.setSize(100, 100);this.setLocation(300, 500);this.setVisible(true);// this.setResizable(false);}}Look2password类:出现密码提示框package ;import java.sql.Connection;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement;import javax.swing.JFrame;import javax.swing.JLabel;public class look2password extends JFrame {public look2password() {String s = "回答错误";JLabel b = new JLabel(s);this.add(b);this.setSize(100, 100);this.setLocation(300, 500);this.setVisible(true);// this.setResizable(false);}}JavaMysql类:用于数据库的链接package ;import java.sql.*;public class JavaMysql{private Connection connecter = null;public JavaMysql() throws ClassNotFoundException, SQLException{ String driver="com.mysql.jdbc.Driver";String url="jdbc:mysql://localhost:3306/QQ";Class.forName(driver);connecter=DriverManager.getConnection(url,"root","1234");}public Connection connnecton (){return connecter;//获得连接}}6 调试分析做到Send类时遇到了瓶颈,主要原因有以下几点,1、主要是进程间的通信不是特别熟悉,总是抛出异常,每次用完输出输入流要记得关闭2、输入输出流的选择也不是很清楚,有可能会产生乱码,其次。