本项目的源代码地址:https://github.com/Alexshi5/learn-parent/tree/master/learn-javaweb/f1chapter10-websocket
本项目的前导文章:JavaWeb高级编程(十)—— 在应用程序中使用WebSocket进行交互
通常聊天有两种实现方式:
聊天室 —— 它有超过两个参与者,通常最大数量没有上限;
私聊 —— 它通常只有两个参与者,其他人都无法看到聊天的内容。
无论是私聊还是聊天室,服务器端的实现基本上都是相同的:服务器接受连接,关联所有相关的连接,并将进入的消息发送到相关的连接中。它们之间最大的区别就是关联彼此连接的数目。
下面是项目的代码示例:
1、使用的Maven依赖和版本号
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.websocket</groupId>
<artifactId>javax.websocket-api</artifactId>
</dependency>
</dependencies>
<!--websocket-->
<websocket.version>1.0</websocket.version>
<!-- jackson工具 -->
<jackson.version>2.9.2</jackson.version>
<!-- jstl标签库 -->
<jstl.version>1.2</jstl.version>
<!-- jsp和servlet -->
<jsp-api.version>2.3.1</jsp-api.version>
<servlet-api.version>4.0.0</servlet-api.version>
<!-- jdk的补充工具jar包 -->
<commons-lang3.version>3.6</commons-lang3.version>
2、创建简单的登录页面login.jsp和处理登录请求的LoginServlet
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
<title>用户登录</title>
</head>
<body>
<h1>用户登录</h1>
<c:if test="${loginFailed}">
账号或密码错误,请重新尝试!
</c:if>
<form method="post" action="login">
用户:<input name="username"><br>
密码:<input name="password"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
package com.mengfei.chat;
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;
import java.util.Hashtable;
import java.util.Map;
/**
* author Alex
* date 2018/12/30
* description 用于用户登录的Servlet
*/
@WebServlet(name = "loginServlet",urlPatterns = "/login")
public class LoginServlet extends HttpServlet{
private static final Map<String, String> userDatabase = new Hashtable<>();
static {
userDatabase.put("customer001", "customer001");
userDatabase.put("customer002", "customer002");
userDatabase.put("service001", "service001");
userDatabase.put("service002", "service002");
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
if(request.getParameter("logout") != null)
{
session.invalidate();
response.sendRedirect("login");
return;
}
else if(session.getAttribute("username") != null)
{
request.getRequestDispatcher("/WEB-INF/jsp/product.jsp")
.forward(request, response);
return;
}
request.setAttribute("loginFailed", false);
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp")
.forward(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpSession session = request.getSession();
if(session.getAttribute("username") != null)
{
request.getRequestDispatcher("/WEB-INF/jsp/product.jsp")
.forward(request, response);
return;
}
String username = request.getParameter("username");
String password = request.getParameter("password");
if(username == null || password == null ||
!LoginServlet.userDatabase.containsKey(username) ||
!password.equals(LoginServlet.userDatabase.get(username)))
{
request.setAttribute("loginFailed", true);
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp")
.forward(request, response);
}
else
{
session.setAttribute("username", username);
request.changeSessionId();
request.getRequestDispatcher("/WEB-INF/jsp/product.jsp")
.forward(request, response);
}
}
}
3、创建一个简单的商品列表页面product.jsp
客户可以在此页面联系客服,客服人员可以在此页面查看发起聊天会话请求的列表。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<html>
<head>
<title>商品列表</title>
<script type="text/javascript" src="js/jquery-3.2.1.js"></script>
</head>
<body>
<h1>商品列表</h1>
<h3>衣服</h3>
<h3>鞋子</h3>
<h3>外套</h3>
<c:if test="${fn:contains(sessionScope.username,'service')}">
<br>
<a href="chat?action=list">查看会话列表</a>
</c:if>
<c:if test="${fn:contains(sessionScope.username,'customer')}">
<br>
<a href="javascript:void(0)" onclick="newChat()">联系客服</a>
</c:if>
<br>
<a href="login?logout=true">退出登录</a>
</body>
</html>
<script>
function newChat() {
hiddenFormSubmit('chat',{action:'new'});
}
function hiddenFormSubmit(url,fields) {
var form = $('<form id="mapForm" method="post"></form>')
.attr({ action: url, style: 'display: none;' });
for(var key in fields) {
if(fields.hasOwnProperty(key))
form.append($('<input type="hidden">').attr({
name: key, value: fields[key]
}));
}
$('body').append(form);
form.submit();
}
</script>
4、创建一个POJO类ChatMessage
p