一、实验目的
1、掌握各个内置对象的含义;
2、理解并熟练应用session、application对象。
二、实验内容
1、设计聊天室,在聊天室中,需要通过JSP内置对象application来实时保存特定数量的当前聊天信息。
聊天室的设计包括:用户进行登录,选择聊天室,进行聊天,退出聊天室。 在聊天室中,用户只需输入一个用户名就可以进入聊天室,但是如果当前有人在使用该用户名,那么就必须换一个唯一的用户名。
具体要求:
- 用户登录成功后,程序会要求用户选择聊天室。可以不设置用户自行建立聊天室的功能,而且在聊天中途不能从一个聊天室切换到另一个聊天室。
- 进入聊天室后,用户可以从用户信息窗口看到该聊天室中所有用户的用户名,也可以在聊天窗口中看到随时更新的聊天信息。用户可以给所有人或某一个聊天用户发送公共的聊天信息,这个聊天内容大家都可以看到。用户也可以给某个用户发送私人的聊天信息,这种信息属于私聊信息,只有发送者和接收者可以看到。此外,聊天窗口还会出现一些系统公告,比如某某上站、某某离开等消息,另外用户还可以自己定义聊天信息和聊天用户信息刷新的时间间隔。
- 在用户单击“退出”按钮后,页面关闭,同时application和session中保存的信息都将丢失。
静态聊天登陆界面:
整体的聊天界面
登陆成功界面(自己不能和自己聊天):
重复登陆会给用户反馈(返回到登陆界面):
多个用户登陆(用户列表实时更新,可显示当前用户登陆的名字):
公共聊天:发送公共消息只在公共聊天区域显示
公共聊天:
私人聊天:私聊在对方私聊区域显示
C位收到消息
点击退出按钮退出,刷新按钮刷新
三、实验方法
1、用户登录信息使用request对象getParameter()方法得到用户登陆的一些信息;
2、公聊信息可以使用application对象,私聊信息使用session对象。
3、聊天的信息要不断刷新页面,使用户实时看到聊天信息。
4、用户退出时,有两种情况需要考虑:一是用户点击“退出”按钮,二是关闭浏览器,强制退出窗口,可查阅windows感知浏览器关闭的事件的相应方法。
四、实验代码
login.jsp:(其实是html,但我写成jsp)
<%@ page contentType="text/html;charset=UTF-8" %>
<!-- 用户登陆界面 -->
<!-- 未添加标签前半部分的<html>,谷歌浏览器会自动识别添加,但是其他浏览器不可以,查看 -->
<!DOCTYPE html>
<html>
<head>
<title>用户登录</title>
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous">
<link rel="stylesheet" type="text/css" media="screen" href="login.css">
</head>
<body>
<section>
<!-- 顶部的“用户登陆/login” -->
<div class="top">
<ul id="loginUl">
<li style="display: inline; padding: 2em;">
<h2 id="h2">Let's chat</h2>
</li>
</ul>
</div>
<!-- 下划线 -->
<hr style="width: 300px">
<!-- 表单部分 -->
<div class="main">
<!-- 表单 -->
<!-- 在地址栏隐藏用户信息 -->
<form action="checkLogin.jsp" name="form" method=POST>
<ul id="mainUl">
<!-- 用户名 -->
<li>username <br> <input type="text" name="username"
id="username" size="17">
</li>
<!-- 登陆按钮 -->
<li>
<button type="submit" class="btn btn-outline-primary"
style="margin-left: 50px;margin-top: 20px;"
>Log In</button>
</li>
</ul>
</form>
</div>
</section>
</body>
</html>
login.css:
@charset "UTF-8";
section {
/*设置四个角为圆滑型*/
border-radius: 8px;
/*设置外边距*/
margin: 100px auto auto auto;
/*设置显示1像素的外边距*/
border: 2px solid rgb(120, 172, 214);
/*背景颜色*/
background-color: rgb(202, 233, 245);
height: 350px;
width: 350px;
}
#loginUl {
list-style: none;
margin-top: 29px;
}
#h2 {
color: dodgerblue;
font-size: 1.5em;
display: inline;
margin-left: auto;
margin-right: auto;
}
#mainUl {
list-style: none;
color: dodgerblue;
margin-top:20px;
margin-left: 30px;
}
/* label默认是内联元素,不可以设置宽度,使其变为一个块级元素 */
#autoRandom {
display: inline-block;
background-color: white;
text-align: center;
width: 50px;
height: 19.33px;
color: red;
border: 0.5px solid rgb(122, 184, 199);
}
#span {
color: crimson;
font-size: 1em;
margin-left: 80px;
margin-top: 10px;
}
.typeMain{
margin-left: 20px;
height: 130px;
width: 300px;
}
checkLogin.jsp
<%@page import="java.text.SimpleDateFormat"%>
<%@page import="java.util.*"%>
<%@ page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>验证登陆界面</title>
</head>
<!-- 验证用户登陆的信息 -->
<body>
<%
//设置客户端的字符编码
request.setCharacterEncoding("UTF-8");
//获取表单中提交过来的值
String username = request.getParameter("username");
//String pwd = request.getParameter("password");
//从applicaton作用域中取出用户列表
List<Object> userList = (List<Object>) application.getAttribute("userList");
//如果该用户列表还不存在,实例化该用户列表
if (userList == null) {
userList = new ArrayList<Object>();
}
//查看当前列表中是否包含当前的登陆用户
if (userList.contains(username)) {
//存在已登录客户则提示
out.print("<script>alert('该用户已登录,重新选择!');window.location.href='login.jsp'</script>");
return;
}
//将当前登陆用户名加入该用户列表
userList.add(username);
//设置application和session当中的用户列表
application.setAttribute("userList", userList);
//方便用户的销毁以及获得当前用户,使用session是一个用户在当前浏览器一个ID
session.setAttribute("user", username);
//记录用户登陆的时间
Date systemTime = new Date();
//此处实例化time对象并获得时间
SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String userLoginTime = time.format(systemTime);
//放入到applicaion当中,和新登录的用户事件进行比较
session.setAttribute("userLoginTime", userLoginTime);
//转向聊天界面
//聊天界面需要获得当前的用户并显示出来
response.sendRedirect("chat.jsp");
%>
</body>
</html>
chat.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@page import="java.util.*"%>
<%@page import="java.text.SimpleDateFormat"%>
<!doctype html>
<html>
<!-- 聊天界面,实时刷新 -->
<head>
<title>Let's chat</title>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport"
content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T"
crossorigin="anonymous">
<link rel="stylesheet" href="chatUI.css">
<script type="text/javascript">
//防刷新冲掉原来选择的按钮
function save() {
radios = document.getElementsByName("radio");
for (i = 0; i < radios.length; i++) {
if (radios[i].checked) document.cookie = 'radioindex =' + i;
}
}
window.onload = function () {
var cooki = document.cookie;
if (cooki != "") {
cooki = "{\"" + cooki + "\"}";
cooki = cooki.replace(/\s*/g, "").replace(/=/g, '":"').replace(/;/g, '","');
var json = eval("(" + cooki + ")"); //将coolies转成json对象
document.getElementsByName("radio")[json.radioindex].checked = true;
}
else
save();
}
function exit()
{
if((document.body.clientWidth-event.clientX)<15&&event.clientY<0||event.altKey)
{
//处理相关事项
var exitEvent = new ActiveXObject("Microsoft.XMLHTTP");
exitEvent.open("POST","logout.jsp",false);
exitEvent.send();
exitEvent = null;
}
}
</script>
</head>
<body>
<section id="chatUI">
<header class="top">
<div class="jumbotron jumbotron-fluid my-3 py-1"
style="height: 30px;">
<div class="container">
<!-- 获得当前登陆的用户并显示 -->
<%
//要使用不同的浏览器进行登陆!!!!!!否则session都是通过一个ID
String username = (String)session.getAttribute("user");
%>
<p>
<strong style="padding-left: 140px;"><%=username%></strong>
</p>
</div>
</div>
</header>
<div id="mainDiv">
<!-- 未添加post,页面刷新消息会一直重复之前发送的!!!!!! -->
<form action="" method="post">
<!-- 显示所有用户 -->
<!-- 使用request.getParameter()获得用户登陆参数 -->
<aside class="aside" name="aside" id="aside">
Online users<br>
<!-- 插入单选按钮 -->
<ul>
<li><input type="radio" name="radio" value="所有人" onclick="save()">所有人
<!-- 从列表当中获得用户的名字 并放入到单选按钮中-->
<%
//需要实时更新用户列表,用户的登陆和注销
response.setHeader("refresh", "10");
List<Object> userList = (List<Object>) application.getAttribute("userList");
for (int i = 0; i < userList.size(); i++) {
String user = (String)userList.get(i);
if(!user.equals(username)){
%>
<li><input type="radio" name="radio" value="<%=user%>" onclick="save()"><%=user%></li>
<%}
%>
<%
}
%>
</ul>
</aside>
<main>
<!-- 显示消息 -->
<!-- 显示聊天记录 -->
<iframe src="showPubMes.jsp" frameborder="0">
</iframe>
<iframe src="showPriMes.jsp" frameborder="0">
</iframe>
<!-- 输入发送消息 -->
<textarea name="inputMes" id="inputMes" cols="1" rows="10" placeholder="Input your message!"></textarea>
<!-- 退出 -->
<input type="button" class="btn btn-primary py-1 my-1" value="Logout" onclick="window.location.href='logout.jsp'">
<!-- 刷新 -->
<input type=button class="btn btn-primary py-1 my-1" value="refresh" onclick="location.reload()">
<!-- 发送按钮 -->
<input type="submit" class="btn btn-primary py-1 my-1" value="Send" style="margin-left:220px">
</form>
</main>
</div>
</section>
<%
//获取当前系统时间,显示信息发送时间
Date systemTime = new Date();
//规定日期显示的格式
SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//获得的时间转化为字符串,可添加到消息当中
String chatTime = time.format(systemTime);
//设置用户端的字符编码
request.setCharacterEncoding("UTF-8");
//获得用户的输入的消息
String mes = request.getParameter("inputMes");
//获得当前用户
String user = (String)session.getAttribute("user");
//获得当前单选按钮的值-->String
String radio = request.getParameter("radio");
//创建消息的盒子
List<Object> msgs = (List<Object>) application.getAttribute("msgs");
if(msgs==null){
msgs = new ArrayList<Object>();
}
//第一次写私聊时:不使用列表的方式存储接收方和发送方,直接在当前页面获取用户名再转向showMes页面,在showMes页面获取到当前用户以及该用户点击的按钮值,再进行判断??????????--出错^@^
//这是不可行的,只要浏览器未关闭application就没有关闭,都是使用的同一个application
//私聊部分,无论私聊还是公聊都将其存入一个列表当中,在取的时候再进行判断
//私聊需要获得按扭的值
//接收方
List<Object> to_sb = (List<Object>) application.getAttribute("receiver");
if (to_sb == null) {
to_sb = new ArrayList<Object>();
}
//发送方,私聊
List<Object> from_sb = (List<Object>) application.getAttribute("sendor");
if (from_sb == null) {
from_sb = new ArrayList<Object>();
}
if(mes!=null && !mes.equals("")){
//当按下发送按钮后消息和接收方和发送方分别写入各自的列表当中
//将消息和接受方都加入到消息盒子当中
msgs.add(user + "发送消息 (" + mes +") 给" + radio + " " + chatTime + "<br/>");
//将接收方加入列表
to_sb.add(radio);
//将当前用户(发送方)加入列表
from_sb.add(user);
//浏览器不关闭application一直存在,那么各登陆的用户列表也一直不变
//在application设置消息列表的消息
application.setAttribute("msgs", msgs);
//将接收方和发送方的列表存入application当中
//也不可以用session,一个session只在当前的浏览器获得当前浏览器的Attribute,所以receiver和sendor不能更新
//session.setAttribute("receiver", radio);
//session.setAttribute("sendor", user);
application.setAttribute("receiver", to_sb);
application.setAttribute("sendor", from_sb);
}
%>
</body>
</html>
chatUI.css
@charset "UTF-8";
#chatUI {
margin: auto;
height: 480px;
width: 600px;
}
.top {
width: 600px;
margin: auto;
height: 30px;
}
.overUI p {
margin-top: 5px;
margin-bottom: 5px;
}
.aside {
float: left;
width: 150px;
height: 450px;
background-color: #e9ecef;
}
#mainDiv {
width: 600pxpx;
height: 450px;
}
section main {
background-color: snow;
width: 450px;
float: right;
height: 450px;
}
#inputMes {
padding: 0;
outline: none;
height: 68px;
width: 450px;
float: right;
}
#showMes {
padding: 0;
border: 0;
outline: none;
height: 340px;
width: 450px;
float: right;
}
#inputMesDiv {
background-color: white;
margin-left: 390px;
}
iframe{
width: 220px;
height: 330px;
}
chowPriMes.jsp
<%@page import="java.text.SimpleDateFormat"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<%
response.setHeader("refresh", "1");
out.print("private chat" + "<br>");
List<Object> msgs = (List<Object>) application.getAttribute("msgs");
List<Object> from_sb = (List<Object>) application.getAttribute("sendor");
List<Object> to_sb = (List<Object>) application.getAttribute("receiver");
//设定时间的格式
SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//获得用户登陆的时间
String userLoginTime = (String) session.getAttribute("userLoginTime");
//将字符串形式的用户时间格式化为Date类型
Date uTime = time.parse(userLoginTime);
//也不可以用session,一个session只在当前的浏览器获得当前浏览器的Attribute,所以receiver和sendor不能更新
//String user =(String) session.getAttribute("user");
//String receiver = (String) session.getAttribute("receiver");
//从session当中获取当前用户
String user = (String) session.getAttribute("user");
//需要加上try catch,不加上则会在客户端显示错误,需要抛给上一级进行解决
try {
for (int i = 0; i < msgs.size(); i++) {
String msg = (String) msgs.get(i);
//获得消息时,就会获得对应的发送方和接收方
String receiver = (String) to_sb.get(i);
String sendor = (String) from_sb.get(i);
//截取存储在消息盒子中的日期
String chatTime = msg.substring(msg.length() - 24, msg.length() - 5);
//将字符串时间转换成标准格式的时间(聊天时间)
Date cTime = time.parse(chatTime);
//判断是公聊还是私聊
//receiver(接收方)和当前用户是相等的那么当前用户就显示消息
//sendor是让发送方显示自己的消息
//“所有人”因为使用的是同一个application,就会receiver就会都是“所有人”,满足条件就显示
//用户登陆的时间比聊天列表的时间早才将聊天记录显示
if (uTime.before(cTime)) {
if (receiver.equals(user) || sendor.equals(user)) {
if(!receiver.equals("所有人")){
out.print(msg);
}
} else {
out.print("");
}
} else {
out.print("");
}
}
} catch (Exception e) {
}
%>
</body>
</html>
showPubMes.jsp
<%@page import="java.text.SimpleDateFormat"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="java.util.*"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<%
response.setHeader("refresh", "1");
out.print("public chat"+"<br>");
List<Object> msgs = (List<Object>) application.getAttribute("msgs");
List<Object> from_sb = (List<Object>) application.getAttribute("sendor");
List<Object> to_sb = (List<Object>) application.getAttribute("receiver");
//设定时间的格式
SimpleDateFormat time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//获得用户登陆的时间
String userLoginTime = (String) session.getAttribute("userLoginTime");
//将字符串形式的用户时间格式化为Date类型
Date uTime = time.parse(userLoginTime);
//也不可以用session,一个session只在当前的浏览器获得当前浏览器的Attribute,所以receiver和sendor不能更新
//String user =(String) session.getAttribute("user");
//String receiver = (String) session.getAttribute("receiver");
//从session当中获取当前用户
String user = (String) session.getAttribute("user");
//需要加上try catch,不加上则会在客户端显示错误,需要抛给上一级进行解决
try {
for (int i = 0; i < msgs.size(); i++) {
String msg = (String) msgs.get(i);
//获得消息时,就会获得对应的发送方和接收方
String receiver = (String) to_sb.get(i);
String sendor = (String) from_sb.get(i);
//截取存储在消息盒子中的日期
String chatTime = msg.substring(msg.length() - 24, msg.length() - 5);
//将字符串时间转换成标准格式的时间(聊天时间)
Date cTime = time.parse(chatTime);
//判断是公聊还是私聊
//receiver(接收方)和当前用户是相等的那么当前用户就显示消息
//sendor是让发送方显示自己的消息
//“所有人”因为使用的是同一个application,就会receiver就会都是“所有人”,满足条件就显示
//用户登陆的时间比聊天列表的时间早才将聊天记录显示
if (uTime.before(cTime)) {
if (receiver.equals("所有人") ) {
out.print(msg);
}
}else{
out.print("");
}
}
} catch (Exception e) {
}
%>
</body>
</html>
logout.jsp
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<%
List<Object> userList = (List<Object>)application.getAttribute("userList");
String user = (String)session.getAttribute("user");
userList.remove(user);
//需要注销该用户,未写上这句-->出错:退出当前用户,其他页面给上的"当前用户就会从session当中获取用户名并显示
session.invalidate();
//更新application当中用户列表
application.setAttribute("userList", userList);
//返回到登陆界面
response.sendRedirect("login.jsp");
%>
</body>
</html>
五、实验问题
当在输入框输入消息,到了刷新时间,输入的消息会不见,这也是js的一大缺点,需要用ajax解决。
私聊记得要使用不同的浏览器!!!!!!!!不同浏览器session的id才会不同。