jdbc-day04-chatroom

client_ui_ChatFrame

package com.chatroom.client.ui;

import javax.swing.*;
import java.net.Socket;

public class ChatFrame extends JFrame {
    //聊天面板
    private ChatPanel chatPanel;
    public ChatFrame(Socket socket, String username, String title) {
        super(title);
        chatPanel = new ChatPanel(socket,username);
        setSize(900,600);
        setUndecorated(true);
        setContentPane(chatPanel);
        setLocationRelativeTo(null);
        setResizable(false);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setVisible(true);
        //调用聊天面板的start方法,用于接受其他客户端包括自己发送过来的消息,应该是一个并发线程。与自己发信息是异步的
        chatPanel.start();
    }
//    public static void main(String[] args) {
//        ChatFrame c = new ChatFrame(null,"聊天窗口");
//    }
}

client_ui_ChatPanel

package com.chatroom.client.ui;

import com.chatroom.server.server.ChatServer;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.*;
import java.net.Socket;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Map;


public class ChatPanel extends JPanel {

    /* 定义Sockt属性 */
    private Socket socket;
    private String currentUsername;
    private JTextArea welcomeArea;
    /* 添加面板属性,三个文本框属性 */
    private JTextArea showText;  //公共聊天显示窗口
    private JTextArea countText; //在线人数
    private JTextArea nameText;

    private JTextArea oneText;  //私聊显示窗口
    private JTextArea inputText; //输入框

    private JTextArea noticeText;

    //发送按钮
    private JButton sendButton;
    //关闭按钮
    private JButton closeButton;
    public ChatPanel(Socket socket,String currentUsername) {
        try {
            this.currentUsername = currentUsername;
            // 取消面板的默认布局, 使用绝对布局,即使用坐标方式进行布局
            this.setLayout(null);
            // 修改面板的背景颜色
            this.setBackground(new Color(200, 200, 200));
            //调用自己封装的初始化布局方式
            initLayout();

            //初始化TCP协议的客户端
            this.socket = socket;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 初始化自己的页面布局:
     * 1. 头部布局
     * 2. 上半部身体的布局
     * 3. 下半部身体的布局
     * 4. 聊天输入框的布局
     * 5. 两个按钮的布局
     */
    public void initLayout(){
        headLayout();
        body1Layout();
        body2Layout();
        chatInputArea();
        buttonArea();
    }

    /**
     * 两个按钮的布局
     */
    private void buttonArea() {
        //两个按钮
        firstButton();
        lastButton();
    }

    /**
     * 第二个按钮"关闭"的布局
     */
    private void lastButton() {
        closeButton = new JButton("关闭");
        closeButton.setBounds(590,550,65,35);
        this.add(closeButton);
        closeButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int option = JOptionPane.showConfirmDialog(null, "您确定要离开吗");
                if (option == JOptionPane.YES_OPTION) {
                    System.exit(0);
                }
            }
        });
    }

    /**
     * 第一个按钮“发送”的布局
     */
    private void firstButton() {
        sendButton = new JButton("发送");
        sendButton.setBounds(590,505,65,35);
        this.add(sendButton);
        sendButton.addMouseListener(new MouseAdapter() {
            public void mouseClicked(MouseEvent e) {
                String content = inputText.getText().trim();
                if (!content.equals("")) {
                    //发送信息
                    sendMessage(currentUsername,content);
                    // 清空文本框的内容
                    inputText.setText("");
                }
            }
        });
    }

    private void sendMessage(String currentUsername,String content) {
        try {
            //获取输出流对象
            OutputStream outputStream = socket.getOutputStream();
            PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream, "utf-8"),true);

            //封装消息,成Map对象,然后转为JSON发送
            Map<String,String> map = new HashMap<>();
            map.put("username",currentUsername);
            map.put("content",content);
            map.put("infoType","2");
            System.currentTimeMillis();
            map.put("chat_time",System.currentTimeMillis()+"");

            ObjectMapper mapper = new ObjectMapper();
            String record = mapper.writeValueAsString(map);

            pw.println(record);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 聊天窗口的布局
     */
    private void chatInputArea() {
        //5. 输入窗口
        inputText = new JTextArea("输入内容");
        //inputText.setBackground(new Color(238,238,238));
        inputText.setBounds(5,495,580,100);
        this.add(inputText);
    }

    /**
     * 私聊的内容显示窗口,与群公告窗口的布局
     */
    private void body2Layout() {
        //5. 私聊显示窗口
        oneText = new JTextArea("私聊窗口");
        oneText.setEditable(false);
        oneText.setBackground(new Color(238,238,238));
        oneText.setBounds(5,390,650,100);
        this.add(oneText);

        //6. 公告窗口
        noticeText = new JTextArea("公告");
        noticeText.setEditable(false);
        noticeText.setBackground(new Color(238,238,238));
        noticeText.setBounds(660,390,235,205);
        this.add(noticeText);
    }

    /**
     * 公共聊天显示窗口和在线成员列表窗口的布局
     */
    private void body1Layout() {
        //3. 公共聊天组件
        showText = new JTextArea();
        showText.setBackground(new Color(238,238,238));
        showText.setEditable(false);// 设置不可编辑
        showText.setBounds(5,30,650,355);
        //为showText设置滚动条
        JScrollPane scroll = new JScrollPane(showText);
        //设置垂直滚动
        scroll.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
        this.add(scroll);
        this.add(showText);

        //在线成员列表
        initPersonnelInfo();

    }
    //表模型对象属性
    private DefaultTableModel personModel;
    //表属性
    private JTable personTable;
    private void initPersonnelInfo() {
        //定义一个表头
        String[] personTitle = {"在线人名单"};
        String[][] personDatas = {};
        personModel = new DefaultTableModel(personDatas,personTitle) {
            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        //初始化表对象,与表模型关联
        personTable = new JTable(personModel);
        personTable.getTableHeader().setFont(new Font("楷体",Font.PLAIN,20));
        personTable.getTableHeader().setBackground(Color.LIGHT_GRAY);
        personTable.setRowHeight(30);
        //模拟多个人在线。 添加行记录

        try {
            Socket socket = new Socket("localhost",11000);

            Runnable task = new GetClientOnlineUsernameHandler(socket);
            Thread thread = new Thread(task);
            thread.start();
        } catch (IOException e) {
            System.out.println("监听服务连接失败");
            e.printStackTrace();
        }




        JScrollPane jScrollPane = new JScrollPane();
        jScrollPane.setBounds(660,30,235,355);
        jScrollPane.setViewportView(personTable);
        this.add(jScrollPane);
    }
    class GetClientOnlineUsernameHandler implements Runnable{
        Socket socket;
        public GetClientOnlineUsernameHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {
            try {
                InputStream input = socket.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(input,"utf-8"));
                String list = "";

                while((list = reader.readLine()) != null) {
                    //清空原有的名单
                    personModel.setNumRows(0);
                    //System.out.println("名单:"+list);
                    String[] usernames = list.split(",");
                    for (String username : usernames) {
                        personModel.addRow(new String[]{username});
                    }
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 欢迎语,与 人数在线统计的 布局
     */
    private void headLayout() {
        //0. 欢迎logo
        welcomeArea = new JTextArea(currentUsername+"您好,欢迎进入聊天室,找到你喜欢的人,开始聊天吧");
        welcomeArea.setBackground(new Color(200, 200, 200));
        //不能编辑
        welcomeArea.setEditable(false);
        welcomeArea.setBounds(5,5,650,20);
        this.add(welcomeArea);

        //1. 统计人数组件
        countText = new JTextArea("在线人数:");
        countText.setEditable(false);
        countText.setBackground(new Color(200,200,200));
        countText.setBounds(660,5,235,20);
        this.add(countText);
    }

    public void start(){
        try{
            //获取一个获取服务端信息的处理器任务
            Runnable task = new GetServerInfoHandler();
            Thread thread = new Thread(task);
            thread.start();

        }catch (Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 编写一个获取服务端信息的处理器。即一个任务体
     */
    class GetServerInfoHandler implements Runnable{
        public void run(){
            try {
                //获取接受服务端发送过来的数据的输入流对象
                InputStream inputStream = socket.getInputStream();
                BufferedReader br = new BufferedReader(
                        new InputStreamReader(inputStream,"utf-8"));


                String info = "";
                while((info = br.readLine()) != null){

                    ObjectMapper mapper = new ObjectMapper();
                    Map<String,String>  record = mapper.readValue(info, Map.class);

                    String username = record.get("username");
                    long chatTime = Long.parseLong(record.get("chat_time"));
                    Timestamp timestamp = new Timestamp(chatTime);

                    showText.append(timestamp+"\r\n");
                    if(username.equals(currentUsername)){
                        showText.append("我说:\r\n");
                    }else {
                        showText.append(username+"说:\r\n");
                    }
                    showText.append("        "+record.get("content")+"\r\n\r\n");
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void flushOnLineList(String names) {
        //更新在线人员名称列表
        String[] nameArray = names.split(":");
        nameText.setText("");
        for (String s : nameArray) {
            nameText.append(s+"\r\n");
        }
    }
}

client_ui_LoginFrame

package com.chatroom.client.ui;

import com.chatroom.client.util.SocketUtil;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * 登录窗口:  继承自JFrame 窗口
 */
public class LoginFrame extends JFrame{
	private Socket socket;
	//提供两个输入框
	private JTextField userText;   //用于输入用户名
	private JTextField passwordText; //用于输入密码
	//                         字体      样式      字号
	Font font = new Font("幼圆",Font.BOLD,28);

	public LoginFrame() {
		//初始化用户名部分
		initUsername();
		//初始化密码部分
		initPassword();
		//初始化两个按钮
		initButton();
		//当前窗口的其他设置
		initFrame();

		//初始化
		try {
			socket =new Socket("localhost",7777);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private void initUsername() {
		//定义标签
		JLabel userLabel = new JLabel("用户名:");
		userLabel.setFont(font);
		//设置标签的位置信息: 左上角的xy坐标以及宽和高
		userLabel.setBounds(200, 200, 100, 40);
		//获取窗口的面板,然后将标签添加到面板上
		this.getContentPane().add(userLabel);

		userText = new JTextField();
		userText.setBounds(350, 200, 250, 40);
		userText.setFont(font);
		this.getContentPane().add(userText);
		
	}
	private void initPassword() {
		JLabel passwordLabel = new JLabel("密  码:");
		passwordLabel.setFont(font);
		passwordLabel.setBounds(200, 280, 100, 40);
		this.getContentPane().add(passwordLabel);


		passwordText = new JTextField();
		passwordText.setBounds(350, 280, 250, 40);
		passwordText.setFont(font);
		this.getContentPane().add(passwordText);
		
	}

	private void initButton() {
		//定义一个按钮对象
		JButton logoutButton = new JButton("退出");
		logoutButton.setFont(font);
		//按钮的美化
		logoutButton.setBorder(BorderFactory.createRaisedBevelBorder());
		logoutButton.setFocusPainted(false);
		//按钮的位置
		logoutButton.setBounds(200,350,100,40);

		//给按钮添加监听事件
		logoutButton.addActionListener(new ActionListener() {

			/**
			 * 执行逻辑
			 * @param e
			 */
			@Override
			public void actionPerformed(ActionEvent e) {
				//定义一个确认框
				int option = JOptionPane.showConfirmDialog(null, "您确定要离开吗");
				if (option == JOptionPane.YES_OPTION) {
					System.exit(0);
				}
			}
		});
		//将登出按钮添加到面板上
		this.getContentPane().add(logoutButton);


		JButton loginButton = new JButton("登录");
		loginButton.setFont(font);
		loginButton.setBorder(BorderFactory.createRaisedBevelBorder());
		loginButton.setFocusPainted(false);
		loginButton.setBounds(350,350,100,40);
		loginButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				//应该获取用户名和密码,提交到服务端
				String username = userText.getText().trim();
				String password = passwordText.getText().trim();
				sendDataToServer(username,password);
			}
		});
		
		this.getContentPane().add(loginButton);
		
		JButton toRegButton = new JButton("注册");
		toRegButton.setFont(font);
		toRegButton.setBorder(BorderFactory.createRaisedBevelBorder());
		toRegButton.setFocusPainted(false);
		toRegButton.setBounds(500,350,100,40);
		toRegButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				//点击注册,应该跳转到注册页面,new一个注册创建即可。
				new RegisterFrame();
				//释放当前窗口
				LoginFrame.this.dispose();
			}
		});
		this.getContentPane().add(toRegButton);
		
	}
	protected void sendDataToServer(String username,String password) {
		if(username==null||username.length()==0) {
			JOptionPane.showMessageDialog(null, "用户名不能为空");
			return;
		}
		if(password==null||password.length()==0) {
			JOptionPane.showMessageDialog(null, "密码不能为空");
			return;
		}

		try {
			OutputStream output = socket.getOutputStream();
			PrintWriter writer = new PrintWriter(
					new OutputStreamWriter(
							output,"utf-8"),true);

			Map<String,Object> map = new HashMap<>();
			map.put("username",username);
			map.put("password",password);
			map.put("infoType","1");

			ObjectMapper mapper = new ObjectMapper();
			String jsonStr = mapper.writeValueAsString(map);

			writer.println(jsonStr);

			InputStream inputStream = socket.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
			boolean result  = Boolean.parseBoolean(br.readLine());
			if(result){
				JOptionPane.showMessageDialog(null,"登录成功..准备跳转到聊天页面...");
				this.dispose();
				try {
					Thread.sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				/**
				 * 登录成功,登录的socket对象,不应该下线,聊天窗口继续使用。
				 * 因此可以作为聊天窗口的实参传入到聊天窗口中,继续使用。
				 * 登录成功的用户名,也可以传入聊天窗口里继续使用。
				 */
				new ChatFrame(socket,username,"聊天窗口");
			}else{
				JOptionPane.showMessageDialog(null,"登录失败,用户名不存在,或者密码错误");
			}

		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private void initFrame() {
		this.getContentPane().setFont(font);
		this.setSize(900,600);
		//取消窗口的边框
		this.setUndecorated(true);
		//窗口居中
		this.setLocationRelativeTo(null);
		//点击窗口的x,表示退出程序
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//取消面板的默认布局
		this.getContentPane().setLayout(null);
		//设置窗口的可见性
		this.setVisible(true);
		
	}
	public static void main(String[] args) {
		new LoginFrame();
	}
}

client_ui_RegisterFrame

package com.chatroom.client.ui;


import com.chatroom.client.util.SocketUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

public class RegisterFrame extends JFrame {

	private JTextField userText;
	private JTextField passwdText;
	private JTextField phoneText;
	//性别的单选框,
	private JRadioButton s1;
	private JRadioButton s2;
	
	private Font font = new Font("幼圆",Font.BOLD,30);
	//定义一个面板属性,  并不像登录窗口那样从this身上获取的。
	private JPanel mainPanel;

	//定义客户端套接字属性
	private Socket socket = null;
	
	public RegisterFrame() {
		initMainPanel();
		initLabel();
		initUserPanel();
		initPasswdPanel();
		initPhonePanel();
		initSexPanel();
		initButtonPanel();
		initFrame();

		//套接字初始化
		try {
			socket = new Socket("127.0.0.1",7777);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	private void initFrame() {
		this.setSize(900, 600);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//false 表示不可以改变窗口的尺寸
		this.setResizable(false);
		this.setLocationRelativeTo(null);
//		this.setUndecorated(true);
		this.setVisible(true);
	}
	//初始化窗口的面板
	public void initMainPanel() {
		//创建面板对象
		mainPanel = new JPanel();
		//设置了面板的布局   6行   1列   水平间隔   垂直间隔
		mainPanel.setLayout(new GridLayout(6, 1, 0, 0));
		//将面板添加到窗口上
		this.add(mainPanel);
	}
	//设置第一行的布局
	public void initLabel() {
		//定义一个标签面板   边框布局:上下左右中
		JPanel labelPanel = new JPanel(new BorderLayout());
		mainPanel.add(labelPanel);
		JLabel label = new JLabel("用户注册",JLabel.CENTER);
		label.setFont(font);
		//将标签添加到标签面板上
		labelPanel.add(label);
		
	}

	private void initUserPanel() {
		JPanel userPanel = new JPanel();
		mainPanel.add(userPanel);
		
		JLabel userLabel = new JLabel("用户名:");
		userLabel.setFont(font);
		userPanel.add(userLabel);
		
		userText = new JTextField();
		userText.setColumns(15);
		userText.setFont(font);
		userPanel.add(userText);
		
		
	}
	public void initPasswdPanel() {
		JPanel passwdPanel = new JPanel();
		mainPanel.add(passwdPanel);
		
		JLabel passwdLabel = new JLabel("密    码:");
		passwdLabel.setFont(font);
		passwdPanel.add(passwdLabel);
		
		passwdText = new JTextField();
		passwdText.setFont(font);
		passwdText.setColumns(15);
		passwdPanel.add(passwdText);
	}
	public void initPhonePanel() {
		JPanel phonePanel = new JPanel();
		mainPanel.add(phonePanel);
		
		JLabel phoneLabel = new JLabel("手机号:");
		phoneLabel.setFont(font);
		phonePanel.add(phoneLabel);
		
		phoneText = new JTextField();
		phoneText.setColumns(15);
		phoneText.setFont(font);
		phonePanel.add(phoneText);
	}
	public void initSexPanel() {
		JPanel panel = new JPanel();
		mainPanel.add(panel);
		
		JLabel sexLabel = new JLabel("性  别:      ");
		sexLabel.setFont(font);
		sexLabel.setBounds(50, 5, 50, 50);
		
		s1 = new JRadioButton("男",true);
		s2 = new JRadioButton("女");
		s1.setFont(font);
		s2.setFont(font);

		//将两个单选框定义为一组
		ButtonGroup bg = new ButtonGroup();
		bg.add(s1);
		bg.add(s2);

		//将标签和单选框添加到性别面板上
		panel.add(sexLabel);
		panel.add(s1);
		panel.add(s2);
		
	}
	public void initButtonPanel() {
		JPanel panel = new JPanel(new FlowLayout());
		mainPanel.add(panel);
		Font font = new Font("宋体",Font.PLAIN,30);
		
		JButton registButton = new JButton("注册");
		registButton.setPreferredSize(new Dimension(100, 50));
		registButton.setFont(font);
		//凸起
		registButton.setBorder(BorderFactory.createRaisedBevelBorder());
		registButton.setFocusPainted(false);
		//给注册按钮添加监听事件
		registButton.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				//将注册信息收集起来
				String info = getRegistInfo();
				if(info!=null){
					sendRegistInfoToServer(info);
				}
			}
		});




		JButton toLoginButton = new JButton("前往登录界面");
		toLoginButton.setPreferredSize(new Dimension(200, 50));
		toLoginButton.setFont(font);
		toLoginButton.setBorder(BorderFactory.createRaisedBevelBorder());
		toLoginButton.setFocusPainted(false);
		//监听
		toLoginButton.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				new LoginFrame();
				//销毁当前窗口
				RegisterFrame.this.dispose();
			}
		});
		panel.add(registButton);
		panel.add(toLoginButton);
	}



	private void sendRegistInfoToServer(String info) {
		try {
			OutputStream output = socket.getOutputStream();
			PrintWriter pw = new PrintWriter(
					new OutputStreamWriter(
							output,"utf-8"),true);
			pw.println(info);

			InputStream inputStream = socket.getInputStream();
			BufferedReader br = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
			boolean result  = Boolean.parseBoolean(br.readLine());
			if(result){
				JOptionPane.showMessageDialog(null,"注册成功");
			}else{
				JOptionPane.showMessageDialog(null,"注册失败");
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
	}


	protected String getRegistInfo() {
		String json = null;
		try {
			String username = userText.getText().trim();
			if(username==null||username.length()==0) {
				JOptionPane.showMessageDialog(null, "用户名不能为空");
				return null;
			}
			String passwd = passwdText.getText().trim();
			if(passwd==null||passwd.length()==0) {
				JOptionPane.showMessageDialog(null, "密码不能为空");
				return null;
			}
			String phone = phoneText.getText().trim();
			if(phone==null||phone.length()==0) {
				JOptionPane.showMessageDialog(null, "手机号不能为空");
				return null;
			}
			String sex = null;
			if(s1.isSelected()) {
				sex = s1.getText();
			}else {
				sex = s2.getText();
			}
			//将四个值封装成Map对象
			Map<String,Object> map = new HashMap<>();
			map.put("username",username);
			map.put("password",passwd);
			map.put("telephone",phone);
			map.put("gender",sex);
			map.put("infoType","0");// 0 注册信息, 1  登录信息  2 公聊   3  私聊
			// 创建ObjectMapper实例
			ObjectMapper mapper = new ObjectMapper();
			// 将Map转换为JSON字符串
			json = mapper.writeValueAsString(map);

		} catch (JsonProcessingException e) {
			throw new RuntimeException(e);
		}

		// 打印JSON字符串
		System.out.println(json);
		return json;
	}
	public static void main(String[] args) {

		new RegisterFrame().setVisible(true);
	}
}

client_util_SocketUtil

package com.chatroom.client.util;

import java.io.IOException;
import java.net.Socket;

/**
 * 客户端获取Socket的工具类
 * 1. 设计成单例模式。 客户端只能单开
 */
public class SocketUtil {
    private static Socket socket;

    private SocketUtil(){}

    public synchronized static Socket getSocketInstance(){
        if(socket == null){
            try {
                socket = new Socket("127.0.0.1",7777);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return socket;
    }

}

server_dao_impl_ChatRecordDaoImpl

package com.chatroom.server.dao.impl;

import com.chatroom.server.dao.ChatRecordDao;
import com.chatroom.server.util.DruidUtil;
import com.chatroom.server.vo.ChatRecord;

import java.sql.Connection;
import java.sql.PreparedStatement;

public class ChatRecordDaoImpl implements ChatRecordDao {
    @Override
    public void addChatRecord(ChatRecord chatRecord) {
        Connection conn = null;
        try{
            conn = DruidUtil.getConnection();
            String sql = "insert into chat_record values (null,?,?,?)";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, chatRecord.getUsername());
            ps.setString(2,chatRecord.getContent());
            ps.setTimestamp(3,chatRecord.getChattime());
            ps.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtil.closeConnection(conn);
        }
    }
}

server_dao_impl_UserDaoImpl

package com.chatroom.server.dao.impl;

import com.chatroom.server.dao.UserDao;
import com.chatroom.server.util.DruidUtil;
import com.chatroom.server.vo.User;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class UserDaoImpl implements UserDao {
    @Override
    public boolean addUser(User user) {
        Connection conn = null;
        try{
            conn = DruidUtil.getConnection();
            String sql = "insert into userinfo values(null,?,?,?,?)";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1,user.getUsername());
            ps.setString(2,user.getPassword());
            ps.setString(3,user.getTelephone());
            ps.setString(4,user.getGender());

            ps.executeUpdate();
            return true;
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtil.closeConnection(conn);
        }
        return false;
    }

    @Override
    public boolean checkLogin(User user) {
        Connection conn = null;
        try{
            conn = DruidUtil.getConnection();
            String sql = "select username,password,telephone,gender from userinfo where username=? and password=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1,user.getUsername());
            ps.setString(2,user.getPassword());

            ResultSet set = ps.executeQuery();
            if(set.next()){
                return true;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtil.closeConnection(conn);
        }
        return false;
    }
}

server_dao_impl_UserOfOnlineDaoImpl

package com.chatroom.server.dao.impl;

import com.chatroom.server.dao.UserOfOnlineDao;
import com.chatroom.server.util.DruidUtil;
import com.chatroom.server.vo.UserOfOnline;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class UserOfOnlineDaoImpl implements UserOfOnlineDao {
    @Override
    public UserOfOnline findUserOfOnlineByUsername(String username) {
        Connection conn = null;
        try{
            conn = DruidUtil.getConnection();
            String sql = "select * from user_online where username=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, username);
            ResultSet rs = ps.executeQuery();
            if(rs.next()){
                UserOfOnline user = new UserOfOnline();
                user.setUsername(rs.getString("username"));
                user.setLoginTime(rs.getTimestamp("login_time"));
                user.setLogoutTime(rs.getTimestamp("logout_time"));
                user.setStatus(rs.getString("status"));
                return user;
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtil.closeConnection(conn);
        }
        return null;
    }

    @Override
    public void addUserOfOnline(String username) {
        Connection conn = null;
        try{
            conn = DruidUtil.getConnection();
            String sql = "insert into user_online values(null,?,now(),null,?)";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, username);
            ps.setString(2, "1");

            ps.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtil.closeConnection(conn);
        }
    }

    @Override
    public void changeToOnline(String username) {
        Connection conn = null;
        try{
            conn = DruidUtil.getConnection();
            String sql = "update user_online set status=?,login_time = now() where username=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, "1");
            ps.setString(2,username);
            ps.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtil.closeConnection(conn);
        }
    }

    @Override
    public void changeToOffline(String username) {
        Connection conn = null;
        try{
            conn = DruidUtil.getConnection();
            String sql = "update user_online set status=?,logout_time = now() where username=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, "0");
            ps.setString(2,username);
            ps.executeUpdate();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtil.closeConnection(conn);
        }
    }

    @Override
    public List<String> findAllOnlineUsername() {
        List<String> usernames = new ArrayList<>();
        Connection conn = null;
        try{
            conn = DruidUtil.getConnection();
            String sql = "select username from user_online where status=?";
            PreparedStatement ps = conn.prepareStatement(sql);
            ps.setString(1, "1");
            ResultSet rs = ps.executeQuery();
            while(rs.next()){
                String username = rs.getString("username");
                usernames.add(username);
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            DruidUtil.closeConnection(conn);
        }
        return usernames;
    }
}

server_dao_ChatRecordDao

package com.chatroom.server.dao;

import com.chatroom.server.vo.ChatRecord;

public interface ChatRecordDao {
    void addChatRecord(ChatRecord chatRecord);
}

server_dao_UserDao

package com.chatroom.server.dao;

import com.chatroom.server.vo.User;

public interface UserDao {
    boolean addUser(User user);

    boolean checkLogin(User user);
}

server_dao_UserOfOnlineDao

package com.chatroom.server.dao;

import com.chatroom.server.vo.UserOfOnline;

import java.util.List;

public interface UserOfOnlineDao {
    UserOfOnline findUserOfOnlineByUsername(String username);
    void addUserOfOnline(String username);
    void changeToOnline(String username);
    void changeToOffline(String username);
    List<String> findAllOnlineUsername();
}

server_server_ChatServer

package com.chatroom.server.server;

import com.chatroom.server.dao.ChatRecordDao;
import com.chatroom.server.dao.UserDao;
import com.chatroom.server.dao.UserOfOnlineDao;
import com.chatroom.server.util.DaoFactory;
import com.chatroom.server.util.InfoUtil;
import com.chatroom.server.vo.ChatRecord;
import com.chatroom.server.vo.User;
import com.chatroom.server.vo.UserOfOnline;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;

/**
 * 聊天服务器
 */
public class ChatServer {
    //定义一个TCP通信协议的服务端属性
    private ServerSocket server;
    //添加一个Map属性,用于存储多个客户端的用户名与输出流对象。 Map集合(散列表)
    private Map<String, PrintWriter> allOut;

    private ServerSocket server2;

    public ChatServer(int port) {
        try {
            server = new ServerSocket(port);
            //给map集合赋值
            allOut = new HashMap<String, PrintWriter>();
            //监听端口
            server2 = new ServerSocket(11000);
        } catch (IOException e) {
            System.out.println("---服务器启动失败---");
        }
    }

    public void listenerOnlineUsername() {
        try {
            while (true) {
                System.out.println("---监听客户端的上线状态---");
                Socket socket = server2.accept();
                System.out.println("---一个客户端正在被监听---");


                //每获取一个客户端的Socket对象,就应该将其放入一个并发线程中
                Runnable task = new GetOnlineUsernameHandler(socket);
                Thread thread = new Thread(task);
                thread.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    class GetOnlineUsernameHandler implements Runnable {
        private Socket socket;

        public GetOnlineUsernameHandler(Socket socket) {
            this.socket = socket;
        }

        @Override
        public void run() {


            Timer timer = new Timer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    try {
                        UserOfOnlineDao userOfOnlineDao = DaoFactory.getUserOfOnlineDao();
                        List<String> allOnlineUsername = userOfOnlineDao.findAllOnlineUsername();
                        StringBuilder builder = new StringBuilder();
                        for (String username : allOnlineUsername) {
                            builder.append(username).append(",");
                        }
                        OutputStream outputStream = socket.getOutputStream();
                        PrintWriter pw = new PrintWriter(new OutputStreamWriter(outputStream), true);
                        pw.println(builder.toString());
                    } catch (IOException e) {
                        throw new RuntimeException(e);
                    }
                }
            }, 1000,1000);
        }
    }

    /**
     * 聊天的主方法
     */
    public void start() {
        try {
            while (true) {
                System.out.println("---等待客户端连接---");
                Socket socket = server.accept();
                System.out.println("---一个客户端连接上了---");


                //每获取一个客户端的Socket对象,就应该将其放入一个并发线程中
                Runnable task = new GetClientInfoHandler(socket);
                Thread thread = new Thread(task);
                thread.start();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //创建一个具体的服务器对象
        ChatServer chatServer = new ChatServer(7777);
        Runnable runnable = () -> {
            //调用聊天的主方法
            chatServer.start();
        };
        Runnable runnable2 = () -> {
            chatServer.listenerOnlineUsername();
        };
        Thread thread = new Thread(runnable);
        Thread thread2 = new Thread(runnable2);
        thread.start();
        thread2.start();
    }

    /**
     * 定义一个处理客户端信息的处理器,即一个任务体
     */
    class GetClientInfoHandler implements Runnable {
        private String nickname;
        //因为run方法中使用了 start方法中的socket局部变量
        //所以可以在该类中添加一个属性,run方法中可以访问该类的属性
        private Socket socket;

        //提供一个构造器,将start方法中的局部变量socket传进来,给属性赋值, 这样,run方法中使用的socket就是
        //start方法中的局部变量指向的对象
        public GetClientInfoHandler(Socket socket) {
            this.nickname = nickname;
            this.socket = socket;
        }

        @Override
        public void run() {
            PrintWriter pw = null;
            try {
                //通过服务端的Socket对象,获取输入流,接受客户端发送过来的数据
                InputStream inputStream = socket.getInputStream();
                BufferedReader br = new BufferedReader(
                        new InputStreamReader(inputStream, "utf-8"));
                //通过服务端的Socket对象,获取输出流,将信息返回给客户端
                OutputStream outputStream = socket.getOutputStream();
                pw = new PrintWriter(
                        new OutputStreamWriter(outputStream, "utf-8"), true);


                //上线通知
                //onlineNotice(nickname,pw);


                //循环处理客户端发送过来的信息
                String info = "";
                while ((info = br.readLine()) != null) {
                    //解析发送过来的信息:
                    String infoType = InfoUtil.getInfoType(info);
                    System.out.println("infoType:" + infoType);
                    if (infoType.equals("0")) {  //注册
                        User user = InfoUtil.getUserFromInfo(info);
                        UserDao userDao = DaoFactory.getUserDao();
                        boolean flag = userDao.addUser(user);
                        //告诉注册界面
                        pw.println(flag);
                        System.out.println("是否注册成功:" + flag);


                    } else if (infoType.equals("1")) {//登录
                        User user = InfoUtil.getUserFromInfo(info);
                        UserDao userDao = DaoFactory.getUserDao();
                        boolean flag = userDao.checkLogin(user);
                        //告诉登录界面
                        pw.println(flag);
                        System.out.println("是否登录成功:" + flag);

                        //登录成功,将输出流添加到Map集合中
                        allOut.put(user.getUsername(), pw);

                        //修改状态
                        UserOfOnlineDao userOfOnlineDao = DaoFactory.getUserOfOnlineDao();
                        UserOfOnline userOfOnline = userOfOnlineDao.findUserOfOnlineByUsername(user.getUsername());
                        if (userOfOnline != null) {
                            //不是第一次登录,改为上线
                            userOfOnlineDao.changeToOnline(user.getUsername());
                        } else {
                            //第一次登录
                            userOfOnlineDao.addUserOfOnline(user.getUsername());
                        }
                    } else if (infoType.equals("2")) { //公开聊天
                        ChatRecord record = InfoUtil.getChatRecordFromInfo(info);
                        ChatRecordDao recordDao = DaoFactory.getChatRecordDao();
                        recordDao.addChatRecord(record);

                        sendToAllClient(info);


                    } else {//私聊

                    }
                }
            } catch (IOException e) {
                System.out.println("---一个客户端离线了---");

                offlineNotice(nickname, pw);

            }
        }
    }

    private void onlineNotice(String nickname, PrintWriter pw) {
        //给自己发送信息
        pw.println(nickname);

        Set<String> names = allOut.keySet();
        //更新在线人数列表
        StringBuilder sBuilder = new StringBuilder();
        for (String name : names) {
            sBuilder.append(name).append(":");
        }
        System.out.println("名字拼接:" + sBuilder.toString());


    }

    private void offlineNotice(String nickname, PrintWriter pw) {

    }


    public void sendToOneClient(String nickname, String info) {
        //获取要私聊的对象名称
        //获取第一个冒号的下标
        int index = info.indexOf(":");
        String toNickName = info.substring(1, index);
        //找到对应的流对象
        PrintWriter printWriter = allOut.get(toNickName);
        printWriter.println(nickname + "对你说:" + info.substring(index + 1));
    }

    public void sendToAllClient(String info) {
        //遍历Map里的所有输出流,来发送info信息
        Collection<PrintWriter> pws = allOut.values();
        System.out.println("---sendToAllClient---");
        for (PrintWriter pw : pws) {
            System.out.println("---进入循环----");
            pw.println(info);
        }
    }
}

server_util_DaoFactory

package com.chatroom.server.util;

import com.chatroom.server.dao.ChatRecordDao;
import com.chatroom.server.dao.UserDao;
import com.chatroom.server.dao.UserOfOnlineDao;
import com.chatroom.server.dao.impl.ChatRecordDaoImpl;
import com.chatroom.server.dao.impl.UserDaoImpl;
import com.chatroom.server.dao.impl.UserOfOnlineDaoImpl;

public class DaoFactory {
    private static UserDao userDao;
    private static ChatRecordDao chatRecordDao;
    private static UserOfOnlineDao userOfOnlineDao;

    private DaoFactory(){}

    public  static UserDao getUserDao() {
        if (userDao == null) {
            userDao = new UserDaoImpl();
        }
        return userDao;
    }

    public  static ChatRecordDao getChatRecordDao() {
        if (chatRecordDao == null) {
            chatRecordDao = new ChatRecordDaoImpl();
        }
        return chatRecordDao;
    }
    public  static UserOfOnlineDao getUserOfOnlineDao() {
        if (userOfOnlineDao == null) {
            userOfOnlineDao = new UserOfOnlineDaoImpl();
        }
        return userOfOnlineDao;
    }
}

server_util_DruidUtil

package com.chatroom.server.util;

import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class DruidUtil {
    //定义一个静态变量:关于Druid的连接池的
    private static DataSource ds;
    static{
        try {
            //先自己读取配置文件,封装到Properties对象里
            InputStream io = DruidUtil.class.getClassLoader().getResourceAsStream("druid.properties");
            Properties properties = new Properties();
            properties.load(io);

            //Druid提供了一个工厂类,里面提供了一个createDataSource(Properties prop)方法
            // 会自动解析prop里的各种键值对,进行赋值
            ds = DruidDataSourceFactory.createDataSource(properties);

        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    public static Connection getConnection() {
        Connection conn = null;
        try{
            conn = ds.getConnection();
            return conn;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }
    public static void closeConnection(Connection conn) {
        if (conn != null) {
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Connection conn = getConnection();
        System.out.println(conn);
        closeConnection(conn);
    }
}

server_util_InfoUtil

package com.chatroom.server.util;

import com.chatroom.server.vo.ChatRecord;
import com.chatroom.server.vo.User;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.sql.Timestamp;
import java.util.Map;

public class InfoUtil {
    /**
     * 将json格式的字符串转成Map对象
     * @param info
     * @return
     */
    public static Map<String,String> parseJsonToMap(String info){
        try {
            ObjectMapper mapper = new ObjectMapper();
            //调用readValue(String jsonStr,JavaClass class)
            //jsonStr:  指的就是json格式的字符串
            //class:  要转成的java类型的描述类对象
            Map<String,String> map = mapper.readValue(info,Map.class);
            //System.out.println("map:"+map.toString());
            return map;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取信息的类型
     * @param info
     * @return
     */
    public static String getInfoType(String info){
        Map<String, String> map = parseJsonToMap(info);
        return map.get("infoType");
    }
    public static User getUserFromInfo(String info){
        Map<String, String> map = parseJsonToMap(info);
        User user = new User();
        user.setUsername(map.get("username"));
        user.setPassword(map.get("password"));
        user.setTelephone(map.get("telephone"));
        user.setGender(map.get("gender"));
        return user;
    }
    public static ChatRecord getChatRecordFromInfo(String info){
        Map<String, String> map = parseJsonToMap(info);
        ChatRecord record = new ChatRecord();
        record.setUsername(map.get("username"));
        record.setContent(map.get("content"));

        long timeString = Long.parseLong(map.get("chat_time"));
        Timestamp timestamp = new Timestamp(timeString);
        record.setChattime(timestamp);
        return record;
    }
}

server_vo_ChatRecord

package com.chatroom.server.vo;

import java.sql.Timestamp;
import java.util.Objects;

public class ChatRecord {
    private int id;
    private String username;
    private String content;
    private Timestamp chattime;
    public ChatRecord() {}
    public ChatRecord(int id, String username, String content, Timestamp chattime) {
        this.id = id;
        this.username = username;
        this.content = content;
        this.chattime = chattime;
    }

    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 getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public Timestamp getChattime() {
        return chattime;
    }

    public void setChattime(Timestamp chattime) {
        this.chattime = chattime;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ChatRecord that = (ChatRecord) o;
        return id == that.id && Objects.equals(username, that.username) && Objects.equals(content, that.content) && Objects.equals(chattime, that.chattime);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username, content, chattime);
    }

    @Override
    public String toString() {
        return "ChatRecord{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", content='" + content + '\'' +
                ", chattime='" + chattime + '\'' +
                '}';
    }
}

server_vo_User

package com.chatroom.server.vo;

import java.util.Objects;

public class User {
    private Integer id;
    private String username;
    private String password;
    private String telephone;
    private String gender;

    public User(){}

    public User(Integer id, String username, String password, String telephone, String gender) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.telephone = telephone;
        this.gender = gender;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer 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;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id && Objects.equals(username, user.username) && Objects.equals(password, user.password) && Objects.equals(telephone, user.telephone) && Objects.equals(gender, user.gender);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username, password, telephone, gender);
    }

    public String toString(){
        return id + "," + username + "," + password + "," + telephone + "," + gender;
    }
}

server_vo_UserOfOnline

package com.chatroom.server.vo;

import java.sql.Timestamp;
import java.util.Objects;

public class UserOfOnline {
    private Integer id;
    private String username;
    private Timestamp loginTime;
    private Timestamp logoutTime;
    private String status;

    public UserOfOnline() {
    }

    public UserOfOnline(Integer id, String username, Timestamp loginTime, Timestamp logoutTime, String status) {
        this.id = id;
        this.username = username;
        this.loginTime = loginTime;
        this.logoutTime = logoutTime;
        this.status = status;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public Timestamp getLoginTime() {
        return loginTime;
    }

    public void setLoginTime(Timestamp loginTime) {
        this.loginTime = loginTime;
    }

    public Timestamp getLogoutTime() {
        return logoutTime;
    }

    public void setLogoutTime(Timestamp logoutTime) {
        this.logoutTime = logoutTime;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserOfOnline that = (UserOfOnline) o;
        return Objects.equals(id, that.id) && Objects.equals(username, that.username) && Objects.equals(loginTime, that.loginTime) && Objects.equals(logoutTime, that.logoutTime) && Objects.equals(status, that.status);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, username, loginTime, logoutTime, status);
    }

    @Override
    public String toString() {
        return "UserOnline{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", loginTime=" + loginTime +
                ", logoutTime=" + logoutTime +
                ", status='" + status + '\'' +
                '}';
    }
}

druid.properties

driverClassName=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/chat_db?serverTimezone=Asia/Shanghai&useTimezone=true
username=root
password=111111
initialSize=5
maxActive=50
maxIdle=10
minIdle=3
maxWait=60000

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值