本次博文对何昊出版的《java程序员面试宝典》的第5章Java Web部分的概括笔记,删除其中部分代码,试题和一部分相对简单的内容题目。
一个web应用程序由客户端程序和服务端程序两部分组成。客户端指用户和浏览器。
用户通过浏览器输入链接地址来请求所需资源。
服务器接受用户请求,并把该请求组装成指定格式发送到服务端,客户端和服务端之间通过HTTP完成具体交互。其中请求的数据流中主要包含http请求方法(GET或POST),请求网址(url)以及一些请求的参数信息。
服务器收到客户端请求并查找用户所需资源。
服务器查找到用户请求的资源将资源返回到客户端。
服务器把响应信息组装成特定的消息格式返回给客户端,这个过程通过HTTP来完成。响应的数据流包含状态编码,Content-type(text,picture,HTML等),响应消息的内容(图片或HTML格式的内容)。
浏览器对HTML进行解析并把响应结果展现给用户。
HTTP请求的方法有很多种类,例如GET,POST,HEAD,TRACE,OPTIONS等,但GET和POST是两个最常用的方法。
GET最简单的请求方式,是从服务器端获取用户所需资源,并将其作为响应返回客户端,这些资源可以是HTML页面,图片等内容的一种。GET方法主要作用是获取服务器端资源信息,如数据库查询操作,不会影响自身状态,增删修改资源都不允许。
POST比GET更强大,能从服务器端获取资源还可以上传数据。
一般不采用GET而是POST上传数据,是因为:
GET上传数据,将数据加到URL后面,二者用“?”连接,变量用&连接。而URL长度存在限制,所以上传数据小,通常是1024Byte。而POST方法传递数据是通过HTTP请求的附件,传送数据量更大,一般认为不受限制。
GET请求因为数据在URL,存在安全隐患,POST没有明文显示,安全性更好。
HTML只能保持静态内容,能以满足实际,故而引入动态页面。
动态页面,能根据不同时间,不同用户显示不同内容。生成动态页面使用公共网关接口(CGI),另一种方法是Servlet。
Servlet是Java语言编写的服务器端程序,运行于Web服务器的Servlet容器,主要提供请求/响应的Web服务模式,可以生成动态web内容。
Servlet的优点:
良好可移植性(Java缘故),执行效率高(针对每个请求创建线程执行,而CGI是创建进程),功能强大(可以与web服务器交互,CGI不行),使用方便(提供许多API读取或设置HTTP头信息,处理Cookie和跟踪会话状态等),可扩展性强。
Servlet处于服务器进程,以多线程形式运行service方法。一个实例可以服务多个请求,实例一般不会被销毁。CGI对每个请求产生新进程,服务完成则销毁,效率不如Servlet。
请求是GET,调用doGet。请求是POST,调用dePost。HttpServlet定义这些方法都是返还error信息,所以当定义一个Servlet,必须实现doPost和doGet方法,这些方法都接受请求和响应。
HTTP请求method是get,请求doGet方法,method是post调用doPost。
整个生命周期由容器控制。只有两个状态,未创建和初始化。主要由三个重要方法控制,init,service,destory。init用于创建或打开与servlet相关资源执行初始化工作。service是处理客户端的请求方法,根据http将请求分发到doGet或doPost。destroy释放任何在init方法打开的与servlet相关的资源。
具体分五个阶段:加载,创建,初始化,处理客户端请求,卸载。
JSP本质是嵌入Java代码的HTML文件,用于解决Servlet存在的问题【所有业务逻辑和HTML响应都在servlet实现,用户响应视图组装成长字段HTML格式字符串写入println方法】。实现理念让每个servlet只负责业务逻辑处理,jsp负责用户html显示,实现业务逻辑与视图实现的分离,极大地提高系统的可扩展性。
JSP被认为是特殊servlet,是对servlet扩展。所有jsp可完成的工作都可由servlet完成。jsp页面最终要被编译成servlet运行。
不同:servlet实现是java中嵌入HTML,编写和修改HTML不方便,适合流程控制和业务处理;jsp实现是在HTML中嵌入java代码,适合页面显示。servlet没有内置对象,jsp中内置对象必须通过HttpServletRequest对象,HttpServletResponse对象及HttpServlet对象得到。
模型层实现业务逻辑,用Javabean或EJB实现;视图层由jsp实现,用于与用户交互。控制层是模型与视图之间桥梁,将用户请求分派并选择恰当视图显示,同时解释用户输入映射成模型层可执行操作。
servlet间跳转方式:forward和redirect。
forward是服务器内部重定向,服务器直接访问目标地址URL,把那个URL响应内容读取过来,服务器端并不知道,所以浏览器地址栏不会显示转向后的地址,还是原来的地址。【整个定向过程用的是同一个Request,因此forward会将Request的信息带到被定向的jsp或servlet中使用】
redirect则是客户端重定向,是完全跳转,即客户端浏览器会获取跳转后的地址重新发送请求,浏览器显示跳转后的地址。这种方式比forward多一次网络请求,效率低于forward。
客户端的重定向可以通过设置特定的HTTP头或JavaScript脚本实现。
用forward可以满足需求,尽可能用forward,但某些时候需要跳转其他服务器上资源必须使用redirect。
filter使用户可以改变一个request并修改一个response。filter不是servlet,不能产生response,但可以在一个request达到servlet之前预处理request,也可以离开servlet时处理response。filter其实是一个servlet链。
作用:在servlet被调用前截获,检查servlet request;根据需要修改request头和request数据。根据需要修改response头和response数据。在servlet被调用后截获。
JSP中一共预先定义了9个这样的对象,分别为:request、response、session、application、out、pagecontext、config、page、exception
request 对象是 javax.servlet.httpServletRequest类型的对象。 该对象代表了客户端的请求信息,主要用于接受通过HTTP协议传送到服务器的数据。(包括头信息、系统信息、请求方式以及请求参数等)。request对象的作用域为一次请求。
response 代表的是对客户端的响应,主要是将JSP容器处理过的对象传回到客户端。response对象也具有作用域,它只在JSP页面内有效。
session 对象是由服务器自动创建的与用户请求相关的对象。服务器为每个用户都生成一个session对象,用于保存该用户的信息,跟踪用户的操作状态。session对象内部使用Map类来保存数据,因此保存数据的格式为 “Key/value”。 session对象的value可以是复杂的对象类型,而不仅仅局限于字符串类型。【从客户端与服务端建立连接会话开始,直到关闭浏览器时结束,是HttpSession类实例】
application 对象可将信息保存在服务器中,直到服务器关闭,否则application对象中保存的信息会在整个应用中都有效。与session对象相比,application对象生命周期更长,类似于系统的“全局变量”。
out 对象用于在Web浏览器内输出信息,并且管理应用服务器上的输出缓冲区。在使用 out 对象输出数据时,可以对数据缓冲区进行操作,及时清除缓冲区中的残余数据,为其他的输出让出缓冲空间。待数据输出完毕后,要及时关闭输出流。【JspWrite类实例】
pageContext 对象的作用是取得任何范围的参数,通过它可以获取 JSP页面的out、request、reponse、session、application 等对象。pageContext对象的创建和初始化都是由容器来完成的,在JSP页面中可以直接使用 pageContext对象。
config 对象的主要作用是取得服务器的配置信息。通过 pageConext对象的 getServletConfig() 方法可以获取一个config对象。当一个Servlet 初始化时,容器把某些信息通过 config对象传递给这个 Servlet。 开发者可以在web.xml 文件中为应用程序环境中的Servlet程序和JSP页面提供初始化参数。
page 对象代表JSP本身,只有在JSP页面内才是合法的。 page隐含对象本质上包含当前 Servlet接口引用的变量,类似于Java编程中的 this 指针。
exception 对象的作用是显示异常信息,只有在包含 isErrorPage=“true” 的页面中才可以被使用,在一般的JSP页面中使用该对象将无法编译JSP文件。excepation对象和Java的所有对象一样,都具有系统提供的继承结构。exception 对象几乎定义了所有异常情况。在Java程序中,可以使用try/catch关键字来处理异常情况; 如果在JSP页面中出现没有捕获到的异常,就会生成 exception 对象,并把 exception 对象传送到在page指令中设定的错误页面中,然后在错误页面中处理相应的 exception 对象。
9个分为四类:
第一类:和servlet有关:page和config
第二类:与Input/Output有关:out,request,response
第三类:与Context有关:application,session,pageContext
第四类:与Error有关:exception
Request对象的主要方法:
include作用是在当前文件引入另外一个文件,以便当前文件使用。
include指令使用方法:<% @ include file = “xx.jsp” %>
include动作:
差异在于二者调用时间。include指令是编译阶段指令,在编译时编译器会把指令所指向目标文件的内容复制到指令所在的位置,替换指令,最终形成一个文件,在运行时只有一个文件。include指令所包含文件的内容是在编译时插入到JSP文件中,当文件内容有变换就需要重写编译,适合于包含静态页面情况。
include动作是运行时语法,在主页面被请求时,才将用到页面包含进来,涉及两个文件,类似方法调用,更适合动态页面。
两者还有3点差别:
1)使用include动作,页面声明变量不可用于另一文件。除非将变量放置在request,session,application作用域中。而在使用include指令,当前页面和被包含页面可以共享变量。
2)使用include指令,新生成jsp页面要符合jsp语法要求,避免变量名冲突。include动作不会。
3)include指令会修改被包含文件,不会立即生效,除非修改主页面或删除主页面的类。include动作修改被包含文件会立即生效。
include动作在维护上的优势,在当两种方法都使用时,优先考虑使用include动作。仅在所包含文件中定义主页面要用到的字段或方法,或所包含文件设置主页面的响应报头时,不应该使用include指令。
不同页面传递参数或做到数据共享。
会话指客户端打开与服务器连接并发出请求到服务器响应客户端请求全过程。
会话跟踪是对同一个用户对服务器连续请求和接受响应的监视,由于客户端和服务器端之间是通过HTTP进行通信,而HTTP本身是无状态协议,不能保存客户信息,即一次响应完成后连接就断开,下一次请求时需要重新建立连接,等到建立完连接后还需判断是否是同一个用户,对会话过程进行监控最好的办法是会话跟踪技术。
有四种:
response.setContentType()指定jsp页面编码。
String序列化成byte数组或反序列化旋转正确编码格式。
结合java,xml和JavaScript的技术,目的是在不刷新页面情况下通过与服务器进行少量数据交互提高页面交互性,减少响应时间,提高用户体验。
好处:只向服务器发生并取回必须数据内容,使交互量大幅降低,从而降低服务器网络负载。其次,通过SOAP(简单对象协议)或其他基于XML的web service接口,在客户端采用JavaScript处理来自服务器的响应,降低了web服务器的处理时间。最后不需要重新加载整个页面,因此系统具有更短响应时间,提高稳定性和可用性。
ajax是客户端技术,核心是XmlHttpRequest,该对象支持异步请求技术,使用JavaScript向服务器提出请求并处理响应而不阻塞用户。
cookie是HTTP下,服务器或脚本可以维护客户工作站上信息的一种形式。由web服务器保存在用户浏览器的小文件,可以包含用户信息(身份识别,密码等)。
session指客户端与服务器端之间保持状态的解决方案及存储结构。
两者区别:
1)cookie机制采用客户端保持状态,数据存放在客户浏览器。session采取服务端保持状态,数据存放在服务器。
2)cookie安全性不够。他人可取本地cookie进行cookie欺骗。session在服务器因而较为安全。
3)session性能更高。session会在一定时间内保持在服务器上,随着访问量增多,服务器性能下降。
4)cookie保持数据最多不超过4kb,一个站点最多20个。session不存在该问题。
所以用户登录信息存放在session,其他重要保留信息在cookie中。
J2EE是java平台企业版简称,是用来开发与部署企业级应用的一个架构。提供统一开发标准的多层平台,该平台由构件,服务和通信构成。
构件包含客户端构件【Applets和Application Clients】和服务端构件【service与JSP,EJB】
服务由J2EE服务商提供,分service API(开发时用)和运行时服务。
通信由容器提供的支持协作构件之间通信。
J2EE本质是行业标准。
指驻留在Internet上的计算机程序,用于接收来自客户端请求,然后对请求的处理结果返回给客户端。web服务器接收请求会去查找用户请求资源,把找到资源返回给用户。是被动程序,只当接收客户端请求才发送响应。
又叫web应用服务器,是服务程序,用来给运行在其中的程序(servlet,jsp)提供运行环境。常见tomcat,JBoss,WebLogic等。
服务端容器,是J2EE应用业务层技术。符合J2EE规范的组件就能在3JB容器运行。该组件会被EJB容器高效管理。EJB还给运行在其中的组件提供安全的服务环境【事务管理,邮件服务等】。
EJB组件不能显式使用EJB容器API来请求容器提供的中间件,但可隐式让EJB容器知道它们需求。
客户端容器,包含组件Applet【是嵌入浏览器的轻量级客户端,是web页面无法充分表现数据或应用界面才使用,是代替web页面的手段,但不能使用J2EE各种service和API】。
客户端容器,包含组件Application Client【相对Applet是较重量级的客户端,能使用J2EE大部分service和API】。
提供目录系统,把服务名称和对象关联。实现快速查找和定位分布式应用程序,使程序有更好可扩展性。独立于目录协议,使用可以用其访问各种特定目录服务【LDAP,轻量级目录访问协议,NDS,网络数据服务,DNS,域名系统】
Java信息服务。是一个Java平台中面向消息中间件的API,主要实现各个应用程序之间进行异步通信(创建,发送,接受,读取信息等)。使用JMS能最大限度提升信息应用的可移植性。即支持点对点的消息通信,也支持发布/订阅式的消息通信。
Java事务服务。提供各种分布式事务服务,为J2EE实现分布式事务处理提供重要支撑。
专用数据处理框架,提供一种统一处理不同数据格式的方法。
远程方法调用,用于远程调用服务。只要满足一定规范,可以实现不同计算机之间进行函数调用。
EJB相当于分布式对象模型(DCOM,Distributed Component Object Model),是服务端组件体系结构,用于开发和部署多层的分布式的以及面向对象的应用系统的跨平台体系结构。EJB简化JavaEE的分布式组件应用程序的过程,定义了一组可重用的组件-Enterprise Beans。
EJB分为:session Bean(会话Bean),Entity Bean(实体Bean)和Message Driven Bean(消息驱动Bean).
用来实现服务器端的业务逻辑,同时协调Bean之间的交互。其仅存在于客户应用于服务器交互的时间段内,数据是不保存在数据库中。根据session Bean是否有状态分为:无状态session Bean和有状态session Bean。
无状态session Bean在方法调用期间不维护任何状态,所有事务处理都是在一个方法中处理完成,因此可以被多个客户共享。即无状态session Bean可以同时处理多个客户应用的请求。有状态session Bean不同,会记录客户应用请求的状态【购物车】,因此只能处理一个客户请求。其优点是能够客户应用的状态,缺点是不能被共享,开销大,性能低于无状态session Bean,因此当请求用户数量较多会消耗更多内存。
资料组件,代表数据库中记录,与数据库中数据有着相同的生命周期。只要数据库中数据存在,则一直存在。可以被多个客户应用共享。
持久化方式:1)CMP(容器管理的持续性),构件的相关数据库操作是由容器自动完成,不需要在bean中编写数据库操作的代码。2)BMP(bean 管理的持续性)构件的相关数据库操作由开发人员在代码中通过JDBC编程实现。
这两种形态不同但目的相同,区别是维护资料角色。前者由EJB Contianer 维护,后者由Bean自行维护一致性。
有三种状态:no-state[bean还没有创建],pooled[已经被创建但没有和EJB Object关联],ready[已经关联,断开则回到前一状态]。
用来处理异步信息,一般不是由用户调用。调用方式是当有异步消息发送到某个MDB后,容器会调用MDB的OnMessage方法处理这个异步请求。
EJB基于JAVA的RMI技术,可被远程访问(跨进程,跨计算机),但必须部署在容器中。EJB客户从不直接访问真正EJB组件而是通过其容器访问。EJB容器是EJB组件代理,EJB组件由容器创建和管理。
JavaBean是可复用组件,理论上,每个java类都是一个Bean。但通常是被容器创建,因此应有无参构造函数,还需实现serializable接口实现bean的持久化,但不能被跨进程访问。
EJB和Javabean都是基于java的构件模型。
区别:
EJB | JavaBean |
---|---|
主在服务端开发 | 主在客户端 |
可做独立单元部署在EJB容器 | 不可部署 |
支持部署描述对EJB应用定制化 | 定制化只能在开发阶段 |
分布式对象,可被远程对象访问 | 非分布式对象,只能应用程序内部被访问 |
对用户不科技 | 对终端用户可见 |
无状态session Bean的生命周期由容器决定。只有两个状态 :No State【没有实例则创建】和Method Ready【创建后变成的状态】。
有状态session Bean的生命周期是与用户操作相关,但不能被共享,使用客户端第一次调用时,容器必须立即在服务器创建新的bean实例并关联到客户端上。每当客户端调用状态session Bean的·方法,容器会把调用分派到此客户机相关联的Bean实例。生命周期有三个:No state[无则创],Method Ready和Passivated(钝化,实例过多,保存正被使用的,其他的从内存移到持久存储上,设置为该状态)。
Entity Bean能存活长时间且持续。数据库数据存在则一直存活。即使EJB奔溃依旧存活。生命周期被容器或bean自身管理。状态有No State【不存在实例】,pooled state【实例未关联EJB对象】,ready state【已关联】。
对象管理组织(OMG)的对象实务服务(OTS),Sun Microsystems的Java Transction Service(JTS),Java Transaction API(JTA),开发组(X/Open)的XA接口。
当客户端调用某个EJB实例业务方法,若对应EJB Object发现自己没有绑定对于Bean实例,则从其去激活Bean存储中(通过序列化机制存储实例)恢复(激活)此实例。状态变迁前会调用对应的ejbActive和ejbPassivate方法。根据MRU(最近最常使用)或NRU(最近未使用),实例在激活和未激活之间迁移。
这六个角色分别是EJB组件开发者(Enterprise Bean Provider) 、应用组合者(Application Assembler)、部署者(Deployer)、EJB 服务器提供者(EJB Server Provider)、EJB 容器提供者(EJB Container Provider)、系统管理员(System Administrator)
EJB组件开发者(Enterprise BeanProvider)负责开发封装有商务规则的EJB组件。EJB组件开发者定义EJB组件的Home接口和Remote接口、编写组件类并且提供部署EJB组件的部署描述文件(DeploymentDescriptor)。EJB组件开发者是商务应用开发领域的专家,不需要精通系统级编程方法以及系统级的组件事务管理、同步、安全性、分布式计算等细节。
部署者(Deployer)负责将打包后的EJB组件部署到EJB服务器等应用环境中。部署者应根据EJB组件的部署描述文件中声明的对各种类型的资源,如数据库、安全性管理等的需求来配置EJB服务器来为组件提供服务。部署者是EJB应用环境方面的专家。
应用组装者(ApplicationAssembler)负责将各种类型的EJB组件组合成一个完整的应用系统,因此应用组装者必须明确待组装EJB组件的Home接口和Remote接口定义的详细内容。
EJB服务器通常由操作系统开发商、中间件开发商或数据库开发商来提供。因此,EJB 服务器提供者(EJBServer Provider)是应用软件系统领域的专家,精通分布式系统管理、分布式对象管理及其它系统服务。
EJB 容器提供者(EJB ContainerProvider)是系统级的编程专家,其工作主要集中于开发可伸缩的,具有事务、交易和安全管理功能的集成在EJB服务器中的EJB容器。EJB容器提供者为EJB组件开发者提供了一组标准的API来访问EJB容器,使EJB组件开发者不需要了解EJB服务器中的各种技术细节就能够开发出部署在EJB容器中的EJB组件。
在实际应用中,通常假定EJB服务器提供者和EJB容器提供者来自同一软件开发商,因而没有定义EJB服务器提供者和EJB容器提供者之间的接口标准。
系统管理员(SystemAdministrator)负责为EJB服务器和EJB容器提供一个企业级的计算环境并利用EJB服务器和EJB容器提供的监测管理工具监测EJB组件的运行情况。
三个对象是Remote(Local)接口【定义业务方法】、Home(LocalHome)接口【提供产生和定位Remote接口实例的方法,分远程和本地两种】,Bean类【javax.ejb.EnterpriseBean接口的类,定义商业逻辑】
开发步骤:
客户端调用EJB步骤:设置JNDI服务工厂以及JNDI服务地址系统属性,查找Home接口,从Home接口调用create方法创建Remote接口,通过Remote接口调用其业务方法。
引入更多概念,实现进一步简化。不再像2.0需要两接口和一个bean实现类。主要是通过annotations元注释来注明是Session Bean类型。EB3.0通过元数据,去掉部署文件,省去对Home接口的使用等方法简化开发操作。EJB2.0访问数据库使用Entity Bean,3.0使用JPA(Java Persistance API)
负责管理运行其中的bean,提供事务管理,持久化管理,安全管理和并发访问控制管理以及生命周期管理和代码生成等,使得开发重点放在业务逻辑上。
不能操作线程和线程API(非线程方法,notify,wait等);不能操作AWT;不能实现服务器功能;不能对静态属性存取;不能使用IO操作直接存取文件系统;不能加载本地库;不能将this作为变量,不能将this返回;不能循环调用。
前者可以向发出请求的浏览器提供文档的程序,主要功能是提供网上信息浏览服务,即收到浏览器请求并把处理结果传回浏览器进行显示。web服务器支持以HTTP的方式来访问,当web服务器接收一个HTTP请求,它同样会议HTTP格式返还一个响应,这个响应可以是一个静态HTML页面也可以是结果处理的一个动态页面。
为处理一个请求,web服务器作出响应并进行页面跳转或把动态响应的产生委托一些其他程序(CGI,JSP,servlet或其他)。web服务器一般使用特有机制(容错)保证web服务器有较好扩展性,并能提供不间断服务。常见web服务器有Apache和IIS。
应用服务器提供访问业务逻辑途径以供客户端应用程序使用。具体来说,是通过HTTP,TCP/IP,IIOP(互联网内部对象请求代理协议)或JRMP(java远程方法协议)等来提供业务逻辑接口。为了系统可靠性,同样使用一些可扩展和容错机制。除此之外,还为应用开发提供许多服务,比如事务管理,安全管理,对象生命周期等。常见应用服务BEA WebLogic Server,Tomcat等。
web服务器是通用的,应用服务器是专用的。web服务器和应用服务器是并列管理,不存在包含关系。访问的是HTML,用web服务器就可以,如果是jsp,就需要应用服务器。只有应用服务器才能解析jsp中的java代码并将解析结果以HTML格式返回给用户。
基于网络的分布式模块化组件,可调用功能分布到web上以供应用程序访问(使用标准的web协议和数据格式)。由于遵循技术规范,使得能与其他组件或系统有很好兼容性。
web service是基于下面协议实现。
调用web service时,服务提供者把所提供的服务发布到服务代理的一个目录上。然后服务请求者使用UDDI首先到服务代理提供的目录上搜索服务,得到如何调用该服务的信息(WSDL),然后根据得到的调用信息使用SOAP调用服务提供者提供的服务。
web service的优点:完好封装性;松耦合【提供者和使用者互补影响】;高度客户操作性【跨平台,跨语言调用】;动态性。
SOAP是严格定义信息交互协议,用于web service中把远程调用和返回封装成机器可读的形式化数据,SOAP数据使用xml数据格式,定义一整套复杂标签,来描述调用的远程过程、参数、返回值和出错信息等内容。
REST(表达性状态转移)形式上为客户端通过申请资源来实现状态的转换,可以被看做一台虚拟的状态机。需要注意是,它仅是一种软件架构风格,而不是一个具体协议或标准。而且它是面向资源,甚至连服务都会被抽象成资源。
SOAP | REST | |
---|---|---|
寻址模型 | URI只用来定位SOAP端点;资源与URI是一一对应;一端点对应多个资源 | 标准化的URI、DNS;URI与资源(包括服务)一一对应 |
接口 | 不提供通用操作,每个服务定义自己方法(操作) | 提供通用操作,即HTTP的GET、PUT、POST和DELETE |
中间媒介 | 不兼容传统web中间媒介 | 兼容传统web中间媒介,包括代理、缓存服务、网管等 |
安全性 | 十分复杂,不能使用观有防火墙控制 | 简单有效,可用现有防火墙控制 |
XML(可扩展标记语言)是一套定义语义标记规则的语言,被用来描述业务数据、数学数据等。用于实现系统解耦。
与HTML比,xml把用户界面与结构化数据分隔开,这种数据与显示的分离使得集成来自不同源的数据成为可能。
XML优点:实用性强(文本存储,易于修改和调试,可用在数据量小场合也可存储大量数据);访问速度快(层次结构);可扩展性好(标记可自定义);跨平台性好(统一语法)。
缺点:数据量大,存储效率变低,比其他存储方式(CSV)占用更大存储空间。
XML两种形式:文档类型定义(DTD)与Schema。一方面定义xml文档结构,一方面验证xml文档是否满足指定结构。DTD是标记语法规则,定义xml文档元素架构,标记和属性,规定可使用什么标记,标记顺序和标记层次关系,并定义实体。
schema是基于xml,是一套预先规定的xml元素的属性创建。schema支持命名空间,能定义比DTD更复杂数据类型和结构。
一个XML可以有多个schema,只能有一个DTD。
XML解析两种方式:DOM【根据XML在内存创建树形结构,占据内存大】和SAX【基于事件驱动,每次对数据请求看成事件,遍历文件获取用户所需数据】。
其体系结构采用MCV模式。
1)客户端(Clinet)
通过浏览器发生HTTP请求,可把接收到的HTTP响应信息在浏览器上展现出来。
2)控制器
包括ActionServlet类和RequestProcessor类。前者是MVC的控制器部分,是框架核心,用于接收用户请求,并根据用户请求从模型模块获得用户数据,选择合适视图响应用户请求。采用命令设计模式实现该功能:通过struts-config.xml配置文件确定处理请求的Action类。在处理请求时,请求的大部分已由RequestProcessor.process()方法来处理。RequestProcessor类的process()方法采用了模板的设计模式。
处理流程:
3)业务逻辑
servlet接收到请求会根据配置文件中的对应关系,把请求转给指定的Action类来处理,Action类采用适配器设计模式,它只是对业务逻辑进行了包装(真正业务逻辑是EJB的session bean或普通Java类实现)
4)模型
模型分系统内部状态和可以改变状态的操作(业务逻辑)。内部状态通常由一组ActionForm Bean表示,ActionForm封装HTTP请求的数据的类或对象。ActionForm是抽象类,每个输入表单都对应着它的一个子类。配置文件struts-config.xml保存HTTP请求表单与具体的ActionForm类的映射关系。
5)视图
视图是JSP文件,没有业务逻辑处理,无需保存系统状态信息。通过标签把数据以浏览器能识别的方式展现出来。
采用MVC模式,实现表现与逻辑分离,具备良好扩展性;标记库包含大量tag,有助于提高系统开发效率;提高页面导航功能,使系统脉络更加清晰。通过一个配置文件建立整个系统各部分之间的联系,使系统结构变得更加清晰,从而增加系统可扩展性与可维护性;提高表单验证功能,加强系统健壮性;提供数据库连接池管理;提供exception处理机制;指出国际化;
大量tag,初学不易,开发难度大;包含很多XML格式配置文件,这些配置文件不易调试,且数量多不便管理;只支持web应用程序开发;structs的Action不是线程安全的,因此所以Action类用到的资源必须进行同步;单元测试不方便【Action与web层紧耦合,十分依赖web容器】;部署繁琐(赚到表示层需要配置forward);对servlet依赖过强;
Struts框架控制器是ActionServlet,对业务逻辑主要是Action,ActionMapping,ActionForward等组件协调完成。Action是控制逻辑实现者,ActionMapping和ActionMapping指定不同业务逻辑或流程的运行方向。
采用Struts框架的web应用,当web应用启动时,会加载并初始化ActionServlet,ActionServlet会从structs-config.xml中读取配置信息,并把它们存放到ActionMapping对象。具体来说,当ActionServlet接收到客户请求,执行下列流程:
如果返回一个(或多个)ActionMessage的ActionErrors对象,则表示表单验证失败,ActionServlet会直接把请求转发给包含客户提交表单的JSP组件。这种情况下不会再创建Action对象并调用Action的execute方法
表单验证【由ActionForm Bean处理】和业务逻辑验证【Action处理】。
四个:
attribute属性:设置和Action关联的ActionForm Bean在request和session范围内的key
className属性:和Action元素对应的配置元素,默认是org.apache.struts.action.ActionMapping
include:指定包含URL路径
path属性:指定请求访问Action的路径
parameter:指定Action配置参数,在Action类的execute方法众可以调用ActionMapping对象的getParameter方法来读取该配置参数
rules:指定允许Action的安全角色,多个角色用逗号隔开。在处理请求时,RequestProcessor会根据该配置项来读取配置项决定是否用户有权限调用Action
type属性:指定Action的完整类名
name属性:指定需要传递给Action的ActionForm Bean
scope属性:指定ActionForm Bean的存放范围
unknown:设置为true,该操作将被作为所有没有定义的ActionMapping的URL的默认操作,设置为true也表示哭晕处理用户发出的所有无效的Action URL,默认是false。
validate属性:指定是否执行表单验证
input属性:指定当表单验证失败时的转发路径。
< action>元素还包含一个< forward>子元素,它定义了一个请求转发路径。
(1)检查Action的映射,确定Action中已经配置了对ActionForm的映射
(2)根据name属性,查找form bean的配置信息
(3)检查Action的formbean的使用范围,确定在此范围下,是否已经有此form bean的实例。
(4)假如当前范围下,已经存在了此form bean的实例,而是对当前请求来说,是同一种类型的话,那么就重用。
(5)否则,就重新构建一个form bean的实例
(6)form bean的reset()方法被调用
(7)调用对应的setter方法,对状态属性赋值
(8)如果validatede的属性被设置为true,那么就调用form bean的validate()方法。
(9)如果validate()方法没有返回任何错误,控制器将ActionForm作为参数,传给Action实例的execute()方法并执行。
forward是根据Action 返回值找到对应的JSP页。当多个Action共同return同一个值时,可将这个forward元素写在Global-Forward中。
准备各语言资源文件,在资源文件定义键和对应字符串,在显示地方指定键就可以。
structs1由ActionForm和JavaBean组成。前者用于封装用户请求参数成ActionForm对象,后由ActionServlet转发给Action,Action根据ActionFrom里面的请求参数处理用户请求。
struct2基础是核心控制器FilterDispatcher,包含框架内的控制流程和处理机制。业务控制器Action和业务逻辑组件是需要用户自己实现。开发Action和业务逻辑组件的同时,还要编写相关配置文件,以供核心控制器FilterDispatcher使用。
两者都是MVC的web框架,但很多不同。
控制反转也称依赖注入,是降低对象耦合关系的设计思想。在分层体系结构中,都是上层调用下层接口,上层依赖下层的执行,即调用者依赖于被调用者。通过Ioc使得上层不再依赖下层接口,即通过采用一定机制选择不同下层实现,完成控制反转,使得由调用者来决定被调用者。Ioc通过注入一个实例化对象来达到解耦目的。使用这种方法,对象不会被显式调用,而是根据需求通过Ioc容器来提供。
Ioc机制提高系统可扩展性。如果对象之间通过显式调用进行交互会使得调用者和被调用者存在紧密联系,一方改动将会导致程序出现很大改动【基类抽象生成,工厂模式生成,本质还是需要改动代码】。Ioc容器比如Spring容器会根据配置文件来创建调用者对象,同时把被调用的对象的实例化对象通过构造函数或者set方法形式注入到调用者对象中。
使用IOC优点
缺点:对象是通过反射机制实例化,对系统性能有影响;创建对象的线程变得比较复杂;
面向切面编程,允许在不改变原来模型基础上动态修改模式以满足新需求。
J2EE框架,提供轻量级IOC支持,和AOP技术封装。设计更加模块化,每个模块都能完成特定工作且独立运行不互相牵制。
主要由7个模块构成:
可以在web容器中用来管理web服务器端的模块,还可以管理用于访问数据库的hibernate。由于IOC和AOP思想,被spring管理的对象都可以脱离EJB容器单独运行和测试。在需要被spring容器管理时,只需增加配置文件,spring框架会根据配置文件与相应的机制实现对这些对象的管理。
1)使用J2EE开发多层应用程序,spring有效管理中间层代码,由于IOS和AOP思想,使得容易单独测试。
2)使得培养起面向接口编程的习惯
3)对数据存取提供一个一致框架
4)支持不同事物处理API(JTA,JDBC,hibernate等)的方法对事物管理提供一致抽象方法。
5)使用spring框架编写的大部分业务不需要依赖Spring
是开源的对象关系映射(ORM,完成对象模型和关系模型的映射技术)框架,它不仅可以运行在J2EE容器,也可以在J2EE外运行。对JDBC进行轻量级的对象封装,所以任何使用JDBC的地方都可以用Hibernate来替代。Hibernate实现了Java对象与关系数据库记录的映射关系。简化开发人员访问数据库的流程,提高软件开发效率。
hibernate提供5个核心接口,分别是Session,SessionFactory,Transaction,Query和Configuration。通过这些接口不仅可以完成对数据库的访问,而且还可以实现对事务的控制。
轻量级非线程安全对象,复杂持久化对象与数据库操作。可用SessionFactory创建一个Session,当对数据库所有操作都执行完成,可以关闭Session,Session在访问数据库时会建立与数据库的连接,这个连接只有在需要时才会被建立
负责初始化Hibernate。可被看做数据源的代理,可以用来创建Session对象。此外SessionFactory是线程安全的,因此可以被多个线程同时访问。一般而言,SessionFactory会在Hibernate启动时创建一次,为方便,SessionFactory用单例实现。
负责事务相关操作。主要方法commit和rollback。其中commit负责事务提交,rollback负责事务回滚。可以通过Session的beginTranaction方法来创建。
负责执行各种数据库查询。可以使用hibernate查询语言(HQL)或SQL语句两种方式进行查询(HQL与SQL不同在于使用类和属性而不是表与列名)。通过Session的createQuery方法创建Query。此外hibernate提供另外一种查询方式QBC(Query By Criteris)。其使用方法为:先使用Session实例的createCriteria方法创建Criteria对象,接着使用工具类Restrictions的方法为Criteria对象设置查询条件,同时还可以用Order工具类的方法设置排序方式,最后用Projections工具类的方法进行统计和分组,使用Criteria对象的list方法进行查询并返回结果。注意QBS是类型安全的面向对象的查询方式。
读取hibernate配置文件,并生成SessionFactory对象。其中配置文件主要有两类:一类是hibernate.cfg.xml或hibernate,properties;另一类是映射文件,例如***.hbm.xml。其中前一类配置hibernate服务的信息(数据库启动类,数据库连接URL,数据库用户名和密码等信息)。后一类用来配置java对象与关系数据库记录的映射关系。为便于管理和维护,会对每个对象创建单独映射文件。
1)应用程序通过Configuration类读取配置文件并创建SessionFactory对象。
2)通过SessionFactory生成一个Session对象
3)通过Session对象的beginTrancation方法创建事务
4)完成所有持久化操作与事务操作后关闭Session和SessionFactory
1)提高开发效率;2)开发面向对象实现,不需关系数据库关系模型;3)良好可移植性,容易实现不同数据库之间移植而不需要关系不同数据库SQL语句的差异;4)支持透明持久化
只适用于单一对象简单增删改查,而批量修和删不适用。当使用数据库特定优化机制则不使用hibernate。
延迟加载(不从数据库把数据加载到对象,而是建立代理对象,代理对象属性设为默认值,当这些数据被使用才从数据库中加载)
缓存技术(合理分配缓存的参数【加载数据个数】)
优化查询语句
体现在表间关系,都是对对象操作。所以表和类都映射一起,通过配置文件中的many-to-one,one-to-many,many-to-many配置。
hibernate缓存用来把数据库查询出来的和使用过的对象保存在内存,以便后期需要该对象直接从缓存中获取(若缓存没有从数据库查询)。
hibernate中,一级缓存由Session管理,二级由SessionFactory。二级可不用,而一级必不可少。
一级缓存用于使用Session查询数据时,然而Session生命周期较短而且线程不安全,不能被多线程共享。对效率提升不明显。
二级缓存用于hibernate配置全局缓存,以实现多个线程与事务共享。使用后,查询数据首先在内部缓存中查找,不存在则在二级缓存查找,最后才去数据库查找。二级缓存是第三方产品,hibernate3默认是EhCache。根据需求通过配置二级缓存插件实现二级缓存。二级缓存可以以内存作为存储介质,也可以选用硬盘等外部存储设备。
二级缓存适用情况
1)数据量较小;2)对数据修改较少;不会被大量应用共享的数据;4)不是很重要的数据。
hibernate对象有三种状态:瞬时态(Transient),持久态(Persistent)和脱管状态(Detached)。持久态对象称为PO,其他被称为VO。
saveOrUpdate包含save和update方法功能。hibernate根据对象状态决定使用哪一个。若是持久化状态,不做操作直接返回。若传入对象与session另一个对象有相同的标识符,则抛出异常;若对象的标识符属性(用来唯一确定一个对象)在数据库中部存在或是临时值,则调用save方法将之保存到数据库中,否则用update方法更新对象的值到数据库中。鉴于此,在使用时,若能确定对象状态,最好不要调用saveOrUpdate方法,有助于提高效率。
get和load方法都是用来通过从数据库中加载所需的数据创建持久化对象,不同有:
1)Assigned。外部程序负责生成,需要调用save方法前指定,否则会抛出异常。在执行新增操作需要查询数据库判断生成主键是否存在,否则会产生主键冲突。
2)Hilo。使用一个高/低位算法生成long,short或int类型标识符。给定一个表和字段作为高位值来源,将id产生源分两部分:DB+内存。然后按照算法产生id,从而在很少连接产生多条数据提高效率。需要额外数据库保存主键生成历史,能保证同一个数据库主键唯一性,而不能保证多个数据库之间主键唯一性。
3)Seqhilo是高/低位算法实现的主键生成机制,只是主键历史状态保存在Sequence中,适用于支持Sequence的数据库。
4)Increment。采用主键自增方式生成新主键。实现机制:当前应用实例维持一个变量保存当前最大值,每次需要生成主键,将此值加1作为主键。该法要求数据库支持Sequence。缺点:新增数据要先查询一遍,影响系统性能。主键只能是int或long型,存在并发问题(如果当前有多个实例访问同一数据库,由各个实例各自维护主键状态,不同实例可能生成主键一样导致主键重复异常)。只适合单线程对数据库访问方式,不适合在多进程并发更新数据库的场合。
5)Identity。由数据库提供自增生成性主键。使用方便但在不同数据库的移植严重不便。
6)Sequence。利用数据库提供的Sequence(序列)机制生成主键。要求数据库提供Sequence机制。不同数据库移植,尤其是支持序列的到不支持的数据库相当麻烦。
7)Native。hibernate根据底层数据库自行选取Identity、Hilo、Sequence中的一种作为主键生成方式。灵活性强,便于移植。
8)UUID。基于128位唯一值产生算法生成的16进制数值(编码后以长度32位字符串表示)作为主键。能保证不同环境下主键一致性,但生成主键占用较多存储空间。
9)Foreign GUID。用于一对一关系中采用特殊算法生成主键,从而保证主键唯一性。
10)select。该方式使用触发器生成主键,现在用得少。
(1)hibernate自带分页机制。
通过Session获取Query对象;使用Query对象的setFirstResult()设置要查询的第一行数据;最后用setMaxResults()设置结果集大小。
2)SQL语句实现
select * from tableName where 条件 limit begin,count
Struts,Spring,Hibernate的首字母组合,是较为流行开发web开源框架,用于构建灵活,易于扩展的多层web应用。
Struts使用jsp实现视图,模型用hibernate提供数据持久化,业务层用spring管理对象。
优点:
1)Struts实现MVC,使得开发重点放在业务逻辑。标签库能提高开发效率。
2)Spring管理对象,降低组件耦合,更专注业务逻辑开发。提供事务管理。
3)Hibernate实现高效对象关系映射,开发完全采用面向对象思想,不需考虑数据库关系模型。具备良好可移植性,实现不同数据库间移植,不需关系不同数据库SQL语句差异。
本次博文对何昊出版的《java程序员面试宝典》的第5章Java Web部分的概括笔记,希望对他人和以后自己有帮助。