MVC发展线
在JSP开发过程中有两种开发模型可供选择:一种是JSP与JavaBean相结合,这种方式称为Model1模式,另一种是JSP、JavaBean、Servlet相结合。
JavaBean
在JSP网页开发的初级阶段,并没有所谓的框架与逻辑分层的概念,JSP网页代码是与业务逻辑代码写在一起的。这种凌乱的书写方式,给程序的调试及维护带来了很大的困难,直至JavaBean的出现,这一问题才得到些许改善。
JavaBean是用于封装某种业务逻辑或对象的Java类,此类具有特定的功能,即它是一个可重用的Java软件组件模型。由于这些模型组件都具有特定的功能,将其进行合理的组织后,可以快速生成一个全新的程序,实现代码的复用。JavaBean的功能是没有任何限制的,对于任何可以使用Java代码实现的部分或需求的对象,都可以使用JavaBean进行封装,如创建一个实体对象、数据库对象、字符串操作等。它对简单或复杂的功能都可以进行实现。
JavaBean可分为两类,即可视化的JavaBean与非可视化的JavaBean。可视化的JavaBean是一种传统的应用方式,主要用于实现一些可视化界面,如一个窗体、按钮、文本框等。非可视化的JavaBean主要用于实现一些业务逻辑或封装一些业务对象,并不存在可视化界面。此种方式的应用比较多,在JSP编程中被大量采用。
将JavaBean应用到JSP编程中,使JSP发展进入了一个崭新的阶段。它将HTML网页代码与Java代码相分离,使其业务变得更加清晰。在JSP页面中,可以通过JSP提供的动作标签来操作JavaBean对象,其中主要包括<jsp:useBean>、<jsp:setProperty>、<jsp:getProperty>3个标签,这3个标签为JSP内置动作标签。在使用过程中,不需要引入任何第三方的类库。
<jsp:useBean id="变量名" scope="page|request|session|application"> { class="完整类型"| type="数据类型"| class="完整类名" type="数据类型"| beanName="完整类名" type="数据类型" } </jsp:useBean>
page范围:与当前页面相对应,JaveBean的生命周期存在于一个页面中,当页面关闭时JavaBean被销毁。
request范围:与JSP的request生命周期相对应,JavaBean的生命周期存在于request对象之中,当request对象销毁时JavaBean也被销毁。
session范围:session超时或会话结束时JavaBean被销毁。
application范围:与JSP的application生命周期相对应,在各个用户与服务器之间共享,只有当服务器关闭时JavaBean才被销毁。
Model1模式与存JSP开发方式相比是一次进步。在存JSP开发中,JSP网页代码与所有业务逻辑代码写在一起,就像在Servlet基础里自己写的charter1~charter2一样,把数据库的操作,业务的操作都写在JSP里。
此种开发方式虽然简单,但它也为Web程序的开发及应用带来了很多不便;在混合交织的代码中,程序的可读性是非常差的,出现了错误不能快速调试,给程序的维护与扩展也带来了诸多不便,更谈不上代码重用。
aveBean的产生使HTML网页代码与Java代码分离开来,在应用JavaBean的JSP程序中,其业务逻辑变得更加清晰,JSP页面也显得整洁了很多。
从上图看出,JSP页面与JavaBean代码相分离,。在此种模式中,Web应用程序的开发开始有了层次的概念,JSP页面用于显示一个视图,JavaBean用于处理各种业务逻辑,Model1模式从JSP页面之中分离出了业务逻辑层。
Model1模式录入商品信息。本实例通过JSP与JavaBean向数据库添加商品信息,共涉及两个JavaBean对象。
package charter5.model1; /** * 商品类 * * @author admin * */ public class Goods { private String name; private double price; private String description; public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } }
package charter5.model1; import java.io.IOException; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Properties; public class GoodsDao { public void saveGoods(Goods goods) { Connection conn = null; PreparedStatement statement = null; Properties properties = new Properties(); try { properties.load(getClass().getResourceAsStream("/db.properties")); String driver = properties.getProperty("driver"); String url = properties.getProperty("url"); Class.forName(driver); conn = DriverManager.getConnection(url); statement = conn.prepareStatement("insert into goods(name,price,description) values(?,?,?)"); statement.setString(1, goods.getName()); statement.setDouble(2, goods.getPrice()); statement.setString(3, goods.getDescription()); statement.executeUpdate(); } catch (IOException e1) { e1.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } finally { try { if (statement != null) { statement.close(); } if (conn != null) { conn.close(); } properties.clear(); } catch (SQLException e) { e.printStackTrace(); } } } }
<!-- goodsForm.jsp --> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <div> <form action="service.jsp" method="post"> <table> <tr> <td> 商品名称: </td> <td> <input type="text" name="name" /> </td> </tr> <tr> <td> 商品价格: </td> <td> <input type="text" name="price" /> </td> </tr> <tr> <td> 商品描述信息: </td> <td> <input type="text" name="description" /> </td> </tr> <tr> <td> <input type="submit" value="提交" /> </td> </tr> </table> </form> </div> </body> </html>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% request.setCharacterEncoding("UTF-8"); %> <jsp:useBean id="goods" class="charter5.model1.Goods"></jsp:useBean> <jsp:setProperty property="*" name="goods"/> <jsp:useBean id="goodsDAO" class="charter5.model1.GoodsDao"></jsp:useBean> <% goodsDAO.saveGoods(goods); %> </body> </html>
在service.jsp页面中对添加商品的请求作了处理,在其中并没有出现java代码与HTML代码混合交织的情况,因为处理业务逻辑的方法由JavaBean来完成,此种开发模式便是Model1模式。
与纯JSP开发方式相比,Model1开发模式是一次进步,但在业务逻辑的控制方面仍然由JSP页面充当。针对Model1的缺陷,Model2提出了MVC的设计理念,分别将显示层、控制层、模型层相分离,使这3层结构各负其责,达到一种理想的设计状态。
MVC是一种经典的程序设计理念,此模式将应用程序分成3个部分,分别为模型层(Model),视图层(View)和控制层(Controller)。
模型层是应用程序的核心部分,主要由JavaBean组件来充当,可以是一个实体对象或一种业务逻辑,之所以称之为模型,是因为它在应用程序中有很好的重用性、扩展性。
视图层提供应用程序与用户之间的交互界面。在MVC模式中,这一层并不包含任何的业务逻辑,仅提供一种与用户交互的视图,在web应用中由JSP、HTML界面充当。
控制层用于对程序中的请求进行控制,起到一种宏观调控的作用,它可以通知容器选择什么样的视图、什么样的模型组件,在Web应用中由Servlet充当。
Model2模式(JSP+Servlet+JavaBean)在Model1模式的基础上引入了Servlet技术。此种开发模式遵循MVC的设计理念,在JSP作为视图层为用户提供与程序交互的界面,JavaBean作为模型层封装实体对象及业务逻辑,Servlet作为控制层接收各种业务请求,并调用JavaBean模型组件对业务进行处理,在视图与业务之间建立起一座桥梁。
在回过头来看Model1和Model2,在model1中还在JSP中存留一些java代码的影子,虽然有了JavaBean来处理业务,但是对业务的调用还需要在JSP中去调用,这是一种宏观的调控,Model1并没有很好的解决这个问题。在Model2中将Model1的宏观调控抽象了出来作为控制层,由Servlet来完成,Servlet调用处理业务逻辑的JavaBean,衔接调控。
依旧是Model1案例中的两个JavaBean:Goods,GoodsDAO
控制层由Servlet充当,不在需要service.jsp了:
package charter5.model2; import charter5.model1.*; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @WebServlet("/GoodsController") public class GoodsController extends HttpServlet { private static final long serialVersionUID = 1L; @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("UTF-8"); resp.setContentType("text/html;charset=UTF-8"); String name = req.getParameter("name"); double price = Double.valueOf(req.getParameter("price")); String description = req.getParameter("description"); Goods goods = new Goods(); goods.setName(name); goods.setPrice(price); goods.setDescription(description); GoodsDao dao = new GoodsDao(); dao.saveGoods(goods); PrintWriter out = resp.getWriter(); out.println("保存成功!"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
goodsForm.jsp表单的action属性填写为上面的Servlet的url
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <div> <form action="/JavaWebPartice/GoodsController" method="post"> <table> <tr> <td> 商品名称: </td> <td> <input type="text" name="name" /> </td> </tr> <tr> <td> 商品价格: </td> <td> <input type="text" name="price" /> </td> </tr> <tr> <td> 商品描述信息: </td> <td> <input type="text" name="description" /> </td> </tr> <tr> <td> <input type="submit" value="提交" /> </td> </tr> </table> </form> </div> </body> </html>
Java代码与HTML代码写在一起的方式使得JSP页面十分混乱,对于一些复杂业务的实现,将会导致大量的问题。如一个上千行代码的JSP文件,程序的可读性非常差,出现一个小小的错误,都会给程序的调试带来一定的难度,不利于代码的编写与维护。
Model1开发模式通过JavaBean改变了Java代码与HTML代码混合交织的情况,但它对JavaBean的操作仍在JSP页面中进行,甚至部分JSP页面只用于与JavaBean交互处理业务逻辑,并不包含HTML网页代码,JSP又充当了控制业务逻辑的角色,使显示层与业务层混合在一起,因此这种开发模式仍然不是一种理想状态。
Model2开发模式的出现是程序设计方面的一次巨大的进步,它以MVC的设计理念,将模型层、视图层、控制层相区分,使各部分独当一面,各负其责,充分体现了程序中的层次概念,改变了JSP网页代码与Java代码的深深耦合的状态,为程序提供了良好的重用性及扩展性。
Model1开发模式虽然适用于小型项目的开发,但由于其自身缺陷,已经被逐渐遗弃。
好了,到此,Servlet,JSP已经算是告一段落了,总结这篇文档和JSP的那篇笔记都是因为开始了解Struts时,对历史渊源不太清晰而回头作的总结,在MVC出现后,Struts框架是早期对Model2模式的一个经典实现,现在可以去到Struts笔记里了。