一、介绍
1. UDP是一种无连接的传输协议。进行数据传输时,首先需要将要传输的数据定义成数据报(Datagram),在数据报中指明数据所要到达的Socket(主机地址和端口号),然后再将数据报发送出去。
JDBC是一种用于执行sql语句的JavaAPI,由一组用java编写的类和接口组成,它可以做三件事:1.与数据库建立连接;2.发送sql语句;3.处理结果;
二、使用步骤
1.导入jar包
mysql-connector-java-8.0.23.jar
gson-2.8.5.jar//用来转换成JSON数据格式
2.连接数据库和编写JDBC工具类
mysql数据库连接的配置文件:jdbc.properties
user=root
password=*********//换成自己的密码
url=jdbc:mysql://localhost:3306/temp?serverTimezone=UTC
driverClass=com.mysql.cj.jdbc.Driver//驱动类
JDBC工具类
public class JDBCUtils {
public static Connection getConnection(){
InputStream is = JDBCUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
Properties pros = new Properties();
Connection conn = null;
try {
pros.load(is);
String user = pros.getProperty("user");
String password = pros.getProperty("password");
String url = pros.getProperty("url");
String driverClass = pros.getProperty("driverClass");
Class.forName(driverClass);
conn = DriverManager.getConnection(url,user,password);
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
public static void closeResourse(Connection conn,PreparedStatement ps,ResultSet rs) {
try {
if(ps!=null)
ps.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(conn!=null)
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
try {
if(rs!=null)
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
public static boolean findUser(String name, String password){
Connection conn = getConnection();
PreparedStatement ps = null;
String sql = "select upassword from user where uname = ?";
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
ps.setString(1,name);
rs = ps.executeQuery();
while(rs.next()){
String pw = rs.getString("upassword");
if(pw.equals(password)){
return true;
}
}
} catch (SQLException e) {
e.printStackTrace();
}finally {
closeResourse(conn,ps,rs);
}
return false;
}
public static void addUser(String name,String password){
Connection conn = getConnection();
PreparedStatement ps =null;
String sql = "insert into user value (?,?)";
try {
ps = conn.prepareStatement(sql);
ps.setString(1,name);
ps.setString(2,password);
ps.execute();
} catch (SQLException e) {
e.printStackTrace();
}finally {
closeResourse(conn,ps,null);
}
}
}
另外,需要在数据库创建一个user表,示例如下:
3.注册界面
public class Register extends JFrame implements ActionListener {
private JPanel panel = new JPanel();
private JLabel userLabel = new JLabel("User:"); // 创建UserJLabel
private JTextField userText = new JTextField(); // 获取登录名
private JLabel passLabel = new JLabel("Password:"); // 创建PassJLabel
private JPasswordField passText = new JPasswordField(20); //密码框隐藏
private JButton loginButton = new JButton("login"); // 创建登录按钮
private JButton registerButton = new JButton("register");
public Register() {
//设置窗体的位置及大小
this.setTitle("欢迎");
this.setSize(300, 200);
this.setLocationRelativeTo(null); //在屏幕中居中显示
this.add(panel); // 添加面板
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 设置X号后关闭
panel.setLayout(null); //设置布局为 null
// 创建 UserJLabel
userLabel.setBounds(30, 30, 80, 25);
panel.add(userLabel);
// 创建文本域用于用户输入
userText.setBounds(105, 30, 165, 25);
panel.add(userText);
// 创建PassJLabel
passLabel.setBounds(30, 60, 80, 25);
panel.add(passLabel);
// 密码输入框隐藏
passText.setBounds(105, 60, 165, 25);
panel.add(passText);
// 创建登录按钮
loginButton.setBounds(25, 100, 80, 25);
panel.add(loginButton);
loginButton.addActionListener(this);
registerButton.setBounds(190, 100, 80, 25);
panel.add(registerButton);
registerButton.addActionListener(this);
this.setVisible(true); //设置窗体可见
}
public void loginFunc(){
String userName = userText.getText();
String passWord = new String(passText.getPassword());
if (JDBCUtils.findUser(userName, passWord) == true) {
//关闭当前界面
this.dispose();
//打开聊天界面
new ClientActivity(userName);
}else{
JOptionPane.showMessageDialog(this,"登录失败!",
"Fail",JOptionPane.INFORMATION_MESSAGE);
}
}
public void registerFunc(){
String userName = userText.getText();
String passWord = new String(passText.getPassword());
if(userName==""&&passWord==""){
JOptionPane.showMessageDialog(this, "用户名或密码为空",
"Fail", JOptionPane.ERROR_MESSAGE);
}
else if (JDBCUtils.findUser(userName, passWord) == true) {
JOptionPane.showMessageDialog(this, "注册失败!用户已存在",
"Fail", JOptionPane.ERROR_MESSAGE);
} else {
JDBCUtils.addUser(userName, passWord);
JOptionPane.showMessageDialog(this, "注册成功!",
"Fail", JOptionPane.INFORMATION_MESSAGE);
}
}
@Override
public void actionPerformed(ActionEvent actionEvent) {//登陆或注册
Object source = actionEvent.getSource();
if(source == loginButton){
this.loginFunc();
}else if(source == registerButton){
this.registerFunc();
}
}
}
3.用户聊天界面
public class ClientActivity extends JFrame{
private String name;
private JTextField textField;
private DatagramSocket socket;
private InetAddress ip;
private JTextArea textArea;
public ClientActivity(String name) {
super("聊天客户端:"+name);
this.name=name;
setSize(500, 500);
getContentPane().setLayout(null);
initLayout();
initUdp();
show();
}
private void initLayout() {
JButton sendBtn = new JButton("发送");
sendBtn.addActionListener(e -> {
String msg=textField.getText();
sendMessage(msg);
textField.setText("");
});
sendBtn.setBounds(366, 419, 97, 23);
getContentPane().add(sendBtn);
textField = new JTextField();
textField.setBounds(10, 419, 346, 23);
getContentPane().add(textField);
textField.setColumns(10);
textArea = new JTextArea();
textArea.setBounds(10, 0, 466, 365);
getContentPane().add(textArea);
}
private void initUdp() {
MyService.loginGroups(this);
try {
socket=new DatagramSocket();
ip=InetAddress.getByName("127.0.0.1");
} catch (SocketException e) {
e.printStackTrace();
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
public void pushMessage(MessageBean bean) {
textArea.append(bean.getName()+":"+bean.getContent()+"\n");//打印用户名和信息
}
private void sendMessage(String msg) {
MessageBean bean=new MessageBean();
bean.setName(name);
bean.setContent(msg);
Gson gson=new Gson();
String json=gson.toJson(bean);//转换为json格式
byte[] bytes=json.getBytes();
DatagramPacket datagramPacket=new DatagramPacket(bytes, bytes.length,ip,MyService.PORT);
try {
socket.send(datagramPacket);//发送报文
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.服务端
public class MyService extends Thread{
public static int PORT=10005;
private static DatagramSocket socket;
private static ArrayList<ClientActivity> mList=new ArrayList<>();
public MyService() {
try {
socket=new DatagramSocket(PORT);
} catch (SocketException e) {
e.printStackTrace();
}
}
public static void loginGroups(ClientActivity clientActivity) {
if(clientActivity==null)
return;
mList.add(clientActivity);
}
private void receiveMessage() {
byte[] buf=new byte[1024];
DatagramPacket datagramPacket=new DatagramPacket(buf, buf.length);
while(true) {
try {
socket.receive(datagramPacket);//阻塞当前系统的报文,直到有一个报文到达socket
String msg=new String(datagramPacket.getData(),0,datagramPacket.getLength());
Gson gson=new Gson();
MessageBean bean=gson.fromJson(msg, MessageBean.class);
for(ClientActivity clientActivity:mList) {
//发送数据给每一个客户端
clientActivity.pushMessage(bean);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void run() {
receiveMessage();
}
}
5.消息类
public class MessageBean {
private String name;
// private String password;//暂时用不到密码
private String content;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
// public String getPassword() {
// return password;
// }
// public void setPassword(String password) {
// this.password = password;
// }
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
}
6.程序主入口
public class Main {
public static void main(String[] args) {
new Register();
new Register();
new Register();//这里可以创建多个用户
MyService myService=new MyService();
myService.start();//服务端多线程接受用户的消息
}
}
附上运行截图: