- 在实训中,利用简单的ETCP网络通信模式来扩展的聊天室,包括服务器启动关闭、登录、注册、聊天群发以及下线(带音效)等功能,还有连接了数据库JDBC的功能,同时对所有的界面进行美化,在登录,注册界面背景图片是动态的,可以实现多人聊天,私聊。
具体效果看下图:
系统整体流程图:
登录:
注册:
聊天界面:
创建JDBC数据库(在dos窗口下):
create database 数据库名 character set utf8;
use 数据库名;
create table 表名(
id int primary key auto_increment,
stuName varchar(50),
password(varchar)
);
注:本项目需要传输在lib下导入sql包,所以有一下的配置文件。
配置文件jdbc.properties:
url=jdbc:mysql://localhost:3306/java_test?useUnicode=true&characterEncoding=utf-8
username=root
- password=123456
注:此外还有个文件夹需要创建 自动生成ip地址的 config.properties文件夹,这个包与jdbc。properties 放在file文件夹中
1.服务端:server
package cn.tedu.server;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import cn.tedu.bean.ChatBean;
import cn.tedu.bean.Client;
import cn.tedu.util.ImageUtil;
import cn.tedu.util.WhisperUtil;
public class Server extends JFrame implements ActionListener{
/**
* 当JAVA 需要远程调用时,传输的数据都是binary 的类型,所以需要把数据序列化,
* 当另一台机器接受以后,需要反序列化然后读出数据。
* 所以就有了把所在类加个serial ID, 这样在反序列化的时候再次验证这个ID
* 以确定是同一个OBJECT (class)。
* JAVA 5 之后,可以加为默认的,所以可以Add default serial version ID,
* 也可以自动获取一个 Add generated serail version ID。
* 所谓的远程调用有RMI ,读取数据库MYSQL
*/
private static final long serialVersionUID = 1L;
//服务器页面相关属性
private JPanel panel;
private JLabel label1,label2;
private JTextField textfield;
private JButton start,end;
//定义了一个相关变量
private ServerSocket serverSocket;
//构建一个键值对为 <String,PECORD>的hashMap对象
private HashMap<String,Client> onlines=new HashMap<>();
//服务器属性初始化
public Server() {
init();
}
//初始化属性
private void init() {
//设置标题
this.setTitle("聊天室服务器");
//设置宽高
this.setSize(500, 335);
//设置关闭方式
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置大小不可变
this.setResizable(false);
//设置居中
this.setLocationRelativeTo(null);
//背景设置
ImageUtil imageUtil=new ImageUtil("images/server.gif");
panel= imageUtil.bg(this);
//构造panel对象
//panel=new JPanel();
//绝对布局
panel.setLayout(null);
label1=new JLabel("端口");
//设置字体的属性
label1.setFont(new Font("微软 雅黑",Font.BOLD,16));
//设置文字的颜色
label1.setForeground(Color.ORANGE);
//设置字体定位
label1.setBounds(170, 100, 50, 30);
textfield=new JTextField();
/*
* 端口号
* 设置端口号
*/
textfield.setText("8088");
/**
* 设置文本框字体
*/
//设置文字的颜色
textfield.setForeground(Color.ORANGE);
//设置字体居中
textfield.setHorizontalAlignment(JTextField.CENTER);
textfield.setBounds(220,100,80,30);
//按钮初始化
start=new JButton("启动服务器");
start.setBounds(170, 220, 140, 35);
//按钮绑定事件
start.addActionListener(this);
//添加组件到画板
panel.add(label1);
panel.add(textfield);
panel.add(start);
//this.add(panel);
this.setVisible(true);
}
//start.addActionListener(this);start点击执行下面的代码
@Override
public void actionPerformed(ActionEvent e) {
//e.getActionCommand()获取按钮的值
if("启动服务器".equals(e.getActionCommand())) {
String text=textfield.getText();
//将端口号保存到配置文件去
Properties pro=new Properties();
pro.setProperty("port", text);
pro.setProperty("ip", "127.0.0.1");
try {
//字节输出流
FileOutputStream fos=new FileOutputStream("file/config.properties");
pro.store(fos,"服务器的端口号配置文件");
} catch (FileNotFoundException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
int port=Integer.parseInt(text);
try {
//创建服务器端的socket
serverSocket=new ServerSocket(port);
onlines=new HashMap<String,Client>();
//更新页面
panel.removeAll();
//panel.setBackground(Color.cyan);
label2=new JLabel("端口:"+port+",服务器正在运行,请勿关闭");
//字体属性
label2.setFont(new Font("宋体",Font.BOLD, 16));
//设置文字的颜色
label2.setForeground(Color.RED);
//定位
label2.setBounds(100, 100, 300, 50);
end=new JButton("关闭服务器");
end.setBounds(170, 220, 140, 35);
end.addActionListener(this);
panel.add(label2);
panel.add(end);
//调用方法更新
panel.updateUI();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//因为服务器要不断监听客户端,所以需要创建一个线程,不断监听客户端连接
new ServerThread().start();
}else if("关闭服务器".equals(e.getActionCommand())) {
System.exit(-1);
}
}
/**
* 服务器线程
* @author Administrator
*
*/
class ServerThread extends Thread{
public void run() {
try {
while(true) {
//监听客户端连接,获取到连接服务器的客户端的socket
Socket socket = serverSocket.accept();
System.out.println(socket+":连上了服务器");
//因为监听到了客户端连接要对该客户端不断进行读写,所以创建了一个对服务器进行读写的线程
new ClientThread(socket).start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 客户端线程
* 服务器专门对客户端进行读写的过程
* @author Administrator
*
*/
class ClientThread extends Thread{
private Socket socket; //客户端的socket
private ChatBean bean;
private ObjectOutputStream oos;
private ObjectInputStream ois;
public ClientThread(Socket socket) {
this.socket=socket;
}
public void run() {
try {
while(true) {
ois=new ObjectInputStream(socket.getInputStream());
bean=(ChatBean)ois.readObject();
switch(bean.getType()) {
case 0:{
//0:表示上下线更新列表
//创建客户端相关信息
Client client=new Client();
client.setName(bean.getName());
client.setSocket(socket);
onlines.put(bean.getName(), client);
//告诉其他客户端XXX上线的消息
ChatBean chatbean=new ChatBean();
//存放在线用户名
HashSet<String>set=new HashSet<>();
set.addAll(onlines.keySet());
chatbean.setClients(set);
chatbean.setInfo(WhisperUtil.getTimer()+" "+bean.getName()+"上线了\n");
bean.setType(0);
sendAll(chatbean);
break;
}
case -1: {
//下线
ChatBean chatbean=new ChatBean();
chatbean.setType(-1);
//返回结果运行客户端下线
oos=new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(chatbean);
oos.flush();
//在线用户列表移除该下线用户
onlines.remove(bean.getName());
//通知剩下的用户有人下线了并刷新其列表
ChatBean chatbean2=new ChatBean();
chatbean2.setType(0);
chatbean2.setInfo(bean.getTimer()+" "+bean.getName()+" 下线了\n");
HashSet<String> set=new HashSet<>();
set.addAll(onlines.keySet());
chatbean2.setClients(set);
sendAll(chatbean2);
return;
}
case 1:{
//聊天
ChatBean chatbean=new ChatBean();
chatbean.setType(1);
chatbean.setTimer(bean.getTimer());
chatbean.setInfo(bean.getInfo());
chatbean.setClients(bean.getClients());
chatbean.setName(bean.getName());
sendMessage(chatbean);
break;
}
default:
break;
}
}
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
close();
}
}
/**
* 发送信息
* @param chatbean
*/
private void sendMessage(ChatBean chatbean) {
Collection<Client> allOnlines=onlines.values();
Iterator<Client>it=allOnlines.iterator();
HashSet<String>clients=chatbean.getClients();
while(it.hasNext()) {
Socket socket=null;
Client client=it.next();
if(clients.contains(client.getName())) {
socket=client.getSocket();
try {
oos=new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(chatbean);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 负责向每个在线用户刷新信息
* @param cb
*/
private void sendAll(ChatBean cb) {
//1.获取所有的在线客户端Socket
Collection<Client>clients=onlines.values();
//2.遍历集合,取到每一个客户端
Iterator<Client>it=clients.iterator();
ObjectOutputStream oos=null;
//3.把消息类用输出流发送给每一个客户端
while(it.hasNext()) {
Socket socket=it.next().getSocket();
try{
oos=new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(cb);
oos.flush();
}catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 关闭流
* 关闭此输入流并释放与该流关联的所有系统资源
*/
public void close() {
if(oos!=null) {
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(ois!=null) {
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(socket!=null) {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) {
Server server=new Server();
}
}
2.Bean包下的实体类:
①客户端:client
package cn.tedu.bean;
import java.net.Socket;
/**
* 封装的客户端实体类
* @author lenovo
*
*/
public class Client {
//客户端名称
private String name;
//客户端的socket
private Socket socket;
public Client() {
super();
}
public Client(String name, Socket socket) {
super();
this.name = name;
this.socket = socket;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Socket getSocket() {
return socket;
}
public void setSocket(Socket socket) {
this.socket = socket;
}
}
②封装类信息:ChatBean
package cn.tedu.bean;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
/**
* 聊天信息的封装类
* @author lenovo
*
*/
public class ChatBean implements Serializable{
private static final long serialVersionUID=1L;
private int type; //聊天类型 1.上线更新 -1下线更新
private HashSet<String> clients; //存放先选中的用户
private HashMap<String,Client> onlines; //存放在线用户
private String name; //姓名
private String info; //信息
private String timer; //时间
public ChatBean() {
super();
}
public ChatBean(int type, HashSet<String> clients, HashMap<String, Client> onlines, String name, String info,
String timer) {
super();
this.type = type;
this.clients = clients;
this.onlines = onlines;
this.name = name;
this.info = info;
this.timer = timer;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public HashSet<String> getClients() {
return clients;
}
public void setClients(HashSet<String> clients) {
this.clients = clients;
}
public HashMap<String, Client> getOnlines() {
return onlines;
}
public void setOnlines(HashMap<String, Client> onlines) {
this.onlines = onlines;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public String getTimer() {
return timer;
}
public void setTimer(String timer) {
this.timer = timer;
}
public static long getSerialversionuid() {
return serialVersionUID;
}
}
③封装用户:User
package cn.tedu.bean;
/**
* 封装用户类
* @author lenovo
*
*/
public class User {
private int id;
private String userName;
private String passWord;
public User() {
super();
}
public User(String userName, String passWord) {
super();
this.userName = userName;
this.passWord = passWord;
}
public User(int id, String userName, String passWord) {
super();
this.id = id;
this.userName = userName;
this.passWord = passWord;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getPassWord() {
return passWord;
}
public void setPassWord(String passWord) {
this.passWord = passWord;
}
@Override
public String toString() {
return "User [id=" + id + ", userName=" + userName + ", passWord=" + passWord + "]";
}
}
3.登录:login
package cn.tedu.login;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import java.awt.BorderLayout;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;
import javax.swing.JTextField;
import cn.tedu.bean.ChatBean;
import cn.tedu.bean.User;
import cn.tedu.client.ChatRoom;
import cn.tedu.dao.UserDao;
import cn.tedu.dao.impl.UserDaoImpl;
import cn.tedu.util.ImageUtil;
import javax.swing.JButton;
import java.awt.Color;
public class Login implements ActionListener{
/**
* 当JAVA 需要远程调用时,传输的数据都是binary 的类型,所以需要把数据序列化,
* 当另一台机器接受以后,需要反序列化然后读出数据。
* 所以就有了把所在类加个serial ID, 这样在反序列化的时候再次验证这个ID
* 以确定是同一个OBJECT (class)。
* JAVA 5 之后,可以加为默认的,所以可以Add default serial version ID,
* 也可以自动获取一个 Add generated serail version ID。
* 所谓的远程调用有RMI ,读取数据库MYSQL
*/
private static final long serialVersionUID = 1L;
/**
* 创建一个标签类的私有成员变量,取名为jLabel1。
*/
private JLabel user;
private JLabel pass;
private JTextField userName;
private JPasswordField password;
private JLabel welcome;
private JButton login;
private JButton register;
//用来设置背景样式
private ImageUtil imageUtil;
private JFrame JFrame;
private Socket socket;
private UserDao userdao=new UserDaoImpl();
/**
* Launch the application.
*/
public static void main(String[] args) {
new Login();
}
/**
* Create the application.初始化属性
*/
public Login() {
init();
}
/**
* 进行属性初始化
*/
private void init() {
JFrame=new JFrame("登陆界面");
JFrame.setTitle("轻聊聊天室");
JFrame.setSize(500,335);
JFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//定位
JFrame.setResizable(false);
JFrame.setLocationRelativeTo(null);
//背景设置
imageUtil=new ImageUtil("images/loginbg.gif");
JPanel pan= imageUtil.bg(JFrame);
//设置绝对布局
pan.setLayout(null);
welcome=new JLabel("欢迎登录");
//设置字体的属性
welcome.setFont(new Font("楷体", Font.BOLD, 38));
//设置文字的颜色
welcome.setForeground(Color.ORANGE);
//字体定位
welcome.setBounds(170, 0, 200, 100);
pan.add(welcome);
//用户名定位
user=new JLabel("用户名");
//设置文字的颜色
user.setForeground(Color.CYAN);
//定位
user.setBounds(130,110,50,30);
pan.add(user);
//用户名框定位
userName=new JTextField(10);
userName.setBounds(180,110,140,30);
pan.add(userName);
//密码定位
pass=new JLabel("密 码");
//设置文字的颜色
pass.setForeground(Color.CYAN);
//定位
pass.setBounds(130,150,50,30);
pan.add(pass);
//密码框定位
password=new JPasswordField(10);
password.setBounds(180,150,140,30);
pan.add(password);
//按钮的初始化
login=new JButton("登录");
login.setBackground(Color.GREEN);
login.setBounds(280,230,80,30);
//登录按钮的点击事件
login.addActionListener(this);
pan.add(login);
register=new JButton("注册");
register.setBackground(Color.RED);
register.setBounds(380, 230,80,30);
//注册按钮的点击事件
register.addActionListener(this);
pan.add(register);
JFrame.setVisible(true);
}
//给按钮绑定点击事件
@Override
public void actionPerformed(ActionEvent e) {
String name=userName.getText();
String pass=password.getText();
if("登录".equals(e.getActionCommand())) {
if(name.equals("")||pass.equals("")) {
JOptionPane.showMessageDialog(null, "用户名或密码为空");
}else {
//传入用户密码,判断是否存在
User user=userdao.login(name,pass);
if(user==null) {
JOptionPane.showMessageDialog(null, "用户名或者密码错误,请重新输入!");
}else {
//表示登录成功
JOptionPane.showMessageDialog(null, "登录成功!");
String ip=getIpOrPort("ip");
int port=Integer.parseInt(getIpOrPort("port"));
try {
//创建客户端的socket
socket=new Socket(ip,port);
//创建聊天界面
ChatRoom cr=new ChatRoom(name,socket);
//关闭当前页面
JFrame.setVisible(false);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}else if("注册".equals(e.getActionCommand())) {
//关闭当前登录页面
JFrame.setVisible(false);
//打开注册页面
Register register=new Register();
}
}
private String getIpOrPort(String key) {
String result=null;
Properties pro=new Properties();
try {
FileInputStream in=new FileInputStream("file/config.properties");
//需要加载的配置文件
pro.load(in);
result=pro.getProperty(key);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
}
4.注册:register
package cn.tedu.login;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.net.Socket;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JTextField;
import cn.tedu.bean.User;
import cn.tedu.dao.UserDao;
import cn.tedu.dao.impl.UserDaoImpl;
import cn.tedu.util.ImageUtil;
public class Register extends JPanel implements ActionListener{
/**
* 当JAVA 需要远程调用时,传输的数据都是binary 的类型,所以需要把数据序列化,
* 当另一台机器接受以后,需要反序列化然后读出数据。
* 所以就有了把所在类加个serial ID, 这样在反序列化的时候再次验证这个ID
* 以确定是同一个OBJECT (class)。
* JAVA 5 之后,可以加为默认的,所以可以Add default serial version ID,
* 也可以自动获取一个 Add generated serail version ID。
* 所谓的远程调用有RMI ,读取数据库MYSQL
*/
private static final long serialVersionUID = 1L;
/**
* 页面布局属性
* 创建一个标签类的私有成员变量,取名为jLabel
*/
private JLabel user;
private JLabel pass,rePass;
private JTextField userName;
private JPasswordField password,rePassword;
private JLabel welcome;
private JButton cancel;
private JButton register;
//用来设置背景样式
private ImageUtil imageUtil;
private JFrame JFrame;
private Socket socket;
private UserDao userdao=new UserDaoImpl();
private User user2;
//初始化属性
public Register() {
init();
}
private void init() {
JFrame=new JFrame("注册界面");
JFrame.setTitle("轻聊聊天室");
JFrame.setSize(500,335);
JFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//定位
JFrame.setResizable(false);
JFrame.setLocationRelativeTo(null);
//背景设置
imageUtil=new ImageUtil("images/registerbg.gif");
JPanel pan= imageUtil.bg(JFrame);
//设置绝对布局
pan.setLayout(null);
welcome=new JLabel("欢迎注册");
welcome.setFont(new Font("楷体",Font.BOLD,38));
//设置文字的颜色
welcome.setForeground(Color.ORANGE);
//字体定位
welcome.setBounds(170, 0, 200, 100);
//用户名定位
user=new JLabel("用 户 名");
user.setForeground(Color.CYAN);
/*
*public void setBounds(int x,int y,int width,int height)
* 移动组件并调整其大小。由 x 和 y 指定左上角的新位置,由 width 和 height 指定新的大小。
*/
user.setBounds(125,100,50,30);
//用户名框定位
userName=new JTextField(10);
userName.setBounds(180,100,140,30);
//密码定位
pass=new JLabel("密 码");
pass.setForeground(Color.CYAN);
pass.setBounds(130,140,50,30);
//密码框定位
password=new JPasswordField(10);
password.setBounds(180,140,140,30);
//确定密码定位
rePass=new JLabel("确认密码");
rePass.setForeground(Color.CYAN);
rePass.setBounds(122,180,80,30);
//确定密码框定位
rePassword=new JPasswordField(10);
rePassword.setBounds(180,180,140,30);
//按钮的初始化
register=new JButton("注册");
register.setBackground(Color.green);
register.setBounds(280,255,80,30);
//登录按钮的点击事件
register.addActionListener(this);
cancel=new JButton("返回");
cancel.setBackground(Color.red);
cancel.setBounds(380,255,80,30);
//取消按钮的点击事件
cancel.addActionListener(this);
/**
* 整体调用pan方法
*/
pan.add(welcome);
pan.add(user);
pan.add(pass);
pan.add(rePass);
pan.add(userName);
pan.add(password);
pan.add(rePassword);
pan.add(cancel);
pan.add(register);
pan.add(imageUtil);
JFrame.add(this);
JFrame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
String name=userName.getText();
String passWord=password.getText();
String repassWord=rePassword.getText();
if("注册".equals(e.getActionCommand())) {
if(name.equals("")||passWord.equals("")||repassWord.equals("")) {
JOptionPane.showMessageDialog(null, "用户名或密码不能为空");
}else {
if(!passWord.equals(repassWord)) {
JOptionPane.showMessageDialog(null, "两次密码不一致");
}else {
//去数据库查询用户名是否重复
boolean b=userdao.selectByName(name);
if(b) {
//提示用户该用户名已存在
JOptionPane.showMessageDialog(null, "该用户名已存在,请重新输入!");
}else {
//输入数据成功,注册成功;向数据库插入数据
user2=new User(name, repassWord);
//判断向数据库插入信息是否成功
if(userdao.insertUser(user2)>0) {
JOptionPane.showMessageDialog(null, "注册成功!");
//JFrame.setVisible(false);
new Login();
}else {
JOptionPane.showMessageDialog(null, "注册失败,请稍后再试!");
}
}
}
}
}else if("返回".equals(e.getActionCommand())) {
//JFrame.setVisible(false);
new Login();
}
}
public static void main(String[] args) {
new Register();
}
}
5.Util包下的3个类:
①图片管理类:image
package cn.tedu.util;
import java.awt.FlowLayout;
import java.awt.Graphics;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* 创建一个图片文件管理工具类来继承Jpanel
* @author lenovo
*
*/
public class ImageUtil extends JPanel{
/**
* 当JAVA 需要远程调用时,传输的数据都是binary 的类型,所以需要把数据序列化,
* 当另一台机器接受以后,需要反序列化然后读出数据。
* 所以就有了把所在类加个serial ID, 这样在反序列化的时候再次验证这个ID
* 以确定是同一个OBJECT (class)。
* JAVA 5 之后,可以加为默认的,所以可以Add default serial version ID,
* 也可以自动获取一个 Add generated serail version ID。
* 所谓的远程调用有RMI ,读取数据库MYSQL
*/
private static final long serialVersionUID = 1L;
private String imgPath;
public ImageUtil(String imgPath) {
this.imgPath = imgPath;
}
/*
* paintComponent()方法是系统自动调用的,
* 一般在组件构造函数自动调用了以后就调用它来显示组件,
* 还有就是在窗体改变大小或者被遮挡的时候(组件的外形被破坏),
* 所以这个时候系统也自动调用paintComponent()方法来从新画组件。
*
*/
protected void paintComponent(Graphics g) {
ImageIcon icon=new ImageIcon(imgPath);
g.drawImage(icon.getImage(), 0, 0, getWidth(), getHeight(), null);
}
/**
* 设置动态图片定义类
* @param frame
* @return
*/
public JPanel bg(JFrame frame) {
ImageIcon icon=new ImageIcon(imgPath);
JLabel label =new JLabel(icon);
label.setSize(500, 300);
frame.getLayeredPane().add(label, new Integer(Integer.MIN_VALUE));
// 2.把窗口面板设为内容面板并设为透明、流动布局。
JPanel pan = (JPanel) frame.getContentPane();
pan.setOpaque(false);
pan.setLayout(new FlowLayout());
return pan;
}
}
②连接数据库:JDBCutil
package cn.tedu.util;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
public class JDBCUtil {
//工具类的特点:方法都是静态的
static String url=null;
static String username=null;
static String password=null;
//读取配置文件
static {
try {
Properties pro=new Properties();
//采用文件字节输入流,对文件数据以字节的形式进行读取操作如读取图片视频
FileInputStream in=new FileInputStream("file/jdbc.properties");
//InputStream in=JDBCUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
pro.load(in);
//Uniform Resource Locator,中文名:统一资源定位符 地址
url=pro.getProperty("url");
username=pro.getProperty("username");
password=pro.getProperty("password");
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//获取连接的方法
public static Connection getConn() {
Connection conn=null;
try {
//1.注册驱动java.sql.DriverManager.registerDriver(new Driver())
//DriverManager.registerDriver(new Driver());
//Class.forName("com.mysql.jdbc.Driver");
//2.创建链接
conn=DriverManager.getConnection(url,username,password);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
//释放资源的方法
public static void close(Connection conn,Statement sta,ResultSet rs) {
closeConn(conn);
closeSta(sta);
closeRs(rs);
}
//释放资源
public static void close(Connection conn,Statement sta) {
closeConn(conn);
closeSta(sta);
}
//关闭连接的方法
private static void closeConn(Connection conn) {
try {
if (conn!=null) {
conn.close();
}
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//关闭通道的方法
private static void closeSta(Statement sta) {
try {
if (sta!=null) {
sta.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
//关闭结果集的方法
private static void closeRs(ResultSet rs) {
try {
if (rs!=null) {
rs.close();
}
} catch (SQLException e) {
e.printStackTrace();
}
}
}
③加载文件: WhisperUtil
package cn.tedu.util;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Properties;
public class WhisperUtil {
// Properties加载配置文件信息
public static void loadPro(Properties pro, File file) {
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
pro.load(new FileInputStream(file));
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
@SuppressWarnings("unused")
/*
* @SuppressWarnings("unused")
* 表示该属性在方法或类中没有使用。
*/
public static String getTimer() {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(new Date());
}
}
6.聊天室界面
package cn.tedu.client;
import java.applet.Applet;
import java.applet.AudioClip;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;
import javax.swing.AbstractListModel;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.border.Border;
import javax.swing.border.TitledBorder;
import cn.tedu.bean.ChatBean;
import cn.tedu.util.ImageUtil;
import cn.tedu.util.WhisperUtil;
/**
* 聊天室界面
* @author lenovo
*
*/
public class ChatRoom extends JPanel implements ActionListener{
//聊天室界面属性
private static final long serialVersionUID=1L;
private JFrame JFrame;
private ImageUtil imageUtil;
//发送框、接收框、好友列表的滚动条
private JScrollPane sendMsg,receiveMsg,friendList;
//信息接收框、消息发送框
private JTextArea receiveInfo,sendInfo;
// 显示指定数组中的元素(列表容器)
private JList<String> list;
// 用于显示当前用户
private JLabel currentUser;
// 发送和关闭按钮
private JButton send, close;
//聊天室其他属性
private String name;
private Socket socket;
private ObjectOutputStream oos;
private ObjectInputStream ois;
private Vector onlines;
//列表模型
private static AbstractListModel listmodel;
//构造私有类
private File file1, file2;
// 消息提示音
private URL sound1;
// 上线提示音
private URL sound2;
private AudioClip audioClip1, audioClip2;
//聊天室构造方法
public ChatRoom(String name,Socket socket) {
this.name=name;
this.socket=socket;
onlines=new Vector<>();
init();
try {
oos=new ObjectOutputStream(socket.getOutputStream());
//记录上线用户的信息在chatbean中,并发送给服务器
ChatBean chatbean=new ChatBean();
chatbean.setType(0);
chatbean.setName(name);
chatbean.setTimer(WhisperUtil.getTimer());
oos.writeObject(chatbean);
oos.flush();
//加载音频:消息提示音
file1=new File("sounds/叮.wav");
file2=new File("sounds/呃欧.wav");
//转化音频文件为URL格式
sound1=file1.toURL();
sound2=file2.toURL();
//包装音频URL
audioClip1=Applet.newAudioClip(sound1);
audioClip2=Applet.newAudioClip(sound2);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
//通知服务器,客户端上线了
ChatBean cb=new ChatBean();
cb.setType(0);
cb.setName(name);
//发送给服务器
oos=new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(cb);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
//读取服务器发送过来的消息(用一个线程,因为不知道什么时候要接收服务器发送的消息)
new ClientInputThread().start();
JFrame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
int result = JOptionPane.showConfirmDialog(JFrame.getContentPane(), "您确定要离开聊天室嘛?");
if (result == 0) {
ChatBean chatBean = new ChatBean();
chatBean.setType(-1);
chatBean.setName(name);
chatBean.setTimer(WhisperUtil.getTimer());
sendMessage(chatBean);
// jFrame.setVisible(false);
}
}
});
}
//聊天室界面属性初始化
private void init() {
JFrame = new JFrame("轻聊聊天室");
JFrame.setSize(800, 600);
JFrame.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
JFrame.setResizable(false);
JFrame.setLocationRelativeTo(null);
this.setLayout(null);
imageUtil = new ImageUtil("images/chatbg.jpg");
imageUtil.setBounds(0, 0, 800, 600);
// 页面布局
// 接收框的布局
receiveInfo = new JTextArea();
receiveInfo.setEditable(false); //关闭编辑
receiveInfo.setLineWrap(true); //自动换行
receiveInfo.setFont(new Font("宋体", Font.BOLD, 15));
//添加文本域到滚动条里
receiveMsg = new JScrollPane();
receiveMsg.setBounds(30, 10, 520, 380);
receiveMsg.setViewportView(receiveInfo);
//发送框布局
sendInfo = new JTextArea();
sendInfo.setLineWrap(false);
sendInfo.setFont(new Font("宋体", Font.BOLD, 15));
//添加到滚动条里
sendMsg = new JScrollPane(sendInfo);
sendMsg.setBounds(30, 400, 520, 120);
//发送按钮
send = new JButton("发送");
send.setBackground(Color.green);
send.setBounds(450, 520, 100, 30);
send.addActionListener(this);//绑定事件
//关闭按钮
close = new JButton("关闭");
close.setBackground(Color.red);
close.setBounds(345, 520, 100, 30);
close.addActionListener(this);//绑定事件
//显示当前用户的名字
currentUser = new JLabel("你好," + name + "!");
//设置字体水平居中
currentUser.setHorizontalAlignment(JLabel.CENTER);
currentUser.setFont(new Font("楷体", Font.BOLD, 20));
currentUser.setBounds(560, 10, 230, 50);
//好友列表
list = new JList<>();
//设置选择模式——表示可以选择不相邻的几页
list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);// 表示可以选择不相邻的几项
list.setFont(new Font("华文行楷", Font.BOLD, 18));
list.setBackground(Color.white);
// 设置虚边框样式
Border etch = BorderFactory.createEtchedBorder();
list.setBorder(BorderFactory.createTitledBorder(etch, "在线用户:", TitledBorder.LEADING, TitledBorder.TOP,new Font("楷体", Font.BOLD, 20), Color.green));
//初始化滚动条
friendList = new JScrollPane();
friendList.setViewportView(list); //不直接将子集添加到滚动窗口
friendList.setBounds(560, 60, 230, 330);
this.add(send);
this.add(close);
this.add(currentUser);
this.add(receiveMsg);
this.add(sendMsg);
this.add(friendList);
this.add(imageUtil);
JFrame.add(this);
JFrame.setVisible(true);
}
/**
* 传入Vector,创建ListModel
* 为了更新页面的list集合,封装了一个model类
*/
class ListModel extends AbstractListModel{
private Vector vs;
public ListModel(Vector vs) {
this.vs=vs;
}
@Override
public int getSize() {
return vs.size();
}
@Override
public Object getElementAt(int index) {
return vs.get(index);
}
}
@Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==close) {
int status = JOptionPane.showConfirmDialog(null, "您要离开聊天室吗?");
System.out.println(status);
if (status == 0) {
close.setEnabled(false);
ChatBean chatBean = new ChatBean();
chatBean.setType(-1);
chatBean.setName(name);
chatBean.setTimer(WhisperUtil.getTimer());
sendMessage(chatBean);
//JFrame.setVisible(false);
}
}else if(send==e.getSource()) {
//发送信息
String string = sendInfo.getText();
List<String> to = list.getSelectedValuesList();
if (to.size() < 1) {
JOptionPane.showMessageDialog(null, "请选择聊天对象!");
return;
} else if (to.toString().contains(name + "(我)")) {
JOptionPane.showMessageDialog(null, "不能向自己发送信息!");
return;
} else if (string.equals("")) {
JOptionPane.showMessageDialog(null, "不能发送空信息!");
return;
}
ChatBean chatBean = new ChatBean();
HashSet<String> set = new HashSet<>();
set.addAll(to);
chatBean.setClients(set);
chatBean.setName(name);
chatBean.setInfo(string);
chatBean.setType(1);
String time = WhisperUtil.getTimer();
chatBean.setTimer(time);
sendMessage(chatBean);
receiveInfo.append(time + "我对" + to + "说:\r\n" + string + "\r\n\n");
sendInfo.setText(null);
}
}
public static void main(String[] args) {
}
/**
* 用户读取服务器发送的信息
* 客户端接收服务器端传送过来的消息
* @author Administrator
*
*/
class ClientInputThread extends Thread{
public void run() {
try {
while(true) {//表示一直可以接收消息
//读取服务器的对象流
ois=new ObjectInputStream(socket.getInputStream());
ChatBean cb=(ChatBean)ois.readObject();
switch(cb.getType()) {
//更新上线
case 0:{
onlines.clear();//清空在线用户列表
HashSet<String>clients=cb.getClients();
Iterator<String>it=clients.iterator();
while(it.hasNext()) {
String clientName=it.next();
if(clientName.equals(name)) {
onlines.add(clientName+"(我)");
}else {
onlines.add(clientName);
}
}
listmodel=new ListModel(onlines);
list.setModel(listmodel);
//在消息接收文本域添加消息
audioClip1.play();
receiveInfo.append(cb.getInfo());
receiveInfo.selectAll();
break;
}
case 1: //聊天
{
String info = cb.getTimer() + " " + cb.getName() + " 对 " + cb.getClients() + "说:\r\n";
if (info.contains(name)) {
info = info.replace(name, "我");
}
audioClip1.play();
receiveInfo.append(info + cb.getInfo() + "\r\n\n");
receiveInfo.selectAll();
break;
}
case -1: //下线
{
return;
}
default:
break;
}
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally {
close();
System.exit(0);
}
}
}
/**
* 关闭流
*/
public void close() {
if (oos != null) {
try {
oos.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (ois != null) {
try {
ois.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (socket != null) {
try {
socket.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 发送信息
*/
private void sendMessage(ChatBean chatBean) {
try {
oos = new ObjectOutputStream(socket.getOutputStream());
oos.writeObject(chatBean);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
7.dao包和dao.imp包下的具体实现类
package cn.tedu.dao;
import cn.tedu.bean.User;
public interface UserDao {
//根据用户名查询用户的方法
boolean selectByName(String username);
//插入数据的方法(注册)
int insertUser(User user);
//登录的方法
User login(String userName,String passWord);
}
//interface java中这个称之为接口,如果你不好理解,我通俗点打个比方就行了!
//火车,很多车厢,每一节车厢都一个挂钩,可以相互挂在一起,你可以把这个挂钩的大小理解成 interface;
//不管哪个火车箱的生产厂家,只要符合这个挂钩的规则,就可以挂在这个火车一起了!
//不管什么对象,只要实现过这个interface几口以后就可以相互联系在一起了! 这就是规则
package cn.tedu.dao.impl;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import cn.tedu.bean.User;
import cn.tedu.dao.UserDao;
import cn.tedu.util.JDBCUtil;
/**
* impl 实现类、接口实现;
* @author lenovo
*
*/
public class UserDaoImpl implements UserDao{
@Override
public boolean selectByName(String username) {
Connection conn=null;
PreparedStatement pre=null;
ResultSet rs=null;
try {
//1.创建连接
conn=JDBCUtil.getConn();
String sql="select * from User where username=?";
//2.创建通道
pre=conn.prepareStatement(sql);
//3.给参数赋值
pre.setString(1, username);
//4.执行查询
rs=pre.executeQuery();
//5.遍历结果集
if(rs.next()) {
return true;
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
//6.释放资源
JDBCUtil.close(conn, pre, rs);
}
return false;
}
@Override
public int insertUser(User user) {
Connection conn=null;
PreparedStatement pre=null;
int i=0;
try {
//1.创建连接
conn=JDBCUtil.getConn();
String sql="insert into user(username,password) values (?,?)";
//2.创建通道
pre=conn.prepareStatement(sql);
//3.给参数赋值
pre.setString(1, user.getUserName());
pre.setString(2, user.getPassWord());
//4.执行更新
i=pre.executeUpdate();
//5.遍历结果集
return i;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
//6.释放资源
JDBCUtil.close(conn, pre);
}
return i;
}
@Override
public User login(String userName, String passWord) {
Connection conn=null;
PreparedStatement pre=null;
ResultSet rs=null;
User user=null;
try {
//1.创建链接
conn=JDBCUtil.getConn();
String sql="select * from User where username=? and password=?";
//2.创建通道
pre=conn.prepareStatement(sql);
//3.给参数赋值
pre.setString(1, userName);
pre.setString(2, passWord);
//4.执行查询
rs=pre.executeQuery();
//5.遍历结果集
while (rs.next()) {
String name=rs.getString("username");
String pass=rs.getString("password");
user=new User(name, pass);
}
return user;
} catch (SQLException e) {
e.printStackTrace();
}finally {
//6.释放资源
JDBCUtil.close(conn, pre, rs);
}
return user;
}
}
以上是全部代码,我在下面放一张具体项目表
注:图中的code是加载验证码的图片,暂时验证码还没加好,是注册界面的验证码,可以不写!
以上是全部内容,如有侵权,可删!
欢迎大家转载!!!