JSP的开发模型即JSP Model,在Web开发中,为了更方便地使用JSP技术,SUN公司为JSP技术提供了两种开发模型: JSP Model1和JSP Model2。JSP Model1简单轻便,适合小型Web项目的快速开发;JSPModel2模型是在JSPModel1的基础上提出的,它提供了更清晰的代码分层,更适用于多人合作开发的大型Web项目,实际开发过程中可以根据项目需求,选择合适的模型。接下来就针对这两种开发模型分别进行详细介绍。
在早期使用JSP开发的JavaWeb应用中,JSP文件是一-个独立的、 能自主完成所有任务的模块,它负责处理业务逻辑、控制网页流程和向用户展示页面等,接下来通过一张图来描述JSP早期模型的工作原理。
从图中可以看出,首先浏览器会发送请求给 JSP,然后 JSP 会直接对数据库进行读取、保存或修改等操作,最后 JSP 会将操作结果响应给浏览器。但是在程序中,JSP 页面功能的 “过于复杂” 会给开发带来一系列的问题,比如 JSP 页面中 HTML 代码和 Java 代码强耦合在一起, 使得代码的可读性很差;数据、业务逻辑、控制流程混合在一起,使得程序难以修改和维护。为了解决上述问题,SUN 公司提供了一种JSP开发的架构模型:JSPModel1。JSP Model1 采用 JSP + JavaBean 的技术,将页面显示和业务逻辑分开。其中,JSP 实现流程控制和页面显示,JavaBean 对象封装数据和业务逻辑。
接下来通过一张图来描述 JSPModel1 的工作原理,如图所示。
JSPModel1 模型将封装数据和处理数据的业务逻辑交给了 JavaBean 组件,JSP只负责接收用户请求和调用 JavaBean 组件来响应用户的请求。这种设计实现了数据、业务逻辑和页面显示的分离,在一定程度上实现了程序开发的模块化,降低了程序修改和维护的难度。
JSPModel1 虽然将数据和部分的业务逻辑从 JSP 页面中分离出去,但是 JSP 页面仍然需要负责流程控制和产生用户界面。对于一个业务流程复杂的大型应用程序来说,在 JSP 页面中依旧会嵌入大量的 Java 代码,这样会给项目管理带来很大的麻烦。为了解决这样的问题,SUN 公司在 Model1 的基础上又提出了 JSPModel2 架构模型。JSP Model2架构模型采用 JSP + Servlet + JavaBean 的技术,此技术将原本 JSP 页面中的流程控制代码提取出来,封装到 Servlet 中,从而实现了整个程序页面显示、流程控制和业务逻辑的分离。实际上,JSP Model2 模型就是 MVC (模型Model - 视图View - 控制器Controller)设计模式。其中,控制器的角色是由 Servlet 实现的,视图的角色是由 JSP 页面实现的,模型的角色是由 JavaBean 实现的。
MVC 设计模式,它是施乐帕克研究中心在 20 世纪 80 年代为编程语言 Smalltalk–80 发明的一种软件设计模式,提供了一种按功能对软件进行模块划分的方法。MVC 设计模式将软件程序分为 3 个核心模块:模型( Model ) 视图( View ) 和 控制器( Controller ),这3个模块的作用如下所示。
1.模型
模型(Model) 负责管理应用程序的业务数据、定义访问控制以及修改这些数据的业务规则。当模型的状态发生改变时,它会通知视图发生改变,并为视图提供查询模型状态的方法。
2.视图
视图(View) 负责与用户进行交互,它从模型中获取数据向用户展示,同时也能将用户请求传递给控制器进行处理。当模型的状态发生改变时,视图会对用户界面进行同步更新,从而保持与模型数据的一致性。
** 3.控制器**
控制器( Controller ) 是负责应用程序中处理用户交互的部分,它负责从视图中读取数据,控制用户输入,并向模型发送数据。
在图中,当控制器接收到用户的请求后,会根据请求信息调用模型组件的业务方法,对业务方法处理完毕后,再根据模型的返回结果选择相应的视图组件来显示处理结果和模型中的数据。
JSP Model2 模型是一种 MVC 设计模式,由于 MVC 模式中的功能模块相互独立,并且使用该模式的软件具有极高的可维护性、可扩展性和可复用性,因此,使用MVC 开发模式的 Web应用越来越受到欢迎。接下来,本任务将按照 JSP Model2 的模型思想编写一个用户注册程序。该程序中包含两个 JSP 页面 register.jsp 和loginSuccess jsp、一个 Servlet类ControllerServlet。两个 JavaBean 类RegisterFormBean 和 UserBean,以及一个访问数据库的辅助类 DBUtil,这些组件的关系如图所示。
关于各个程序组件的功能和相互之间的工作关系介绍如下。
( 1 ) UserBean 是代表用户信息的 JavaBean,ControllerServlet 根据用户注册信息创建出一个UserBean对象,并将对象添加到 DBUtil 对象中,loginSuccess.jsp 页面从 UserBean 对象中提取用户信息进行显示。
( 2 ) RegisterFormBean 是封装注册表单信息的 JavaBean,用于对从 ControllerServlet 中获取到的注册表单信息中的各个属性(也就是注册表单内的各个字段中所填写的数据)进行校验。
( 3 ) DBUtil 是用于访问数据库的辅助类,它相当于一个 DAO (数据访问对象)。
( 4 ) ControllerServlet 是控制器,它负责处理用户注册的请求。如果注册成功,就会跳到 loginSuccess.jsp页面;如果注册失败,重新跳回到 register.jsp 页面并显示错误信息。
( 5 ) register.jsp 是显示用户注册表单的页面,它将注册请求提交给 ControllerServlet 程序处理。
( 6 ) loginSuccess.jsp 是用户登录成功后进入的页面,新注册成功的用户自动完成登录,直接进入 loginSuccess.jsp 页面。
package cn.itcast.chapter11.model2.domain; import java.util.HashMap; import java.util.Map; public class RegisterFormBean { private String name; //定义用户名 private String password; //定义密码 private String password2; //定义确认密码 private String email; //定义邮箱 private Map<String, String> errors = new HashMap<String, String>(); public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getPassword2() { return password2; } public void setPassword2(String password2) { this.password2 = password2; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public boolean validate() { boolean flag = true; if (name == null || name.trim().equals("")) { errors.put("name", "请输入姓名."); flag = false; } if (password == null || password.trim().equals("")) { errors.put("password", "请输入密码."); flag = false; } else if (password.length() > 12 || password.length() < 6) { errors.put("password", "请输入6-12个字符."); flag = false; } if (password != null && !password.equals(password2)) { errors.put("password2", "两次输入的密码不匹配."); flag = false; } // 对email格式的校验采用正则表达式 if (email == null || email.trim().equals("")) { errors.put("email", "请输入邮箱."); flag = false; } else if (!email.matches("[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+")) { errors.put("email", "邮箱格式错误."); flag = false; } return flag; } // 向Map集合errors中添加错误信息 public void setErrorMsg(String err, String errMsg) { if ((err != null) && (errMsg != null)) { errors.put(err, errMsg); } } // 获取errors集合 public Map<String, String> getErrors() { return errors; } }
package cn.itcast.chapter11.model2.domain; public class UserBean { private String name; private String password; private String email; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
package cn.itcast.chapter11.model2.util; import java.util.HashMap; import cn.itcast.chapter11.model2.domain.UserBean; public class DBUtil { private static DBUtil instance = new DBUtil(); // // 定义users集合,模拟数据库 private HashMap<String,UserBean> users = new HashMap<String,UserBean>(); private DBUtil() { UserBean user1 = new UserBean(); user1.setName("Jack"); user1.setPassword("12345678"); user1.setEmail("jack@it315.org"); users.put("Jack ",user1); UserBean user2 = new UserBean(); user2.setName("Rose"); user2.setPassword("abcdefg"); user2.setEmail("rose@it315.org"); users.put("Rose ",user2); } public static DBUtil getInstance() { return instance; } // 获取数据 public UserBean getUser(String userName) { UserBean user = (UserBean) users.get(userName); return user; } // 插入数据 public boolean insertUser(UserBean user) { if(user == null) { return false; } String userName = user.getName(); if(users.get(userName) != null) { return false; } users.put(userName,user); return true; } }
package cn.itcast.chapter11.model2.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.itcast.chapter11.model2.domain.RegisterFormBean; import cn.itcast.chapter11.model2.domain.UserBean; import cn.itcast.chapter11.model2.util.DBUtil; public class ControllerServlet extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setHeader("Content-type", "text/html;charset=GBK"); response.setCharacterEncoding("GBK"); // 获取用户注册时表单提交的参数信息 String name = request.getParameter("name"); String password=request.getParameter("password"); String password2=request.getParameter("password2"); String email=request.getParameter("email"); // 将获取的参数封装到注册表单相关的RegisterFormBean类 RegisterFormBean formBean = new RegisterFormBean(); formBean.setName(name); formBean.setPassword(password); formBean.setPassword2(password2); formBean.setEmail(email); // 验证参数填写是否符合要求,不符合,转发到register.jsp重新填写 if(!formBean.validate()){ request.setAttribute("formBean", formBean); request.getRequestDispatcher("/register.jsp").forward(request, response); return; } // 参数填写符合要求将数据封装到UserBean类中 UserBean userBean = new UserBean(); userBean.setName(name); userBean.setPassword(password); userBean.setEmail(email); // 调DBUtil类中的insertUser()方法执行添加操作,返回一个boolean类型的标志 boolean b = DBUtil.getInstance().insertUser(userBean); // 如果返回为false,注册的用户存在,则重定向到register.jsp重新填写 if(!b){ request.setAttribute("DBMes", "你注册的用户已存在"); request.setAttribute("formBean", formBean); request.getRequestDispatcher("/register.jsp").forward(request, response); return; } response.getWriter().print("恭喜你注册成功,3秒钟自动跳转"); request.getSession().setAttribute("userBean", userBean); response.setHeader("refresh", "3;url=loginSuccess.jsp"); } }
准备好的jsp
<%@ page language="java" pageEncoding="GBK" import="cn.itcast.chapter11.model2.domain.UserBean"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>login successfully</title> <style type="text/css"> #main { width: 500px; height: auto; } #main div { width: 200px; height: auto; } ul { padding-top: 1px; padding-left: 1px; list-style: none; } </style> </head> <body> <% if (session.getAttribute("userBean") == null) { %> <jsp:forward page="register.jsp" /> <% return; } %> <div id="main"> <div id="welcome">恭喜你,登录成功</div> <hr /> <div>您的信息</div> <div> <ul> <li>您的姓名:${userBean.name }</li> <li>您的邮箱:${userBean.email }</li> </ul> </div> </div> </body> </html>
<%@ page language="java" pageEncoding="GBK"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <title>用户注册</title> <style type="text/css"> h3 { margin-left: 100px; } #outer { width: 750px; } span { color: #ff0000 } div { height:20px; margin-bottom: 10px; } .ch { width: 80px; text-align: right; float: left; } .ip { width: 500px; float: left } .ip>input { margin-right: 20px } #bt { margin-left: 50px; } #bt>input { margin-right: 30px; } </style> </head> <body> <form action="ControllerServlet" method="post"> <h3>用户注册</h3> <div id="outer"> <div> <div class="ch">姓名:</div> <div class="ip"> <input type="text" name="name" value="${formBean.name }" /> <span>${formBean.errors.name}${DBMes}</span> </div> </div> <div> <div class="ch">密码:</div> <div class="ip"> <input type="password" name="password" /> <span>${formBean.errors.password}</span> </div> </div> <div> <div class="ch">确认密码:</div> <div class="ip"> <input type="password" name="password2" /> <span>${formBean.errors.password2}</span> </div> </div> <div> <div class="ch">邮箱:</div> <div class="ip"> <input type="text" name="email" value="${formBean.email }" /> <span>${formBean.errors.email}</span> </div> </div> <div id="bt"> <input type="reset" value="重置 " /> <input type="submit" value="注册" /> </div> </div> </form> </body> </html>