实现业务逻辑组件
系统没有采用数据库存储用户信息,而是使用Properties文件存放用户名和密码。所有的用户登录、新用户注册都需要Properties文件校验。
ChartServlet.java文件
package dem.com;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.*;
public class ChartServlet {
//使用单例模式来设计ChartServlet
private static ChartServlet cs;
//使用Properties对象保存聊天信息
private Properties userList;
//使用LinkedList对象保存聊天信息
private LinkedList<String> chatMsg;
//构造函数
private ChartServlet(){
}
//通过静态方法返回唯一的ChartServlet对象
public static ChartServlet instance(){
if(cs==null){
cs=new ChartServlet();
}
return cs;
}
//读取系统用户信息
private Properties loadUser() throws IOException{
if(userList==null){
//加载userFile.properties文件
File f=new File("userFile.properties");
//如果文件不存在,新建该文件
if(!f.exists()){
f.createNewFile();
}
//新建Properties文件
userList=new Properties();
//读取userFile.properties文件里的用户信息
userList.load(new FileInputStream(f));
}
return userList;
}
//保存系统所有用户
private boolean saveUserList() throws IOException{
if(userList==null){
return false;
}
//将userList信息保存Properties文件中
userList.store(new FileOutputStream("userFile.properties"),"Users Info List");
return true;
}
//验证用户登录
public boolean validLogin(String user,String pass)
throws IOException{
//根据用户名获取密码
String loadPass=loadUser().getProperty(user);
//登录成功
if(loadPass!=null&&loadPass.equals(pass)){
return true;
}
return false;
}
//新注册用户
public boolean addUser(String name,String pass)throws Exception{
//当userList为null时,初始化userList对象
if(userList==null){
userList=loadUser();
}
//如果userList是已经注册的用户
if(userList.containsKey(name)){
throw new Exception("用户名已经存在,请重新选择用户名");
}
userList.setProperty(name,pass);
saveUserList();
return true;
}
//获取系统所有聊天信息
public String getMsg(){
//如果chatMsg对象为null,表明不曾开始聊天
if(chatMsg==null){
chatMsg=new LinkedList<String>();
return "";
}
StringBuilder result=new StringBuilder();
//将chatMsg中所有聊天信息拼接起来
for(String line:chatMsg){
result.append(line+"\n");
}
return result.toString();
}
//用户发言,添加聊天信息
public void addMsg(String user,String msg){
//如果chatMsg对象为null,初始化chatMsg对象
if(chatMsg==null){
chatMsg=new LinkedList<String>();
}
//最多保存40条聊天信息,当超过40条时,将前面的聊天信息删除
if(chatMsg.size()>40){
chatMsg.removeFirst();
}
chatMsg.add(user+"说:"+msg);
}
}
注册、登录视图
本系统含有三个视图,分别对应于用户登录、用户注册和用户聊天三个用户界面
登录页面index.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>登录页面</title>
</head>
<body>
<center>
<div style="width: 540px;border: 1px solid lightgray;background-color:gray;">
<div style="color:red;">
${requestScope.tip}
</div>
<form id="loginForm" method="post" action="login.do">
<table border="0">
<tr>
<td colspan="2" align="center">
请输入用户名和密码登录
</td>
</tr>
<tr>
<td>用户名:</td>
<td><input type="text" id="name" name="name" required/></td>
</tr>
<tr>
<td>密 码</td>
<td><input type="password" id="pass" name="pass" required/></td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="submit" value="提交"/>
<input type="reset" value="重置"/>
</td>
</tr>
</table>
<br/>
<div align="center">
<a href="reg.jsp">注册用户</a>
</div>
</form>
</div>
</center>
</body>
</html>
注册页面reg.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>注册页面</title>
</head>
<body>
<form action="reg.do" method="post">
账号<input type="text" name="name"/><br/>
密码<input type="password" name="pass"/><br/>
<input type="submit" value="注册">
</form>
<center>${requestScope.tip}</center>
</body>
</html>
聊天页面chat.html
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>聊天页面</title>
<script type="text/javascript">
//创建XMLHttpRequest()对象
var xhr=new XMLHttpRequest();
//发送请求函数
function sendRequest(){
//用户输入聊天信息的单行文本框
var input=document.getElementById("chatMsg");
var chatMsg=input.value;
//定义open方法取得与服务器的链接
var url="chat.do";
//通过open方法取得与服务器的连接
//发送post请求
xhr.open("POST",url,true);
//设置请求头,发送post请求时需要该请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
//指定处理服务器响应事件处理函数
xhr.onload=processResponse;
//清空输入框的内容
input.value="";
//发送请求,send的参数包含许多的key-value对
//即以:请求参数名=请求参数值的形式发送请求参数
xhr.send("chatMsg="+chatMsg);
}
function sendEmptyRequest(){
//定义发送请求的目标URL
var url="chat.do";
//发送POST请求
xhr.open("POST",url,true);
//设置请求头,发送POST请求时需要该请求头
xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
//指定处理服务器响应的事件处理函数
xhr.onload=processResponse;
//发送请求,不发送任何参数
xhr.send(null);
//指定0.8秒之后再次发送请求
setTimeout("sendEmptyRequest()",800);
}
//定义处理响应的回调函数
function processResponse(){
//服务器响应正确
if(xhr.status==200){
document.getElementById("chatArea").value=xhr.responseText;
}else{
window.alert("您所请求的页面异常"+xhr.status);
window.open("index.jsp",true);
}
}
function enterHandler(event){
//获取用户单击键盘的“键值”
var keyCode=event.keyCode?event.keyCode:event.which?event.which:event.charCode;
//如果是回车键
if(keyCode==13){
sendRequest();
}
}
</script>
</head>
<body onload="sendEmptyRequest()">
<div style="width:780px;border: 1px solid black;text-align: center">
<h3>聊天页面</h3>
<p>
<textarea id="chatArea" name="chatArea" cols="90" rows="20" readonly="readonly"></textarea>
</p>
<div align="center">
<input id="chatMsg" type="text" name="chatMsg" size="90" onkeypress="enterHandler(event);"/>
<input type="button" name="button" value="提交" onclick="sendRequest();"/>
</div>
</div>
</body>
</html>
登录、注册、聊天控制器
系统的控制器使用Servlet充当,Servlet负责拦截用户请求,然后调用ChartServlet对象处理用户请求,根据处理结果,将请求forword到适合的页面显示。
LoginServlet.java
package dem.com;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns={"/login.do"})
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置使用utf-8字符集来解析请求参数
request.setCharacterEncoding("utf-8");
//取得用户的两个请求参数
String name=request.getParameter("name");
String pass=request.getParameter("pass");
request.setAttribute("tip","");
//进行服务器端的输入校验
if(name==null||name.trim().equals("")||pass==null||pass.trim().equals("")){
request.setAttribute("tip","用户名和密码都不能为空");
forward("/index.jsp",request,response);
}else if(ChartServlet.instance().validLogin(name, pass)){
request.setAttribute("chatList", ChartServlet.instance().getMsg());
request.getSession(true).setAttribute("user", name);
forward("/chat.html",request,response);
}else{
request.setAttribute("tip","用户名和密码都不匹配");
forward("/index.jsp",request,response);
}
}
//执行转发请求的方法
private void forward(String url,HttpServletRequest request, HttpServletResponse response)
throws ServletException,IOException{
//执行转发
request.getRequestDispatcher(url).forward(request, response);
}
}
RegServlet.java
package dem.com;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(urlPatterns={"/reg.do"})
public class RegServlet extends HttpServlet{
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置使用utf-8字符集来解析请求参数
request.setCharacterEncoding("utf-8");
//取得用户的两个请求参数
String name=request.getParameter("name");
String pass=request.getParameter("pass");
//进行服务器端的输入校验
if(name==null||name.trim().equals("")||pass==null||pass.trim().equals("")){
request.setAttribute("tip","用户名和密码都不能为空");
}else{
try{
//调用ChartServlet对象的addUser方法来增加用户
//如果注册成功
if(ChartServlet.instance().addUser(name, pass)){
request.setAttribute("tip","注册成功,请登录系统");
}else{
request.setAttribute("tip", "无法正常注册,请重试");
}
}catch(Exception e){
request.setAttribute("tip", e.getMessage());
}
}
forward("/reg.jsp",request,response);
}
//执行转发请求的方法
private void forward(String url,HttpServletRequest request, HttpServletResponse response)
throws ServletException,IOException{
//执行转发
request.getRequestDispatcher(url).forward(request, response);
}
}
ChatServlet.java
package Servlet;
import java.io.IOException;
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 dem.com.ChartServlet;
@WebServlet(urlPatterns={"/chat.do"})
public class ChatServlet extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//设置使用UTF-8字符集来解析请求参数
request.setCharacterEncoding("UTF-8");
String msg=request.getParameter("chatMsg");
if(msg!=null&&!msg.equals("")){
//取得当前用户
String user=(String)request.getSession(true).getAttribute("user");
//调用ChartServlet的addMsg来添加聊天消息
ChartServlet.instance().addMsg(user, msg);
}
//将全部聊天信息设置为request属性
request.setAttribute("chatList", ChartServlet.instance().getMsg());
//转发到chatreply.jsp页面
forward("/chatreply.jsp",request,response);
}
//执行 转发请求的方法
private void forward(String url,HttpServletRequest request,HttpServletResponse response)
throws ServletException,IOException{
//执行转发
request.getRequestDispatcher(url).forward(request, response);
}
}
其他
使用jsp页面控制输出聊天信息(对应ChatServlet.java)
chatreply.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" contentType="text/html;charset=GBK" errorPage="error.jsp"%>
<%--输出当前的聊天信息 --%>
${requestScope.chatList}
运行结果:
当用户1234输入111,在登录李女士的浏览器上会立刻更新内容,显示“1234说:111”。