项目:网页聊天室

一个基于WebSocket的网页聊天室项目:
先展示一下最终结果(代码在文末):

功能及结果展示:

1. 用户注册及注册账号校验

注册时判断数据库中是否已有用户名与预注册用户名相同,若有,则弹出窗口,提示"注册失败",点击确定后回到注册页面,继续注册。

注册页面:

项目:网页聊天室_第1张图片

注册失败:

项目:网页聊天室_第2张图片

2. 用户登录及登录账号校验

注册成功之后页面跳转至登录页面,输入用户名或密码,若用户名或密码错误,则弹出窗口,提示"用户名或密码错误",点击确定后回到登录页面,继续登录,若用户名和密码都正确,则进入聊天页面。

登录页面:

项目:网页聊天室_第3张图片

登录失败:

项目:网页聊天室_第4张图片

3. 用户上线通知及下线通知

每当有一个用户登录,其他在线用户都会收到上线通知,每当有用户下线或直接退出,其他在线用户也会收到下线通知

上线通知:

项目:网页聊天室_第5张图片

下线通知:

项目:网页聊天室_第6张图片

4. 多个用户之间的群聊

当左上角所有用户用户名前格子显示被选中时,任何一个用户发送消息,其他用户都能看到,即群聊功能
项目:网页聊天室_第7张图片

5. 单独用户之间的私聊

要实现私聊功能,只需要点击左上角对应用户名复选框,被取消选中的用户将看不到发送者发送的消息,要实现私聊,只需要选中私聊对象用户,发送消息即可
项目:网页聊天室_第8张图片
项目:网页聊天室_第9张图片
结果展示结束,总结一下具体实现方法及所用到的知识

1、JDBC常规操作

首先,这个项目中的用户名,密码等信息需要存储在数据库中,并且需要在合适的时候使用MySQL,语句操作数据库进行一些判断(如注册时需要判断预注册用户名是否在数据库中已存在或在登录时需要判断输入的用户名和密码是否在数据库中已存在),所以,需要先了解一下JDBC。
Java数据库连接(java DataBase Connectivity),又称JDBC,用于在Java程序中实现数据库操作功能,它提供了执行SQL语句,访问各种数据库的方法,并为各种不同的数据库提供统一的操作接口,java.sql包中包含了JDBC操作数据库的所有类。通过JDBC访问数据库一般有如下步骤:

1. 加载JDBC驱动器及加载JDBC驱动

在Java程序中,可以通过 Class.forName(“指定数据库的驱动程序”) 方式来加载添加到开发环境中的驱动程序,本项目使用的是MySQL数据库,加载MySQL的数据驱动程序的代码为:Class.forName("com.mysql.jdbc.Driver");

2. 建立数据库连接,取得Connection对象

通过DriverManager类创建数据库连接对象Connection。DriverManager类作用于Java程序和JDBC驱动程序之间,用于检查所加载的驱动程序是否可以建立连接,然后通过它的getConnection方法,根据数据库的URL、用户名和密码,创建一个JDBC Connection 对象。如:Connection connection = DriverManager.geiConnection(“连接数据库的URL", "用户名", "密码”)。其中,URL=协议名+IP地址(域名)+端口+数据库名称;用户名和密码是指登录数据库时所使用的用户名和密码。

3. 建立Statement对象或PreparedStatement对象

Statement 类的主要是用于执行静态 SQL 语句并返回它所生成结果的对象。通过Connection 对象的 createStatement()方法可以创建一个Statement对象:Statement statament = connection.createStatement();
但是Statement对象存在SQL注入漏洞的问题:即SQL可以使用关键字将一条查询语句变成多条,或将后面的语句变成注释【如:or,–】,这个问题可以通过**使用PrepareedStatement(预处理SQL)**来解决:
PrepareStatement继承于Statement,但他与Statement在两方面有所不同:
1)PreparedStatement 实例包含已编译的 SQL 语句。这就是使语句“准备好”。包含于 PreparedStatement 对象中的 SQL 语句可具有一个或多个 IN 参数。IN参数的值在 SQL 语句创建时未被指定。相反的,该语句为每个 IN 参数保留一个问号(“?”)作为占位符。每个问号的值必须在该语句执行之前,通过适当的setXXX 方法来提供。
2)由于 PreparedStatement 对象已预编译过,所以其执行速度要快于 Statement 对象。因此,多次执行的 SQL 语句经常创建为 PreparedStatement 对象,以提高效率。

4. 执行SQL语句

调用Statement对象的相关方法执行相对应的 SQL 语句。
例如通过execuUpdate()方法用来判断数据是否插入成功,再这个项目中可转换为是否注册成功的判断。
又如通过executeQuery()方法把数据库响应的查询结果存放在ResultSet类对象中,供我们判断或查询,在这个项目中可以转换为登录时用户名和密码是否是数据库中存在的用户的判断。

5. 关闭数据库资源

使用完数据库或者不需要访问数据库时,通过Connection和Statement的close() 方法关闭连接和Statement对象,若执行了查询操作(即本项目中的登录操作),则还需要通过ResultSet类的close()方法关闭查询的结果集对象。

2、JDBC优化

使用数据库连接池:

在JDBC常规操作流程中,需要第一步首先是加载数据库驱动,然后通过DriverManager.geiConnection()获取连接,如果是对于一个简单的数据库,且对数据库访问不是很频繁,这种方式完全可行,但是如果面对较复杂的数据库且需要频繁访问数据库时,频繁的建立、关闭连接,会极大的减低系统的性能,所以可以考虑使用DataSource数据源,数据源建立多个数据库连接,这些数据库连接会保存在数据库连接池中,当需要访问数据库时,只需要从数据库连接池中获取空闲的数据库连接,当程序访问数据库结束时,数据库连接会放回数据库连接池中。其基本原理是是在内部对象池中维护一定数量的数据库连接,并对外暴露数据库连接获取和返回方法。
使用数据库连接池的优势:
1、资源复用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
2、更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接至于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间,从而缩减了系统整体响应时间。
3、统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。

数据库连接池方式步骤:

  1. 创建数据源:private static DataSource dataSource;
  2. 加载数据源配置文件(配置文件为xxx…properties,包含了数据库的配置,如:name,password等):Properties properties = CommUtils. loadProperties("datasource.properties");
  3. 根据配置文件加载数据源:dataSource = DruidDataSourceFactory.createDataSource(properties);
  4. 配置文件已加载完成,获取连接:数据库连接池获取连接不同于前一种方式的DriverManager.getConnection(),而是DataSource.getConnection();
  5. 其余步骤与前一种方式完全相同,依次为:建立Statement对象或PreparedStatement对象,执行SQL语句, 关闭数据库资源。

该项目中使用的是DruidDataSource

Druid号称是Java语言中最好的数据库连接池。

  1. 可以监控数据库访问性能,Druid内置提供了一个功能强大的StatFilter插件,能够详细统计SQL的执行性能,这对于线上分析数据库访问性能有帮助。
  2. 替换DBCP和C3P0。Druid提供了一个高效、功能强大、可扩展性好的数据库连接池。
  3. 数据库密码加密。直接把数据库密码写在配置文件中,这是不好的行为,容易导致安全问题。DruidDruiver和DruidDataSource都支持PasswordCallback。
  4. SQL执行日志,Druid提供了不同的LogFilter,能够支持Common-Logging、Log4j和JdkLog,你可以按需要选择相应的LogFilter,监控你应用的数据库访问情况。
  5. 能够提供基于Filter-Chain模式的插件体系。
    来源:使用Druid作为数据源

3、使用Gson(Google Gson)库的Json序列化与反序列化:

Gson(又称Google Gson)是Google公司发布的一个开放源代码的Java库,主要用途为序列化Java对象为JSON字符串,或反序列化JSON字符串成Java对象。
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成,广泛应用于各种数据的交互中,尤其是服务器与客户端的交互。
在需要提交的属性或元素项较多时,一个一个提交是一件很麻烦的事:

  • Json序列化可以通过Gson对象的toJson();方法将任意类型的元素合成为一个Json字符串。
  • Json反序列化可以通过Gson对象的fromJson();方法将一个Json字符串还原为原始类型。

4、Servlet:

Servlet(Server Applet)是Java Servlet的简称,称为小服务程序,即用Java编写的服务器端程序;主要功能在于交互式地浏览和修改数据,生成动态Web内容。
狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了Servlet接口的类。
一般情况下,我们将Servlet理解为前者。Servlet运行于支持Java的应用服务器中。从原理上讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。
Servlet 的主要功能在于交互式地浏览和修改数据,生成动态 Web 内容

一般步骤:
  1. 客户端发送请求至服务器端;
  2. 服务器将请求信息发送至 Servlet;
  3. Servlet 生成响应内容并将其传给服务器。响应内容动态生成,通常取决于客户端的请求;
  4. 服务器将响应返回给客户端。

一个 Servlet 就是 Java 编程语言中的一个类,它被用来扩展服务器的性能,服务器上驻留着可以通过“请求-响应”编程模型来访问的应用程序。虽然 Servlet 可以对任何类型的请求产生响应,但通常只用来扩展 Web 服务器的应用程序。

doGet() 方法与doPost() 方法:
  • doGet() 方法:
    当一个客户通过 HTML表单发出一个 HTTP GET 请求或直接请求一个 URL 时,doGet() 方法被调用。与 GET 请求相关的参数添加到 URL 的后面,并与这个请求一起发送。当不会修改服务器端的数据时,应该使用 doGet() 方法。
  • doPost() 方法:
    当一个客户通过 HTML 表单发出一个 HTTP POST 请求时,doPost() 方法被调用。与 POST 请求相关的参数作为一个单独的 HTTP 请求从浏览器发送到服务器。当需要修改服务器端的数据时,应该使用 doPost() 方法。

5、FreeMarker:

FreeMarker是一个用Java语言编写的模板引擎,它基于模板来生成文本输出。它不仅可以用作表现层的实现技术,而且还可以用于生成XML,JSP或Java等。模板用servlet提供的数据动态地生成HTML,通常由Java程序准备要显示的数据,由FreeMarker生成页面,通过模板显示准备的数据。

特点:
  • 能够生成各种文本:HTML、XML、RTF、Java源代码等等。
  • 易于嵌入到产品中:轻量级;不需要Servlet环境。
  • 插件式模板载入器:可以从任何源载入模板,如本地文件、数据库等等。

后端必须加载模板引擎

5、WebSocket:

  • WebSocket协议是基于TCP的一种新的网络协议。属于应⽤层协议,是TCP/IP协议的⼦集。
  • HTTP协议是单向通信协议,只有客户端发起HTTP请求,服务端才会返回数据。
  • WebSocket协议实现了浏览器与服务器全双工(full-duplex)通信——允许服务器主动发送信息给客户端。 但是WebSocket协议的建⽴需要先借助HTTP协议,在服务器返回101状态码之后,才可以进⾏全双工通信。

WebSocket 的实现分为握手,数据发送/读取,关闭连接

6、整体实现流程:

  1. 实现后端JDBC的操作:在数据库连接池加载配置文件,获取连接,建立Statement对象或PreparedStatement对象,执行SQL语句, 关闭数据库资源。

  2. 实现用户注册功能:在前端页面输入待注册用户名和密码,通过websocket提交到后端注册模块,进入步骤1中‘执行SQL语句’过程,返回数据库被改变的行数,返回0,则说明待注册用户名已存在不可注册,留在注册页面继续注册。返回1,则说明待注册用户名在数据库中不存在,可以注册,注册成功之后跳转至登录页面。

  3. 实现用户登录功能:在前端页面输入待注册用户名和密码,通过websocket提交到后端登录模块,进入步骤1中‘执行SQL语句’过程,返回一个查询的结果集,若返回为空,说明该用户名和密码在数据库中不存在,或用户名/密码错误,返回登录页面重新登录,若得到结果不为空,说明该用户名和密码在数据库中存在,可以直接登录,跳转至聊天页面。

  4. 实现上线通知和下线通知:
    上线:将当前客户端聊天实体,用户名和SessionID保存到会话中,向所有在线用户广播上线通知,同时进入聊天就绪状态;
    下线:将当前客户端聊天实体移除,将登入的用户名和SessionID保存到会话中,向所有在线用户广播下线通知

  5. 聊天功能实现:服务端收到当前被序列化处理后的Json字符串,将其反序列化,通过判断得到聊天类型(群聊/私聊),分别进行处理,若为群聊,需得到发送消息的用户名和消息实体,再将其序列化为Json字符串向当前WebSocket中的所有在线用户发送。若为私聊,只需在接受的信息中心添加发送对象信息,再经过判断以同样的方式将消息发送给特定对象即可。

7、项目源码:

GitHub:网页聊天室

参考资料:
数据库连接池优缺点详解
DruidDataSource源码解析
Gson全解析
Servlet

你可能感兴趣的:(其它,项目)