目录
1.数据库设计
这里用MySQL数据库,借助phpstudy可快速安装
列名 | 类型 | 长度 | 备注 |
id | smallint | 10 | 主键 |
username | varchar | 10 | 用户登录名 |
password | varchar | 10 | 登录密码 |
name | varchar | 15 | 用户姓名 |
sex | varchar | 2 |
用户性别 |
建一个test数据库
create database test;
建表
create table user(
id smallint(10) NOT NULL auto_increment PRIMARY KEY,
username varchar(10) default NULL,
password varchar(10) default NULL,
name varchar(15) default NULL,
sex varchar(2) default NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
插入几条用户数据
insert into user values('1', '历', '123', '阿良良木历', '男');
insert into user values('2', '吸血鬼', '123', '忍野忍', '女');
insert into user values('3', '毒舌', '123', '战场原黑仪', '女');
insert into user values('4', '班长', '123', '羽川翼', '女');
2.连接数据库的JavaBean
首先引入mysql的jdbc驱动jar包,放在 \WebRoot\WEB-INF\lib\ 目录下面
该 JavaBean 提供了连接数据库的方法 getConnction()
/src/bean/Dbcon.java
package bean;
import java.sql.Connection;
import java.sql.DriverManager;
public class DBcon {
private static final String DRIVER_CLASS = "com.mysql.cj.jdbc.Driver";
private static final String DATABASE_URL = "jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8";
private static final String DATABASE_USRE = "root";
private static final String DATABASE_PASSWORD = "123456";
public static Connection getConnction() { //返回连接
Connection dbCon= null;
try {
Class.forName(DRIVER_CLASS);
dbCon = DriverManager.getConnection(DATABASE_URL,DATABASE_USRE, DATABASE_PASSWORD);
} catch (Exception e) {
e.printStackTrace();
}
return dbCon;
}
}
3.用户登录程序设计
编写 javascript ,定义一个检查表单中是否将用户名和密码输入完整的函数 fnc()
当聊天者按“登录”按钮后,会调用 fnc()方法进行
如果用户名和密码输入不完整,则给出提示
如果输入完整则提交给 checkuser.jsp 进行数据库用户正确性验证,提交时会携带表示用户名和和密码的“loginname”和“password”参数
/WebRoot/index.jsp
<%@ page import="java.util.*" contentType="text/html;charset=utf-8"%>
<html>
<head>
<title>登录</title>
</head>
<body>
<div style="text-align:center;font-weight:bold">聊天室登录</div>
<div style="text-align:center">
<form name="frm" method="post" action="checkuser.jsp">
<label><b>用户名:</b></label>
<input type="text" name="loginname"><br><br>
<label><b>密 码:</b></label>
<input type="password" name="password"><br><br>
<input type=button value='登录' onclick="fnc()">
</form>
</div>
<Script>
function fnc() {
if (frm.loginname.value == "" || frm.password.value == "") {
window.alert("请输入用户名与密码!");
document.frm.elements(0).focus(); //表单中的第一个输入框可以获得焦点
return;
}
frm.submit();
}
</Script>
</body>
</html>
/WebRoot/checkuser.jsp
<%@ page language="java" import="java.util.*,java.sql.*" pageEncoding="utf-8"%>
<jsp:useBean id="db" class="bean.DBcon" scope="request"/>
<html>
<body>
<% //登录数据库,进行用户验证
Connection con = db.getConnction();
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select * from user"+" where username = '" + request.getParameter("loginname") + "'");
if(!rs.next()) //用户验证失败,提示重新登录
{
%>
<div>很遗憾,数据库中没有"<%=request.getParameter("loginname")%>"这个用户!<br>
<a href="index.jsp">请重新登录!</a>
</div>
<%
}
else //用户验证成功
{
%>
<div>
<div><%= rs.getString("name") %> 同学,登录成功!</div>
<div>您的登录名是:<%=request.getParameter("loginname")%></div>
<div>您的 IP 地址是:<%= request.getRemoteAddr()%></div>
</div>
<%
String name=rs.getString("name");
String sex=rs.getString("sex");
session.setAttribute("name",rs.getString("name"));
session.setAttribute("sex",rs.getString("sex"));
String opwin="login.jsp?name=" + name + "&sex=" + sex;
%>
<script>
function opwinfnc(){
window.open("<%=opwin%>","_blank");
}
</script>
<div>
<button name="chatbutton" onclick="opwinfnc()">进入聊天室</button>
</div>
<%
}
rs.close();
stmt.close();
con.close();
%>
</body>
</html>
4.进入聊天室的准备工作
通过 window.open()方法打开的聊天窗口中,首先载入的是 login.jsp
它进行聊天室程序的个性化信息和公共信息的初始化工作
将聊天者的姓名和性别存入 session 对象,对 application 对象中的相关数据进行初始化与维护
在application中以属性的形式创建三个字符串数组(talki,visitnami,visitsexi),分别保存聊天记录、聊天者姓名和性别
完成所有准备工作后转到聊天室窗口程序 frame.jsp
/WebRoot/login.jsp
<%@ page contentType="text/html; charset=utf-8"%>
<%@ page import="java.util.Date,java.text.SimpleDateFormat"%>
<%
String guestname=request.getParameter("name");
String guestsex=request.getParameter("sex");
session.setAttribute("nam0",guestname);
session.setAttribute("sex0",guestsex);
int i = 0, talker = 0; //talker用于计算聊天室人数的变量
Object talk = null;
Object visitnam = null;
Object visitsex = null;
//调整聊天室的人数,talker为聊天室人数,存于 application
String talkerstr=(String)application.getAttribute("talker");
if(talkerstr == null) {
//如为第一位进入聊天室,则聊天室人数 talker 置 1
//同时,在 application 中设定可保存的聊天语句数 sentence为 50 条,超出 50 条时则按先进先出规则替换
application.setAttribute("talker", "1");
application.setAttribute("sentence", "50");
} else {
talker = Integer.parseInt(talkerstr); //否则,聊天室人数 talker+1
application.setAttribute("talker", String.valueOf(talker+1));
}
//sentence是在 application中设定的可保存的聊天语句数
String sentencestr = (String)application.getAttribute("sentence");
int sentence = Integer.parseInt(sentencestr);
//为保存聊天语句准备空间
//如为第一位聊天者,则初始化发言记录的整个空间
if(talker == 0) {
for(i=1;i<=sentence;i++) {
application.setAttribute("talk"+i,"");
application.setAttribute("visitnam"+i,"");
application.setAttribute("visitsex"+i,"");
}
} else{
//如已有发言,则将所有发言记录数组及姓名、性别数组向后挪一格,为填入新进人员欢迎词及新进人员姓名、性别挪出空间
for(i = sentence; i >= 2; i--) {
talk = application.getAttribute("talk"+(i - 1));
application.setAttribute("talk"+i, talk);
visitnam = application.getAttribute("visitnam"+(i - 1));
application.setAttribute("visitnam"+i, visitnam);
visitsex = application.getAttribute("visitsex"+(i - 1));
application.setAttribute("visitsex"+i, visitsex);
}
}
//聊天记录数组的首行,填入新进人员的姓名和性别
application.setAttribute("visitnam1", guestname);
application.setAttribute("visitsex1", guestsex);
//构建欢迎词,作为一条发言填入首行
String tking = null;
Date dat = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD HH:mm:ss");
String tim=sdf.format(dat);
tking = "<tr><td bgcolor = 'yellow' align='left'>欢迎"+guestname+"! "+tim+"</td></tr>";
application.setAttribute("talk1", tking);
//客户端跳转到聊天显示页面
response.sendRedirect("frame.jsp");
%>
5.创建聊天窗口框架
聊天室窗口界面设计
将聊天室窗口分成三个子窗口 frame0、frame1、frame2
使用 Session 对象存放聊天者自己的姓名、性别等个人信息
使用 Application 对象存放聊天室的公共信息,例如所有人的发言记录、聊天室成员等等
这里我使用jquery实现页面的局部刷新, frame0和frame2每3秒刷新一次,frame1不刷新
jquery下载地址
在WebRoot目录下创建一个jquery文件夹,将下载完的jquery.js文件放入该文件夹中
导入该文件Syntax error on token "catch", Identifier expected报错的解决方案
/WebRoot/frame.jsp
<%@ page contentType="text/html; charset=utf-8" import="java.util.Date,java.text.SimpleDateFormat"%>
<%
//取出在 login.jsp页面存入的本人姓名和性别
String guestnam = (String)session.getAttribute("nam0");
String guestsex = (String)session.getAttribute("sex0");
%>
<html>
<head>
<title>欢迎<%= guestnam%>进入聊天室</title>
</head>
<body>
<div style="width:100%;height:100%;border:3px solid brown;">
<div style="width:80%;height:100%;float:left">
<div id="frame0" style="width:100%; height:60%;overflow-y:auto;">
<%
//先从 application对象中获取聊天室人数"talker"
String talkerstr=(String)application.getAttribute("talker");
%>
<div style="color:green">
<h4>【现在聊天室中有<%=talkerstr%>位访问者】</h4>
</div>
<table>
<%
//从 application对象中获取可保存的聊天语句数 sentence
String sentencestr = (String) application.getAttribute("sentence");
int sentence = Integer.parseInt(sentencestr);
//循环输出 application 对象中的所有聊天语句 talki
for(int i = 1; i <= sentence; i++){
String content = (String)application.getAttribute("talk" + i);
//发言内容为null,就不输出
if(content == null) continue;
%>
<tr><%= content %></tr>
<%
}
%>
</table>
</div>
<div id="frame1" style="width:100%;height:40%;border-top:3px solid brown;padding:5px 5px">
<form name=frm1 action="talking.jsp" method="post" target="fram0">
<%= guestnam %>:<br>
<textarea rows="2" cols="60" name="txttalk"></textarea><br><br>
<button onclick="chk()">发言</button>
<button name="reset1" type="reset">清除</button>
</form>
<form name=frm2 action="logout.jsp" method="post">
<button type="submit" onclick="lgot()">退出聊天</button>
</form>
</div>
</div>
<div id="frame2" style="width:19%;height:100%;float:right;border-left:3px solid brown;padding:1px 1px">
<div style="color:blue">
聊天室人员
<hr>
<%
int talker = Integer.parseInt(talkerstr);
for(int i = 1; i <= talker; i++) {
%>
<%= application.getAttribute("visitnam" + i)%>
<%= application.getAttribute("visitsex" + i)%><br>
<%
}
%>
</div>
</div>
</div>
<script src="jquery/jquery.js"></Script>
<script>
// frame0和frame2每3秒刷新一次
setInterval(function() {
$("#frame0").load(location.href+" #frame0>*","");
$("#frame2").load(location.href+" #frame2>*","");
}, 3000);
function chk(){
if(frm1.txttalk.value == ""){
return;
} else {
frm1.submit();
frm1.txttalk.value == "";
}
}
function lgot(){
top.close();
}
</Script>
</body>
</html>
6.聊天信息处理
在 fram1 框架的“发言”文本框中输入了发言内容后,单击“发言”按钮,便将含有发言信息的表单提交给 talking.jsp 进行处理
/WebRoot/talking.jsp
<%@ page import="java.util.Date,java.text.SimpleDateFormat" contentType="text/html;charset=utf-8" %>
<%
String guestnam = (String) session.getAttribute("nam0");
//整体向后挪一行,本次发言填入首行;application 中的"sentence"为设定的聊天语句数。
String sentencestr = (String) application.getAttribute("sentence");
int sentence = Integer.parseInt(sentencestr);
for(int i = sentence; i >= 2; i--){
String talk = (String)application.getAttribute("talk" + (i - 1));
application.setAttribute("talk" + i, talk);
}
String[] strNow3 = new SimpleDateFormat("HH:mm:ss").format(new Date()).toString().split(":");
String hour = strNow3[0]; //获取时(24小时制)
String minute = strNow3[1]; //获取分
String second = strNow3[2]; //获取秒
String tim = hour + ":" + minute + ":" + second;
//接收 frame1 传来的发言("txttalk"),前后加入姓名和时间,填入记录数组首行.
String talking = "<td>" + guestnam +"【"+tim+"】:" +request.getParameter("txttalk") + "</td>";
application.setAttribute("talk1", talking);
response.sendRedirect("frame.jsp");
%>
7.退出机制
在 fram1 框架中,还有一个退出表单 frm2,该表单中只有一个名为“退出聊天”的按钮
单击“退出聊天”按钮,程序便提交给 logout.jsp 进行退出处理
/WebRoot/logout.jsp
<%@ page contentType="text/html; charset=utf-8" import="java.util.Date,java.text.SimpleDateFormat"%>
<%
String guestnam = (String) session.getAttribute("nam0"); //拿到退出聊天者的姓名
String talk = null;
Object visitnam = null;
Object visitsex = null;
String visittmp = null;
String vnmtmp = null;
String sentencestr = (String) application.getAttribute("sentence");
int sentence = Integer.parseInt(sentencestr);
String tmp;
int kint=0;
//由于 visitnami 要退出聊天室,所以要将这个姓名连同性别从 application 对象中删除
for(int i = 1; i <= sentence; i++){
tmp=(String)application.getAttribute("visitnam"+i);
if(tmp.equals(guestnam))
kint = i;
}
//删除的方法是将在它后面的姓名连同性别依次向前挪动一个位置
for(int i = kint; i <= sentence; i++){
tmp=(String) application.getAttribute("visitnam"+(i+1));
application.setAttribute("visitnam"+i,tmp);
tmp=(String) application.getAttribute("visitsex"+(i+1));
application.setAttribute("visitsex"+i,tmp);
}
application.setAttribute("visitnam"+sentence,"");
application.setAttribute("visitsex"+sentence,"");
//将所有 talki后移一位,留出第一个位置存放离开谢词
for(int i = sentence; i >= 2; i--){
talk = (String)application.getAttribute("talk" + (i - 1));
application.setAttribute("talk" + i, talk);
}
Date dat = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("YYYY-MM-DD HH:mm:ss");
String tim=sdf.format(dat);
String tking;
tking = "<tr><td bgcolor = cyan align=left>谢谢"+guestnam+"光顾! 离开时间:"+tim+"</td></tr>";
application.setAttribute("talk1", tking);
//将聊天室中的人数 talker减 1,再存入 Application 对象的 talker属性中
String talkerstr = (String)application.getAttribute("talker");
int talker = Integer.parseInt(talkerstr);
application.setAttribute("talker", String.valueOf(talker - 1));
%>
<html>
<head>
<script>
function logoutcls(){
self.close(); //关闭本操作窗口
}
</script>
</head>
<body onload="logoutcls()"></body>
</html>
8.设计过滤器统一解决参数传递时可能出现的中文乱码问题
/src/filter/CharacterEncodingFilter.java
package filter;
import java.io.IOException;
import javax.servlet.*;
public class CharacterEncodingFilter implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("utf-8"); //设置获取请求参数时所使用的编码集合
chain.doFilter(request, response);
}
public void init(FilterConfig arg0) throws ServletException {
}
}
在 web.xml中对过滤器进行配置,代码如下,放在<web-app></web-app>里面
<filter>
<filter-name>character</filter-name>
<filter-class>filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>character</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
9.效果演示
我这里用两个不同浏览器模拟(数据库记得打开)
ps: 有点小bug,会多一个聊天室的窗口,也不知道是因为什么。。。o(╥﹏╥)o