《Java EE 轻量级框架应用与开发——S2SH》笔记

Spring Booot笔记 专栏收录该内容
10 篇文章 1 订阅

嗯,那本书看完了,但是还没有整理完笔记,不太愿意在电脑旁太久,总会看到她,嗯,所以大部分时间在图书馆,只能刷这本书,哎,这些时日,大概是我一生中仅有的阴霾吧,我希望如此,不知道,希望早些赚钱,以此偿还那些曾经为我付出的,真的好累,这世间,我不愿意这样活着,我想到了黑塞《彼得卡门青》中的波比,我不是他,我不愿意那样生活,有一个倚着的东西就好啦,不要托着。嗯,总会过去的,那么麻木的日子都走了过来。2018.11.16

第一章  Java EE应用

Java EE 概述

Java平台分为Java SE ,java EE(企业级应用标准开发平台), JavaME三个版本,如今Java EE不仅是指一种软件技术,更多的是表达一种软件架构,和设计思想,是一系列技术标准所组成的开发平台。

Java EE分层框架

企业级应用的开发过程,软件的可维护性和可复用性是降低开发成本所必须要考虑的两个重要指标

实体层(POJO层):由POJO(Plain Old Java Object,普通的传统的Java对象)组件构成,这些对象代表系统的实体,通常与数据库中的表对应,主要作用是将数据保存起来,即持久化数据,一般保存的数据库或文件中,

数据访问层(DAO层):由DAO(Data Access Object)组件组成,这些DAO组件提供了对实体对象的创建,查询,删除,和修改等操作。

业务逻辑层(service层)有业务逻辑对象组成,用于实现系统所需要的业务逻辑方法。

控制器层(Controller层):由控制器构成,用于响应用户请求,并调用业务逻辑组件的对应业务方法处理用户请求,然后根据处理结果转发到不同的表现层组件。

表现层(View层):由页面(如JSP,HTML)或其他视图组件组成,负责收集用户的请求,并显示处理结果。

在轻量级Java EE应用架构中,通常会交给类似于Spring框架的IOC(Inversion of Control,控制反转)容器来管理组件之间的依赖,耦合度低。

Java EE架构技术:Sping,Struts ,Hibernate三个开源框架的组合,成为最流行的Java EE 架构。

Struts2

Struts是一个为开发基于MVC模式的应用架构的开源框架,是利用Servlet和JSP构建Web应用的一项非常有用的技术。

Struts2是在Struts框架和WebWork框架基础上发展起来的。

Hibernate

持久化(Persistence):是指把数据保存到可永久保存的存储设备中的过程,最常见的持久化是将内存中的数据存储在关系型数据库中.

持久化层( Persistence Layer):即专注与实现数据持久化应用领域的某个特定系统的一个逻辑层面。将数据使用者和数据实体相关联。

对象和关系数据是业务逻辑的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据,内存中的对象之间存在关联和继承关系,而在数据库中无法直接表达多对对以及继承关系,所以把对象持久化到关系数据库中,需要进行关系对象-映射(Object-Relation Mapping ,ORM)

开源框架Hibernate是一种Java语言下ORM解决方案,实现了数据持久化功能,Hibernate能够将对象模型所表示的实体映射到基于SQL的关系模型结构中去,为面向对象的领域模型到传统的关系型数据库的映射提供方案,Hibernate对JDBC进行了对象式封装,不仅管理Java类到数据库表的映射(包括从Java数据库类型到SQL数据类型的映射),还提供数据查询和获取数据的方法,基本不在使用SQL和JDBC,Hibernate可以应用在任何使用JDBC的场所,可以在Java胖客户和瘦客户之间使用。

Spring 介绍

Spring是基于Java平台的一个开源应用框架,在Java EE领域,Spring是作为EJB模型之外的另一个选择甚至代替品,Spring 为企业提供了轻量级的解决方案,包括基于依赖注入的核心机制,基于AOP的申明式事务管理。与多种持久化层技术的整合。优秀的Web MVC框架,Spring框架的主要优势就是其模块化的分层结构,由7个定义良好的模块组层,基于此分层架构,Spring框架允许用户选择使用任一组件,Spring模块构建在核心容器上,核心容器定义了创建,配置和管理Bean的方式。Spring AOP,Spring ORM,Spring DAO,Spring Web,Spring Context,Spring Core。使用Spring框架时,必须使用Spring Core(代表Spring框架的核心机制),每个模块和组件都可以单独存在。或者与多个模块联合使用。

EJB(Enterprise Java Bean):是基于Java开发,部署服务器端分布式组件的标准规范,EJB是sun的服务器端组件模式,最大的作用是部署分布式应用程序,EJB组件主要有会话Bean(Session Bean),实体Bean(Entity Bean)和消息驱动Bean(Message Driven Bean)等三种类型,其中会话Bean和消息驱动Bean用于实现EJB应用中的业务逻辑,而实体Bean用于持久化。

Struts2基础

起源:2001年Struts1广泛使用,Struts1是第一个得到广泛使用的MVC框架,核心为控制器,由两部分组成:核心控制器ActionServlet,以及用户自定义的业务逻辑控制器,

Struts原理图

  1. Web应用发送请求,请求将被核心控制器ActionServlet拦截。
  2. ActionServlet根据请求决定是否调用业务逻辑控制器,否转发给JSP。是
  3. 业务逻辑控制器调用相应的模型来处理用户请求。
  4. 处理结果通过JSP呈现给用户。

Struts1的缺点:与JSP,Servlet耦合非常紧密,表现层技术单一,仅支持JSP,在Model2的基础上发展,完全基于Servlet API,与Servlet API严重耦合,脱离Web服务器,Action的测试变得非常困难。Action类必须继承其提供的Action基类,使用大量Struts1专有的API,入侵式设计的最大弱点,系统重构,Action类没有利用价值。

Struts2优势:支持更多的表现层(JSP,Veloccity),Action无需与Servlet API耦合,测试更加容易,提高代码重用率,具有更好的模块化和可扩展性,适合团队协作开发大项目,提供插件机制,

框架结构:Struts2的框架结构与Struts1 的差别,Struts2是以WebWork为核心,采用拦截器的机制对用户的请求进行处理Struts2的拦截器机制使得业务逻辑控制器与Servlet API完全分离,业务逻辑更像一个POJO,

处理步骤:

  1. 客户端浏览器发送一个HTTP请求
  2. Web容器收到请求后,会将请求传递给一个标准的ActionContextCleanUp过滤器来清除属性,不让后续的过滤器清除,从而延长Action中属性的生命周期(),以便在页面中访问。
  3. ActionContextCleanUp处理过后在经过其他过滤器,如SitMesh等,然后传递给核心控制器StrutsPrepareAndExecuteFilter;
  4. StrutsPrepareAndExecuteFilterd调用ActionMapper确定请求那个Action,在将控制权委派给ActionProxy代理。
  5. ActionProxy代理调用配置管理器ConfigurationManager从配置文件struts.xml中读取配置信息,然后创建ActionInvocation对象
  6. ActionInvocation在调用Action之前会依次调用所有配置拦截器链,一旦Action执行结果返回结果字符串,ActionInvocation会根据结果字符串查找对应的Result。
  7. Result会调用视图模板(如JSP,FreeMarker等)来显示,并在给客户端HTTP响应之前,以相反的顺序执行拦截器链。
  8. 最后,HTTP响应又被返回给核心控制器StrutsPrepareAndExecuteFilter,在依次经过Web.xml中配置的过滤器。最终发送到客户端。

控制器:Struts2的控制器组件是struts2整个框架的核心,由两部分组成:核心控制器(StrutsPrepareAndExxcuteFilter)+业务控制器Action。

StrutsPrepareAndExecuteFilter:实际为一个过滤器,作用于整个Web程序,需要在Web.xml配置

<filter>
<filter-name>struts2</filter-name>
<filter-class>实现类的全限定名</filter-calss>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

任何MVC框架需要与Web应用整合时都需要借助web.xml配置文件,通常MVC框架只需要在Web应用中加载一个核心控制器即可,一个Web应用只要加载StrutsPrepareAndExecuteFilter后,就具有了Struts2的基本功能。所有的请求都需要经过该过滤器后才能进一步得到处理。

Action:是用户定义的业务控制器,可以为普通的POJO,没有使用任何Servlet API,Action中有一个execute()方法,该方法用于业务逻辑。返回一个String值,映射对应的视图,实际中Struts2中起作用的业务控制器并不是用户定义Action,而是由Struts2框架生成的ActionProxy代理,但是该ActionProxy代理是以用户定义的Action为目标的。

标签库:Strues2标签库功能非常全,完全代替JSTL标签库,支持OGNL(Object Graph Notation Language)表达式语言,功能强大。

在Struts2框架下开发Web应用的步骤:

  • 下载安装Struts2框架,配置应用环境。(web.xml配置StrutsPreparAndExecuteFilter)
  • 创建输入视图,即input.jsp页面,接受用户数据,
  • 创建用户业务控制器,即UserAction类,并实现其业务处理方法execute()方法,
  • 在struts.xml中配置业务控制器UserAction。
  • 创建结果视图,即result.jsp页面,显示数据。
  • 运行web 应用,显示结果页面。

配置文件(降低各组件的耦合):

虽然Struts2 提供了Convenient插件来管理Action,result,但大多数情况下还是采用xml文件的形式,通过配置文件将Struts2  的核心控制器与业务控制器以及视图等组件联系在一起,实现相关功能,

当Struts框架生成ActionProxy代理时,需要访问Struts2的配置文件,该文件中有用户定义的Action相关信息。

Struts2的配置文件有两种:struts.properties(用于配置Struts的全局属性),struts.xml。通常放在源代码目录中。

struts.xml:用于配置Action与请求的对应关系,配置逻辑视图名与物理视图资源之间的对应关系,配置Bean,常量,以及导入其他配置文件。,Struts的默认配置文件,通常放在WEB-INF/classes路径下(Web 应用的加载类路径),

常量:对整个Struts2应用起作用的常量,通过配置常量的值,可以Struts2 的一些默认行为,Struts2可以在三种文件中对常量进行配置:struts.xml,struts.properties和Web.xml,在不同文件中配置会出现常量覆盖,后一个会覆盖前一个常量值,

                                           常量加载顺序(左到右)
struts.xmlstruts.propertiesweb.xml
                                          常量的覆盖顺序(右到左)

定义常量需要指定两个属性(常量名name和常量值vlaue).

在struts.xml配置文件中使用<constant>标签元素来配置常量。<constant name  = "struts.il8n.encoding" value = "GBK">

在struts.properties中配置常量:struts.i18n.encoding = GBK;

struts.properties:属性文件是Struts2应用的全局属性文件,文件中的内容以键值对的形式存储,

strtus.i18n.encoding = UTF-8
#指定默认的编码集
struts.configuration.xml.reload = true
#修改struts.xml后是否从新加载该文件,开发阶段打开。
struts.serve.static.browserCache = false
#设置浏览器是否缓存静态内容,开发阶段关闭。

 

在web.xml中配置核心过滤器时可以配置Struts2常量,采用初始化参数的方式来配置常量,<init-param>

struts.configuration指定加载Struts2配置文件的配置管理器,默认为默认配置文件管理器
struts.locale指定Web应用的默认Locale,默认值为en_US,中文环境为zh_CN
struts.i18n.encoding指定Web应用的默认编码集,默认值为UTF-8
struts.objectFactory指定Struts2默认的ObjectFactory Bean
struts.multipart.parser指定处理multipart、form-data的MIME类型(文件上传)请求的框架,默认为jakarta,可以支持cos,pell,及common-fileupload等文件上传框架
struts.multipart.maxSize指定上传文件的最大字节数
struts.multipart.saveDir指定上传文件的临时保存路径,默认java.serlet.context.tempdir
struts.custom.properties指定Struts2框架加载用户的常量文件,多个逗号隔开
struts.action.extendion指定需要Struts2处理的后缀请求,默认值为action,即所有与*.action匹配的请求都由Struts2 处理
struts.server.static.browserCache设置浏览器是否缓存静态内容,开发阶段通常设置为false
struts.configuration.xml.reload当struts.xml改变后,系统是否从新加载该文件,默认fluse,开发阶段通常设置为true
struts.xslt.nocache指定XSLTResult是否使用样式表缓存,开发阶段true
struts.custom.i18n.resources指定Struts2所需要的国际化资源文件,多个资源文件之间使用英文逗号隔开
struts.devMode指定Struts是否使用开发模式,默认值为false
struts.mapper.calss指定将HTTP请求映射到指定的Action过滤器,Struts2 提供了默认映射器org.apache.struts2.dispatchar.mapper,Default.DefaultActionMapper

通常在struts.xml中配置,不在struts.propertise(保持与WebWork的向后兼容)和web.xml(降低可读性)中配置。

struts.xml:配置一个Action时,必须指定该Action的实现类,并定义该Action的处理结果映射的视图资源。

<struts>
	<!-- 指定struts2处于开发阶段,可以进行调试 -->
	<constant name = "struts.devMode" value = "true"/>
	<package name = "default" namespace = "/" extends = "struts-default">
		<action name = "Action_name" calss = "类的全限定名">
			<result name = "映射字符串1">视图资源地址1</result>
			<result name = "映射字符串2">视图资源地址2</result>
			<result name = "映射字符串3">视图资源地址3</result>
		</action>
	</package>
</struts>

:在struts2配置文件中使用包来组织Action,Action的定义是放在包的定义下完成的。包由多个Action,多个拦截器,多个拦截器引用组合的集合构成。可以方便地对Struts2框架的核心组件进行组织管理。每个<package>元素定义一个包配置,package元素属性

name指定包的名字,用于声明该包被其他包引用的key
extends指定包继承的其他包,即继承其他包的Action,拦截器等的定义。可选
namespace指定包的命名空间,可选
abstract指定包是否是一个抽象包,抽象包不能包含Action定义,属性可选。true或false

struts -default是struts2框架的默认抽象包,包含大量的结果类型定义,拦截器及引用定义,是配置Action的基础,因此定义包时,通常继承struts-default包。解析方式从上往下解析,所以父包要放在子包前否则会抛出异常。如果同一个包中定义了两个同名的Action,后者会覆盖前者。

命名空间:同一个命名空间不能有同名的Action,不同的命名空间可以出现同名的Action,Struts2不支持为单独的Action设置命名空间,可以由namespace指定共同的命名空间,没有指定则属于默认命名空间。当为默认命名空间时,直接通过Action名访问,URL:http://id地址:端口号/web路径应用名称/add.action。当指定名称空间时,/命名空间名/add.action的方式访问。

struts2还可以显示的指定"/"命名空间,访问方式与默认命名空间一样。区别:默认命名空间的Action可以处理任何命名空间的下的Action,根命名空间下的Action只能处理根命名空间下的请求,

配置命名空间后Struts2 搜索Action方式:

  1. 指定命名空间,2.默认命名空间。3.报错。

struts.xml配置文件可以使用<include>标签元素包含其他的配置文件,但xml文件必须是完整得Struts2配置文件,(单独解析每个xml文件)。

实现Action:Action 是Struts2  的应用的核心,用于处理用户的请求,每个action 类就是一个工作单元。

Struts2框架下实现Action类:

  1. 普通的POJO类,该类通常有无参的execute()方法,返回值为字符串。
  2. 实现Action接口;(包含返回字符串的execute方法,定义5个字符串常量,统一execute的返回值error,input,longin,none,success)
  3. 继承ActionSuport类(框架为Action接口提供的实现类ActionSupport,提供默认方法, 是Struts2 默认的处理方法(配置时没有指定class属性),书写Action时一般继承Actionsupport类,重写方法validate等);Struts2 提供了完整的验证框架,可以通过配置文件的方式对需验证的内容进行配置。
  4. 访问ActionContext:struts2 中Action不与任何的ServletAPI耦合,提供ActionContext类来访问Servlet API,提供了读写Servlet API中的HttpServletRequest ,HttpSession,ServletContext中数据的方法。
Object get(Object key)获取属性值,与HttpservletRequest的getAttribute(String name)方法类似
Map getApplication()返回一个Map对象,该对象 模拟了Web中ServletContext对象
static ActionContext getContext()静态对象,用于获取系统的Action对象
Map getParameters()

获取所有的请求参数,类似于HttpServletRequest的getParameterMap()方法

Map getSession()返回一个Map对象,模拟了HttpSession
void setApplication(Map application)直接传入一个Map对象,将该Map对象里的键/值转换为属性名/值
void setSession(Map session)直接传入一个Map对象,将该Map对象里的键/值转换成session的属性名/值。

    6.访问Servlet API 的接口(重写相应的方法)

ServletContextAware实现该接口的ACtion可以直接访问Web应用的ServletContext实例
ServletRequestAware实现该接口的Action可以直接访问用户的请求的HttpServletRequest实例。
ServletRequestAware实现该接口的Action可以直接访问服务器响应的HttpServletResponse实例。
private HttpServletRequest request;
public void setServletrequest(HttpServletRequest request){
    this.request = request;
}

 

   7.Struts2框架还提供一个ServletActionContext工具类。提供静态方法继承的到。

static PageContext getPageContext()

获取Web应用的PageContext对象

static HttpServletRequest getRequest()获取Web应用的HttpServletRerquest对象
static HttpServletResponse getResponse()获取Web应用的HttpServletResponse对象
static ServletContext getServletContext()获取Web应用的对象ServletContext对象

配置Action

实现了action后需要制作wweb.xml中配置action.

基本配置:指定action 的基本属性,Action只是一个逻辑控制器,不直接对用户请求生成任何响应,通过< result>元素来实现逻辑视图与物理视图之间的映射关系。

name:指定action 的名字,即指定该action所处理的请求的URL,ActionName.action.

class:指定Action的实现类,可选,如果没有指定默认使用ActionSupport类。

 

动态方法调用:Struts1 中提供了DispatchAction,从而允许一个Action内包含控制处理逻辑。Struts2 中请求一个Action中不同的处理逻辑方法,称为DMI(Dynamic Method Invocation,动态方法调用),struts 2 开启动方法调用需要在struts.xml 配置文件中配置struts.enable.DynamicMethodInvocation的值为true。

语法 :actionName!methodName.action;//actionName :表示Action的名字,method表示Action实现类中处理逻辑的方法名,

<a href = "produnct!edit.ction?productId = 1002">

除了使用DMI,还可以使用method属性及通配符,实现相同的功能,将Action定义为多个多个逻辑的Action。在配置<action>元素时,需要指定name,class,method属性。指定method属性后,可以让Action调用指定的方法,而不是execute()方法来处理请求,

<action name = "调用URL名1" class = "实现类全限定名1" method= "方法名1">
	<result name = "映射字符串">视图资源地址</result>
</action>
<action name = "调用URl名2" class = "实现类全限定名1" method = "方法名2">
			<result name = "映射字符串">视图资源地址</result>
</action>

通配符:可以在class,method属性及<restult>子元素中使用{N}的形式代表前面第N个*所匹配的字符串

<action name = "*-*" class = "com.liruilong.actiuon.{1}Action" method = "{2}">
    <result>/{1}.jsp</result>
</action>
<action name = "*" calss = "com.liruilong.actiuon.UserAction" method = "{1}">
     <result>/{1}.jsp</result>
</action>
		

result元素:负责逻辑视图(普通字符串)与物理视图之间的映射关系。

struts2框架将物理资源结果转向实际资源时,不仅可以为JSP视图,也可以为FreeMarker视图资源,甚至可以将请求转向下一个Action处理,形成Action链式处理.

配置result:根据struts.xml中<result>元素所处的位置不同,分为局部和全局。

局部result:将<reslult>元素作为<action>元素的子元素配置。在特定Action范围内有效,即一个Action不能使用另一Action配置的局部result,属性name指定逻辑视图名,默认值为success,type指定result类型,默认值为dispatcher,表示请求转发到JSP页面。

全局的result:将<result>元素作为<global-result>元素的子元素配置。作用范围对全局的Action都有效,如果Action中定义了与全局result同名的局部result,则后者会覆盖前者。

<global-results>
       <result>/物理资源地址</result>
</global-results>

result类型

chain

用于进行Action链式处理

chart用于整合JFreeChart技术
dispatcher用于整合JSP技术,将请求forward到指定的JSP,
freemarker用于整合FreeMarker技术
httpheader用于控制特殊的HTTP行为
jsf用于整合JSF技术
redirect用于重定向到其他的URL
redirectAction用于重定向到其他的Action,与readirect的区别redirectAction使用ActionMapperFactory提供的ActionMapper进行重定向,而redirect使用HttpServletResponse的sendRedirect(),
steam用于向浏览器返回InputStream,一般用于文件下载
tiles用于整合Tiles技术
velocity用于整合Velocity技术
xslt用于整合XML/XSLT技术
plain Text 用于显示某个页面的源代码
Jasper用于整合JasperReport报表技术

使用redirectAction类型需要指定actionName和namespace两个参数。

actionName:参数指定重定向的Action名称。namespace:参数指定需要重定向的Action的命名空间。

<result type = "redirectAction">
	<param name = "actionName">Action名</param>
	<param name = "namespace">Action命名空间</param>
</result>

Struts2异常处理:

最好使用声明式的方式管理异常处理,申明式的异常处理机制使得异常处理和代码的耦合度降低,有利于维护。

声明式异常处理机制:当Action处理用户的请求时,如果出现了异常1,则系统转入视图资源1,同时在该视图资源输出服务器提示,如果出现异常2,则系统转入视图资源2,并在该资源上输出服务器提示。

配置异常:Struts2框架捕获异常后,按照struts.xml文件中<sxception-mapping>元素配置的映射,转入到相应的页面进行进一步处理,需要两个属性,exception用于指定Action出现异常所映射的异常类型。result属性用于指定Action抛出的异常时,系统转入该属性值对应的<action>或者<global-results>中配置的<result>元素

根据出现的位置:分为局部映射(将该元素作为<action>元素的子元素匹配)和全局映射(该元素作为<global-exception-mappings>元素的子元素配置),

throw new RuntimeException("用户登录失败");
struts.xml
<action>
    <exception-mapping result = "error" exception = "java.lang.Exception"/>
    <result>/OK.jsp</result>
    <result name = "error">/error.jsp</result>
</action>

第四章,struts2标签库

MVC框架都是表现层框架,,因此所有的MVC框架都会提供自己的标签库,Struts2的标签分类,Struts2将所有的标签都定义在URL为/struts-tags的空间下,并提供严格的标签库分类。

UI(User Interface,用户界面):标签--主要用于生成HTML元素的标签。包括表单标签和非表单标签。

非UI的标签:主要用于数据访问,逻辑控制的标签。包括流程控制标签和数据访问标签。

Ajax标签:用于支持Ajax的标签。

Struts2标签库的导入:在JSP页面中使用,必须使用taglib指令引入标签库:<%@ taglib prefix="s" uri = "/struts-tags"%>

OGNL表达式语言:

OGNL(Object-Graph Navigation Language,对象图导航语言):提供存取对象属性,调用对象方法,遍历对象结构图,对象类型转换的特定语法,是Struts2内建的表达式语言,加强了Struts2的数据库访问功能。

具有依赖关系的类调用:

String teacherName = student.getGrade().getTeacher().getName();
在Struts2中通过OGNL表达式语言:
String teacherName  = (String)Ogn1.getValue("grade.teacher.name",student);

OGNL上下文和值栈:

OGNL中的getValue方法中有两个参数。

第一个参数:为表达式,是OGNL的核心,是一个带有语法含义的字符串,规定了操作的类型和操作的内容。OGNL支持大量的表达式语法,包括链式对象的路径访问和简单的计算等。

第二个参数:Root对象,即操作对象,表达式规定了做什么,而Root对象规定了对谁操作。

实际中OGNL的取值还需要一个上下文环境,即操作对象的所在环境,上下文规定了OGNL的操作在哪里进行。

在Struts2 中,采用标准命名的上下对象(OGNL Context)来处理OGNL表达式,处理OGNL的一个顶级对象是一个Map(也可以称为Context Map),而OGNL在这个OGNLContext中就是一个顶级对象或根对象。在用法上,Root对象的属性访问时不需要任何标记前缀的,而其他的非顶级对象则需要使用“#”标记。

Struts2构造了一个Action的上下文环境,称之为ActionContext,它封装了当前Action与Web容器交互的request,response等对象,并且使用ThreadLoad模式对每一次请求对会实例化一个新的ActionContext与当前线程绑定。所以Struts2的action是线程安全的。可以说ActionContext封装了一个处理Web请求的环境,而在这个环境中对请求的数据储存传输则是交给了ValueStatic。

ValueStack被称为值栈:是对OGNL的扩展,struts2正是通过ValueStack来使用OGNL进行赋值和取值操作的。

ValueStack封装了OGNL 的所有功能,并且主要对OGNL的Root对象进行了扩展。ValueStack封装了一个CompoundRoot类型的对象作为root属性,CompoundRoot是一个继承ArrayList的栈存储结构,而所有被压如栈中的对象,都会被视为OGNL的Root对象,在使用OGNL计算表达式时,首先会将栈顶元素作为Root对象,进行表达式匹配,匹配不成功向下匹配,返回第一个匹配成功的表达式计算结果。Struts2通过了ValueStack实现了多Root对象的OGNL操作。

提交一个请求,会为这个请求创建一个和web容器交互的ActionContext,与此同时会创建ValueStack,并置于ActionContext中,实例化Action后,就会将这个action对象压入valueStack中,

在请求映射过程中,Struts2通过parametersInterceptor拦截器将提交的参数值封装入对应的Action属性中,因此action实例可以作为OGNL的Root对象,对于Action中的属性方法都可以使用OGNL获取。

在Struts2中,值栈对应valueStack接口,该接口的实现类为OgnlValueStack。

OGNL常用符号的用法:

#,%,$符号在OGNL表达式中经常出现

#:访问非根对象的属性。用于过滤和投影集合,用于构造Map对象。

访问非根对象的属性:

parameterrs对象:用于访问HTTP请求参数。#parameters.name==request.getParameter("name");

request对象:用于访问HttpServletRequest属性,#request.name ==调用getAttribute("name");方法

session对象:用于访问HTTPSession对象,例如#session.name==调用getAttribute("name");方法

application对象:用于访问ServletContext对象。例如#applicant.name相当于调用ServletContext的getAttribute()方法。

attr对象:用于按照page--request--session--application的顺序访问其属性。

%符号:在标识的属性为字符串类型时,计算OGNL的表达式的值,如果不使用%符号则会按照普通的字符串处理,

此外在JSP页面中"%{"就表示OGNL表达式的开始,"}"表示OGNL的结束。访问根对象中的方法和属性可以通过%{object.fieid}

利用%可以取出值栈中的Action对象的方法。%{getText('key')}

$符号:在国际化资源文件中,引用OGNL表达式,即"键=年龄必须在${min}和¥{max}之间。在Struts2框架配置文件中引入OGNL表达式。

OGNL集合表达式:可以通过OGNL表达式直接生成一个集合,

第五章Hibernate入门

Hibernate是一个开放源码的ORM(Object Relational Mapping,对象关系映射),可以将ORM理解为一种规范,这种规范概述了此类框架的基本特征,完成面向对象语言到关系型数据库的映射,

ORM优势:通过面向对象的思想对数据库进行访问,提高开发效率,最大限度的降低代码的编写工作。降低数据库访问权限,提高应用程序性能,相对独立,b变动不会影响上层实现。

ORM映射通常使用配置文件来完成,ORM基本的映射规律:

  • 表与类映射:数据库中的表被映射到一个持久化类上,当对该持久化类操作时,系统会自动转换为对数据库的表进行添加等操作。受ORM管理的持久化类只是一个普通的Java类,也成POJO(Plain Ordinary Java Object)。
  • 表中的行与对象(持久化类的实例)映射,持久化类会产生许多实例对象,每个实例对都与表中的一行记录相对应,当修改持久化类时,ORM工具会自动转换成相对应数据表中的特定行进行操作。
  • 表中的字段与对象的属性相映射,当修改持久化对象的属性值时,ORM工具会自动转换成相应的数据库表中指定的行,指定的列操作。
  • 表与表之间的关系映射为对象与对象的关系。

ORM框架:JPA(本身是一种ORM规范,不是OMR产品,JPA实体与HIbernate的POJO相似,JPA完全可以做Hibernate的POJO使用,JavaEE规范标准,具有通用性。),Hibernate(被选为JBoss的持久化解决方案,属于Red Hat组织的一部分),iBATIS(Apache软件基金组织的子项目,一种SQL Mapping框架),TOLink(Oracle公司的产品)

Hibernate框架:

是java语言下的ORM解决方案:具有的优势:

  • 开源,免费,便于研究代码等,轻量级封装,具有可扩展性,API开放,自行扩展,性能稳定。

Hibernate的持久化解决方案将开发者从复杂的JDBC访问中释放出来,用户无需关心底层数据库JDBC的操作,以面向对象的方式进行持久层操作,底层数据连接的获得,数据库的访问的实现,事务控制都无需开发者关心,将应用层从底层JDBC/JTA API 中抽象出来。通过配置文件来管理底层的JDBC连接,让Hibernate解决持久化访问的实现。

对象名功能描述
SessionFactory是Hibernate的关键对象,是单个数据库映射关系经过编译后的内存镜像,是线程安全的,是生成Session的工厂,本身要应用到connectionProvider,该对象可以在进程和集群的级别上,为那些在事务之间可以重用的数据提供可选的二级缓存。
Session是应用程序和持久存储层之间交互操作的一个单线程对象,是Hibernate的关键对象,所有的持久化对象必须在Session的管理下才能够进行持久化操作,该对象的生存周期很短,其隐藏了JDBC连接,也是Transaction的工厂,Session有一个一级缓存,现实执行Fluse前时,所有的持久化操作的数据都是缓存在Session对象处。
Transaction提供持久化中的原子操作,具有数据库事务的概念,代表一次原子操作,通过抽象,将应用程序从底层的具体的JDBC,JTA,和CORBA事务中隔离开,在某些情况下,一个Session之内可以包含多个Transaction对象,,虽然事务操作是可选的,但是所有的事务操作都应该在事务管理下进行,即使是只读操作。
Persistent Object持久化对象,与Session关联,处于持久化状态,系统创建的POJO实例一旦与特定的Session关联,并对应数据表中的指定记录,那该对象就处于持久化状态,这些对象都被称为是持久化对象,程序中对持久化对象的修改,都将自动转换为对持久层的修改。持久层对象完全可以是普通的Java Reans/POJO,
Transient Object瞬态对象,没有与Session关联,尚未持久化的对象,系统进行new 关键字进行创建的java实例后,没有Session相关练,此时处于瞬态,如果一个曾经持久化的实例,但是因为Session的关闭而转换为托管状态。
ConnectionProvider数据库连接提供者,用于生成与数据库建立连接的JDBC对象,是生成JDBC的连接的工厂,同时具备连接池的作用,他通过抽象将底层的DataSourcs和DriverManager隔离开,这个对象无须应用程序直接访问,仅在应用程序需要扩展时使用。
TransactionFactory是生成Transaction对象的工厂,实现了对事务的封装,是生成Transaction对象实例的工厂,该对象也无须应用程序的之间访问。

Hibernate API:

应用程序通过Hibernate API访问操作数据库,Hibernate API中的接口可以分为如下几类:

1,提供访问数据库的操作(增删改查)接口,包括Session,Transaction,Query接口

2,用于配置Hibernate的接口如Configuration接口。

3,使用应用程序接受Hibernate内部发生事件的回调接口,Intercept,Lifecycle和Validatable接口。

4,用于扩展Hibernate功能的接口,如UserType,CompositeUserType和IdentifierGenerator接口。

Hibernate内部封装了JDBC,JTA(Java Transacation API),JNDI(Java Naming and Direcory Interface),JDBC提供底层的数据库访问操作,只要用户提供了相应的JDBC驱动程序,Hibernate就可以访问任何一个数据库系统了。

Hibernate常用的5个核心接口:

Configuration接口:配置和启动Hibernate,创建SessionFactory对象,Hibernate应用通过Configuration实例获取对象关系映射文件的元数据,以及动态配置Hibernate的属性,然后创建sessionFactory实例。

SessionFactory接口:初始化Hibernate,充当数据储存元的代理,创建Session对象。

Session接口:也称持久化管理器,提供持久化相关的操作,增删改查对象。

Transaction接口:管理事务:

Query和Criteria接口:执行数据库查询,Query接口用于执行HQL数据库查询,Criteria用于QBC检索方式。

持久化对象:

Hibernate应用开发通过持久化对象作为媒介,负责将对象的操作转换为相应的数据表的操作,Hibernate需要两个文件:

Hibernate配置文件:该文件用于配置Hibernate和数据库之间的连接信息。

Hibernate映射文件:该文件用于确定持久化类和数据表,数据列之间的对应关系。

Hibernate采用低侵入式设计持久化类,这种设计对持久化类不进行任何要求,完全使用POJO作为持久化对象,

POJO约定成俗规则:

持久化类需要实现Serializable接口,实现可序列化,便于数据传输;

持久化类不能是最终类,即非final类;

持久化类需要提供一个无参数的构造方法(默构),

持久化类需要提供一个标识属性,通常映射到数据库表中的主键;

每个属性都提供相应的setter和getter方法,

为使POJO具备可持久化操作的能力,Hibernate采用XML格式的文件来制定POJO类和数据库表的映射。在程序运行时,Hibernate根据这个映射文件生成各种SQL语句,映射文件的扩展名为hbm.xml、映射文件和其持久化类要放到同一目录下。

PO = POJO+映射文件;

Hibernate映射文件(映射文件的扩展名为hbm.xml):

映射文件的结构:HIbernate映射文件的根元素是<Hibernate-mapping>,该元素可以有多个<class>子元素,每个class元素对应一个POJO持久化类的映射。

<hibernate-mapping 属性 = 值>
	<calss name="类的全限定名" table="表名">
		<id name = "主键名" column  ="主键列"><!-- 主键 -->
			<generator calss = "生成策略"/><!-- 主键生成器 -->
		</id>
		<property name="属性名" column= "列名" type = "数据类型"/><!-- 属性列表 -->
		……
	</calss>
	……
</hibernate-mapping>
<hibernate-mapping>元素的可选属性
auto-import是否允许在查询语言中使用非全限定名的类名,默认值为true
catalog所映射数据库的Catalog名
default-access默认属性访问策略,默认值为property
default-cascadeHibernate默认的级联风格,默认值为none
package指定包名,对于映射文件中非全限定的类名,默认在该包下
schema映射数据库的模式名
<calss>元素常用的可选属性
name持久化类的类名
table持久化类映射的表名
discriminator-value区分不同子类的值?
mutable指定持久化类的实例是否可变,默认为ture
proxy延迟装载时的代理,可以是该类自己的子类?
<id>元素的可选属性
name标识属性名
type标识属性的数据类型,可以为Hibernate内建类型,也可以是Java类型(带包名)
column标识属性所映射的数据库中表的列名
unsaced-value指定刚创建,未保存的某个实例的标识属性值
access指定访问标识属性的访问策略,默认为property

通常情况下,推荐使用逻辑主键,尽量避免使用复杂的物理主键,使用物理主键会增加数据库维护的复杂度,Hibernate为逻辑主键提供了主键生成器,以便为每个持久化实例生成唯一逻辑主键。

主键生成器列表
incerment获取数据库表中所有主键中的最大值,在最大值基础上加一,为最新记录的主键,
identity自动增长。MS SQL Server,MySQL和DB2等数据库中可以设置表的某个字段(列)的数值自动增长。此种方式生成的主键的数据类型可以是long,short,int,及其对应的封装类的类型。
sequence序列,Oracle,DB2等数据库可以创建一个序列,然后从序列中获取当前序列号作为主键值
hilo"高/低位"高效算法产生主键值,此种方式生成主键的数据类型可以是long,short,int及其对应的封装类类型。
seqhilo与hilo类似,但使用指定的sequence获取高位值。
uuid采用128位的UUID算法生成一个字符串类型的主键
guid采用GUID字符串产生主键值
native由Hibernate根据所使用的数据库支持能力从identity,sequence或者hilo中选择一种,例如,Oracle中使用的sequence,Mysql的identity
assigned指派值
foreign通过的关联持久化对象为主键的赋值。

在Hibernate的主键生成器策略时,参考原则:如果应用系统不需要分布式部署,在数据库支持的情况下使用sequence,identity,hilo,seqhilo,uuid;如果应用需要使用多个数据库或者进行分布式的部署,则uuid是最佳的选择。

映射集合的属性:集合属性大致有两种:第一种是单纯的集合属性,例如List,Set或数组;第二种是Map结构的集合属性,每个属性都是"键/值"对。

Hibernate要求集合必须属性必须声明为接口,例如List,Set,Map接口,Hibernate之所以要求使用集合接口申明集合属性,是因为当程序持久化某个实例时,Hibernate会自动把集合的实现了类替换为自己的实现类。对于不同的集合接口,在Hibernate映射文件中需要采用不同的集合映射元素。
 

 

HIbernate集合映射元素
<list>java.util.List集合中的元素可以重复,可以通过索引获得
<set>java.util.Set集合中的元素不重复。
<map>java.util.Map集合中的元素是以键/值对的形式存放
<array>数组可以是对象数组或基本数组类型的数组
<primitive-array>基本数据类型的数组基本数据类型的数组,例如,int[],char[]等
<bag>java,util.Collection无序集合
<idbag>java.util.collection无序集合,但是可以增加逻辑顺序。

 

Hibernate配置文件:

Hibernate配置文件用于配置访问数据库的一些参数信息,如连接数据库的URL连接字符串,用户名,密码以及是否创建或更新表信息,对于所有的持久化类都是通用的。

要使用Hibernate配置文件,可以采用3中形式:

hibernate.cfg.xml文件形式,采用XML文件形式。是Hibernate最常用的配置方式。

hibernate.properties文件形式:采用"键/值"对的属性文件形式,能够快速配置Hibernate的信息。

hibernate.cfg.xml和hibernate.properties文件结合使用的形式。一起作为配置文件。

HIbernate配置文件常用属性
 hibernate.dialect针对不同的数据库提供不同的方言,允许Hibernate针对特定的数据库生成优化的SQL语句
hibernate.connection.driver_calss数据库驱动类
hibernate.connection.datasource数据源的JNDI的名字
hibernate.connection.urlJNDI数据库提供者的URL
hibernate.connection.username连接数据库的用户名
hibernate.connection.password连接数据库的密码
hibernate.connection.pool_size数据库连接池的最大容量
hibernate.show_sql是否输出Hibernate操作数据库使用的SQL语句
hibernate.format_sql是否格式化输出SQL语句

hibernate.hbm2ddl.auto

是否根据映射文件自动建立数据库表,该属性可以是create,create-drop和update三个值,值为create时会根据POJO创建表,但每次运行都要重新生成表,值为create-drop时,则关闭sessionFactory时,自动删除创建的表,update是最常用的属性,不会删除以前的记录行

 

Hibernate连接不同的数据库需要使用不同的方言,在Hibernate配置文件中,通过设置hibernate.dialect属性来指定不同的数据库方言。

数据库方言类
Oracle9i/10g/11gorg.hibernate.dialect.OracleDialect
MySQLorg.hibernate.dialect.MySQLDialect
DB2org.hibernate.dialect.DB2Dialect
Microsoft SQL Servletorg.hibernate.dialect.SQLServletDialect
Sybaseorg.hibernate.dialect.SybaseDialect

 

hibernate.cfg.xml:是Hibernate配置文件的常用的形式,因为XML文件的结构性强,容易读取以及配置灵活等优势,且可以直接配置POJO所对应的映射文件。可以省略hibernate前缀。

Hibernate配置文件中有如下几个元素:

<hibernate-configuration>元素,Hibernate配置文件的根元素。

<session-factory>:是<hibernate-configuration>的子元素。

<property>元素:是<session-factory>元素的子元素,用于配置访问数据库的参数信息,可以有多个<property>。

<mapping>元素:是<session-factory>的子元素,用于注册所有的ORM映射文件,每个<mapping>子元素注册一个Hibernate映射文件,可以有多个。

<hibernate-configuration>
	<session-factory>
	<property name =  "属性名">
		属性值
	</property>
	……
	<mapping resource = "注册所有ORM映射文件"/>
	……
	</session-factory>
</hibernate-configuration>

hibernate.properties文件是以键值对的形式出现的,与hibernate.cfg.xml本质一样,只是在hibernante.properyise中不能对Hibernate的映射文件进行配置。需要在Hibernate应用程序中调用Configuration对象的addResource()方法添加映射文件。

Configuration configuration = new Configuration();
configuration.addResource("com/qst/chapter05/pojos/Student.hbm.xml");

联合使用:

hibernante.cfg.xml和hibernante.properties文件结合使用,在hibernate.properties中配置数据相关的信息。在hibernate.cfg.xml文件中对Hibernate映射文件进行配置。

开发Hello Hibernate应用程序的方式有一下三种:

第一种:自顶向下从持久化类到数据库表,即先编写持久化类,再编写映射文件,进而生成数据库表的结构。

第二种:自底向下从数据库表到持久化类,即根据数据库表结构生成对应的映射文件和持久化类。

第三种:从中间出发向下与向上同时发展,即先编写映射文件,然后根据映射文件向上生成持久化类,向下生成数据库表结构。

自顶向下开发Hibernate应用程序的步骤:

1,配置Hibernate应用环境,在应用中添加HIbernate所需要的jar包,并创建Hibernate配置文件;

2,编写PO;PO = POJO+映射文件;

3,创建Configuration对象:

Configuration对象代表一个应用程序到数据库的映射配置,根据配置文件不同,创建Configuration对象的方式也不同,通常采用hibernate,cfg.xml文件作为配置文件。

Configuration configuration - new Configuration();//实例化Configuration对象
configuration.cofigure("/hibernate.cfg.xml");//加载hibernate.cfg.xml文件;

Configuration对象可以产生一个不可变的SessionFactory对象,Configuration对象只存在于系统的初始化阶段,所有的持久化操作都是通过SessionFactory实例来完成的。

4,创建SessionFactory对象;

通过Configuration对象的buildSessionFactory()方法可以创建一个SessionFactory对象,SessionFactory对象是Hibernate进行持久化操作所必须的对象,该对象是整个数据库映射关系经过编译后形成的内存镜像,通常一个应用程序只有一个SessionFactory对象,且唯一不可改变。

//创建一个StandardServiceRegistryBuilder对象,具有注册表功能,可以对服务进行统一的加载,初始化,存放和获取,
StandardServiceRegistryBuilder standardServiceRegistryBuilder = new 
 StandardServiceRegistryBuilder();
standardServiceRegistryBuilder.applySettings(configuration.getProperties());
//Configuration对象会根据配置文件的内容构建SessionFactory实例,即SessionFactory一旦构建完毕,就会包含配置文件信息,之后任何的对Configuration实例的改变都不会影响到已经构建的SessionFactory对象。
SessionFactory sessionFactory = configuration.buildSessionFactory(standardServiceRegistryBuilder.build();)

5,创建Session对象;

Session对象是Hibernate持久化操作的基础,持久化对象的生命周期,事务的处理,对象的查询,更新和删除等操作都是通过Session对象完成的,通过调用SessionFactory对象中的openSession()或getCurrentSession()都 可以获取Session对象。Session对象封装了JDBC连接,具有一个一级缓存,在显示执行flush()方法前,所有的持久化操作的数据都在Session对象的缓存中,

获取Session对象:Session session = sessionFactory.openSession();

Session中的方法
save()保存持久化对象,在数据库中新增一条记录
get()获取数据库中的一条记录,当未找到符合条件的持久化对象时返回null,查找对象时先从Hibernate一级缓存中查找,找不到则直接从数据库中查找记录。
load()获取数据库中的一条记录,当未找到符合条件的持久化对象时抛出异常(HibernateException),在一级缓存中找不到的情况下,还会查找二级缓存。然后才是数据库
update()跟新数据库中的对应记录
delete()删除数据库中的一条记录

6,使用Transaction管理事务;

Transction对象主要用于管理事务,所有持久化操作都需要在事务管理下进行,Transaction通过抽象将应用程序从底层的JDBC,JTA以及CORBA事务中隔离开,允许开发人员使用一个统一的事务操作让自己的项目可以在不同的环境和容器之间迁移。

通过Session对象的beginTransaction()方法可以获得一个Transaction对象的实例。Transaction对象主要有commit()和rollback()方法。commit():用于提交事务;rollback():用于回滚事务;

事务:一个Transaction对象的事务可能包括多个持久化操作,程序员可以根据需要将多个持久化操作放在开始事务和提交事务之间,从而形成一个完整的事务。

7,使用Query进行HQL查询或利用Criteria实现条件查询。

Hibernate Query Language (HQL)查询是完全面向对象的查询,所操作的对象是类,实例,属性等。

HQL优势:支持继承,多态,各种条件查询,连接查询,和子查询。支持分页,分组查询。支持聚集函数和自定义函数。支持动态绑定查询参数。

HQL查询依赖于Query类,每个Query实例对应一个查询对象。利用Querey进行HQL查询的步骤如下,

1,获取Hibernate Session对象。2,编写HQL语句。

3,以HQL语句作为参数,调用Session的createQuery()方法创建Query查询对象。

4,如果HQL语句包含参数,则调用Query的setXxx()方法为参数赋值。5,调用Query对象的list等方法返回查询结果。

Query query = session.createQuery("from User");

Criteria方式为一种面向对象的查询方式,通过Session对象的createCriteria()方法可以创建Criteria的实例对象。

Criteria Criteria = session.createrCriteCritria( Customer.class);

POJO状态:对需要被持久化的POJO对象,其生命周期有以下三种状态:

顺时状态(Transient):刚用new关键字创建,还没有被持久化,且尚未与Hibernate Session关联,不处于Session的缓存中,此时的对象处于瞬时状态,处于瞬时状态的对象被称为瞬态对象。不会被持久化到数据库,也不会被赋予持久化标识,程序失去了瞬态对象的引用,瞬态对象将垃圾回收机制销毁。

持久化状态(Persistent):已经被持久化,加入到Session缓存中,与数据库中的表的一条记录对应,并拥有一个持久化标识。持久化对象可以是刚刚保存的,也可以是刚被加载的,Hibernate会检测到持久化状态的对象的任何改动。并且在Session关闭或Transaction提交的同时更新数据库中的对应数据,不需要手动更新。

托管状态(Detached):已经被持久化,但不再处于Session的缓存中,即对象曾经处于持久化状态,但与之关联的Session关闭后,就变成托管状态,如果重新让托管对象与某个Session发生了关联,变为持久化对象。

调用Hibernate Session的不同方法会引起对象的状态改变。

持久化状态save()该方法保存持久化对象,进而在数据库中新增一条数据
saveOrUpdate保存或者根新,根据映射文件中<id>标签的unsave-value属性值决定执行新增或跟新。
get()根据标识符属性值获取一个持久化对象,如果未找到,则返回null;
load()根据标识符属性值获取一个持久化对象,如果未找到,抛出异常
update()对托管状态的对象重新定义完成持久化,并更新数据库中对应的数据。
瞬时状态delete()用于删除数据库中的一条记录,在删除时,首先需要get()或load()获取要删除记录的持久化对象,然后调用该方法。
托管状态close()关闭当前Session对象,并清空该对象的数据
cvivt()清除Session缓存中的某个对象
cleat()清除Session中的所以缓存对象。

在执行HIbernate持久化操作时都需要创建Configuration对象,SessionFactory对象,Session对象。因此一般封装为一个工具类。

public class HibernateUtils {
	private static String CONFIG_FILE_LOCATION = "/hibernate.cfg.xml";
	private static final ThreadLocal<Session>threadLocal = new ThreadLocal<>();
	private static Configuration configuration = new Configuration();
	private static StandardServiceRegistryBuilder standardServiceRegistryBuilder= new StandardServiceRegistryBuilder();
	private static SessionFactory sessionFactory;
	private static String configFile = CONFIG_FILE_LOCATION;
	static {
		try {
			configuration.configure(configFile);
			standardServiceRegistryBuilder.applySettings(configuration.getProperties());
			sessionFactory = configuration.buildSessionFactory(standardServiceRegistryBuilder.build());
		}catch(Exception e) {
			System.out.println("%%%%%%%%%%%%%%Error Creating SessionFactory%%%%%%%%");
			e.printStackTrace();
		}
	}
	public HibernateUtils() {
		// TODO Auto-generated constructor stub
	}
	/*
	 * 返回TheradLocal中的session实例
	 * 
	 * 
	 */
	public static Session getSession() throws HibernateException{
		
		Session session = (Session)threadLocal.get();
		if(session == null || !session.isOpen()) {
			if(sessionFactory ==null) {
				rebuildSessionFactory();
			}
			session = (sessionFactory != null)?sessionFactory.openSession():null;
			threadLocal.set(session);
		}
		return session;
	}
	/*
	 * 返回Hibernate的SessionFactory
	 * 
	 */
	private static void rebuildSessionFactory() {
		try {
			configuration.configure(configFile);
			sessionFactory = configuration.buildSessionFactory(standardServiceRegistryBuilder.build());
		}catch(Exception e) {
			System.out.println("%%%%%%%% Error Createing SessionFactory%%%%%%%%");
			e.printStackTrace();
		}
	}
	/*
	 * 关闭Session实例并且把ThreadLocal中的副本清除
	 * 
	 */
	public static void closeSession() throws HibernateException{
		Session session = (Session)threadLocal.get();
		threadLocal.set(null);
		if(session != null){
			session.close();
		}
	}
	/*
	 * 返回SessionFactory
	 * 
	 */
	public static SessionFactory getSessionFactory() {
		return sessionFactory;
	}
	public static void setConfjgFile(String configFile) {
		HibernateUtils.configFile = configFile;
		sessionFactory = null; 
	}
	public static Configuration getConfiguration() {
		return configuration;
	}
	
}

第六章:Hibernate进阶

Hibernate 关系映射:

关联关系是面向对象分析,设计最重要的基础理论,关联关系从访问方向上讲分:

单向关系:只需单向访问关联端,分单向1-1、1-N,N-1,N-N。

双向关系:关联的两端可以相互访问,双向1-1,1-N,N-N。

1-N关联:

    单向N-1关联:在Hibernate映射文件中,使用<many-to-one>元素来实现N-1的关联映射,通过<many-to-one>元素来映射关联实体时需要在N的一端对应的数据表中增加一个外键列。用于参照主表记录。

N的一端写:

<many-to-one name = "1的实体(1的表)" cascade = "all" calss = "实体类名" column ="N端的外键列(1端的主键)"/>
<!--用于映射N-1关联实体,指定关联实体类为:1的实体,指定外键列名为:N端的外键列,并指联级操作-->
many-to-one常用属性及介绍
name指定属性的名字(即从表的字段对应的类属性)
column指定进行关联的外键列的列名(从表字段)
class指定关联实体的类名,默认是通过反射得到的该属性所属类的类名,
cascade指定那些持久化操作会从主表记录级联到字表记录,
fetch指定Hibernate的抓取策略,可以是join(外连接)和select(选择)两个值之一。
property-ref指定关联类的一个属性,该属性将会和本类的外键相对应,默认直接使用对方关联类的主键(主表的对应字段)
access指定Hibernate访问此关联属性的访问策略,默认是property。
unique指定Hibernate通过DDL为外键列添加唯一约束,也可以使用property-ref的目标属性。
not-found该属性指定当外键参照的主表记录不存在时如何处理,可以是ignore和exception(默认).
formula指定一个SQL表达式,该外键值将根据该SQL表达式来计算
lazy指定引用关联的实体的延迟加载特性,该属性只能接受false,prox(默认),no-proxy三个值,Hibernate默认会启动单实例关联(N-1,1-1)的代理,当指定no-proxy时则实例变量第一次访问时采用延迟抓取,当指定false时则该关联实体总是被预先抓取。
not-null指定使用DDL为外键字段添加非空约束,如果true表示属性不能为空,默认为false。

 

单向1-N关联:单向1-N关联的持久化类发生了改变,持久化类里需要使用集合属性,一的一端要访问N的一端,而N的一端将以集合的Set形式表现,在Hibernate映射文件中,使用set元素来映射1-N的关联。

1的一端要有N的一端的对象集合,1端写。

<!--映射集合的属性,集合元素是其他持久化的实体-->
<set name = "1的N端集合属性">
    <!--指定关联的外键列-->
    <key column  ="1的标识列属性(1表的主键)"/>
    <!--用以映射到关联类的属性-->
    <one-to-many class = "N的实体(N端表)"/>
</set>

set元素常用属性:

set元素常用属性及介绍
name指定需要映射的持久化类的属性名
key指定关联表的外键
one-to-many指定关联的持久化类

双向的1-N关联

将单向的1-N关联和单向的N-1关联整合在一起就只双向的1-N或N-1关联,双向1-N关联表示既可以从1到访问到N端,反之也可以,在实际开发中不建议使用单向的1-N关联,而是使用1-N双向关联,只需要在1端配置<set>元素,在N端配置<many-to-one>元素,即可形成双向的1-N。

1-1关联:

1-1关联可分为4种类型:

基于外键的单向的1-1关联,可以理解为特殊的单向的N-1关系,只不过N端也为1; 在基于外键的单向的1-1需要的原有的<many-to-one>元素中设置unique属性值为true(默认为false),用以表示N的一端必须唯一。

<many-to-one name = "1实体类对应属性(另一端)" class  ="另一端实体类" cascade ="all" column = "一端的主键" unique ="true"/>

基于主键的单向的1-1关联,基于主键的关联持久化类不能拥有自己的主键生成器策略,主键有关联实体负责生成。关联时,需要使用<one-to-one>元素来映射关联实体。

<one-to-one>元素常用属性
name指定需要映射的持久化类的属性名
class指定关联实体的全限定类名,默认是通过反射得到该属性的所属类的类名
cascade指定那些操作会从主表记录级联到字表记录
constrained指定该类对应的表和被关联的对象的表之间,通过一个外键引用对主键进行约束,会影响save()和delete()在联级执行的先后顺序,以及该关联是否被委托。
fetch指定抓取策略
property-ref指定关联类的一个属性,该属性与本类的主键相对应,默认使用对方关联类的主键。
access指定Hibernate访问该关联属性的访问策略,默认property。
lazy指定引用关联实体的延迟加载特性,该属性只能接受false,proxy,no-proxy三个值。

没有主键生成策略的一端。

<id name = "id" column = "ID" >
<generator class = "foreign">
    <param name = "property">关联实体主键</param>
</generator >    
</id>
…………
<one-to-one name = "映射的持久化类属性名" class = "类名" constrained= "true"/>

 

基于外键的双向的1-1关联,外键可以放在任意一边,存外键的一端增加<many-to-one>元素(从表),而另一端需要使用<one-to-one>元素(主表)。

//从表,有外键的一端
<many-to-one name = "主表的实体" calss = "实体类" cascade = "all" column = "主表的主键" unique = "true"/>
//主表,
<one-to-one name = "从表的实体" class = "实体类" constrained  ="true"/>

 

基于主键的双向的1-1关联,两个使用相同的主键值,其中一个表的主键共享另一个表的主键。

<!--主键由关联实体生成-->
<id name = "id" column = "ID">
    <generator calss = "foreign">
        <param name = "property">customer</param>
    </generator>
</id>
……
<one-to-one name ="一端中另一端的实体" class = "实体类" constrained = "true"/>
<!--基于主键一端-->
<id name = "id" column = "ID">
    <generator class = "uuid.hex"/>
</id>
……
<one-to-one name ="一端的实体(没有主键的一端)" class = "实体类" cascade = "all"/>

N-N关联:(在Hibernate中可以使用两个1-N关联来代替N-N关联)

单向的N-N关联:单向的N-N关联和1-N关联的持久化类代码完全相同。只需要在主关联关系的一端增加一个Set类型的属性,被关联的持久化对象以集合形式存在。N-N关联必须使用连接表,与有连接表的1-N关联非常相似,只要去掉<many-to-many>元素 的unique="true";

在主表的一端写

<!--单向的N-N关联-->
<set name = "主表的从表的集合属性" table = "连接表的表名">
    <!--指定连接表中参照本表记录的外键字段-->
    <key column ="主表的ID">
    <!--使用many-to-many来映射N-N关联,没有unique = "true"-->
    <many-to-many class = "从表名" column = "从表ID"/>
</set>
<!--连接表中只有两个字段:分别为主表的ID和从表的ID-->

双向的N-N关联:是指具有关联关系的两端可以相互控制,双向的N-N关联只是在单向的N-N的基础上在被动方对象上增加了主动方关联。双向N-N关联需要两端都使用Set集合属性,两端都增加对集合属性的访问,采用连接表来建立两个实体之间的关联关系。

<!--甲方-->
<!--N-N关联实体,两边的table属性值相同-->
<set name ="乙方集合属性" table= "连接表的表名">
    <!--指定列表的参照本表记录的外键列名-->
    <key column ="甲表的主键">
    <many-to-many class = "乙实体类" column ="乙表主键">

<!--乙方-->
<set name = "甲方的从表的集合属性" table = "连接表的表名">
    <!--指定连接表中参照本表记录的外键字段-->
    <key column ="乙表的ID">
    <many-to-many class = "甲实体类" column = "甲表主键"/>
</set>

拆分N-N为两个1-N关联:在实际的应用中需要在连接表添加额为的字段类记录信息,一般把N-N关联关系拆分为两个1-N关联,需要创建一个中间类。

<!--中间实体-->
<many-to-one name = "1端实体" class = "实体类" column = "1端主键">
<many-to-one name =  "1端实体" class ="实体类" column ="1端主键">
……
<!--一端实体-->
<set name = "中间实体" cascade = "save-update" inverse ="true" table ="中间表">
    <key column = "一端实体ID"/>
    <one-to-many class="中间实体类" >
<!--一端实体-->
<set name = "中间实体" table= "中间表" inverse = "true">
    <key column ="一端实体ID" />
    <one-to-many calss = "中间实体类">
</set>

级联关系

在使用HIbernate进行开发时,持久化对象通过关联关系相互作用是常见的。需要使用Hibernate级联(cascade)的功能解决。在实际开发中级联通常用在1-N和1-1关联关系中。save-update最为常用。

cascade属性及描述
none默认值,表示关联对象之间无级联操作
save-update表示主动方对象在调用save(),update(),和saveOrUpdate()方法时被关联对象执行保存或更新操作。
delete表达主动方对象在调用delete()方法时对被关联对象执行删除操作
delete-orphan

用在1-N关联中,表示主动方对象在调用delete()方法时删除不被任何一个关联对象所引用的关联对象,多用于父子对象关联中。

all等价于save-update和delete的联合使用

在1-N关联关系中,通常将控制权交给N方,这可以在set元素中通过配置inverse属性来实现,当inverse=“true”时,表示关联关系有对方维护,当将关联关系交给N方时,无须执行update语句就可以完成两个关联关系对象之间的级联操作。

  • 1
    点赞
  • 1
    评论
  • 3
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

©️2022 CSDN 皮肤主题:数字20 设计师:CSDN官方博客 返回首页

打赏作者

山河已无恙

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值