# 智原java课件练习题 **Repository Path**: begit/zy_java_homework ## Basic Information - **Project Name**: 智原java课件练习题 - **Description**: 智原java课件练习题 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 3 - **Forks**: 1 - **Created**: 2021-12-19 - **Last Updated**: 2025-03-06 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # WEB聊天室项目截图 ![image-20220405171636579](readme.assets/image-20220405171636579-16729901512961.png) ![image-20220405171733259](readme.assets/image-20220405171733259-16729901512963.png) ![image-20220405171746011](readme.assets/image-20220405171746011-16729901512965.png) ![image-20220405171754096](readme.assets/image-20220405171754096-16729901512967.png) ![image-20220405171801882](readme.assets/image-20220405171801882-16729901512969.png) ![image-20220405171815114](readme.assets/image-20220405171815114-167299015129611.png) ![image-20220405171837162](readme.assets/image-20220405171837162-167299015129613.png) ![image-20220405171844866](readme.assets/image-20220405171844866-167299015129615.png) ![image-20220405171902973](readme.assets/image-20220405171902973-167299015129617.png) ![image-20220405171925031](readme.assets/image-20220405171925031-167299015129619.png) ![image-20220405171958585](readme.assets/image-20220405171958585-167299015129621.png) # 实训 自己整理记录笔记 作业,项目管理工具,组长跟踪组员进度,技术组长同步解决问题 代码协通Git 分小组(5人)答辩项目,组长或组员答辩 录屏地址:https://www.bilibili.com/video/BV13i4y1Q7Dx?spm_id_from=333.999.0.0 代码地址:https://gitee.com/begit/zy_java_homework web聊天室代码:https://gitee.com/begit/chat_room_web20220419 笔记大全:http://www.sunpinewater.tech/mydownload/notes/ 毕业设计不重复:https://www.bilibili.com/video/BV1Nq4y1G7pw?spm_id_from=333.337.search-card.all.click ## 作业 | 日期 | 作业 | | | ---- | ------------------------------------------------------------ | ---- | | 3.28 | 读取模板文件C:\pet.templater的内容,按照pet.template的模板格式保存宠物数据到文本文件,即把{name}、{type}、{master}替换为具体的宠物信息,将替换后的内容写入到D\myDoc\pet.txt中 | | | | | | | | | | ## 作业练习完成 # 简易聊天室 -> web ->多人聊天 ## 实现技术 IO,Socket,Thread 源码参考地址:https://gitee.com/begit/zy_java_homework Java菜鸟教程:https://www.runoob.com/java/java-files-io.html java全栈知识体系:https://www.pdai.tech/ TCP/IP:https://www.runoob.com/tcpip/tcpip-tutorial.html WebSocket:https://www.ruanyifeng.com/blog/2017/05/websocket.html CSS在线手册:http://www.w3chtml.com/css3/ java中JSON的使用:https://www.runoob.com/w3cnote/java-json-instro.html ServletContext:https://www.w3cschool.cn/servlet/servlet-3ceg2p0t.html ajax调用:https://www.runoob.com/jquery/jquery-ajax-get-post.html js的JSON:https://www.runoob.com/js/js-json.html jquery服务端传参: https://www.cnblogs.com/loveer/p/11354485.html https://blog.csdn.net/wufewu/article/details/85223157 # IO ![java-io-overview](readme.assets/java-io-overview-16484338294692.jpg) ## 二进制文件复制 ``` public static void main(String[] args) throws IOException { IOTest io = new IOTest(); io.copyFile("C:\\Users\\gongb\\Pictures\\java.png","d:/temp/io/java.png"); } public void copyFile(String sourcePath,String desPath) throws IOException { FileInputStream fileInputStream = new FileInputStream(sourcePath); FileOutputStream fout = new FileOutputStream(desPath); int i = -1; byte[] buff = new byte[1024];//1k while ((i=fileInputStream.read(buff)) != -1){ //写文件 fout.write(buff,0,buff.length); } fileInputStream.close(); fout.close(); System.out.println("复制完毕"); } ``` ## 字符文件复制 ``` public void copyFile() throws IOException { Reader fr = new FileReader("d:/temp/io/"+ File.separator+"1.txt"); Writer fw = new FileWriter("d:/temp/io/"+ File.separator+"writer.txt"); int l = -1; char[] buf = new char[1024]; BufferedReader br = new BufferedReader(fr); BufferedWriter bw = new BufferedWriter(fw); while((l = br.read(buf)) > -1){ bw.write(buf,0,buf.length); } bw.flush();//立刻把缓冲数据刷到磁盘 bw.close(); fw.close(); } ``` # 线程 ![image-20220329105917331](readme.assets/image-20220329105917331.png) # 网络 ![image-20220329211950916](readme.assets/image-20220329211950916.png) ![image-20220329215901890](readme.assets/image-20220329215901890.png) ![image-20220329220213647](readme.assets/image-20220329220213647.png) ![image-20220329212848804](readme.assets/image-20220329212848804.png) ![image-20220329212916586](readme.assets/image-20220329212916586.png) ![image-20220329215438353](readme.assets/image-20220329215438353.png) # SOCKETQQ聊天室 ## 基础版 ![image-20220331114503647](readme.assets/image-20220331114503647.png) ``` package com.md.sockettest; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import java.net.Socket; /** * @Author Gong * @Description 接收服务端数据 * @dATE 2022/3/30 17:02 **/ public class ClientThread extends Thread{ private Socket socket; public ClientThread(Socket socket){ this.socket = socket; } BufferedReader br = null; @Override public void run() { String str = null; try { br = new BufferedReader(new InputStreamReader( socket.getInputStream())); while (!(str=br.readLine()).equals("exit")){ System.out.println(str); } br.close(); } catch (IOException e) { e.printStackTrace(); } } } ``` ``` package com.md.sockettest; import java.io.*; import java.net.Socket; /** * @Author Gong * @Description 接收客户端数据 * @dATE 2022/3/30 17:02 **/ public class ServerThread extends Thread{ private Socket socket; public ServerThread(Socket socket){ this.socket = socket; } BufferedReader br = null; @Override public void run() { String str = null; try { br = new BufferedReader(new InputStreamReader( socket.getInputStream())); // BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); while (!(str=br.readLine()).equals("exit")){ System.out.println("客户端说:"+socket+":"+str); sendMessageToALLClient(socket+":"+str); bw.write("服务端收到客户端:"+socket+":"+str); bw.newLine(); bw.flush(); } br.close(); } catch (IOException e) { e.printStackTrace(); } } //广播 private void sendMessageToALLClient(String str) throws IOException { for(Socket s: ServeSockeTest.allSocket) { try{ BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); bw.write(str); bw.newLine(); bw.flush(); }catch(IOException e) { e.printStackTrace(); } } } } ``` ``` package com.md.sockettest; import java.net.ServerSocket; import java.net.Socket; import java.util.HashSet; /** * @Author Gong * @Description * @dATE 2022/3/30 15:33 **/ public class ServeSockeTest { public static HashSet allSocket; public static void main(String[] args) { try { ServerSocket server = null ; try { //创建ServerSocket对象,指定端口是 server = new ServerSocket(8080); System.out.println("服务启动成功"); } catch (Exception e) { System.out.println("服务器启动出错"); } allSocket=new HashSet(); Socket socket = null; try { while(true){ //调用ServerSocket的accept方法,可以接受客户端的请求 socket = server.accept(); System.out.println(socket+"上线"); allSocket.add(socket); System.out.println("链接socket成功"); ServerThread st = new ServerThread(socket); st.start();//服务端接客户端数据 } } catch (Exception e) { e.printStackTrace(); } }finally { // System.out.println("未知异常。。。"); } } } ``` # 窗口版 ## 界面 ![image-20220330211429761](readme.assets/image-20220330211429761.png) ## 单线程 ``` package com.md.sockettest.QQChatv1; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.Properties; /** * @Author Gong * @Description * @dATE 2022/3/30 21:16 **/ public class ServerChatMain extends JFrame{ public static void main(String[] args) { new ServerChatMain(); } //文本区域 private JTextArea jta; //滚动条 private JScrollPane jsp; //面板 private JPanel jp; //文本框 private JTextField jtf; //按钮 private JButton jb; private BufferedWriter bufferedWriter; static{ //加载文件信息 Properties prop = new Properties(); try { File f = new File("src/com/md/sockettest/QQChat/chat.properties"); prop.load(new FileReader(f)); //赋值 System.out.println(prop); } catch (IOException e) { e.printStackTrace(); }; } public ServerChatMain(){ jta = new JTextArea(); jta.setEditable(false); jsp = new JScrollPane(jta); jp= new JPanel(); jtf = new JTextField(10); jb = new JButton("发送"); jp.add(jtf); jp.add(jb); //将滚动条,面板全添加到窗体中 this.add(jsp, BorderLayout.CENTER); this.add(jp,BorderLayout.SOUTH); //设置标题,大小,位置,关闭,是否可见 this.setTitle("QQ聊天-服务端"); this.setSize(500,500); this.setLocation(300,500); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); jb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("发送按钮被点击"); sendMsg(); } }); jtf.addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode()==KeyEvent.VK_ENTER){ System.out.println(e); //发送数据 sendMsg(); } } @Override public void keyReleased(KeyEvent e) { } }); //服务端start try { ServerSocket serverSocket = new ServerSocket(8888); Socket socket = serverSocket.accept(); //写出数据 bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //读入数据 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = null; while ((line = bufferedReader.readLine()) != null){ jta.append(line + System.lineSeparator()); } serverSocket.close(); } catch (IOException e) { e.printStackTrace(); } //服务端end } private void sendMsg(){ //获取文本内容 String text = jtf.getText(); text = "服务端说:"+text; jta.append(text+System.lineSeparator()); try { bufferedWriter.write(text); bufferedWriter.newLine(); bufferedWriter.flush(); //清空文本框 jtf.setText(""); } catch (IOException ex) { ex.printStackTrace(); } } } ``` ``` package com.md.sockettest.QQChatv1; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.io.*; import java.net.Socket; /** * @Author Gong * @Description * @dATE 2022/3/30 21:16 **/ public class ClientChatMain extends JFrame{ public static void main(String[] args) { new ClientChatMain(); } //文本区域 private JTextArea jta; //滚动条 private JScrollPane jsp; //面板 private JPanel jp; //文本框 private JTextField jtf; //按钮 private JButton jb; private BufferedWriter bufferedWriter; public ClientChatMain(){ jta = new JTextArea(); jta.setEditable(false); jsp = new JScrollPane(jta); jp= new JPanel(); jtf = new JTextField(10); jb = new JButton("发送"); jp.add(jtf); jp.add(jb); //将滚动条,面板全添加到窗体中 this.add(jsp, BorderLayout.CENTER); this.add(jp,BorderLayout.SOUTH); //设置标题,大小,位置,关闭,是否可见 this.setTitle("QQ聊天-客户端"); this.setSize(500,500); this.setLocation(300,0); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setVisible(true); jb.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.out.println("发送按钮被点击"); //获取文本内容 sendMsg(); } }); jtf.addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { if(e.getKeyCode()==KeyEvent.VK_ENTER){ System.out.println(e); //发送数据 sendMsg(); } } @Override public void keyReleased(KeyEvent e) { } }); //客户端start try { Socket socket = new Socket("127.0.0.1", 8888); //写出数据 bufferedWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); //读入数据 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream())); String line = null; while ((line = bufferedReader.readLine()) != null){ jta.append(line + System.lineSeparator()); } socket.close(); } catch (IOException e) { e.printStackTrace(); } //客户端end } private void sendMsg(){ //获取文本内容 String text = jtf.getText(); text = "客户端说:"+text; jta.append(text+System.lineSeparator()); try { bufferedWriter.write(text); bufferedWriter.newLine(); bufferedWriter.flush(); //清空文本框 jtf.setText(""); } catch (IOException ex) { ex.printStackTrace(); } } } ``` ## 多线程版 ``` package com.zy.socket.chat_0; import java.io.*; import java.net.Socket; import java.net.UnknownHostException; /** * @Author Gong * @Description * @dATE 2021/12/19 18:59 **/ public class Client { Socket socket; BufferedWriter bw; BufferedReader br ; public Client(String ip, int port){ try { socket =new Socket(ip,port); bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); br=new BufferedReader(new InputStreamReader(socket.getInputStream())); }catch (UnknownHostException e){ e.printStackTrace(); }catch(IOException e){ e.printStackTrace(); } } public void sendMessage(String message) { try{ bw.write(message); bw.newLine(); bw.flush(); }catch(IOException e){ e.printStackTrace(); } } public String reciveMessage() { String message=null; try { message = br.readLine(); }catch(IOException e) { e.printStackTrace(); } return message; } public void close(){ try{ socket.close(); }catch(IOException e){ e.printStackTrace(); } }} ``` ``` package com.zy.socket.chat_0; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.text.SimpleDateFormat; import java.util.Date; /** * @Author Gong * @Description * @dATE 2021/12/19 18:58 **/ public class ClientFrame extends JFrame { private JPanel contentPane; private JLabel lblUserName; private JTextField tfMessage; private JButton btnSend; private JTextArea textArea; private String userName; private Client client; public ClientFrame(String ip,String userName){ this.userName = userName; init();//添加窗体初始化内容 addListener(); client=new Client(ip,8080); ReadMessageThread t=new ReadMessageThread(); t.start(); } private class ReadMessageThread extends Thread{ @Override public void run() { while(true) { String str=client.reciveMessage(); textArea.append(str+"\n");//添加文本内容 } } } private void init(){ setTitle("客户端"); setResizable(false); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100,100,450,300); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5,5,5,5)); contentPane.setLayout(null); setContentPane(contentPane); JScrollPane scrollPane = new JScrollPane(); scrollPane.setBounds(5,5,434,229); contentPane.add(scrollPane); textArea =new JTextArea(); scrollPane.setViewportView(textArea); textArea .setEditable(false); JPanel panel =new JPanel(); panel.setBounds(5,235,434,32); contentPane.add(panel); panel.setLayout(null); lblUserName = new JLabel(userName); lblUserName.setHorizontalAlignment(SwingConstants.TRAILING); lblUserName.setBounds(2,4,55,22); panel.add(lblUserName); tfMessage =new JTextField(); tfMessage.setBounds(62,5,274,22); tfMessage.setColumns(10); panel.add(tfMessage); btnSend =new JButton("发送"); btnSend.setBounds(336,4,93,23); panel.add(btnSend); tfMessage.validate(); } private void addListener(){ btnSend.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e){ Date date=new Date(); SimpleDateFormat sf=new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss"); client.sendMessage(userName+""+sf.format(date)+":\n"+tfMessage.getText()); tfMessage.setText("");//清空 } }); this.addWindowListener(new WindowAdapter(){//开启窗口监听 @Override public void windowClosing(WindowEvent atg0) { int op = JOptionPane.showConfirmDialog(ClientFrame.this,"确定要退出聊天室吗?","确定",JOptionPane.YES_NO_OPTION); if(op == JOptionPane.YES_OPTION) { client.sendMessage("%EXIT%:" + userName); try { Thread.sleep(200); }catch(InterruptedException e) { e.printStackTrace(); } client.close(); System.exit(0); } } }); } } ``` ``` package com.zy.socket.chat_0; import javax.swing.*; import javax.swing.border.EmptyBorder; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * @Author Gong * @Description * @dATE 2021/12/19 18:57 **/ public class LinkServerFrame extends JFrame{ private JPanel contentPane;//下方面板 private JLabel lblIP; private JLabel lblUserName; private JTextField tfIP; private JTextField tfUserName; private JButton btnLink; public LinkServerFrame(){ setTitle("连接服务器"); setResizable(false); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setBounds(100, 100, 390, 150); contentPane = new JPanel(); contentPane.setBorder(new EmptyBorder(5,5,5,5)); contentPane.setLayout(null); setContentPane(contentPane); lblIP =new JLabel("服务器IP地址:"); lblIP.setFont(new Font("微软雅黑",Font.PLAIN,14)); lblIP.setBounds(20,15,100,15); contentPane.add(lblIP); tfIP =new JTextField("127.0.0.1"); tfIP.setBounds(121,13,242,21); contentPane.add(tfIP); tfIP.setColumns(10); lblUserName = new JLabel("用户名:"); lblUserName.setFont(new Font("微软雅黑",Font.PLAIN,14)); lblUserName.setBounds(60,40,60,15); contentPane.add(lblUserName); tfUserName =new JTextField(); tfUserName.setBounds(121,42,242,21); contentPane.add(tfUserName); tfUserName.setColumns(10); btnLink =new JButton("连接服务器"); btnLink.addActionListener(new ActionListener(){ @Override public void actionPerformed(ActionEvent e){ do_btnlink_actionPerformed(e); } }); btnLink.setFont(new Font("微软雅黑", Font.PLAIN,14)); btnLink.setBounds(140,80,120,23); contentPane.add(btnLink);//显示连接服务器窗口 } public static void main(String[] args){ LinkServerFrame linkServerFrame = new LinkServerFrame(); linkServerFrame.setVisible(true); } protected void do_btnlink_actionPerformed(ActionEvent e) { if(!tfIP.getText().equals("")&&!tfUserName.getText().equals("")) {//文本框的内容不能为空 dispose();//销毁当前窗口 ClientFrame clientFrame=new ClientFrame(tfIP.getText().trim(), tfUserName.getText().trim()); clientFrame.setVisible(true);//显示客户窗体 } else { JOptionPane.showMessageDialog(null,"文本框里的内容不能为空!","警告",JOptionPane.WARNING_MESSAGE); } } } ``` ``` package com.zy.socket.chat_0; import java.io.*; import java.net.ServerSocket; import java.net.Socket; import java.util.HashSet; /** * @Author Gong * @Description * @dATE 2021/12/19 18:56 **/ public class Server { private HashSet allSocket; private ServerSocket server; public Server() { try { server = new ServerSocket(8080); }catch(IOException e) { e.printStackTrace(); } allSocket=new HashSet(); } public void startServer() throws IOException{ while(true) { Socket socket =server.accept(); System.out.println("用户已经进入聊天室"); allSocket.add(socket); ServerThread t= new ServerThread(socket); t.start(); } } //多线程接收聊天信息 private class ServerThread extends Thread{ Socket socket; public ServerThread(Socket socket) { this.socket=socket; } @Override public void run() { BufferedReader br=null; try { br=new BufferedReader(new InputStreamReader(socket.getInputStream())); while(true) { String str=br.readLine(); if(str.contains("%EXIT%")) { String tmp=str.split(":")[1]+"用户退出聊天室"; sendMessageToALLClient(tmp); allSocket.remove(socket); socket.close(); return; } sendMessageToALLClient(str); } }catch(IOException e) { e.printStackTrace(); } }} private void sendMessageToALLClient(String str) throws IOException { for(Socket s: allSocket) { try{ BufferedWriter bw=new BufferedWriter(new OutputStreamWriter(s.getOutputStream())); bw.write(str); bw.newLine(); bw.flush(); }catch(IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { Server s = new Server(); try { s.startServer(); }catch(IOException e){ e.printStackTrace(); } } } ``` # Web版聊天室 ## 技术选型 servlet+Jsp+websocket+mysql+hutools+(html+css+js+es6+node)+vue/jquery ServletContext application ## HTML5 WebSocket 最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于[服务器推送技术](https://en.wikipedia.org/wiki/Push_technology)的一种。 WebSocket 是 HTML5 开始提供的一种在单个 TCP 连接上进行全双工通讯的协议。 WebSocket 使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。 在 WebSocket API 中,浏览器和服务器只需要做一个握手的动作,然后,浏览器和服务器之间就形成了一条快速通道。两者之间就直接可以数据互相传送。 现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。 HTML5 定义的 WebSocket 协议,能更好的节省服务器资源和带宽,并且能够更实时地进行通讯。 ![img](readme.assets/ws.png) 浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。 当你获取 Web Socket 连接后,你可以通过 **send()** 方法来向服务器发送数据,并通过 **onmessage** 事件来接收服务器返回的数据。 以下 API 用于创建 WebSocket 对象。 参考教程: ![image-20220405172321333](readme.assets/image-20220405172321333.png) ![image-20220405172513771](readme.assets/image-20220405172513771.png) ![image-20220405172616127](readme.assets/image-20220405172616127.png) ![image-20220410224651672](readme.assets/image-20220410224651672.png) ### 实现 ![image-20220410225120389](readme.assets/image-20220410225120389.png) ![image-20220410225129060](readme.assets/image-20220410225129060.png) ![image-20220410225351832](readme.assets/image-20220410225351832.png) ![image-20220411134213739](readme.assets/image-20220411134213739.png) ![image-20220411214541843](readme.assets/image-20220411214541843.png) ![image-20220411215606700](readme.assets/image-20220411215606700.png) ![image-20220411215718959](readme.assets/image-20220411215718959.png) ## 链接测试 ``` javax.websocket javax.websocket-api 1.1 provided ``` ``` package websocket; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; /** * @Author * @Description * @dATE 2022/4/11 21:48 **/ @ServerEndpoint(value = "/chat") public class ChatEndPoint { @OnOpen public void onOpen(Session session,EndpointConfig config){ System.out.println("连接调用"); } @OnMessage //接收到数据时调用 public void onMessage(String message, Session session){ System.out.println("接消息调用:"+message); } @OnClose public void onClose(Session session){ System.out.println("关闭调用"); } @OnError public void onError(Session session,Throwable error){ System.out.println("报错调用"); } } ``` 页面WebSocket教程:https://www.ruanyifeng.com/blog/2017/05/websocket.html ## 聊天室进阶 ``` 聊天登录
``` ``` Title
``` ``` package com.md.websocket; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @Author Gong * @Description * @dATE 2022/4/12 22:12 **/ @WebServlet("/SessionTrack") public class SessionTrack extends HttpServlet { private static final long serialVersionUID = 1L; @Override public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.setCharacterEncoding("utf-8"); response.setCharacterEncoding("utf-8"); String username = request.getParameter("username"); request.getSession().setAttribute("username",username); response.sendRedirect(request.getContextPath()+ "/websocketChat.html"); } } ``` ``` package com.md.websocket; import javax.servlet.http.HttpSession; import javax.websocket.HandshakeResponse; import javax.websocket.server.HandshakeRequest; import javax.websocket.server.ServerEndpointConfig; /** * @Author Gong * @Description * @dATE 2022/4/12 20:57 **/ public class GetHttpSessionConfigurator extends ServerEndpointConfig.Configurator{ @Override public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) { HttpSession httpSession = (HttpSession)request.getHttpSession(); sec.getUserProperties().put(HttpSession.class.getName(), httpSession); } } ``` ``` package com.md.websocket; import javax.servlet.http.HttpSession; import javax.websocket.*; import javax.websocket.server.ServerEndpoint; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Map; import java.util.Random; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; /** * @Author Gong * @Description * @dATE 2022/4/11 21:48 **/ @ServerEndpoint(value = "/chat",configurator = GetHttpSessionConfigurator.class) //@ServerEndpoint(value = "/chat") public class ChatEndPoint { //因为每个客户端都有一个本类对象存在,对每个客户端进行管理 private static Map onlineUsers = new ConcurrentHashMap(); //声明session,通过该对象可以发送消息给指定的用户。 private Session session; private HttpSession httpSession;//可以拿到对应的用户信息 @OnOpen public void onOpen(Session session,EndpointConfig config){ System.out.println("连接调用"); this.session = session; HttpSession httpSession =(HttpSession) config.getUserProperties().get(HttpSession.class.getName()); this.httpSession = httpSession; String username = "匿名"+ new Random().nextInt(100); if(null != httpSession){ username = (String)httpSession.getAttribute("username"); } onlineUsers.put(username,this); //登录成功后需要进行广播通知 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String nowTime = sdf.format(new Date()); broadcastAllUsers(nowTime+"["+username+"]登录成功。"); //当前在线用户信息 broadcastAllUsers("在线用户:"+onlineUsers.keySet()); } private void broadcastAllUsers(String message){ //将消息广播给所有的客户端 Set users = onlineUsers.keySet(); for (String username : users) { try { ChatEndPoint chatEndPoint = onlineUsers.get(username); //发送数据 chatEndPoint.session.getBasicRemote().sendText(message); System.out.println("已广播数据"+username); } catch (Exception e) { e.printStackTrace(); System.out.println("用户"+username+"过期,已移除。"); onlineUsers.remove(username); } } } @OnMessage //接收到数据时调用 public void onMessage(String message, Session session){ System.out.println("接消息调用:"+message); if(null != this.httpSession){ String username = (String)httpSession.getAttribute("username"); SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String nowTime = sdf.format(new Date()); broadcastAllUsers(nowTime+"["+username+"]:"+message); }else{ broadcastAllUsers("匿名用户:"+message); } } @OnClose public void onClose(Session session){ System.out.println("关闭调用"); } @OnError public void onError(Session session,Throwable error){ System.out.println("报错调用"); } } ``` ## 需求原型 ### 版本1 ![image-20220403085738489](readme.assets/image-20220403085738489.png) ![image-20220331161156904](readme.assets/image-20220331161156904.png) ![image-20220331161254356](readme.assets/image-20220331161254356.png) ![image-20220331161342553](readme.assets/image-20220331161342553.png) ![image-20220331162110063](readme.assets/image-20220331162110063.png) 1.存消息,主动刷新取数据。 2.ajax定时取消息。可以活动新消息。不及时。及时。服务器压力比较大。配合使用ServletContext获得公共数据。 3.websocket,服务器主动推送新消息。 (html,css,js,ui框架,vue,servelt,jsp,mysql,websocket) ssm->springboot(效率更高)->JavaEE netty->mq->微服务 CS->BS ![image-20220421085156122](readme.assets/image-20220421085156122.png) ### 版本2 ![image-20220405171636579](readme.assets/image-20220405171636579.png) ![image-20220405171733259](readme.assets/image-20220405171733259.png) ![image-20220405171746011](readme.assets/image-20220405171746011.png) ![image-20220405171754096](readme.assets/image-20220405171754096.png) ![image-20220405171801882](readme.assets/image-20220405171801882.png) ![image-20220405171815114](readme.assets/image-20220405171815114.png) ![image-20220405171837162](readme.assets/image-20220405171837162.png) ![image-20220405171844866](readme.assets/image-20220405171844866.png) ![image-20220405171902973](readme.assets/image-20220405171902973.png) ![image-20220405171925031](readme.assets/image-20220405171925031.png) ![image-20220405171958585](readme.assets/image-20220405171958585.png) ![image-20220411220630155](readme.assets/image-20220411220630155.png) ### 消息格式 ![image-20220411220931519](readme.assets/image-20220411220931519.png) # 功能实现 ## 登录登出过滤 ``` package filter; import constutil.Constants; import javax.servlet.*; import javax.servlet.annotation.WebFilter; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; /** * @Author Gong * @Description * @dATE 2022/4/20 14:36 **/ @WebFilter("/*") public class LoginFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("init LoginFilter"); } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { //如果用户未登录,我们强制跳转到登录页 System.out.println("do filter"); //当访问/chat/ , /chat/index.jsp ,/chat/loginServlet HttpServletRequest req = (HttpServletRequest)servletRequest; HttpServletResponse resp = (HttpServletResponse)servletResponse; String requestURI = req.getRequestURI(); System.out.println("当前路径URI:"+requestURI); if(!(null!= requestURI && (requestURI.equals(req.getContextPath()) || requestURI.equals(req.getContextPath() + "/")) || requestURI.equals(req.getContextPath() + "/index.jsp") || requestURI.equals(req.getContextPath() + "/loginServlet"))){ //验证是否登录成功 HttpSession session = req.getSession(); Object attribute = session.getAttribute(Constants.SESSION_USER_ID); if(null == attribute){ // 登录不成功 //重定向到登录页 req.setAttribute(Constants.LOGIN_INFO,"抱歉,没登录,请登录再试试。"); req.getRequestDispatcher("/index.jsp").forward(req,resp); } } filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { System.out.println("destroy LoginFilter"); } } ``` ``` package chatroom; import constutil.Constants; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; /** * @Author Gong * @Description * @dATE 2022/4/18 16:37 **/ @WebServlet("/loginServlet") //不能重名 public class LoginServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String username = req.getParameter("username"); String password = req.getParameter("password"); String[] k1s = req.getParameterValues("k1"); System.out.println(k1s); if(null != username && username.equals("zs") && null != password && password.equals("123")){ //登录成功 //跳转到聊天主页 HttpSession session = req.getSession(true); session.setAttribute(Constants.SESSION_USER_ID,"zs");//登录成功 resp.sendRedirect(req.getContextPath()+"/chatroom/chatroom.jsp"); }else{ //如果没有登陆了成功 //提示用户未成功登录,账号或密码异常 //TODO req.getRequestDispatcher("/index.jsp").forward(req,resp); } } } ``` ``` package chatroom; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; /** * @Author Gong * @Description * @dATE 2022/4/18 16:37 **/ @WebServlet("/logoOutServlet") //不能重名 public class LogoOutServlet extends HttpServlet { @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { HttpSession session = req.getSession(); if(null != session){ session.invalidate(); } resp.sendRedirect(req.getContextPath()+"/index.jsp"); } } ```