一.技术提要
1.webSocket介绍:webSocket是应用在Web浏览器和服务器之间进行任意的双向数据传输的一种技术,webSocket的长连接,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送技术的一种。。
在HTML 5之前,消息推送基本上都是使用HTTP请求的,但HTTP请求只能在客户端发起请求之后服务端才会返回消息。不能实现在客户端未发送请求时,服务端主动推送消息给客户端。
2.基于Http实现消息推送的方式包括:
轮询方式
长轮询
长连接
2.实现过程
(1)进入登录页面;
(2)登录成功之后,进入该系统主页面;
(3)在主页面中可以选择相关操作;
3.预览
前端登录页面:
前端注册页面:
登录页面需同数据库操作,在数据库里查找如果与前端返回的用户账户和密码相同则允许登录注册功能则是向数据库导入用户填入的信息。
主界面:
index.html
该界面为登录界面登录成功后跳转到主界面
<html>
<head>
<title>登录/注册</title>
<link type="text/css" rel="stylesheet" href="/css/login.css">
<link rel="shortcut icon" href="#"/>
</head>
<body>
<form action="loginServlet" method="post" id="form">
<div class="container">
<div class="head">
<div class="leftzi"><a href="#" class="leftzi">首页</a></div>
<div class="mid">没账号?</div>
<div class="rightzi"><a href="register.jsp" class="rightzi">
去注册
</a></div>
</div>
<div class="login">Login</div>
<div class="inputtop">
<label>用户名</label>
<input type="text" size="25" class="beau" id="username" name="username" placeholder="请输入用户名" required>
</div>
<div class="inputbuttom">
<label>密 码</label>
<input type="password" id="userpwd" name="userpwd" size="25" class="beau" placeholder="请输入密码" required>
<%-- 设置id属性在servlet层要调用 --%>
</div>
<div class="sub">
<input type="submit" class="dl" value="登录">
</div>
<c:if test="${!empty errormsg}">
<div class="loginerror">
${errormsg}
</div>
</c:if>
</div>
</form>
</body>
</html>
<html>
<head>
<title>聊天界面</title>
<link type="text/css" rel="stylesheet" href="/css/chat.css">
<link rel="shortcut icon" href="#"/>
<script type="text/javascript" src="/js/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
//加载后立即连接
var ws;
var ws_url = "ws://localhost:8080/websocket";
var lockReconnect=false;
$(function (){
ws_connect();
$(".btn").click(function (){
ws_sendMsg();
});
});
// function reconnect() {
// if(lockReconnect) return;
// lockReconnect = true;
// setTimeout(function () { //没连接上会一直重连,设置延迟避免请求过多
// ws_connect();
// lockReconnect = false;
// }, 2000);
// }
window.onbeforeunload = function() {
ws.close();
}
function ws_connect() {
var userinf='${sessionScope.name}';
if ('WebSocket' in window) {
console.log('111');
ws = new WebSocket(ws_url+"?user="+userinf);
} else if ('MozWebSocket' in window) {
ws = new MozWebSocket(ws_url);
} else {
console.log('Error: WebSocket is not supported by this browser.');
return;
}
ws.onopen = function () {
console.log('Info: WebSocket connection opened.');
};
ws.onclose = function (e) {
console.log('websocket 断开: ' + e.code + ' ' + e.reason + ' ' + e.wasClean)
console.log(e);
console.log('Info: WebSocket closed.');
};
ws.onmessage = function (message) {//后端传的messag
console.log(message.data);
var str2=message.data;//后面带user
var time = new Date().toLocaleTimeString();//实时获取时间
const array=str2.split("user=");
str2=array[0];
var user=array[1];
if(str2!="") {
$(".chat-messages").append("<div class='contentleft'><div class='yuanleft'>"+user+ "</div><div class='left2'><div>" + time + "</div><div class='leftzi'>" + str2 + "</div></div></div>")
}
};
}
// 聊天对象
function ws_sendMsg() {
var chatInput = document.querySelector('.chat-input input[type="text"]');
var msg=chatInput.value;//要发的信息
ws.send(msg);
document.querySelector('.chat-input input[type="text"]').value='';
console.log("发送成功")
}
</script>
</head>
<body>
<div class="chatcontain">
<div class="chat-header">
<h2>Chat</h2>
</div>
<div class="chat-messages">
<!-- 信息面板 -->
</div>
<div class="chat-input">
<form>
<input type="text" placeholder="请输入消息">
<input type="button" class="btn" value="发送">
<input type="text"style="display: none"/>
</form>
</div>
</div>
</body>
</html>
4.后端实现:注解的方式
注解成员数据介绍
@OnClose——连接关闭时的调用方法;
@OnOpen——有连接时进行调用的方法;
@OnMessage——收到消息进行调用的函数;
各个包及后端项目结构:
bean层封装user信息方便后续对象的操作,dao层为数据库操作层,servlet为响应请求层,util
层定义更具类,websocket层写入聊天逻辑代码
LoginServlet.java
package com.servlet;
import com.bean.User;
import com.dao.LoginDaolmp;
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.Iterator;
import java.util.List;
@WebServlet("/loginServlet")
public class loginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public loginServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
response.getWriter().append("Served at: ").append(request.getContextPath());
response.setContentType("text/html");
response.setCharacterEncoding("gb2312");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=UTF-8");
//请求前端页面的值
String username = request.getParameter("username"); //获取表单里用户名文本框信息
String userpwd = request.getParameter("userpwd");//获取表单里用户密码文本框信息
LoginDaolmp dl = new LoginDaolmp();//实例化对象
HttpSession session = request.getSession();//
boolean isHave = dl.searchName(username, userpwd);//调用查询用户名和密码是否匹配方法
if (isHave) {//
List<User> list = LoginDaolmp.fhui(username, userpwd);
Iterator<User> iter = list.iterator();
User u=iter.next();
session.setAttribute("name",u.getName());
session.setAttribute("username", username);
session.setAttribute("userpwd",userpwd);
request.getRequestDispatcher("/main.jsp").forward(request, response);//带着我们请求取main
} else {//失败
request.setAttribute("errormsg", "账号或密码错误请重新登录!");//setattribute 设置位置返回信息
request.getRequestDispatcher("/index.jsp").forward(request, response);//返回错误信息还是同页面
//response.sendRedirect("index.jsp");
}
}
}
Wssocket.java
package com.webSocket;
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
@ServerEndpoint("/websocket")
public class Wssocket {
static Set<Session> set = new HashSet<Session>();
static Iterator<Session> iter = set.iterator();
//定义Session记录访问状态
@OnOpen
public void onOpen(Session session) {
System.out.println("连接建立成功!");
String str = session.getQueryString();//获取前台传参
try {
str = URLDecoder.decode(str, "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
System.out.println("这是" + str);//str是每个用户的用户名
set.add(session);
}
@OnClose
public void onClose() {
try {
while (iter.hasNext()) {
iter.remove();
}
}catch (Exception e){
e.printStackTrace();
}
System.out.println("连接已关闭!");
}
@OnMessage
public void onMessage(String message, Session session) {
String str = session.getQueryString();//这里要确保以当前session为准给其它所有存入set的session发信息 不然会出错
try {
str = URLDecoder.decode(str, "utf-8");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
message = message + str;
System.out.println("信息接收!" + message);
for (Session s : set) {
try {
s.getBasicRemote().sendText(message); //也要把user的str发过去
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
@OnError
public void onError(Throwable t) throws Throwable {
System.out.println("系统异常");
}
}
注意前后端交互时方便使用后端传的数据需要导入js的jquery库
5.建立数据库连接数据库:
连接数据库:
package com.util;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
public class DButils {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://localhost:3306/test1";
static final String USER = "root";
static final String PASS = "1828808086";
static Connection conn = null;
public static Connection getConnection() {
try {
//加载oracle驱动
Class.forName(JDBC_DRIVER);
//通过驱动获取数据库的连接
conn = DriverManager.getConnection(DB_URL, USER, PASS);
System.out.println("连接成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return conn;
}
public static void Close() {
try {
if (conn != null) {
conn.close();
}
} catch (SQLException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
最后附上笔者代码文件:
https://gitee.com/liaoshengyuan/webtest.git
常见错误及其解决方法:
1.检查连接数据库未导入connector jar包
官方下载对应版本的jar包
2.tomact服务器显示子目录出错
检查后端servlet代码的servlet地址有没有出错一定一定要避免重复
3.session覆盖问题
开启多个浏览器来运行