TA的每日心情 | 开心 2021-3-12 23:18 |
---|
签到天数: 2 天 [LV.1]初来乍到
|
(一) 学习Java Web应用已经快有一个月了,基本上已经掌握了一些基本的皮毛。所以一个阶段性的小编成实战就是必须的了。
为了便于对知识的巩固,所以决定选取一个比较简单的基于MVC模式的网站用户认证实例。 这个小的应用主要用到了JSP+Servlet+javaBean+Filter+JSTL。
我的运行环境仍然是tomcat5.5+jdk1.5+mysql4.1
废话一下: JSP主要是用于做页面展示的,javabean主要是用来为数据库访问做服务的,而servlet主要就是处理请求,页面转发之类的。 详细的应用,我们在设计到的时候会说明的。 好了,开始动手!
首先是做一个验证用户的数据库。用于存储用户名及密码。
sql代码如下:
(为了便于操作访问数据库所使用的是root用户,密码设为空)
----------------------------------------------------------
use mysql
create database new_db;
create table user
(
username varchar(24)
primary key,
password varchar(20)
);
insert into user values ("island","Mobile");
insert into user values ("bodao051","871016");
----------------------------------------------------------
好了数据库已经建好了
我们可以试着查询一下看看数据库是否正确
----------------------------------------------------------
use mysql;
use new_db;
select * from user;
----------------------------------------------------------
确定自己的数据库成功建立之后,就开始后面的工作了。运行图:
首先我们需要一个前端的展示。我们采用JSP。
我们默认index.jsp为首页。而login.jsp为页面用来展示登陆的标单。
我们采用这样的模式来处理用户的登陆的判断:
首先页面welcome-file是设置为index.jsp。这个页面里面包含了一个认证是否成功登陆的JSTL代码,判断的方法就是如果user的session范围的对象是空的话,转发至login.jsp进行登陆。如果不为空则显示已经成功登陆。 index.jsp的代码如下:
---------------------------------------------------------
index.jsp
---------------------------------------------------------
<%@page contentType="text/HTML; charset=GBK"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:set var="user" value=""/>
<html>
<head>
<title>index</title>
</head>
<body>
<center>
<h1>用户管理</h1>
<br/>
<c:if test="true">对不起,您还未登录!请点击<a href="pagecontrol?action=out">这里</a>登陆。</c:if>
<c:if test="false">
<p><b></b> 用户,您好,您已经登陆本站! </p>
<p>若重新登录,请<a href="pagecontrol?action=out">注销</a></p>
</c:if>
</center>
</body>
</html>
---------------------------------------------------------
这段代码中涉及到这么一句代码
<a href="pagecontrol?action=out">
这个index.jsp的精华所在。
这个链接是和一个叫做CheckServlet.java的servlet相连的。这个servlet的作用就是用来处理Http的请求即验证用户是否输入正确的。稍后会重点介绍。 接着我们再作一个login.jsp用来进行用户的表单的登陆。
为了简单起见我们只作一个比较简单的页面。
代码如下:
----------------------------------------------------------
index.jsp
----------------------------------------------------------
<%@page contentType="text/html; charset=GBK"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<title>login</title>
<script language="JavaScript1.2">
function submitForm(theForm)
{
if(theForm.username.value==""){
alert("请输入用户名");
theForm.username.focus();
return false;
}else if(theForm.password.value==""){
alert("请输入密码");
theForm.password.focus();
return false;
}else return true;
}
</script>
</head>
<body bgcolor="#ffffff">
<center>
<h1>登录页面</h1>
<form name="form1" method="post" action="checkservlet" onsubmit="javascript:return submitForm(this);">
<br>
<br>
<table align="center">
<tr><td>用户名</td><td><input type="text" name="username" value=""/></td></tr>
<tr><td>密码</td><td><input type="password" name="password" value=""/></td></tr>
<tr>
<td>
<input type="submit" name="Submit" value="登陆">
<input type="reset" value="重置">
</td>
</tr>
</table>
</form>
</center>
</body>
</html>
----------------------------------------------------------
从这句代码中
<form name="form1" method="post" action="checkservlet" onsubmit="javascript:return submitForm(this);">
我们可以看出,表单的结果是以post的方式提交到checkservlet的
。 到这里我们的展示基本上已经结束,可以得到展示层都和checkservlet这个文件有着很大的关系。我们下一步的任务就是搞清楚checkservlet的用途和怎么写这个servlet。 (二)我们由展示层提交上来的HttpServletRequest,到底该怎么处理?
我们猜想既然这是一个验证用户登陆认证的MVC模式例子,那么请求所涉及的用户名和密码就必然需要一个验证的机制,简单的理解就是我们需要和数据库取得连接,然后从数据库那儿比较用户的请求是否是合法的。思路基本上就是这样,可是我们该怎么去实现它呢?于是CheckServlet.java就应运而生啦!
好了,先让我们看一下CheckServlet.java的代码,再去理解它为什么要这样去写。
----------------------------------------------------------
CheckServlet.java
----------------------------------------------------------
package com.teach.servlet; import javax.servlet.*;
import javax.servlet.http.*; import com.teach.bean.*; import java.io.*; public class CheckServlet extends HttpServlet
{
private static final long serialVersionUID = 1L; //为保持版本兼容性附给对象的唯一标识符 // 在这里初始化全局变量
public void init() throws ServletException {}
//这里处理HTTP的GET请求
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
if (request.getParameter("username") != null &&
request.getParameter("password") != null)
{
String userName = request.getParameter("username");
String userPwd = request.getParameter("password");
SQLBean db = new SQLBean();
UserBean ub=db.checkUsersLogin(userName, userPwd);
db.close();
request.getSession().setAttribute("user",ub);
response.sendRedirect("index.jsp");
}
} // 处理HTTP的POST请求
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws
ServletException, IOException
{
doGet(request, response);
} //在这里清理资源
public void destroy(){}
}
---------------------------------------------------------
从这里我们可以得知我们checkservlet首先从HttpServletRequest中取出两个元素一个是用户名"username",一个是密码"password",取出这两个元素之后下一步需要做的就是进行验证,思路很简单将这两个元素与我们所建立的数据库里面所存储的纪录进行比较,如果数据库中含有请求的两个元素的纪录则用户为合法的,反之则为非法用户,对于非法用户之后的处理我们这个例子先不涉及,以后会逐渐的完善的。
呵呵,下一个步骤就很清楚了,和数据库取得连接。 我们把对数据库处理的代码放在Bean里面。
首先呢,我们需要访问new_db这个数据库,步骤是规定好的。
第一步装载,注册数据库的JDBC驱动程序。
第二步就是建立与数据库的连接。
第三步就是创建statement对象,准备要调用的SQl语句。
第四步调用SQL语句。
第五步访问ResultSet中的纪录集。
最后一步一次关闭ResultSet,statement,Connection对象。
之所以详细的列出这些步骤,是因为这些步骤都是规定,必须一步一步完成。是很重要的!
我们把连接数据库德步骤和判断用户合法性的方法封装在一个Bean里面,取名叫作SQLBean.java
----------------------------------------------------------
SQLBean.java
---------------------------------------------------------- package com.teach.bean; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException; public class SQLBean {
private Connection conn = null;
private ResultSet rs = null;
private java.sql.PreparedStatement pstmt = null;
public SQLBean() {
try
{
//连接MySQL数据库的字符串
String cstr="jdbc:mysql://localhost:3306/new_db?useUnicode=true&characterEncoding=GBK";
//装载MySQL数据库的驱动程序
Class.forName("com.mysql.jdbc.Driver").newInstance();
//创建连接
conn= java.sql.DriverManager.getConnection(cstr, "root",""); }
catch(SQLException e){ System.out.println(e.getMessage()); }
catch(Exception ex){ System.out.println(ex.getMessage());} } public UserBean checkUsersLogin(String userName, String userPwd) //登陆验证
{
UserBean ub = null;
if (!checkParameter(userName + userPwd))
{
userName = "null";
userPwd = "null";
}
try
{
String sql =
"select count(*) from user where username=? and password=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, userName);
pstmt.setString(2, userPwd);
rs = pstmt.executeQuery();
if (rs.next())
{
if (rs.getInt(1) > 0)
{
ub = this.getUser(userName);
}
else
{
ub = null;
}
}
}
catch (Exception e)
{
ub = null;
e.printStackTrace();
}
return ub;
} public boolean checkParameter(String para) //过滤非法字符
{
int flag = 0;
flag += para.indexOf(""") + 1;
flag += para.indexOf(";") + 1;
flag += para.indexOf("1=1") + 1;
flag += para.indexOf("|") + 1;
flag += para.indexOf("<") + 1;
flag += para.indexOf(">") + 1;
if (flag != 0)
{
System.out.println("提交了非法字符!!!");
return false;
}
return true;
}
public UserBean getUser(String userName) //提取登陆用户信息
{
UserBean ub = new UserBean();
String sql = "select * from user where username=?";
try
{
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, userName);
rs = pstmt.executeQuery();
while (rs.next())
{
ub.setUserName(rs.getString("username"));
ub.setPassword(rs.getString("password"));
ub.setUserId(rs.getString("userid"));
ub.setTrueName(rs.getString("truename"));
ub.setUserType(rs.getString("usertype"));
}
}
catch (SQLException ex)
{
ex.printStackTrace();
} return ub;
}
//关闭resultset、statement和connection
public void close()
{
try{
if(rs!=null) rs.close();
if(pstmt!=null) pstmt.close();
if(conn!=null) conn.close();
}catch(SQLException e){ System.err.println(e.getMessage());}
} }
----------------------------------------------------------
(三)这样的话,我们只要在checkservlet里面对SQLBean声明一个实例就可以完成一些列的操作啦!
好了,如果我们的用户是合法的用户,那么我们就需要将这个用户的信息作为一个对象存储起来,具体的所就是通过Request里的getSession()方法获取与客户端请求相联系的会话即session,在通过session中的setAttribute()方法将对象的值赋给该session变量。并通过Respone里的sendRedirect()方法进行重新定向,我们这里把index.jsp作为了重新定向的Location。
这样的话,我们在回头去看index.jsp就明白为什么要从session里面取值是否为空来判断用户是否合法了。 我们设置怎么一个用于存储用户对象,并通过对它的判断来得知用户的合法性,具体的是非空就合法,空就非法。刚才的SQLBean就用到了。这个很简单我们定义一个名为Userbean.java的Bean
----------------------------------------------------------
UserBean.java
----------------------------------------------------------
package com.teach.bean;
/*
用户Bean
*/
public class UserBean
{
private String _userId;
private String _userName;
private String _password;
private String _trueName;
private String _userType;
public UserBean(){} public void setUserId(String userId)
{
_userId = userId;
}
public void setUserName(String userName)
{
_userName = userName;
} public void setPassword(String password)
{
_password = password;
} public void setTrueName(String trueName)
{
_trueName = trueName;
}
public void setUserType(String userType)
{
_userType = userType;
}
public String getUserId()
{
return _userId;
}
public String getUserName()
{
return _userName;
} public String getPassword()
{
return _password;
}
public String getTrueName()
{
return _trueName;
}
public String getUserType()
{
return _userType;
}
}
----------------------------------------------------------
呵呵,这个Bean似乎方法有点多,有人说我们只需要用户名和密码就可以了。对!这个是为了以后我们考虑到数据的全面性。比如用户的真实姓名,用户的ID等等。 我们似乎很满意自己的思路,可是问题是,我们是用什么方法完成页面转发的呢?
很多人知道,在MVC的框架模式中,Servlet通常作为整个web应用的控制器来使用。大部分的请求信息都是递交给Servlet来处理,Servlet再根据不同的请求转发到不同的JSP。 我们回头看一下login.jsp。看这个代码片断<form name="form1" method="post"
我们的请求是以post的方式传递出去的。所以我们应该有个dopost的方法来处理这些请求。于是我们利用ControlServlet来进行对请求信息的处理。
----------------------------------------------------------
ControlServlet.java
----------------------------------------------------------
package com.teach.servlet; import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
//import com.teach.bean.UserBean; public final class ControlServlet extends HttpServlet {
private static final long serialVersionUID = 1L; //为保持版本兼容性附给对象的唯一标识符
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
String action = request.getParameter("action");
String jspPage = "index.jsp";
if ((action == null) || (action.length() < 1))
{
action = "default";
} if ("default".equals(action))
{
jspPage = "index.jsp";
}
else if ("out".equals(action))
{
request.getSession().invalidate();
jspPage = "login.jsp";
}
dispatch(jspPage, request, response);
} protected void dispatch(String jsp, HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
if (jsp != null)
{
RequestDispatcher rd = request.getRequestDispatcher(jsp);
rd.forward(request, response);
}
} protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException
{
doPost(request, response);
} }
---------------------------------------------------------- (四)
ControlServlet继承了HttpServlet,并对其dopost方法进行了重写。我们分析一下这个重写的dopost()方法。
首先login.jsp表单的结果是由CheckServlet来处理的,action用来存储处理的信息,我们可以知道如果该用户是非法的,那么action就会被赋值out,如果用户是合法的,我们通过对CheckServlet的了解知道,页面被重新定向到index.jsp,我们看一下index.jsp的代码,注意到有这么一段
<c:if test="false">
<p><b></b> 用户,您好,您已经登陆本站! </p>
呵呵,可以知道此时的action的值为默认的null
那么可以很明白的知道下一步肯定就是对action值的判断,没错!
从ControlServlet的dopost方法可以看出,如果action的值是null那么页面转发至index.jsp页面即回到首页显示“用户,您好,您已经登陆本站!”;如果action的值是out那么页面转发至login.jsp要求用户重新登陆。 这样我们就基本上掌握了这个简单的MVC模式的用户认证实例了。 呵呵,或许还有朋友会问,我们设置的welcome-file是index.jsp啊,为什么事实上我们一开始进入的是login.jsp呢?
呵呵,很细心哪,其实我们还漏了一个很重要的东西!
对了,就是Filter(过滤器技术),这个可是Servlet2.3新增的功能哪!很重要的!千万别把它和servlet混为一谈哦!
它的作用是:在Request到达Servlet和JSP之前进行预处理,或者在离开Servlet或JSP时处理返回给客户端的Response。呵呵,很难懂?没事,通过下面的分析或许会有个感性的认识。 通过上面的理解我们知道这个应用的Request请求主要是"user",要知道电脑的速度是很快的,我们刚访问我们的应用的时候确实是先进入的index.jsp而且这个时候生成的request,在这个request被传递到servlet或Jsp之前的时候神奇的恶filter出现了,它拦截了Request,并通过getRequestURI()方法获取该Request将要传递的目的地,而且通过httpRequest.getSession().getAttribute("user")方法获得session变量的值,并将该值强制转换为UserBean的一个实例。下面就是判断过程了。
如果这个实例是空的话,分两种情况讨论:
1,若这个request的目的地与login.jsp或者checkservlet或者reg.jsp有关的话那么就让这个request该区哪儿去哪儿。否则的话就把它强制传递到login.jsp。想想也对,如果request中的user的值为空的话,那么就说明我们还没有登陆,下一步肯定是要去login.jsp的。
2,如果这个request中已经包含"user",根据我们上面的思路则认为已经合法登陆,所以filter也不会插手这个request,爱去哪儿就去哪儿。
而我们的实际情况是:我们第一访问这个应用的时候都是还没有登陆的。所以虽然我们设定的welcome-file是index.jsp可是我们还是要进入login.jsp进行登陆的。而filter就帮助我们解决了这个问题。因为计算机的速度问题,我们是察觉不到刚开始时的页面是index.jsp。除非我们的机器慢得像蜗牛一样!呵呵!所以呢,我们一下子就进入了login.jsp。这个就是filter的作用啦! 明白了吧?
呵呵我们给这个filter取名为:LoginFilter.java
----------------------------------------------------------
LoginFilter.java
----------------------------------------------------------
package com.teach.servlet; import javax.servlet.*;
import javax.servlet.http.*;
import com.teach.bean.*; /*
过滤器servlet 用于判断用户是否登陆成功
*/ public class LoginFilter extends HttpServlet implements Filter { private static final long serialVersionUID = 1L; //为保持版本兼容性附给对象的唯一标识符
//private FilterConfig filterConfig;
public void init(FilterConfig filterConfig) throws ServletException {
//this.filterConfig = filterConfig;
}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) {
HttpServletRequest httpRequest=(HttpServletRequest)request;
HttpServletResponse httpResponse=(HttpServletResponse)response;
try
{
request.setCharacterEncoding("GBK");
String url= httpRequest.getRequestURI(); UserBean ub=(UserBean)(httpRequest.getSession().getAttribute("user"));
if(ub==null)
{ if(url.indexOf("login.jsp")!=-1||url.indexOf("checkservlet")!=-1||url.indexOf("reg.jsp")!=
-1||url.indexOf("regservlet")!=-1)
{
filterChain.doFilter(httpRequest, response); }else
{
httpResponse.sendRedirect("login.jsp");
}
}else
filterChain.doFilter(httpRequest, httpResponse);
}
catch (Exception ex)
{
ex.printStackTrace();
} }
public void destroy() {}
} ----------------------------------------------------------
大家觉得这个filter是不是很酷呢!
呵呵! 如果我们是这个web应用的管理员或者说是开发者,我们很想知道用户每次对我们的页面进行访问请求时的情况,比如说请求的地址,请求的时间,请求被执行的时间,和关于这次请求的报告。这对于开发者或者管理者是很重要的! 呵呵,这个时候我们可爱的filter又起作用了
我们可以编写一个日志Filter。来记录我们这个用户认证应用的访问情况。命名为:LogFilter.java
----------------------------------------------------------
LogFilter.java
----------------------------------------------------------
package com.teach.servlet;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.Date; public class LogFilter extends HttpServlet implements Filter { private static final long serialVersionUID = 1L; //为保持版本兼容性附给对象的唯一标识符 FilterConfig filterConfig;
public void setFilterConfig(FilterConfig filterConfig) {
this.filterConfig = filterConfig;
}
public FilterConfig getFilterConfig() {
return filterConfig;
}
public void init(FilterConfig filterConfig) throws ServletException //初始化
{
setFilterConfig(filterConfig);
}
// 日志过滤器的doFilter方法
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain)throws ServletException,IOException
{
HttpServletRequest httpRequest=(HttpServletRequest)request; //获得HTTP请求的对象
ServletContext context = getFilterConfig().getServletContext(); //获得过滤器配置环境
String filterName = getFilterConfig().getFilterName(); //获得过滤器的名字
long bef = System.currentTimeMillis();
filterChain.doFilter(request,response);
long aft = System.currentTimeMillis();
context.log(httpRequest.getRemoteHost() +"请求地址"
+httpRequest.getRequestURL() +"在" + new Date() + ",执行时间:" +(aft-bef)
+" (" +filterName + "报告.)");
} }
---------------------------------------------------------- 至此我们的MVC用户认证的简单应用就算是告一段落了!
是不是觉得这个实例确实用到了很多东西呢?
呵呵,麻雀虽小五脏俱全!
哦,忘了,我把这个应用的web.xml贴出来吧。
----------------------------------------------------------
web.xml
----------------------------------------------------------
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" version="2.4">
<description>teach</description>
<filter>
<filter-name>LoginFilter</filter-name>
<filter-class>com.teach.servlet.LoginFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>LoginFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>Logger</filter-name>
<filter-class>com.teach.servlet.LogFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Logger</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>CheckServlet</servlet-name>
<servlet-class>com.teach.servlet.CheckServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>PageControl</servlet-name>
<servlet-class>com.teach.servlet.ControlServlet</servlet-class>
</servlet> <servlet-mapping>
<servlet-name>CheckServlet</servlet-name>
<url-pattern>/checkservlet</url-pattern>
</servlet-mapping> <servlet-mapping>
<servlet-name>PageControl</servlet-name>
<url-pattern>/pagecontrol</url-pattern>
</servlet-mapping> <welcome-file-list>
<welcome-file>
index.jsp
</welcome-file>
</welcome-file-list>
</web-app>
----------------------------------------------------------
这样的话,运行就应该没问题了,启动tomcat服务器输入http://localhost:8080/island5/
就可以运行了,当然,前面的建立数据库仍然是必要的!呵呵!
源码下载:http://file.javaxxz.com/2014/10/2/044124031.zip |
|