通过上一节model1的第二种方法的改进,我们系统框架在可读性/维护性和扩展性上有了明显的改善,但也存在一些不足:
1、jsp技术主要做界面的,但是loginCl.jsp这里调用了java class(模型),完成对用户验证,显得有点怪怪的。
2、wel.jsp是用于显示用户信息的(显示数据),但wel.jsp除了显示数据,还调用了java class(模型),代码的优雅就荡然无存了。也不利于将来的分工开发。
3、Servlet技术处理页面的跳转是最快捷和方便的,难道我们就此不用了么?
下面就是MVC(软件设计模式)模型的提出。
模型(M)+视图(V)+控制器(C)
M主要由java class来做,也可以是java bean,ejb等;V 由jsp来做;C由Servlet来做
通过对问题的分析,我们:
1、增加控制器(Servlet)
2、在控制器中去调用模型(model)去完成用户验证,并准备要显示的用户信息数据。
拿用户登录来说,是如何体现MVC模式的:
首先Login.jsp界面相当于v层,wel.jsp也相当于v层,即界面显示,UserBeanCl.java相当于model层,原来我们通过LoginCl.jsp来调用UserBeanCl.java处理获得结果,是否验证成功并实现跳转到wel.jsp显得有点不伦不类。现在我们通过LoginClServelt.java来获得用户Login.jsp界面用户提交的数据,并调用model模型UserBeanCl.java来验证用户是否正确。这里LoginClServlet相当于一个控制器C。
下面是代码:
login.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="gb2312"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'login.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body bgcolor="pink">
<center>
用户登录<br>
<hr>
<form action="LoginClServlet" method="post">
用户名:<input type="text" name="username"/><br>
密 码:<input type="password" name="passwd"/><br>
<input type="submit" value="登录"/>
<input type="reset" value="重置"/>
</form>
</center>
</body>
</html>
LoginClServlet.java:
//这是一个控制器,主要完成对用户身份的验证
//控制器本身不会去完成业务逻辑的,他主要是去调用model模型层来完成处理
package com.jingchenyong.controller;
import com.jingchenyong.model.*;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LoginClServlet extends HttpServlet {
/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//得到用户名和密码
String u=request.getParameter("username");
String p=request.getParameter("passwd");
//使用模型(UserBeanCl),完成对用户的验证
//创建一个UserBean处理对象
UserBeanCl ubc=new UserBeanCl();
if(ubc.checkUser(u, p)){
//合法
//这种事转向跳转方法,但是这种跳转方向效率不是很高,这样每次重定向后,request啥的都会消失
//response.sendRedirect("wel.jsp");
//因为sendRedirect方法效率不高,所以软件公司常常使用转发的方法
//这种方法效果高,同时request中的对象还可以在下一页面使用
request.getRequestDispatcher("wel.jsp").forward(request, response);
}else{
request.getRequestDispatcher("login.jsp").forward(request, response);
}
}
/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to post.
*
* @param request the request send by the client to the server
* @param response the response send by the server to the client
* @throws ServletException if an error occurred
* @throws IOException if an error occurred
*/
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
this.doGet(request, response);
}
}
wel.jsp:
<%@ page language="java" import="java.util.*,java.sql.*,com.jingchenyong.model.*" pageEncoding="gb2312"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'wel.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<br>登录成功!恭喜你!<%=request.getParameter("user") %>
<a href="login.jsp">返回重新登录</a>
<hr>
<h1>用户信息列表</h1>
<%
//定义四个分页会用到的变量
int pageNow=1;//默认显示第一页
//接收用户希望显示的页数(pageNow)
String s_pageNow=request.getParameter("pageNow");
//当用户是从初始登录进去的话就可能为空
if(s_pageNow!=null){
//确实接收到pageNow
pageNow=Integer.parseInt(s_pageNow);
}
//调用UserBeanCl的方法(创建一个UserBeanCl的方法,然后完成处理),完成分页显示
UserBeanCl ubc=new UserBeanCl();
ArrayList al=ubc.getUserByPage(pageNow);
%>
<table border="1">
<tr><td>用户id</td><td>用户名字</td><td>密码</td><td>电邮</td><td>级别</td></tr>
<%
for(int i=0;i<al.size();i++)
{
//从al中取出UserBean
UserBean ub=(UserBean)al.get(i);//这里要强转一下,因为al.get(i)返回的是一个object类型
%>
<tr>
<td><%=ub.getUserId() %></td>
<td><%=ub.getUsername()%></td>
<td><%=ub.getPasswd() %></td>
<td><%=ub.getEmail() %></td>
<td><%=ub.getGrade() %></td>
</tr>
<%
}
%>
</table>
<%
//上一页
if(pageNow!=1){
out.println("<a href=wel.jsp?pageNow="+(pageNow-1)+">上一页</a>");
}
//显示超链接
for(int i=pageNow;i<=pageNow+4;i++){
out.println("<a href=wel.jsp?pageNow="+i+">["+i+"]</a>");
}
//得到pageCount
int pageCount=ubc.getPageCount();
//下一页
if(pageNow!=pageCount)
out.println("<a href=wel.jsp?pageNow="+(pageNow+1)+">下一页</a>");
%>
</body>
</html>
UserBeanCl.java等参考上一节。这里只是体现他们一个调用关系。
关于LoginClServlet.java中为什么通过转发的方式实现跳转,下节介绍。
转发方式:request.getRequestDispatcher("wel.jsp").forward(request, response);