5.1.8 如何使用JSP和Servlet实现MVC模型
MVC是Model(模型)、View(视图)、Controller(控制器)3个单词的首字母组合。MVC是一种目前广泛流行的应用模型,其目的是实现Web系统的职能分工。下图为MVC模型关系图:
其中,模型层实现系统中的业务逻辑,通常可以用JavaBean或EJB来实现;视图层则用于与用户的交互,通常用JSP来实现;控制层则是模型与视图之间沟通的桥梁,它可以把用户的请求分派并选择恰当的视图来显示他们,同时它也可以解释用户的输入并将其映射为模型层能够执行的操作。
MVC强制性的分离Web应用的输入、处理和输出,使得MVC应用陈旭被分为3个核心部件:模型、视图和控制器。他们各自处理自己的任务。
1>模型(业务逻辑层)
模型表示企业数据和业务逻辑,他是应用程序的主体部分。业务流程的处理过程对其他层来说是黑箱操作,模型接收视图请求数据,并返回最终的处理结果。业务模型的设计可以说是MVC最主要的核心。目前流行的是EJB模型就是一个经典的应用例子,它从应用技术实现的角度对模型做了进一步的划分,以便充分利用现有的组件,但它不能作为应用设计模型的框架。它仅仅告诉设计人员按这种模式设计就可以利用某些技术组件,从而减少了技术上的困难,可以使设计人员专注于业务模型的设计。
MVC把应用的模型按一定的规则抽象出来。抽象的层次很重要,这也是判断设计人员是否优秀的主要依据。抽象与具体不能隔得太远,也不能太近。MVC并没有提供模型的设计方法,而只告诉设计人员应该如何组织管理这些模型,以便于模型的重构和提高重用性。
业务模型还有一个很重要的模型那就是数据模型。数据模型主要是指实体对象的数据持续化,比如将一张订单保存到数据库,从数据库获取订单,将这个模型单独列出,所有相关数据库的操作只限制在该模型中。
2>视图(表示层)
视图是用户看到的并与之交互的界面。对早期的Web应用来说,视图就是由HTML元素组成的界面,在新式的Web应用中,HTML依旧在视图中扮演者重要的角色,但一些新的技术已层出不穷,它们包括Adobe Flash以及诸如XHTML、XML\XSL等一些标识语言和Web服务等。
随着Web应用开发技术的发展,用户要求的日益提高,如何处理应用程序的界面已经变得越来越有挑战性。MVC架构一个大的好处是它能为Web应用处理很多不同的视图。在视图中其实没有真正的业务处理发生,不管这些数据是联机存储的还是一个雇员列表,作为视图来讲,它只是作为一种输出数据并允许用户操纵的方式。
视图功能强大,主要表现在以下两个方面:
1)根据客户类型显示信息
2)显示商业逻辑(模型)的结构,而不关心信息如何获得何时获得
3>控制器
控制器接收用户的输入并调用模型和视图去完成用户的需求。所以当用户单击Web页面中的超链接和发送HTML表单时,控制器(例如Servlet)本身不输出任何东西,也不执行任何处理,它只是接收请求并决定调用哪个模型构件去处理请求,然后确定哪个视图来显示模型处理返回的数据。
MVC的处理过程是这样的:对于每一个用户输入的请求,先被控制器接收,并决定由哪个模型来进行处理,然后模型通过业务逻辑层(模型层)处理用户的请求并返回数据,最后控制器用相应的视图格式化模型数据,并通过显示页面呈现给用户。
MVC这种特殊的架构设计,给应用开发带来了很多便利,通过使用MVC架构,大大提高了Web应用的开发效率,具体来说,MVC设计结构主要有以下几个方面的优点:
1)低耦合性。由于视图层和业务层分离,这样就使得修改视图层代码时不需要重新编译模型和控制器的代码,同样,一个应用的业务流程或者业务规则的改变只需要改动MVC的模型层即可。因为模型与控制器和视图相分离,所以很容易改变应用程序的数据层和业务规则。
2)高重用性和可适用性。由于技术的不断进步,现在访问应用程序可以有越来越多的方式。MVC模式允许使用各种不同样式的视图来访问同一个服务器端的代码。它包括任何Web(HTTP)浏览器或者无线浏览器(WAP)。例如,用户可以通过计算机或者手机来订购某种产品,虽然订购的方式不一样,但处理订购产品的方式是一样的。由于模型返回的数据没有进行格式化,因此同样的构建能被不同的界面使用。例如,很多数据可能用HTML来表示,但是也有可能用WAP来表示,而这些表示所需要的命令仅是改变视图层的实现方式,而控制层和模型层无需做任何改变。
3)较低的生命周期成本。MVC使得开发和维护用户接口的技术难度降低。
4)部署快速。使用MVC模式可以大大缩减开发时间,这使得后台开发人员集中精力于业务逻辑上,使界面开发人员(包括HTML和JSP开发人员)集中精力于表现形式上。
5)可维护性。分离视图层和业务逻辑层也使得Web应用更易于维护和修改。
6)有利于软件工程化管理。由于采用了分层思想,每一层不同的应用具有某些相同的特征,有利于通过工程化、工具化管理程序代码。
用JSP和Servlet实现的MVC模型如下图所示:
在这个MVC模型,视图模块采用JSP来实现,主要负责数据的展现。视图可以从控制器上获取模型的状态,当然不是直接从控制器上获取,而是控制器把模型的数据方法一个视图可以访问的地方,通过间接方式来访问模型的数据。控制器采用Servlet来实现,客户端的所有请求都发送到Servlet,它接受请求,并根据请求消息把它们分发给对应的JSP页面来响应,同时根据需求生成JavaBean实例供JSP来使用。模型采用JavaBean来实现,这个模块实现了实际的业务逻辑。
5.1.9 Servlet中forward和redirect有什么区别
在设计一个Web应用程序时,经常需要把一个系统进行结构化设计,即按照模块进行划分,让不同的Servlet来实现不同的功能,例如可以让其中一个Servlet接受用户的请求,另外一个Servlet来处理用户的请求。为了实现这种程序的模块化,就需要保证在不同的个Servlet之间可以互相跳转,而Servlet中主要有两种实现跳转的方式:forward方式与redirect方式。
forward是服务器内部的重定向,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,而客户端并不知道,因此在客户端浏览器的地址栏中不会显示转向后的地址,还是原来的地址。由于在整个定向过程中用的是同一个Request,因此forward会将Request的信息带到被定向的JSP或Servlet中使用。
redirect则是客户端的重定向,是完全的跳转,即客户端浏览器会获取到跳转后的地址,然后重新发送请求,因此浏览器中会显示跳转后的地址,同时,由于这种方式比forward方式多了一次网络请求,因此其效率要低于forward方式。需要注意的是,客户端的重定向可以通过设置特定的HTTP头或写JavaScript脚本实现。
下图展示了forward和redirect的区别:
鉴于以上区别,一般当forward方式可以满足需求时,尽可能地使用forward方式。但是有些情况下,例如,需要跳转到一个其他服务器上的资源,则必须使用redirect方式。
引申:filter的作用是什么?主要实现什么方法?
filter使得用户可以改变一个request并且修改一个response。filter不是一个Servlet,它不能产生一个response,但它能够在一个request到达Servlet之前预处理request,也可以在离开Servlet时处理reaponse。filter其实是一个”Servlet Chaining(Servlet链)”。
一个filter的作用包括以下几个方面:
1)在Servlet被调用之前截获。
2)在Servlet被调用之前检查Servlet Request。
3)根据需要修改Request头和Request数据。
4)在Servlet被调用之后截获。
5.1.10 JSP内置对象有哪些
在JSP中,内置对象又称为隐含对象,是指在不声明和不创建的情况下就可以被使用的一些成员变量,JSP一共提供了9个内置对象:request(对象)、request(响应对象)、pageContext(页面上下文对象)、session(会话对象)、application(应用程序对象)、out(输出对象)、config(配置对象)、page(页面对象)与execption(例外对象)。JSP内置对象的具体描述如下:
- request:客户端请求,此请求包含来自GET/POST请求的参数,客户端的请求信息被封装在request对象中,通过它才能了解到客户的需求,然后做出响应,因此request对象是用来获取请求参数的非常重要的途径。他是HttpServletRequest类的实例
- response:用来表示服务器端对客户端的响应,将Web服务器处理后的结果返回给客户端。但是在JSP中很少直接使用到它。它是HttpServletResponse类的实例
- pageContext:提供了对JSP页面的所有对象及命名空间的访问,也就是说,用它可以访问到本页面中的所有其他对象,例如前面已经描述的request、response以及后面要介绍的session和application对象等。它的本类名也叫pageContext。
- session:用来表示客户端与服务器的一次会话。从客户端与Web服务器建立连接的时候,会话开始,直到关闭浏览器时结束会话。它是HttpSession类的实例。
- application:代表JSP所属的Web应用本身,application对象可存放全局变量,因此可以实现用户间的数据共享。它的生命周期与服务器的生命周期一致,也就是说,服务器启动后这个对象即被创建出来,直到服务器停止后这个对象的生命周期才结束,在任何地方,对此对象属性的操作都将影响到其他用户对此的访问。它是ServletContext类的实例
- out:用于在客户端浏览器内输出信息,他是JspWrite类的实例
- config:主要作用是取得服务器配置信息。当一个Servlet初始化时,容器把某些信息通过config对象传输给这个Servlet,Servlet可以使用这个对象获取所需的配置信息
- page:表示当前JSP页面,类似于Java中的this指针。它是java,lang.Object类的实例
- exception:用来表示异常。当一个页面在运行过程中发生了例外,就会产生这个对象。如果JSP需要使用这个对象,就必须把isErrorPage设为true,否则将无法编译。它是java.lang.Throeable的对象。
根据以上9个内置对象的作用的不同,可以分为4类:第一类,与Servlet有关的page和config;第二类,与Input/Output有关的out,request和response;第三类,与Context有关的application,session和pageContext;第四类,与Error有关的exception。
5.1.11 request对象主要有哪些方法
当使用JSP和Servlet开发Web应用程序时,如何获取用户提交的请求信息是非常重要的内容之一。request对象就是用来封装用户请求数据的,每当有请求到达服务器时,系统都会创建一个request对象。在服务器进行处理时可以通过获取request对象的属性来获取用户的请求数据。此外,还可以通过对request对象设置新的一些属性来实现在Servlet与JSP之间跳转时传递一些参数的功能。具体如下:
- setAttribute(String name,Object) 用来设置名字为name所对应的属性值。在对请求进行转发处理时,也可以通过该方法设置一些属性,从而将数据传递到转发后的页面中。
- getAttribute(String name) 用来获取名字为name所对应的属性值,可以用来获取通过setAttribute方法设置的一些属性
- getAttributeName() 返回request对象所有属性的名字集合。返回值为枚举的实例
- getCookie() 返回客户端的所有Cookie对象,结果是一个Cookie数组
- getCharacterEncoding() 返回请求的消息中字符的编码方式
- getContentLength() 获取请求消息的Body的长度
- getInputStream() 返回请求的输入流,这个输入流可以被用于获得请求中的数据
- getMethod() 用来获取HTTP的请求方式,如get或post
- getParameter(String name) 用来获取用户提交的数据,其中name与表单中的name属性一一对应
- getParameterNames() 用来获取客户端传送给服务器端的所有参数的名字,其结果是一个枚举的实例
- getParameterValues(String name) 获得有name指定的参数的所有值
- getProtocol() 用来获取客户端向服务器端传送数据所使用的协议名称
- getQueryString() 获取查询字符串,返回值为URL后面的参数串
- getRequestURI() 获取发出请求字符串的客户端地址
- getRemoteAddr() 获取客户端的IP地址
- getRemoteHost() 获得客户端的名字
- getSession(boolean create) 用来获取与请求相关的session
- getServerName() 获得服务器名字
- getServletPath() 获取客户端所请求的脚本文件(jsp或Servlet)的路径
- getServerPort() 获取服务器端口号
- removeAttribute(String name) 用来删除名字为name对应的属性
5.1.12 JSP有哪些动作
JSP使用动作来实现动态地插入文件、实现重定向和对JavaBean的引用功能。它共有六个基本动作:jsp:include、jsp:useBean、jsp:setProperty、jsp:getProperty、jsp:forward和jsp:plugin。下面分别进行介绍:
1>jsp:include。用来在页面被请求时引入一个文件。include指令是在JSP文件被转换成为Servlet时引入文件,而jsp:include插入文件的时间是在页面被请求时,而且被引用文件不能包含某些JSP代码(例如不能设置HTTP头),示例如下:
<jsp:include page="test.jsp" flush="true">
<jsp:param name="name" value="value">
</jsp:include>
以上代码表示在当前文件中可以引入test.jsp文件
2>jsp:useBean。用来寻找或者实例化一个JavaBean,它使得开发人员既可以发挥Java组件重用的优势,同时也避免了损失JSP区别于Servlet的方便性,示例如下:
<jsp:useBean id="car" scope="session" class="com.Car">
以上代码表示实例化了一个com.Car类的实例。
3>jsp:setProperty。用来设置已经实例化的Bean对象的属性,示例如下:
<jsp:setProperty name="car" property="colour" value="red"/>
以上代码用来将名字改为car的实例的colour属性设置为red。
4>jsp:getProperty。用来获取某个JavaBean的属性,示例如下:
Colour = <jsp:getProperty name="car" property="colour"></jsp:getProperty>
以上代码用来获取名字为car的实例的color属性。
5>jsp:forward。用来吧请求转到一个新的页面,示例如下:
<jsp:forward page="/Servlet/login"/>
以上代码用来把当前页面重定向到/Servlet/login来处理。
6>jsp:plugin。用于在浏览器中播放或显示一个对象。使用这个动作能插入所需的特定的浏览器的OBJECT或EMBED元素来指定浏览器运行一个Java Applet所需的插件,示例如下:
<jsp:plugin type="applet" codeBase="/ch5" code="Hello.class" height="40" width="320">
以上代码用来在浏览器中运行一个applet插件。
5.1.13 JSP中include指令和include动作有什么区别
include的主要作用是用来在当前文件中引入另一个文件,以便在当前文件中使用,例如当应用程序中的所有页面的某些部分(例如标题、页脚、导航栏等)都一摸一样时,就可以考虑把相同的部分提取出来写入一个独立的文件中,然后通过include方式引入。
include有两种使用方法:include指令和include动作。其中,include指令的使用方法为:<%@ include file=”test.jsp” %>,include动作的使用方法为:
<jsp:include page="test.jsp" flush="true">
<jsp:param name="name" value="value">
</jsp:include>
include指令与include动作之间的根本差异在于二者被调用的时间。include指令是编译阶段的指令,即在编译时,编译器会把指令所指向目标文件的内容复制到指令所在的位置,替换指令,最终形成一个文件,在运行时只有一个文件。也就是说,include指令所包含文件的内容是在编译时插入到JSP文件中的,当文件内容有变化时就需要重写编译,因此适合于包含静态页面的情况,例如可以包含一个Servlet。而include动作是运行时的语法,在主页面被请求时,才将用到的页面包含进来,涉及两个文件,类似于方法调用,因此更适合于包含动态页面的情况。除此之外还有一下3点区别:
1>当使用include动作时,在页面中声明的变量不可用于另一文件,除非将变量放置在request、session、application作用域中;而在使用include指令时,当前页面和被包含页面可以共享变量。
2>当使用include指令时,新生成的JSP页面要符合JSP语法要求,应该避免变量名的冲突;而在使用include动作时,不存在变量名冲突的问题。
3>include指令会修改被包含文件,但不会立即生效,除非修改主页面或删除主页面的类;而include指令会修改被包含的文件,会立即生效。
考虑到include动作在维护上的优势,当这两种方法都适用时,优先考虑使用include动作。仅在所包含文件中定义了主页面要用到的字段和方法,或包含文件设置了主页面的响应报头时,才应该使用include指令,例如,很多站点的导航部分和版权信息部分都是相同的,在每个文件中都会出现,所以可以考虑把这些内容放在单独的文件中,然后使用<%@ include%>指令引用即可。
5.1.14 会话跟踪技术有哪些?
在开发Web应用程序时,经常需要能够做到数据共享或者是在不同页面之间可以传递参数,而且,一个会话中的数据可能会在不同的地方使用,因此就需要有专用的机制来传递和保存这些数据。
所谓会话,指的是从客户端打开与服务器的连接并发出请求到服务器响应客户端请求的全过程。会话跟踪则是对同一个用户对服务器的连续请求和接收响应的监视,由于客户端与服务器端之间是通过HTTP进行通信的,而HTTP本身是无状态协议,它不能保存客户的信息,即一次响应完成之后连接就断开了,在下一次请求时,需要重新建立连接,等到建立完连接后还需要判断是否是同一个用户,因此,要想对会话的过程进行监控,最好的方法就是使用会话跟踪技术。
具体而言,会话跟踪技术主要有如下四种:
1>page。代表一个页面相关的对象和属性。一个页面由一个编译好的Java Servlet类(可以带有任何的include指令,但是没有include动作)表示。这既包括Servlet又包括被编译成Servlet的JSP页面
2>request。代表与Web客户端发送的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个Web组件。
3>session。代表与用于某个Web客户端的一个用户体验相关的对象和属性,一个Web会话经常也会跨越多个客户端请求。
4>application。代表与整个Web应用程序相关的对象和属性,这实质上是跨越多个Web应用程序,包括多个页面、请求和会话的一个全局作用域。
5.1.15 Web开发中如何制定字符串的编码
在Java语言中,常用的字符串编码方式有:ISO-8859-1,GB2312,GBK,UTF-8/UTF-16/UTF-32等。其中,ISO-8859-1用来编码拉丁文,它由单字节(0~255)组成。GB2312,GBK用来编码简体中文,由单字节和双字节混合组成,最高位为1的字节和下一个字节构成一个汉字,最高位为0的字节是ASCII码。UTF-8/UTF-16/UTF-32是国际标准UNICODE的编码方式,UTF全称为Unicode Translation Format,即把Unicode转作某种格式的意思。其中,使用最多的是UTF-8,因为该方式对拉丁文编码时节约空间,它的特点是针对不同范围的字符使用不同长度的编码。
String序列化为byte数组或反序列化时需要选择正确的编码方式,如果编码方式使用不正确,就会得到一些0x3F的值。所以,在Web应用开发中,经常会遇到需要指定字符串的编码格式的情况,潍坊市出现乱码,最好的方式就是指定编码格式。
需要注意的,在Web开发时也可以通过response.setContextType()方法来指定JSP页面显示的编码格式。
5.1.16 什么是Ajax
Ajax(Asynchronous JavaScript and XML,异步JavaScript与XML)是一个结合了Java技术、XML以及JavaScript的编程技术,其主要目的是在不断刷新页面的情况下通过与服务器进行少量的数据交互来提高页面的交互性,减少响应时间,从而改善用户体验。使用Ajax技术后,页面就不需要在每次用户提交修改时重新加载了。
在使用传统软件架构开发的应用程序中,当客户端需要与服务器端频繁交互时,用户只有等整个页面重新加载后才能看到从服务器中获取到的资源信息,页面会被重新加载很多次。当前后两个页面中的大部分HTML代码相同时,这种做法就会非常浪费网络带宽,毕竟很多资源信息的获取都是重复无用的。
在这种情况下,如果使用Ajax技术会带来许多好处:首先,由于Ajax技术可以只向服务器发送并取回必须的数据内容,使得数据交互量大幅降低,从而降低了服务器的网络负载;其次,由于它通过使用SOAP(Simple Object Access Protocol,简单对象访问协议,一种交换数据的协议规范)或其他一些基于XML的Web Service接口,在客户端采用JavaScript接口,在客户端采用JavaScript处理来自服务器的响应,也降低了Web服务器的处理时间;最后,由于不需要重新加载整个页面,因此系统有更短的响应时间,而这有利于提高系统的稳定性和可用性,从而增强用户的满意度。
需要注意的是,Ajax技术是客户端技术,其核心是JavaScript对象XmlHttpRequest,该对象是一种支持异步请求的技术,它使得开发人员可以使用JavaScript向服务器提出请求并处理响应,而不阻塞用户。
5.1.17 cookie和session有什么区别
cookie是在HTTP下,服务器或脚本可以维护客户工作站上信息的一种方式。它是由Web服务器保存在用户浏览器上的小文件,可以包含有关用户的信息(如身份证号码、密码等信息)。session是指用来在客户端与服务器之间保持状态的解决方案以及存储结构。
尽管二者都能够进行信息存储,但也存在着区别。具体而言,二者有一下几个方面的区别:
1>cookie机制采用的是在客户端保持状态的方案,即数据存放在客户的浏览器上;而session机制采用的是服务器端保持状态的方案,即数据放在服务器上
2>cookie安全性不够。由于cookie信息存放在客户端,其他人可以很容易的得到存放在本地的cookie,并进行cookie欺骗;而session信息存放在服务器端,因此较为安全。
3>cookie性能更高一些。由于session会在一定时间内保存在服务器上,因此当访问量增多时,会降低服务器的性能。
4>单个cookie保存的数据不能超过4KB,很多浏览器都限制一个站点最多保存20个cookie;而session不存在此问题。
鉴于以上几点区别,一般情况下,将用户登录信息等重要信息存放至session中,而其他需要保留的信息可以放在cookie中。