1.1 MVC思想概述
下面通过一个登录案例概述一下MVC思想。
1.1.1 简单的登录案例
在学习框架之前必须很好地掌握Java Web的基础知识(如JSP、Servlet、JDBC),这样学习框架才不会吃力,才会觉得顺手。
下面来使用JSP编写一个简单的登录项目,判断用户是否合法,如果合法就显示登录成功,否则就显示登录失败。暂时不需要使用数据库,这里使用固定的用户名和密码。
步骤如下。
(1)首先新建Web项目,其实就是一个普通的文件夹,不过在这个文件夹中包含一个名为“WEBINF”的文件夹,并且在它之下有一个“web.xml”的文件。“web.xml”代码如下。
<? xml version="1.0" encoding="UTF-8"? > <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi=" http://www.w3.org/2001/XMLSchema-instance" version="2.5" xsi:schemaLocation=" http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
(2)分析该项目。项目中包含一个用户登录页、一个用来接收用户请求信息并判断用户信息合法语法的登录判断页、一个登录成功显示页、一个登录失败显示页。
用户登录页包含一个简单的表单,表单中包含两个文本域,分别用来接收用户输入的用户名和密码,还包括两个按钮,分别用来提交表单和重置表单。登录页“login.jsp”代码如下。
<%@page contentType="text/html; charset=gb2312"%> <html> <head> <title>用户登录</title> </head> <body> <center> <h2>用户登录</h2> <%--登录表单--%> <form action="login_conf.jsp" method="post"> <table> <tr> <td>用户名:</td> <%--接收用户输入的用户名,其name属性为uname--%> <td><input type="text" name="uname"></td> </tr> <tr> <%--接收用户输入的密码,其name属性为upassword--%> <td>密  ;码:</td> <td><input type="password" name="upassword"></td> </tr> <tr> <td colspan="2"> <%--登录按钮和重置按钮--%> <input type="submit" value="登录"> <input type="reset" value="重置"> </td> </tr> </table> </form> </center> </body> </html>
(3)登录判断页首先接受用户登录页传递的用户信息,并对用户信息进行判断。如果合法则跳转到用户登录成功页,如果非法则跳转到用户登录失败页。登录判断页“login_conf.jsp”代码如下。
<%@page contentType="text/html; charset=gb2312"%> <html> <head> <title>登录判断</title> </head> <body> <% // 接收请求的内容 String name = request.getParameter("uname") ; String password = request.getParameter("upassword") ; %> <% // 判断用户名及密码 if("xiaoqiang".equals(name)&&"xiaoqiang".equals(password)){ // 合法用户 %> <jsp:forward page="login_success.jsp"/> <% } else { // 非法用户 %> <jsp:forward page="login_failure.jsp"/> <% } %> </body> </html>
(4)登录成功页和登录失败页代码只是简单地显示信息,用来提示是否登录成功。其中登录成功页“login_success.jsp”代码如下。
<%@page contentType="text/html; charset=gb2312"%> <html> <head> <title>登录成功</title> </head> <body> <center> <h2>登录成功</h2> </center> </body> </html>
登录失败页“login_failure.jsp”代码如下。
<%@page contentType="text/html; charset=gb2312"%> <html> <head> <title>登录失败</title> </head> <body> <center> <h2>登录失败</h2> </center> </body> </html>
(5)部署该项目。打开Tomcat安装目录下的conf文件夹,打开其中的“server.xml”文件。在文件的最下面的“</host>”标签之前添加如下代码。
<Context path="/01"docBase="E:\BookDemo\ch01\01"reloadable="true"crossContext="true"> </Context>
其中docBase属性用来指定项目所在目录,path属性用来指定虚拟路径,也就是通过浏览器访问时的路径地址。
1.1.2 测试案例
下面一起运行这个程序,看是否实现了项目的要求。
步骤如下。
(1)运行Tomcat服务器,启动Tomcat服务(如果Tomcat为安装版本),或者打开Tomcat的安装目录下的bin目录,找到“startup.bat”,双击运行该批处理来运行Tomcat服务器。
(2)打开浏览器,访问登录页地址“http://localhost:8080/01/login.jsp”,页面显示效果如图1.1所示。
(3)在表单中填写用户信息,这里是随意填写的一个用户信息。单击“登录”按钮进行提交。页面提交到登录判断页。
因为用户信息是随意填写的,所以登录判断页判断该用户为非法用户。登录判断页会执行下面这段代码。
<jsp:forward page="login_failure.jsp"/>
因此将执行服务器端跳转到登录失败页(如图1.2所示)。
(4)输入正确的用户信息,单击“登录”按钮进行提交。页面提交到登录判断页,页面显示效果如图1.3所示。
图1.1 用户登录页
图1.2 登录失败页
图1.3 登录成功页
输入的是正确的用户信息,所以登录判断页判断该用户为合法用户。因此登录判断页会执行下面这段代码。
<jsp:forward page="login_success.jsp"/>
因此将执行服务器端跳转到登录成功页。但是这里发现一个问题,直接浏览“login_success.jsp”页面就可以显示成功,根本就不用登录,因此必须在登录成功页加上判断。
修改代码步骤如下。
(1)修改登录判断页“login_conf.jsp”。如果判断为合法用户,则将在request范围中添加属性login,并将属性值设置为true,修改代码如下所示。
<%@page contentType=”text/html; charset=gb2312”%> <html> <head> <title>登录判断</title> </head> <body> <% // 接收请求的内容 String name = request.getParameter("uname") ; String password = request.getParameter("upassword") ; %> <% // 判断用户名及密码 if("xiaoqiang".equals(name)&&"xiaoqiang".equals(password)){ // 合法用户 //在request范围中添加属性login,其属性值为true request.setAttribute("login", "true"); %> <jsp:forward page="login_success.jsp"/> <% } else { // 非法用户 %> <jsp:forward page="login_failure.jsp"/> <% } %> </body> </html>
(2)修改登录成功页“login_success.jsp”。在该页面中添加对request范围内login属性的判断,如果该属性存在并且其属性值为true才显示用户登录成功,否则将跳转到登录页,代码如下所示。
<%@page contentType="text/html; charset=gb2312"%> <html> <head> <title>登录成功</title> </head> <body> <center> <% if(request.getAttribute("login") ! = null && request.getAttribute("login").equals("true")){ %> <h2>登录成功</h2> <% } else { %> <jsp:forward page="login.jsp"></jsp:forward> <% } %> </center> </body> </html>
打开浏览器,直接访问登录成功页“http://localhost:8080/01/login_success.jsp”。这时页面并没有显示登录成功,而是直接跳转回了“login.jsp”用户登录页。这样就能够避免用户直接进入成功页。不过代码中还有很多地方需要改进,如直接通过JSP来进行业务逻辑的判断,其实这样是非常不好的。“login_conf.jsp”页面完成的是判断和跳转功能,完全可以使用Servlet来进行操作,而不是使用JSP。下面讲解MVC设计模式,并通过使用MVC设计模式来改进这个项目。
1.1.3 Model 1和Model 2
首先来看什么是Model 1模式。前面编写的那个登录项目为例就是用典型的基于Model 1模式来开发的,整个Web项目都是由JSP页面构成的。其中登录判断页“login_conf.jsp”既要接受客户端的请求,还必须对其用户信息判断进行跳转。JSP页面既要负责显示还要负责控制,将控制逻辑和表现逻辑混在一起了。
使用Model 1模式开发代码重用性非常低,对于功能相似的代码只能选择复制的方式,而不是直接调用。这样使得整个JSP页面充斥着功能类似的代码。
使用Model 1模式开发程序扩展性也非常差,如果以后想要给程序扩展功能是非常困难的。假如在一个JSP页面添加了某一功能,那么可能其他的很多页面都需要变动,甚至整个Web应用都要修改。这种牵一发而动全身的应用,会使得后期工作异常的困难和烦琐。
JSP页面中大量充斥着Java脚本,这使得后期的维护非常困难。有时候一个地方出现错误就要到处去找。还有代码重用性,笔者就是经常在使用复制、粘贴,已经成了一种习惯。
不过使用Model 1模式来开发比较简单和方便。因此如果是小型的Web站点,后期的更新和维护工作不是很大,就可以采用Model 1模式来开发。
Model 2是基于MVC架构的设计模式。MVC包含3个基本部分,分别是Model(模型)、View(视图)和Controller(控制器)。JSP只负责显示,而控制器则由Servlet充当,模型由JavaBean充当。为了更好地明白Model 1和Model 2的区别,下面给出Model 1以及Model 2的程序流程图,如图1.4和图1.5所示。
图1.4 Model 1的程序流程图
图1.5 Model 2的程序流程图
Model 1的程序流程比较容易理解。用户提交信息给JSP页面,JSP接受用户提交的值,通过JavaBean连接数据库并操作数据库,然后将结果返回给用户。
Model 2将JSP的功能简化了,在Model 1中JSP负责的东西过多了。在Model 2中使用Servlet来充当控制器,而JSP只是充当显示。至于为什么会这样设计,是因为在JSP中进行接受参数和判断还有跳转等功能会用到大量的Java脚本代码。过多的Java脚本代码会使得页面维护起来非常困难,而Servlet本来就是一个Java文件,这样使用Servlet来接受参数和判断还有跳转等功能是非常合适的。用户可以把Servlet看成是一个大管家,它负责所有的业务逻辑并通过JavaBean来操作数据库以及决定显示页面。
通过分层的思想使得程序执行更加清晰,各层都只负责自己的功能,不会出现混乱。而且如果程序后期需要增加功能或者进行维护都是非常方便的,下面来演示如何使用MVC设计模式来改进前面的登录案例。
1.1.4 使用MVC设计模式改进代码
如果要使用MVC设计模式,那么控制器就要使用Servlet。具体的逻辑判断则交给业务逻辑组件来判断,而业务逻辑组件判断的结果则返回交给Servlet来判断并实现跳转。
步骤如下。
(1)新建一个Web项目,把上个项目中的“login.jsp”、“login_success.jsp”以及“login_failure.jsp”复制到本项目中。
(2)新建业务逻辑组件类,类名为LoginCheck,包含一个isLogin方法,用来判断用户是否合法,代码如下所示。
public class LoginCheck {
//判断是否为合法用户
public boolean isLogin(String name, String password){
if("xiaoqiang".equals(name)&&"xiaoqiang".equals(password)){
return true;
}else{
return false;
}
}
}
(3)新建Servlet, Servlet类名为LoginConf。该Servlet接受用户提交的参数,并通过实例化一个业务逻辑组件,然后通过调用业务逻辑组件中的isLogin返回值来分别对合法用户和非法用户执行跳转,代码如下所示。
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 LoginConf extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //接受用户参数 String name = request.getParameter("uname"); String password = request.getParameter("upassword"); //new一个LoginCheck对象 LoginCheck lc = new LoginCheck(); //调用业务逻辑组件的判断功能 if(lc.isLogin(name, password)){ //如果为合法用户,在request范围中添加属性login,其属性值为true,并跳转到登录成功页 request.setAttribute("login", "true"); request.getRequestDispatcher("login_success.jsp").forward(request, response); }else{ //如果为非法用户则跳转到登录失败页 request.getRequestDispatcher("login_failure.jsp").forward(request, response); } } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request, response); } }
(4)分别编译LoginCheck类和LoginConf类,并将编译后的class文件放入项目的WEB-INF文件夹下的classes文件夹中。
(5)配置Servlet,修改“web.xml”文件,代码如下所示。
<? xml version="1.0" encoding="UTF-8"? > <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> <servlet> <servlet-name>LoginConf</servlet-name> <servlet-class>LoginConf</servlet-class> </servlet> <servlet-mapping> <servlet-name>LoginConf</servlet-name> <url-pattern>/LoginConf</url-pattern> </servlet-mapping> </web-app>
(6)修改“login.jsp”,即页面提交页,使页面跳转到LoginConf,代码如下所示。
<form action="LoginConf"method="post">
(7)部署该项目。打开Tomcat安装目录下的conf文件夹,打开其中的“server.xml”文件。在文件的最下面的“</host>”标签之前添加如下代码。
<Context path="/02"docBase="E:\BookDemo\ch01\02"reloadable="true"crossContext="true"> </Context>
1.1.5 测试MVC改进代码
下面运行这个程序,看是否实现了项目的要求(本实例参照第1.1.2节进行了改进)。
步骤如下。
(1)启动Tomcat服务(如果Tomcat为安装版本),或者打开Tomcat安装目录下的bin目录,找到“startup.bat”,双击运行该批处理来运行Tomcat服务器。
(2)打开浏览器,访问登录页地址“http://localhost:8080/02/login.jsp”,页面显示效果如图1.6所示。
(3)在表单中填写用户信息,这里随意地填写一个用户信息。单击“登录”按钮进行提交。页面提交到登录判断页,页面显示效果如图1.7所示。
因为用户信息是随意填写的,所以登录判断页判断该用户为非法用户。在LoginConf的Servlet中调用业务逻辑组件LoginCheck的isLogin方法,返回的是“false”。在LoginConf中会执行下列代码。
request.getRequestDispatcher("login_failure.jsp").forward(request, response);
因此将执行服务器端跳转到登录失败页。
(4)输入正确的用户信息,用户名和密码都填写“xiaoqiang”,单击“登录”按钮进行提交。页面提交到登录判断页,页面显示效果如图1.8所示。
图1.6 用户登录页
图1.7 登录失败页
图1.8 登录成功页
输入的是正确的用户信息,所以登录判断页判断该用户为合法用户。在LoginConf的Servlet中调用业务逻辑组件LoginCheck的isLogin方法,返回的是“true”。在LoginConf中会执行下列代码。
request.getRequestDispatcher("login_success.jsp").forward(request, response);
因此将执行服务器端跳转到登录成功页。
(5)直接访问登录成功页地址“http://localhost:8080/02/login_success.jsp”,这时页面将自动跳转回登录页。