https://download.csdn.net/download/weixin_40789841/12496057
3系统实现
3.1表示层
3.1.1登录界面(loginForm.jsp):
(1)初始化application,采用以下代码:
ArrayList customers = (ArrayList)application.getAttribute("customers"); //初始化customers
if(customers==null) {
customers = new ArrayList();
application.setAttribute("customers",customers);
}
ArrayList msgs = (ArrayList)application.getAttribute("msgs");//初始化msgs
if(msgs==null) {
msgs = new ArrayList();
application.setAttribute("msgs",msgs);
}
(2)使用javascript实现验证码的点击刷新功能,代码如下:
<script type="text/javascript">
function refresh(){
loginForm.imgValidate.src = "validate.jsp?id=" + Math.random();//验证码点击刷新
}
</script>
(3)添加登录界面表单,并用<p style="text-align:center">,实现表单居中显示,代码如下:
<p style="text-align:center">
★★欢迎登录在线交流系统★★<br>
<form action="login.action" name="loginForm" method="post">
输入账号:<input name="account" type="text"><BR>
输入密码:<input name="password" type="password"><br>
请输入验证码: <input type="text" name="code" size="10">
<img name="imgValidate" src="validate.jsp" οnclick="refresh()"><BR>
<input type="submit" value="登录" ><br>
<a href = "logininsert.jsp">还没账号,点击这里注册</a>
</form> </p>
- 在<body>里面加bgcolor="#fffff",实现界面颜色的更换。
- 实现效果如图2

图 2 登录界面
3.1.2注册界面(logininsert.jsp):
(1)添加注册的表单,,并用<p style="text-align:center">,实现表单居中显示,代码如下:
<p style="text-align:center">
---欢迎来到注册页面---<br>
<form action="insert.action" name="form1" method="post">
输入账号:<input name="account" type="text"><BR>
输入密码:<input name="password" type="password"> <br>
输入名字:<input name="cname" type="text"> <br>
请输入验证码: <input type="text" name="code" size="10">
<img name="imgValidate" src="validate.jsp" οnclick="refresh()"><BR>
<input type="submit" value="注册" >
</p>
</form>
(2)使用javascript实现验证码的点击刷新功能,代码如下:
<script type="text/javascript">
function refresh(){
form1.imgValidate.src = "validate.jsp?id=" + Math.random();//验证码点击刷新
}
</script>
(3)在<body>里面加bgcolor="#fffff",实现界面颜色的更换。

图 3 注册界面
3.1.3验证码实现(validate.jsp)
(1)在内存中创建图象,代码如下:
int width = 60, height = 20;
BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_INT_RGB);
(2)获取画笔,代码如下:
Graphics g = image.getGraphics();
(3)设定背景色,代码如下:
g.setColor(new Color(200, 200, 200));
g.fillRect(0, 0, width, height);
(4)取随机产生的验证码(4位数字),代码如下:
Random rnd = new Random();
int randNum = rnd.nextInt(8999) + 1000;
String randStr = String.valueOf(randNum);
(5)将验证码存入session,实现代码如下
session.setAttribute("randStr", randStr);
(6)将验证码显示到图象中,代码如下:
g.setColor(Color.black);
g.setFont(new Font("", Font.PLAIN, 20));
g.drawString(randStr, 10, 17);
(7)随机产生100个干扰点,使图象中的验证码不易被其他程序探测到,代码如下:
for (int i = 0; i < 100; i++){
int x = rnd.nextInt(width);
int y = rnd.nextInt(height);
g.drawOval(x, y, 1, 1);
}
(8)输出图象到页面,代码如下:
ImageIO.write(image, "JPEG", response.getOutputStream());
out.clear();
out = pageContext.pushBody();
(9)验证码实现截图,如图4:
![]()
图 4 验证码实现
3.1.4登录失败页面、注册失败页面:基本原理都一样,至于登录成功的话,将跳转到聊天界面,注册成功将跳转到登录界面。以登录失败为例:
(1)输出文字,以及返回相应界面的连接。代码如下:
<p style="text-align:center">
----- 密码或账号错误,登录失败 -----<br>
<a href = "loginForm.jsp">---点击这里,重新登录---</a>.
</p>
(2)使用转向语句,实现3秒未操作返回上一个界面。代码如下:
response.setHeader("Refresh", "3;URL=javascript:history.back(-1)");
(3)在<body>里面加bgcolor="#fffff",实现界面颜色的更换。
(4)页面实现如图5:

图 5 登录失败
3.1.5验证码错误页面(vfail.jsp):跟3.1.4的代码差不多,不同的是用了javascript:history.back(-1)来返回到上一页。页面如图6:

3.2 业务逻辑层
3.2.1登录验证(loginAction.java、strurs2.xml、loginsuccess.jsp):
(1)用javabean获取account、password及code(验证码)。代码如下:
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public void setCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
(2)编写execute(),先用HttpSession类的API接口获得存在session中的源验证码randStr,让code与源验证码进行对比,如果不同,则return “fail1”;如果相同,则进入账号密码验证。账号密码验证:通过输入的账号,查询数据库中该账号的密码,将查询得到的密码与输入的密码进行对比,如果相同,则return“success”,否则return “fail”。代码如下:
public String execute()throws Exception{
CustomerDao cdao = new CustomerDao();
HttpSession session = ServletActionContext.getRequest().getSession(); //用HttpSession类的API接口获得存在session中的源验证码randStr
String checkcode = (String)session.getAttribute("randStr");
if(!code.equals(checkcode)) //让code与源验证码进行对比
{
return "fail1";
}
else{
Customer customer = cdao.getCustomerByAccount(account);// 通过输入的账号,查询数据库中该账号的密码。
if(customer==null || !customer.getPassword().equals(password)){// 将查询得到的密码与输入的密码进行对比
return "fail";
}
return "success";
}
}
(3)编写strurs2.xml。先写入相应action的跳转界面,实现从表单跳转到loginAction.java,然后编写loginAction.java中execute()返回的字符串所要跳转的相应JSP网页。代码如下:
<action name = "login" class="login.loginAction">
<result name="success">/loginsuccess.jsp</result>
<result name="fail">/loginfail.jsp</result>
<result name="fail1">/vfail.jsp</result>
</action>
(4)编写loginsuccess.jsp。如果只有以上的代码,会出现一个账户同时在线多个。因此需要一个判断机制,来判断一个账户是否已经登录。该系统将在线的账号添加到application类的customers中,该jsp通过输入的账号,与customers中的所有的账号进行对比,如果相同,让temp这个标志变量为1,直接进入聊天界面,不在让其加入到customers中,如果不相同,则temp为0,将该customer加入到session中和application类的customers中。不过只有以上判断还不够,这缺少第一次登录时customers为空的判断,所以要添加改判断。代码如下:
int temp = 0;
request.setCharacterEncoding("gb2312");
String account = request.getParameter("account");
String password = request.getParameter("password");
CustomerDao cdao = new CustomerDao();
Customer customer = cdao.getCustomerByAccount(account);
ArrayList cuss = (ArrayList)application.getAttribute("customers");
if(cuss.size()>0) //判断是否时该系统第一次启动
{
for(int i=cuss.size()-1;i>=0;i--)
{
Customer cus = (Customer)cuss.get(i);
if(cus.getAccount().equals(account))//判断customers的account是否与输入的account相同
{
temp=1;
break;
}
}
if(temp==1) //如果相同则跳转到聊天界面
{
response.sendRedirect("chatForm.jsp");
}
else{ //不同则将该customer加入到session中和application类的customers中。
session.setAttribute("customer",customer);
ArrayList customers = (ArrayList)application.getAttribute("customers");
ArrayList msgs = (ArrayList)application.getAttribute("msgs");
customers.add(customer); //将customer添加到customers中
msgs.add(customer.getCname() + "上线啦!");
response.sendRedirect("chatForm.jsp");
}
}
else if(cuss.size()==0){ //如果为第一次登录,直接将该customer加入到session中和application类的customers中。
session.setAttribute("customer",customer);
ArrayList customers = (ArrayList)application.getAttribute("customers");
ArrayList msgs = (ArrayList)application.getAttribute("msgs");
customers.add(customer);
msgs.add(customer.getCname() + "上线啦!");
response.sendRedirect("chatForm.jsp"); }
(5)相关实现截图如图6:

图 6 登录成功跳转至聊天界面
3.2.2 注册验证(loginAction.java、strurs2.xml)
(1)用javabean获取account、password、cname及code(验证码)。代码如下:
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public void setCode(String code) {
this.code = code;
}
public String getCode() {
return code;
}
(2)编写execute(),先用HttpSession类的API接口获得存在session中的源验证码randStr,让code与源验证码进行对比,如果不同,则return “fail1”;如果相同,则验证新加入的账号是否数据库中已经存在。验证新加入的账号是否数据库中已经存在:通过输入的账号,查询数据库中是否存在该账号如果存在则return “fail”,并判断账号、密码、用户名是否有没输入的,如果没有输入,也return “fail”,否则将其插入数据库,并return “success”,代码如下:
public String execute()throws Exception{
HttpSession session = ServletActionContext.getRequest().getSession(); // 用HttpSession类的API接口获得存在session中的源验证码randStr
String checkcode = (String)session.getAttribute("randStr");
if(!code.equals(checkcode))// 让code与源验证码进行对比
{
return "fail1";
}
else{
CustomerDao cdao = new CustomerDao();
Customer customer = cdao.getCustomerByAccount(account);
System.out.println(account);
if(customer != null||account.equals("")||password.equals("")||cname.equals(""))//验证新加入的账号是否数据库中已经存在:通过输入的账号,查询数据库中是否存在该账号
{
return "fail";
}
else{
int i = cdao.insertCustomer(account,password,cname);
if(i>0)
{
System.out.println("注册成功 ");
return "success";
}
return "fail";
}
}
}
(3)编写strurs2.xml。先写入相应action的跳转界面,实现从表单跳转到insertAction.java,然后编写insertAction.java中execute()返回的字符串所要跳转的相应JSP网页。代码如下:
<action name = "insert" class="login.insertAction">
<result name="success">/loginForm.jsp</result> //当返回success时跳转到登录界面,以方便刚注册的账号进行登录
<result name="fail">/insertfail.jsp</result>//返回fail时跳转到insertfail.jsp
<result name="fail1">/vfail.jsp</result>//返回fail1时跳转到vfail.jsp
</action>
(4)相关实现截图如图7、图8:

图 7 注册

图 8 注册失败
3.2.3聊天消息及相关功能(msgs.jsp、chatAction.jsp):
(1)编写chatAction.jsp。使用request对象获取用户发送的信息,然后将发送信息的用户名和信息内容加入到application的msgs对象中。
<%
Customer customer = (Customer)session.getAttribute("customer");
%>
<%
request.setCharacterEncoding("UTF-8");
String msg = request.getParameter("msg");//使用request对象获取用户发送的信息
ArrayList msgs = (ArrayList)application.getAttribute("msgs");
if(msg!=null && !msg.equals("")){
msgs.add(customer.getCname() + "说:" + msg); //将发送信息的用户名和信息内容加入到application的msgs对象中
response.sendRedirect("chatForm.jsp");
}
%>
(2)编写msgs.jsp。将application中的msgs对象输出、显示,然后从application中的customers中将所有用户账户和用户名显示在当前在线列,并加入response.setHeader("Refresh","3")进行3秒一次的刷新,以保证信息的实时显示。代码如下:
<%
response.setHeader("Refresh","3"); //进行3秒一次的刷新,以保证信息的实时显示
%>
<table width="80%" border="0" align="center">
<tr bgcolor="orange" align="center">
<td width="75%">消息</td>
<td width="25%">当前在线</td>
</tr>
<tr bgcolor="yellow">
<td><%
ArrayList msgs = (ArrayList)application.getAttribute("msgs");
for(int i=msgs.size()-1;i>=0;i--){ //将application中的msgs对象输出、显示
out.println(msgs.get(i) + "<BR>");
}
%></td>
<td valign="top"><%
ArrayList customers = (ArrayList)application.getAttribute("customers");
for(int i=customers.size()-1;i>=0;i--){
Customer customer = (Customer)customers.get(i);
out.println(customer.getAccount() + "(" + customer.getCname() + ")" + "<BR>"); 从application中的customers中将所有用户账户和用户名显示在当前在线列
}
%></td>
</tr>
</table>
(3)相关截图如图9:

图 9 聊天功能
3.3数据访问层
3.3.1编写Customer.java,将用户信息用VO封装,将输入的数据进行封装。代码如下:
package vo;
public class Customer {
private String account;
private String password;
private String cname;
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
}
3.3.2编写CustomerDao.java。该类主要进行对数据库的访问和操作。
(1)编写一个连接数据库的函数,同时要将相应的驱动程序导入本系统中。因为本系统采用的时sqlserver2008,所以驱动包为sqljdbc4.jar,连接数据库函数为:
public void initConnection() throws Exception {
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
conn= DriverManager.getConnection("jdbc:sqlserver://192.168.11.128:1433;DatabaseName=SalesDB;user=123;password=12345");
}
(2)编写查询函数getCustomerByAccount()。首先,调用上一步的函数连接数据库,然后设置sql语句,并使用PreparedStatement方法对sql语句设置,以防止sql语句因组织依赖变量导致的出错发生。接着,用executeQuery()运行sql语句,实现数据的查询,并使用ResultSet对查询所得数据进行存储。然后将这些数据添加进customer中,关闭数据库连接。代码如下:
public Customer getCustomerByAccount(String account) throws Exception {
Customer cus = null;
initConnection(); //连接数据库
String sql =
"SELECT ACCOUNT,PASSWORD,CNAME FROM T_CUSTOMER WHERE ACCOUNT=?"; //sql语句
PreparedStatement ps = conn.prepareStatement(sql);//sql语句设置
ps.setString(1, account);
ResultSet rs = ps.executeQuery(); //运行sql语句
if(rs.next()){
cus = new Customer();
cus.setAccount(rs.getString("ACCOUNT")); //将查询的数据添加到customer中
cus.setPassword(rs.getString("PASSWORD"));
cus.setCname(rs.getString("CNAME"));
}
closeConnection(); //关闭数据库连接
return cus;
}
(3)编写查询函数insertCustomer()。首先,调用第一步的函数连接数据库,然后设置sql语句,并使用PreparedStatement方法对sql语句设置,以防止sql语句因组织依赖变量导致的出错发生。接着,用executeUpdate ()运行sql语句,实现数据的插入,最后关闭数据库连接。代码如下:
public int insertCustomer(String account,String password,String cname) throws Exception {
initConnection();//连接数据库
String sql =
"insert into T_CUSTOMER(ACCOUNT,PASSWORD,CNAME) values(?,?,?)";//插入的sql语句
PreparedStatement ps = conn.prepareStatement(sql);//设置sql语句
ps.setString(1, account);
ps.setString(2, password);
ps.setString(3, cname);
int i= ps.executeUpdate();//运行sql语句
closeConnection();//关闭数据库连接
return i;