掌握Model I的开发原理
掌握Mode II 的开发原理
两种开发模式为整个WEB 的核心操作,其中以模式二 最为重要,可以这么说,如果可以将模式而 彻底的掌握了。
Mode I
1、Mode I 就是指在开发中讲显示层、控制层、数据层的操作统一交给JSP 或者是JavaBean来进行处理
客户端 [ (<——response )(request ——>)] <————> JSP <————>JavaBean <————>数据库
之前的的JavaB的DAO设计模式,实际上在这道程序中可以发现,DAO负责完成数据层的操作,而JSP 负责显示,一个典型的JSP + JavaBean 的开发模式
客户端现在通过访问的Jsp , 调用里面的JavaBean, 而通过JavaBean调用数据库
在JavaBean 中就包含了有专门负责处理数据的操作,数据层主要是以DAO为主,除了数据之外还包含了业务的处理。
在整个的开发中本身就存在了一个问题,现在的程序肯定是需要JSP + JavaBean 一起开发完成后才可以使用,此时就可能出现推诿的问题,例如: 美工同志说了,程序必须先写成,我再作美工,程序员说了,你必须先做美工我再写程序,所以,这种的开发本身只适合与较快速的开发,但是后期维护困难,可以发现这种开发之后的代码在JSP文件之中的, Scriptlet代码非常多。
Mode II: Model - View -Controller (mvc)
在Mode II 中所以的开发都是以Servlet为主体展开的,由Servlet 接收所有的客户端请求,之后根据请求调用相应的JavaBean, 并将所有的显示结果交给JSP完成,也就是俗称的MVC设计模式
Servlet特点: 可以接收用户的请求参数,环科院调用 java程序,而且由于本身就是以java 程序运行的,所以肯定要比JSP性能高很多的,而且安全性也高
最终Servlet 所以操作的内容都要交给JSP进行显示,这样一来,Servlet 的缺点就避免了
JavaBean 完成具体的单个的功能: JSP完成显示的功能,而Servlet负责连接JSP和JavaBean
JSP ————> Servlet ————> JavaBean 。 这种设计非常适合于大型的项目开发,而且维护方便
MVC有自己的处理流程,实际上最重要的就是输出和跳转的问题了
而且一定要再次强调,由于所有的内容都是要交给JSP进行显示,那么这个时候最方便的属性范围就是request 属性范围,例如: 以一个雇员列表操作为例,可以发现,JSP中只是负责显示一次即可,而且Servlet 应该负责将所有的一次显示的内容交给JSP 完成,那么最合适的属性范围就是request 范围了,因为之前强调过,能用page(pageContext) 就不要使用request ,能用request 就不要使用session ,能使用session 就不要使用application
从实际的开发来讲, session 属性范围用于登录验证上使用较多,而request 范围主要的功能就是在MVC 设计模式上,将Servlet 的内容交给JSP显示,而且这种显示在另外一次提交之后属性就消失了。
本章目标
掌握MVC 在实际开发中的应用
掌握MVC完成一个用户登录程序的开发
内容
登录程序之前已经学习过,是使用JSP + JDBC完成的开发操作, 但是之前的登录程序开发中可以发现有很多问题,就是一个JSP 文件中代码过多了,即便是使用了JSP + JavaBean 的开发模式,其本身也存在JSP 中代码过多的问题
现在就可以利用MVC设计模式来彻底解决掉这些代码过多的问题了
在本程序中用户登录信息提交给Servlet 进行接收,Servlet 接收到请求内容后首先对其合法性进行校验(例如: 输入的内容是否为空或者长度是否满足要求等),如果验证失败,则将错误信息传递给登录页显示,如果数据合法,则调用DAO 层完成数据库的验证,根据验证的结构跳转到“登录成功” 或登录失败的页面,在本程序中,为了操作便捷,将登录成功或失败的显示页都统一设置成登录页。
use mydata; drop table user; create table user( userid varchar(30) primary key, name varchar(30) not null, password varchar(30) not null ); insert into user(userid,name,password) values ('admin','tom','admin');
只要有异常一定要交给被调用处进行处理
数据库创建脚本完成之后,那么下面就开始进行程序的开发操作了
DAO的操作注意是完成数据层的操作,但是下面在MVC设计模式之中,还有Servlet 也很重要,建立一个LoginServlet.java的操作类
在MVC开发中注意,客户端验证和服务器端的验证都需要进行处理的操作
而且从这道程序中,读者也可以发现这样一个问题,以前的jsp 页面中的代码实在是太多了,但是现在的代码明显比以前少很多,实际上对于一个jsp 页面应该只包含如下的代码
1、通过本MVC程序,读者可以清楚的感觉到,与最初的JSP 开发(例如JSP+JDBC 或者是 JSP+DAO) 相比,现在的JSP 页面中的代码已经减少了很多,只是简单的完成了输出,实际上在开发中,JSP中最好只包含以下三种类型的代码:
接收属性: 接收从Servlet 传递过来的属性
判定语句: 判定传递到JSP 中的属性是否存在
输出内容: 使用迭代或者是VO进行输出
一定要记住一点, 在JSP 页面中唯一允许导入的包只能是java.util 包,只要能把握住这一点,就可以开发出一 个简洁、清晰的JSP 页面
一 个好的页面应该不导入任何一个开发包
明白MVC的实际开发作用,以及:JSP 、Servlet、DAO的各个组成部分的作用。DAO只是负责实际的操作,JSP只是负责显示,Servlet只是负责接收数据,调用JavaBean ,并进行跳转的功能
以下是整个页面程序的代码
package org.gz.mvc.vo; public class User { private String userid; private String name; private String password; public void setUserid(String userid) { this.userid = userid; } public void setName(String name) { this.name = name; } public void setPassword(String password) { this.password = password; } public String getUserid() { return this.userid; } public String getName() { return this.name; } public String getPassword() { return password; } }
package org.gz.mvc.dbc; import java.sql.*; public class DatabaseConnection { private static final String DBDRIVER = "org.gjt.mm.mysql.Driver"; private static final String DBURL = "jdbc:mysql://localhost:3306/mydata"; private static final String DBUSER = "root"; private static final String DBPASSWORD = "root"; private Connection conn = null; public DatabaseConnection () throws Exception { try { Class.forName(DBDRIVER); this.conn = DriverManager.getConnection(DBURL,DBUSER,DBPASSWORD); } catch (Exception e) { throw e; } } public Connection getConnection () { return this.conn; } public void close() throws Exception { if(conn != null) { try { conn.close(); } catch (Exception e) { throw e; } } } }
package org.gz.mvc.dao; import org.gz.mvc.vo.*; public interface UserDao { //现在完成的的登录验证,那么登录操作只有两种返回结果 (成功|失败) public boolean findLogin(User user) throws Exception ; }
package org.gz.mvc.dao.imp; import org.gz.mvc.vo.*; import org.gz.mvc.dao.*; import org.gz.mvc.dbc.*; import java.sql.*; public class UserDaoImp implements UserDao { private Connection conn = null; private PreparedStatement pstm = null; public UserDaoImp (Connection conn) { this.conn = conn; } //现在完成的的登录验证,那么登录操作只有两种返回结果 (成功|失败) public boolean findLogin(User user) throws Exception { boolean flag = false; String sql = "select name from user where userid=? and password=?"; this.pstm = this.conn.prepareStatement(sql); this.pstm.setString(1,user.getUserid()); this.pstm.setString(2,user.getPassword()); ResultSet rs = pstm.executeQuery(); if(rs.next()) { user.setName(rs.getString(1)); //取出一个用户名的真实姓名 flag = true; } this.pstm.close(); return flag; } }
package org.gz.mvc.dao.proxy; import org.gz.mvc.vo.*; import org.gz.mvc.dao.*; import org.gz.mvc.dao.imp.*; import org.gz.mvc.dbc.*; import java.sql.*; // 代理类的主要功能是负责关闭 public class UserDaoProxy implements UserDao { private DatabaseConnection dbc = null; private UserDao dao = null; public UserDaoProxy () { try { this.dbc = new DatabaseConnection(); } catch (Exception e) { e.printStackTrace(); } this.dao = new UserDaoImp(dbc.getConnection()); } //现在完成的的登录验证,那么登录操作只有两种返回结果 (成功|失败) public boolean findLogin(User user) throws Exception { boolean flag = false; try { flag = this.dao.findLogin(user); //调用真实主题完成操作 } catch (Exception e) { throw e; } finally { this.dbc.close(); } return flag; } }
package org.gz.mvc.factory; import org.gz.mvc.dao.*; import org.gz.mvc.dao.proxy.*; public class UserDaoFactory { public static UserDao getUserDaoInstance() { return new UserDaoProxy(); } }
package org.gz.mvc.servlet; import java.util.*; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import org.gz.mvc.factory.*; import org.gz.mvc.vo.*; public class LoginServlet extends HttpServlet { public void doGet(HttpServletRequest req,HttpServletResponse resp) throws ServletException ,IOException { String path = "login.jsp"; String userid = req.getParameter("userid"); String userpass = req.getParameter("userpass"); List<String> info = new ArrayList<String>(); //收集错误信息 if(userid == null || "".equals(userid)) { info.add("用户id不能为空"); } if(userpass == null || "".equals(userpass)) { info.add("密码不能为空"); } if(info.size() == 0) { //里面没有记录任何的错误 User user = new User(); user.setUserid(userid); user.setPassword(userpass); try { if(UserDaoFactory.getUserDaoInstance().findLogin(user)) { info.add("用户登录成功,欢迎" + user.getName() + "光临"); } else { info.add("用户端登录失败,错误的用户名或密码!"); } } catch (Exception e){ e.printStackTrace(); } } req.setAttribute("info",info); req.getRequestDispatcher(path).forward(req,resp); } public void doPost(HttpServletRequest req,HttpServletResponse resp) throws ServletException ,IOException { this.doGet(req,resp); } }
<%@ page contentType="text/html" pageEncoding="GBK"%> <%@ page import="java.util.*"%> <html> <head> <title>欢迎光临</title> </head> <body> <script language="javascript"> function validate(f) { if(!(/^\w[5,15]$/.test(f.userid.value))) { alert("用户ID必须是5~15!"); f.userid.focus(); return false; } if(/^\w[5,15]$/.test(f.userpass.value)) { alert("密码必须是5~15!"); f.userpass.focus(); return false; } } </script> <% request.setCharacterEncoding("GBK"); %> <% List<String> info = (List<String>) request.getAttribute("info"); if(info != null) { Iterator<String> iter = info.iterator(); while(iter.hasNext()) { %> <h3><%=iter.next()%></h3> <% } } %> <form action="LoginServlet" method="post" onSubmit="return validate(this)"> 用户ID: <input type="text" name="userid"><br> 密 码: <input type="password" name="userpass"><br> <input type="submit" value="登录"> <input type="reset" value="重置"> </form> </body> </html>
Servlet and JSP Examples. </description> <servlet> <servlet-name>login</servlet-name> <servlet-class>org.gz.mvc.servlet.LoginServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>login</servlet-name> <url-pattern>/servletdemo/LoginServlet</url-pattern> </servlet-mapping>