Java工程师培训课(十七【新的领域】)

夜光序言:

你不愿意种花,你说,我不愿看见它一点点凋落。是的,为了避免结束,你避免了一切开始。

但是.............这样就好了么?

正文:

叮咚购书商城功能说明书:

扫描二维码关注公众号,回复: 4466895 查看本文章

 

一、对象-领域模型-需求分析

被管理对象,是系统操作、数据流转、数据封装的主要对象。一般情况下称为领域模型。一张表,与一个JavaBean形成一一对应关系,即领域模型。

通过以下分析,应该生成表结构。JavaBean对象。

1、图书分类

分类:types

列名

名称

主否主键

长度

备注

id

 

Y

Varchar(32)

 

name

 

 

 

 

descr

说明

 

 

 

 

 

 

 

 

 

2、图书

图书是系统是管理的主要对象。

 

图书:books

列名

名称

主否主键

长度

备注

id

 

Y

Varchar(32)

 

name

 

 

 

 

price

 

 

 

原价

auth

 

 

 

 

img

图片名称UUID

 

 

只保存图片的名称全名。不用打散目录。

rebate

折扣

 

numeric(3,2)

0.xx保留两位

stock

库存数量

 

int

 

publisher

出版社

 

 

 

publishdate

出版时间

 

 

yyyy-MM-dd

pages

页数

 

 

 

size

开本

 

 

16开,8开等

printtimes

印次

 

int

主要记录第几次印刷

versions

版次

 

int

主要记录第几个版本

brief

内容简介

 

Text || varchar(2000)

 

content

目录

 

Varchar(4000)

必须以HTML形式保存。显示格式良好的HTML文档。

 

 

 

 

 

onlinetime

上架时间

 

 

用于设置是何时上架的。Yyyy-MM-dd

 

3、图书分类和图书关系表

一本书可能会属于多种分类。所以应该是多对多的关系。至少一本书,要属于一种分类

booktype

列名

名称

主否主键

长度

备注

Bookid

 

 

 

外键

typeid

 

 

 

外键

 

 

 

 

 

 

 

 

 

 

 

priamy key(booki,typeid)

3、管理员

维护人员,是系统的管理员。对于不同的管理员,应该具有不同的功能。

管理员:admins

列名

名称

主否主键

长度

备注

id

 

Y

Varchar(32)

 

name

 

 

 

不能相同

password

 

 

 

需要MD5加密,使用Spring的MD5算法

sex

 

 

 

 

email

 

 

 

 

descr

 

 

 

 

 

 

 

 

 

 

4、用户表-即注册成为本网会员的用户

 

Users:

列名

名称

主否主键

长度

备注

id

 

Y

 

 

name

 

 

 

不可以重复

password

 

 

 

 

phone

 

 

 

 

email

 

 

 

 

 

 

 

 

 

 

5、用户收货地址列表

一个用户可以拥有多个收货地址,但多个收货地址,只可以一个有效。一个用户,最多只能拥有5个收货地址。

address:

列名

名称

主否主键

长度

备注

id

 

Y

 

 

name

收货人姓名

 

 

不可以重复

 

 

 

 

 

phone

收货人电话

 

 

必须输入

zip

收货人邮编

 

 

 

dft

是否是默认收货地址

 

Char(1)

1:是,0:否。

userid

Users表的外键

 

 

 

mktime

设置时间

 

 

按时间倒序排列

 

 

 

 

 

 

6、用户订单表

记录用户已经交易成功,或是没有交易成功的所有记录。对于已经发货的交易,用户不可以取消。只可以在收货后再做退货处理。

且退货状态,只可以由维护人员完成。用户无权在页面上设置状态为退货。

orders:

列名

名称

主否主键

长度

备注

id

订单编号

 

订单生成规则为User.hashCode+

ddHHmmssSSS不可以使用同步。

userid

所属用户ID

F

 

 

consignee

收货人明细信息

 

Varchar(300)

将收货人信息全部写入此处。保证在修改了原始收货信息后,不会影响到已经生成的订单。如:张三,广州天河区棠东东路,13146789813。

paytype

付款方式

 

Char(1)

1:货到付款,2:网上支付。

amt

订单总金额

 

Numeric(10,2)

 

state

订单状态

 

 

0:客户已经提交,等待发货。1商家已经发货2:交易已经完成,3:交易取消。4:客户已经退货。

orderdate

下单时间

 

 

Yyyy-MM-dd HH:mm:ss

 

 

 

 

 

 

7、订单明细

订单明细,主要记录一张订单的详细内容。修改源数据后,不应该对已经买过的商品产生任何影响。所以,应该将产品信息,全部拷贝到明细中来。

 

orderline:

列名

名称

主否主键

长度

备注

id

 

Y

 

 

orderid

所属于的订单编号

 

 

 

bookid

图书id

 

 

只需要保存id,查询时也可以带更多的信息。需要JavaBean的信息比表多。需要时再添加即可。

Amt

数量,如购入了几本

 

 

 

price

价格

 

 

 

 

 

 

 

 

 

二、详细设计

1、根据需求分析完成表结构。

2、根据需求分析完成领域模型的创建

略。注意建立实体之间的关系。

 

3、创建JavaWeb项目(搭建基础环境)

创建一系列的公共组件:gz.itcast.util

3.1  EncodingFilter - 字符编码过滤器(GET和POST字符编码过滤器统一为UTF-8)

3.2  ValidateCodeUtil- 验证码生成工具类

3.3  MD5Util - MD5加密字符串工具类(MessageDigest

3.4  WebUtil - 拷贝请求数据到javabean的工具类

3.5  BaseServlet - 控制层servlet的基础类, 具体业务servlet继承此类

        3.6  BaseDao<T> -  数据访问层泛型DAO ,具体业务dao继承此类

 

4、开发客户端程序

开发要求:

1、任意用户都可以登录本系统浏览。

2、用户选购图书时,必须是已经注册用户。没有注册的用户不可以在本系统中购买。

3、用户购买的所有图书,可以永久的保在用户的订单系统中。

4、提供用户注册功能。

5、用户登录,查看订单进度。历史订单信息等。

6、用户登录后,修改收货人地址信息。

7、在没有发出货物之前,用户可以取消订单。

4.1、功能-实现主页的显示

实现主页显示。

主要解决的问题:主页如何演示,如何显示分类,如何显示图书。

4.2、实现用户注册

只有注册用户才可以在本系统是购物。

4.3、功能-实现用户登录

用户只有在成功登录后才可以将商品添加到购物车中。

4.4、实现用户购物

用户购物的过程就是将产品不断的向购物车中添加的过程。

4.5、实现用户提交订单

用户只有在提交了订单以后,才可以将本次所购买的所有信息保存到订单及订单明细表中。用户在提交了订单以后,可以不支付,也可以继承支付。系统将自动计算本次费用总和。

如果用户选择是货到付款则直接提交订单。如果用户选择银行支付,则转到银行的支付网关。

 

4.6、实现用户查询订单进度,订单明细功能

 

 

5、开发后台程序

1、管理员登录。

2、管理员添加分类信息。

3、管理员添加一本图书。

4、管理员修改、删除一本图书。

(更加高级的功能)

5.1、功能-实现维护人员登录

仅管理用户登录。

5.2、功能-实现增加分类

在表单中增加一个新的分类。所有分类,都是顶层分类。目前先不涉及子分类。

5.3、功能-实现增加图书

在保存图书时,必须要选择此图书是何种分类。至少选择一项。

 

 

未来可以扩展的功能:

 

1, 实现网站在线支付功能。对接第三方支付平台(如易宝支付)

2. 用户注册成功后需通过邮件激活,以及订单生成后,通过发送邮件给用户提醒。

3. 后台区分不同分角色的管理员,实现不同角色的管理员拥有不同系统操作权限,更加灵活。

    4. 购物车信息保存到数据库,这样用户下次登录后依然可以看到上次加入购物车的图书。

..........

一、密码采用使用MD5加密

使用MD5加密之后再保存到数据库

md5算法是生成一个32位的16进制的字符串

 

12345 -> fdfdfrerer

root  ->  dsdfxcv

 

二、数据库设计

一对多的关系:在多方表设计一个外键

多对多的关系: 独立设计一个关系表,存放两张表的外键

 

三、收货地址

 

 

Struts2入门

1.1 简介

Struts2就是基于MVC模式的开发框架,对servlet技术的封装!!!!

 

回顾MVC模式:

M: Model 模型。使用javabean技术,对业务数据的封装

V: View 视图。 使用jsp技术,对业务数据的显示。

C:Control 控制器。使用servlet技术

控制器的作用:

1)接收请求,获取用户的参数

2)调用业务逻辑处理方法

3)获取结果,导航视图,把结果显示视图中。

 

需求: 用户登录和注册功能(用户模块)。使用MVC模式进行开发。

 

设计:

dao层:

UserDao类:

   queryUser(User user); //查询登录用户

   addUser(User user);//添加用户方法

service层:

UserService类:

login(User user);//登录业务方法

register(User user);// 注册业务方法

web层:

 一个功能对应一个Servlet类

 

登录功能: LoginServlet类  :    /login访问

处理登录请求

跳转到视图(jsp)

如果是登录成功

跳转到主页

否则,不成功

跳转到失败页面

注册功能: RegisterServet类:    /register访问

处理注册请求

跳转到视图(jsp)

注册成功,

跳转到登录页面

 

关注: 能不能优化web层的MVC的代码呢???

现状: 一个功能对应一个Servlet处理类,这样的话项目管理的servlet就会很多!!!管理web.xml文件很麻烦!!更多的servlet对象会消耗更多的服务器内存。(单例)

目标: 一个项目只对应一个Servlet处理类。

 

1.2 自定义Struts2框架

编写ActionServlet类,这是核心控制器类,在这个类读取mystrus.xml文件

(为了了解struts2框架的核心原理)

2 Struts2的使用

2.1 使用步骤

1)导入strust2的支持jar包

commons-beautils  [beanutils工具包]

commons-filupload.ajr    [文件上传]

commons-io.jar  

commons-lang   [struts2对java.lang.*类的支持]

freemarker.jar        [视图显示技术]

javassit            [struts2对字节码运算的支持]

ognl.jar            [struts2对ognl表达式的支持]

    struts2-core.jar      [ struts2的核心包 ]

    xwork-core.jar   [webwork框架的支持,struts2的前身就是webwork(对webwork的封装)]

 

2)配置启动的全局的过滤器(Filter)   - 和ActionServlet类似!!!

 

    在web.xml中配置

<!--  配置启动strut2的全局过滤器 -->

<filter>

<filter-name>struts2</filter-name>

<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>struts2</filter-name>

<!-- 过滤所有请求 -->

<url-pattern>/*</url-pattern>

</filter-mapping>

 

3)编写不同的业务Action类,编写不同业务方法。默认execute方法。

 

public class LoginAction implements Action{

//默认方法

public String execute() throws Exception {

System.out.println("执行了LoginAction的execute方法");

return "success";

}

 

}

 

4)在src目录下(类路径的根目录下),新建一个struts.xml,配置Action对象

 

<struts>

<package name="xxx" extends="struts-default">

 

<!-- 配置Action http://localhost:8080/day28_struts/login.action-->

<action name="login" class="gz.itcast.action.LoginAction">

<result name="success" type="redirect">/index.jsp</result>

</action>

</package>

 

</struts>

5)访问Action的业务方法

http://localhost:8080/day28_struts/login.action

2.2 struts2框架的作用

strurs2是基于MVC开发模型的web层框架。

struts1也是MVC开发模式的框架。struts2并不是struts1的升级版。

struts2是基于webwork的升级版。struts2=webwork+sturts1

struts2的具体功能:

   请求数据封装

   简化国际化

简化文件上传

后台数据校验

......

 

2.3 Struts2的执行过程

项目启动:

1)创建核心过滤器StrutsPrepareAndExecuteFilter对象

2)执行核心过滤器的init方法

  读取了依次以下的配置:

struts-default.xml      [struts2框架的默认配置文件(不需要自定修改)]

struts-plugin.xml       [struts2的插件配置文件]

struts.xml             [我们写的业务配置文件(包含配置的Action)]

 

访问资源:

3) 在内存中查询对应的Action配置,得到class内容,创建Action对象。

4)读取Action配置的method内容,执行Action对象对应的方法。

2.4 struts-default.xml文件的详解

1)声明struts2框架运行过程中使用到的一些对象

 

<bean class="com.opensymphony.xwork2.ObjectFactory" name="xwork" />

    

2)默认包,包名叫struts-default(注意:我们自己写的package必须继承这个默认包,只有继承了这个默认包才可以使用该默认包下的功能)

 

<package name="struts-default" abstract="true">

2.1 )跳转类型:

常用的跳转类型

redirect:   重定向到页面

dispatcher: 转发到页面

redirectAction: 重定向到Action

chain:    转发到Action

 

<result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>

 

2.2 ) 声明拦截器(Interceptor)

struts2默认的拦截器(32个): 完成strutrs2的核心功能。(请求封装,文件上传,国际化..)

 

 拦截器(Intercptor)  vs   过滤器(Filter)

过滤器: 可以过滤任何类型的请求(html、servlet、jsp)和响应。加入通用的代码逻辑。

拦截器: 是sturts2的特有功能。只能过滤Action!!在执行Action的时候加入通用的代码。

 

2.3) 声明拦截器栈 (<interceptor-stack name="basicStack">)

默认拦截器:

 

<interceptor-stack name="defaultStack">    (18个拦截器)

 

2.4 ) 默认包当前使用的拦截器:

 

<default-interceptor-ref name="defaultStack"/>

注意:

我们写的包(package)就是继承struts-default默认包的,那么就继承了默认的18个拦截器

 

2.5) 当前默认包下的默认Action

 

<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />

 

2.5 struts.xml文件详解

该文件是开发者自行配置的业务配置文件。(关键是Action的配置)

1)包(package),用于管理Action,一般可以按模块划分包!!

 

  package: 代表一个包。管理action配置。在用一个包下面不能有同名的action

name: 包名.在一个项目中不能出现同名的包。

 extends:  继承。类似于类的继承。如果一个包继承另一个包,那么就会把父包的功能继承下来。

   我们开发的包就必须继承struts-default包。

 namespace:  名称空间。区分不同的包的访问路径。默认值  “/”

用户访问Action的路径搜索规则:

      http://localhsot:8080/day28/namespace/action的name

      

http://localhost:8080/day28_struts/user/a/b/login2.action   ok

http://localhost:8080/day28_struts/user/a/login2.action     ok

http://localhost:8080/day28_struts/user/login2.action        ok

http://localhost:8080/day28_struts/a/user/login2.action     不行!!  

      

用户访问: http://localhost:8080/day28_struts/user/a/b/login2.action

 先搜索:  http://localhost:8080/day28_struts/user/a/b/login2.action    没有,  有就返回

 接着搜索: http://localhost:8080/day28_struts/user/a/login2.action     没有,   有就返回

 再搜索 :  http://localhost:8080/day28_struts/user/login2.action            有,   有就返回 (为止)     

 

abstract: 表示当前包是否抽象。如果当前包是抽象包,那么不能含有action. 抽象包中一般用来定义拦截器,公共视图,不做具体的业务。       

 

 

2)Action和result的配置

 

action配置:

  name:  action的名称。用于访问该Action的路径

  class:  Action业务对象的类名。一定是全名(包名+类名),这里struts2是用反射构造Action对象的

  method: 执行的业务方法。不写默认值 execute

 

result配置:

name: 视图的标记。在一个Action中名称不要重复!

           type: 跳转的类型。

           redirect: 重定向

           dispatcher: 转发(默认值)

           redirectAction: 重定向到Action

           chain:  转发到Action。可以在不同Action中通过request共享数据

           stream: 用在下载文件的时候。

           文本内容: 跳转到的页面或者Action

 

  3)可以通过划分不同的xml文件来管理package

 

 

       <!-- 包含读取其他xml文件 注意: 声明的顺序就是读取的顺序!!!!-->

<include file="config/struts-book.xml"></include>

<include file="config/struts-user.xml"></include>

 

 

1 Struts2入门

1.1 简介

Struts2就是一基于MVC模式的开发框架,对servlet技术的封装!!!!

 

回顾MVC模式:

M: Model 模型。使用javabean技术,对业务数据的封装

V: View 视图。 使用jsp技术,对业务数据的显示。

C:Control 控制器。使用servlet技术

控制器的作用:

1)接收请求,获取用户的参数

2)调用业务逻辑处理方法

3)获取结果,导航视图,把结果显示视图中。

 

需求: 用户登录和注册功能(用户模块)。使用MVC模式进行开发。

 

设计:

dao层:

UserDao类:

   queryUser(User user); //查询登录用户

   addUser(User user);//添加用户方法

service层:

UserService类:

login(User user);//登录业务方法

register(User user);// 注册业务方法

web层:

 一个功能对应一个Servlet类

 

登录功能: LoginServlet类  :    /login访问

处理登录请求

跳转到视图(jsp)

如果是登录成功

跳转到主页

否则,不成功

跳转到失败页面

注册功能: RegisterServet类:    /register访问

处理注册请求

跳转到视图(jsp)

注册成功,

跳转到登录页面

 

关注: 能不能优化web层的MVC的代码呢???

现状: 一个功能对应一个Servlet处理类,这样的话项目管理的servlet就会很多!!!管理web.xml文件很麻烦!!更多的servlet对象会消耗更多的服务器内存。(单例)

目标: 一个项目只对应一个Servlet处理类。

 

1.2 自定义Struts2框架

编写ActionServlet类,这是核心控制器类,在这个类读取mystrus.xml文件

2 Struts2的使用

2.1 使用步骤

1)导入strust2的支持jar包

2)配置启动的全局的过滤器(Filter)   - 和ActionServlet类似!!!

 

 

<!--  配置启动strut2的全局过滤器 -->

<filter>

<filter-name>struts2</filter-name>

<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

</filter>

<filter-mapping>

<filter-name>struts2</filter-name>

<!-- 过滤所有请求 -->

<url-pattern>/*</url-pattern>

</filter-mapping>

 

3)编写Action类,业务方法方法

4)在src目录下,新建一个struts.xml,配置Action对象

 

<struts>

<package name="xxx" extends="struts-default">

 

<!-- 配置Action http://localhost:8080/day28_struts/login.action-->

<action name="login" class="gz.itcast.action.LoginAction">

<result name="success" type="redirect">/index.jsp</result>

</action>

</package>

 

</struts>

5)访问Action的业务方法

http://localhost:8080/day28_struts/login.action

 

回顾重点内容:

  struts2开发步骤:

1)导入jar包

2)在web.xml配置全局过滤器(启动时候创建)

3)写业务的Action类

4)在src目录下写struts.xml文件,在这个文件配置action

 

 

大纲:

struts2的配置相关:

1)struts2的Action三种使用方式

2)struts2的路径通配符

3)struts2的常量配置

4)struts2的全局视图配置和默认配置

5)Action的属性注入

 

struts2的核心业务功能:

1)sruts2的数据共享的三种方式

2)请求参数数据的封装

3)自定义类型转换

4)文件上传和下载

 

1 struts2的Action三种使用方式

1.1 第一种方式,不实现Action接口

 

/**

 * 第一种方式:不需要实现或继承任何接口或类

 * @author APPle

 *

 */

public class UserAction2 {

 

public String login()throws Exception{

System.out.println("UserAction2.login()");

return "success";

}

 

}

 

1.2第二种方式,实现Action接口

/**

 * 第二种方式:实现Action接口

 * 1)定义了默认的execute方法的标准

 *  2)提供了项目中常用的视图标记

 * @author APPle

 *

 */

public class UserAction implements Action {

 

public String login() throws Exception {

System.out.println("执行了UserAction的login方法");

return SUCCESS;

}

 

public String execute() throws Exception {

return null;

}

 

}

 

1.3 第三种方式, 继承ActionSupport类(推荐)

 

/**

 * 第三种方式: 继承ActionSupport类(推荐使用)

 * 好处:

 * 1)提供了常用的视图标记

 * 2)提供了数据校验功能

 *

 * @author APPle

 *

 */

public class UserAction3 extends ActionSupport{

 

public String login()throws Exception{

System.out.println("UserAction3.login()");

return SUCCESS;

}

}

2 路径通配符

 

<!-- 一个模块(Action对象)使用一个action配置 -->

<!-- * (星号) :表示路径的通配符。   使用通配符的内容:   {1}  (表示获取第一个通配符的实际内容)  

好处: 大大地减少action的配置

-->

<!--

<action name="user_*" class="gz.itcast.b_path.UserAction" method="{1}">

<result name="{1}">/{1}.jsp</result>

</action>

 -->

 

 <!-- 多个模块使用一个action配置

 约定前提:  第一个*代表模块,第二个代表方法

  User_login

  -->

 <action name="*_*" class="gz.itcast.b_path.{1}Action" method="{2}">

  <result name="{2}">/{1}/{2}.jsp</result>

 </action>

 

3 strus2的常量配置

struts2的常量就是用于在strut2的程序运行过程中使用的一些常量参数。

 

    指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出 

    <constant name="struts.i18n.encoding" value="UTF-8"/>

    自定义后缀修改常量 

    <constant name="struts.action.extension" value="do"/>

    设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭

    <constant name="struts.serve.static.browserCache" value="false"/>

    当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开

    <constant name="struts.configuration.xml.reload" value="true"/>

    开发模式下使用,这样可以打印出更详细的错误信息

    <constant name="struts.devMode" value="true" />

    默认的视图主题

    <constant name="struts.ui.theme" value="simple" />

    与spring集成时,指定由spring负责action对象的创建 

    <constant name="struts.objectFactory" value="spring" />

    该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性

    为 false

    <constant name="struts.enable.DynamicMethodInvocation" value="false"/>

    上传文件的大小限制 

    <constant name="struts.multipart.maxSize" value=“10701096"/>

 

 

注意:

通过struts.xml文件声明<constant name="struts.action.extension" value="action,do,,"></constant>修改常量配置。

 

4 struts2的全局视图配置和默认配置

4.1 全局视图作用: 当该包下的所有action都使用到的一些视图就是可以放到全局视图配置中

注意:

当action中也有相同名称的视图,那么action的局部视图会覆盖全局视图。

 

<!-- 全局视图配置: 把该包下的所有action共用的视图都机集中在这里写 -->

<global-results>

<result name="success">/login.jsp</result>

</global-results>

 

4.2 action的默认配置

 

 

<!-- 默认配置

 name: 必填项

 class: 可选项 。默认配置:  ActionSupport类   该类继承自struts-default (<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />)

 method: 可选。默认配置

    result:

     name: 可选。默认配置: success

     type: 可选。默认配置: dispatcher

 -->

 <!-- 全部使用默认配置的action的作用 :专门用于转发到WEB-INF下的页面 -->

 <action name="book">

  <result>/WEB-INF/jsp/login.jsp</result>

 </action>

 

5 Action的属性注入

作用: 如果Action对象中需要把一些经常改变的参数提取到配置文件中,那么就可以使用属性注入的方法。

 

Action属性注入的步骤

1)在Action类中声明一个成员变量,用于接收xml配置文件传入内容

2)在Action类提供一个该变量的setter方法,该方法接收了xml配置的内容

 

//1)在action中提供一个属性

private String savePath;

//2)提供属性的setter方法,用于外部的action的参数进行注入

public void setSavePath(String savePath) {

this.savePath = savePath;

}

 

3)在对应的struts.xml文件中,找到对应的action对象的配置,然后在action中使用

<param name=""></param> 这个标签来向Action对象的属性注入内容

 

 

<action name="upload" class="gz.itcast.d_ioc.UploadAction" method="upload">

<!-- 3)使用该配置可以往Action对象的属性注入内容(只要有setter都可以使用param进行注入)

param:

name: setter方法名。setSavePath -> savePath

 -->

<param name="savePath">e:/images/</param>

<result>/login.jsp</result>

</action>

 

 

6 sruts2的数据共享的三种方式

在web项目中都是使用域对象来共享数据。

 

struts2提供给开发者使用域对象来共享数据的方法一共有三种。

 

6.1 第一种方式

ServletActionContext类

getRequest() : 获取request对象

getRequest().getSession() : 获取session对象

getServletContext() : 获取ServletContext对象

注意:

1)该方式依赖servlet的api,耦合比较高

2)如果要通过域对象来获取域对象的相关信息必须使用该方式

 

6.2 第二种方式

 

ActionContext类

getContextMap() : 获取操作request域对象数据的map集合

        getSession() :     获取操作session域对象数据的map集合

getApplication()  获取操作context域对象数据的map集合

 

注意:

1)不依赖servlet的api,耦合性低

2)只能用在Action对象的一个方法中。不能在所有方法中都是用同一个ActionContext

 

6.3 第三种方式

使用  RequestAware  ,   SessionAware   ApplicationAware 接口

注入操作对应域对象数据的Map集合

 

注意:

1)不依赖servlet的api

2)可以在Action对象的所有方法中共享Map集合

7请求参数数据的封装

7.1 直接赋值给简单数据类型

 

public class UserAction extends ActionSupport{

//参数赋值(注入方式)

private String name;

private String password;

private String gender;

private String[] hobit;

//参数通过这个set方法注入到Action中

public void setName(String name) {

this.name = name;

}

public void setPassword(String password) {

this.password = password;

}

public void setGender(String gender) {

this.gender = gender;

}

public void setHobit(String[] hobit) {

this.hobit = hobit;

}

 

7.2 赋值给一个javabean对象

 

<form action="${pageContext.request.contextPath }/data/user_register.action" method="post">

     用户名: <input type="text" name="user.name"/><br/>

     密码: <input type="password" name="user.password"/><br/>

     性别: <input type="radio" name="user.gender" value="男"/>

      <input type="radio" name="user.gender" value="女"/><br/>

     爱好:

     <input type="checkbox" name="user.hobit" value="篮球"/>篮球

     <input type="checkbox" name="user.hobit" value="足球"/>足球

     <input type="checkbox" name="user.hobit" value="羽毛球"/>羽毛球<br/>

     <input type="submit" value="注册"/>

      

    </form>

 

public class UserAction2 extends ActionSupport{

//使用一个javabean对象接收

private User user;

 

public User getUser() {

return user;

}

 

public void setUser(User user) {

this.user = user;

}

 

注意:请求参数的封装通过struts2的ParametersInterceptor拦截器进行赋值.

 

8 自定义类型转换

作用: 默认情况下,页面的日期类型只能接收 yyyy-MM-dd类型,如果要转换yyyy/MM/dd这种类型,则需要使用自定义类型转换器进行转换。

 

strut2提供了自定义类型转换器的基类: StrutsTypeConverter

 

/**

 * 自定义日期类型转换器

 * @author APPle

 *

 */

public class MyDateConverter extends StrutsTypeConverter{

 

SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy/MM/dd");

 

/**

 * 从页面的数据到服务器的类型转换

 * 参数一: context: 值栈上下文对象

 * 参数二: values:  从页面传递过来的参数值

 * 参数三: toClass: 转换到的类型。String->java.util.Date

 */

@Override

public Object convertFromString(Map context, String[] values, Class toClass) {

System.out.println("进入了转换器");

try {

//1)判断values是否为空

if(values==null || values.length==0){

return null;

}

 

if(values.length>1){

//多个值的情况

Date[] dates = new Date[values.length];

//2)取出数据进行转换

for(int i=0;i<dates.length;i++){

Date date = sdf1.parse(values[i]);

dates[i] = date;

}

return dates;

}else{

//一个值的情况

Date date = sdf1.parse(values[0]);

return date;

}

} catch (ParseException e) {

e.printStackTrace();

}

return null;

}

/**

 * 从服务器到页面的类型转换

 */

@Override

public String convertToString(Map context, Object o) {

return null;

}

}

 

 

绑定自定义转换器的方式:

方式一: 局部绑定(只能绑定一个Action)

1)建立一个 Action的文件名-conversion.properties

2)一定和绑定的Action放在同一个目录下。

 

user.birth=gz.itcast.g_convert.MyDateConverter

 

 

方式二: 全局绑定(绑定整个项目多个Action)(推荐使用)

1)建立一个xwork-conversion.properties

2)该文件一定放在src目录下。

 

java.util.Date=gz.itcast.g_convert.MyDateConverter

 

9文件上传和下载

9.1 文件上传

1)三个条件:

表单有file

post提交

enctype="multipart/form-data"

 

2)在Action中接收文件内容

File attach;   (attach是file表单的name属性)

String attachContentType;  文件类型

String attachFileName;   文件名称

细节:

修改上传大小

 

<!-- 修改默认文件上传大小 -->

<constant name="struts.multipart.maxSize" value="100000000"></constant>

修改允许上传的文件类型和文件后缀

 

<action name="upload" class="gz.itcast.h_upload_down.UploadAction" >

<!-- 往FileUploadInterceptor拦截器的属性注入值(调用setter方法) -->

 

  <interceptor-ref name="defaultStack">

  <!-- 改变当前文件上传拦截器的允许文件类型 -->

  <param name="fileUpload.allowedTypes">image/jpeg,image/jpg</param>

  <!-- 允许的文件后缀 -->

  <param name="fileUpload.allowedExtensions">jpg,jpeg,gif</param>

  <!-- 如果以上配置都写了,那么取他们的交集  -->

  </interceptor-ref>

 

<param name="savePath">e:/images/</param>

<result>/login.jsp</result>

<result name="input">/error.jsp</result>

</action>

 

9.2 文件下载

 

视图类型一定是stream类型

 

<action name="down_*" class="gz.itcast.h_upload_down.DownAction" method="{1}">

<param name="serverPath">e:/images/</param>

<result name="list">/listFile.jsp</result>

<!-- 文件下载的关键: 视图类型一定是stream -->

<result name="down" type="stream">

 <!--  往StreamResult类中的属性注入内容 -->

 <!-- 返回给浏览器的文件类型。返回通用的二进制 -->

 <param name="contentType">application/octet-stream</param>

 <!-- 返回给浏览器的输入流 -->

    <param name="inputName">inputStream</param>

    <!--  告诉浏览器的方式下载资源

    ${name}: 获取Action中的getName()方法的数据

    -->

    <param name="contentDisposition">attachment;filename=${name}</param>

    <!-- 缓存大小 -->

     <param name="bufferSize">1024</param>

</result>

</action>

 

在Action对象中提供一个对应的获取输入流的方法

 

 

//需要提供给struts写出数据的输入流

public InputStream getInputStream(){

try {

FileInputStream fis = new FileInputStream(new File(serverPath+name));

return fis;

} catch (FileNotFoundException e) {

e.printStackTrace();

throw new RuntimeException(e);

}

}

 

public String getName() {

return name;

}

 

 

 

回顾重点内容:

 struts2第二天:

1)struts2使用Action方法:

1.1 不实现任何接口,不继承任何类

1.2  实现Action接口(定了标准,提供了视图的常量)

1.3 继承ActionSupport类(只需选择覆盖方法,提供了视图常量,提供数据验证的功能)

2)struts2的常量配置

struts-core.jar   default.properties 常量文件

在struts.xml文件使用<constant name="" value=""/>  修改常量值

2.1 默认请求编码 : struts.i18n.encoding

2.2 动态方法调用: struts. *** .DynamicMethodInvocation      actionName ! methodName

2.3 修改上传文件的临时目录: struts.multipart.saveDir  

2.4 修改上传文件的大小: struts.multipart.maxSize

2.5 访问action的后缀名:  struts.**.actionExtesion

3)全局视图:

<grobal-results> 当前包下的所有action共享这些视图

 

4)(域对象)数据共享三种方法

  4.1  ServletActionContext 得到servlet的api(依赖servlet)

  4.2  ActionContext得到操作域对象数据的Map集合(不依赖servlet,方法局部)

  4.3  Action类实现RequestAware,SessionAware ,ApplicationAware接口(action全局)

实现提供的方法: 获取操作域对象数据的Map集合

  

5)请求参数封装

5.1 基本数据类型接收参数(action中提供setter方法)

5.2 javabean类型接收参数: user(action提供getter和setter)

表单的name属性值: user.name/user.passowrd.......

6) 类型转换

默认情况下: 基本数据类型可以直接从String转换,日期只能转yyyy-MM-dd类型

如果按照自己需要转换,定义自定义类型转换器。

 

继承 StrutsTypeConverter类

convertFromString()  从页面的String数据转换为后台需要的类型

 

 局部绑定:

1)在action的同一个包下建立 ActionName-conversion.properties  (约定)

2)user.birth=xxxx.xxxxx

全局绑定:

1)在src下建立  xwork-conversion.properties(约定)

2)java.util.Date=xxxxxx

 

7)上传与下载:

上传:

表单: <input type="file" name="img"/>

单文件Action处理文件:

File img;

String imgFileName;

String imgContentType;

 

表单:

<input type="file" name="img"/>

<input type="file" name="img"/>

<input type="file" name="img"/>

 

多文件Action处理文件:

File[] img;

String[] imgFileName;

String[] imgContentType;

 

   下载:

<action name="down" class="xxxxx">

<result  type="stream">

<param name="contentType">xxxxx</param>

<param name="inputName">Action中定义获取输入流的方法(方法名)</param>

<param name="contentDispostion">xxxxx</param>

<param name="bufferedSize"></param>

</result>

</action>

 

 

大纲:

拦截器(interceptor)(重点)

拦截器编写规则

拦截器的生命周期

拦截器栈(引用多个拦截器)

案例

值栈(value stack): (重点)

OgnlContext对象使用

分析值栈的内部组成结构(关键点)

页面获取值栈数据

struts2的常用逻辑标签

1 拦截器

1.1 拦截器简介

拦截器  类似于  过滤器的功能,过滤器可以过滤项目的任何请求(servlet/jsp/html/img),但拦截器只能拦截Action资源。拦截完Action,添加逻辑代码

1.2 拦截器的编写规则

struts2提供Interceptor接口用于自定义拦截器

 

步骤:

1)编写类,实现Interceptor接口

 

 

public class MyInterceptor1 implements Interceptor{

 

public MyInterceptor1(){

System.out.println("1)创建了拦截器1对象");

}

 

public void destroy() {

 

}

 

public void init() {

System.out.println("2)调用了拦截器1的init方法");

}

 

public String intercept(ActionInvocation invocation) throws Exception {

System.out.println("4)拦截了Action---前面的代码");

 

//放行,调用下一个拦截器,如果没有下一个拦截器,那么调用目录的action

invocation.invoke();

 

System.out.println("6)拦截了Action---后面的代码");

 

return null;

}

 

}

 

2)在struts.xml文件中定义和使用拦截器

 

 

<package name="inter" extends="struts-default" namespace="/inter">

     <!-- 定义拦截器 -->

     <interceptors>

     <interceptor name="inter1" class="gz.itcast.a_interceptor.MyInterceptor1"></interceptor>

     </interceptors>

    

    

 

     <action name="user_*" class="gz.itcast.a_interceptor.UserAction" method="{1}">

     <!-- 使用拦截器 -->

     <interceptor-ref name="inter1"></interceptor-ref>

     <result>/index.jsp</result>

     </action>

    

    </package>

 

注意1:拦截器的执行顺序:

启动:

1)拦截器对象创建,调用拦截器的init方法

访问

2)创建Action对象

3)执行拦截器的intercepot方法

 3.1  执行拦截器前面的代码(invocation.invoke();方法之前的)

 3.2 执行 invocation.invoke(); 放行执行下一个拦截器或Action的方法

 3.3 执行拦截器后面的代码(invocation.invoke();方法之后的)

 

 

注意2:拦截器范围:

局部使用:action其作用

 

<action name="user_*" class="gz.itcast.a_interceptor.UserAction" method="{1}">

     <!-- 局部起作用的使用拦截器 -->

     <interceptor-ref name="inter1"></interceptor-ref>

     <result>/index.jsp</result>

     </action>

 

全局使用: 当前包其作用:

 

<package name="inter" extends="struts-default" namespace="/inter">

     <!-- 定义拦截器 -->

     <interceptors>

     <interceptor name="inter1" class="gz.itcast.a_interceptor.MyInterceptor1"></interceptor>

     </interceptors>

    

     <!-- 全局其作用的拦截器 -->

     <default-interceptor-ref name="inter1"></default-interceptor-ref>

 

 

1.3 拦截器栈

概念: 当一个或多个Action同时被多个拦截器所拦截,就可以使用拦截器。

 

 

<interceptors>

     <interceptor name="inter1" class="gz.itcast.a_interceptor.MyInterceptor1"></interceptor>

     <interceptor name="inter2" class="gz.itcast.a_interceptor.MyInterceptor2"></interceptor>

     <!-- 定义栏截器栈 -->

     <interceptor-stack name="interStack">

     <interceptor-ref name="inter1"></interceptor-ref>

     <interceptor-ref name="inter2"></interceptor-ref>

     </interceptor-stack>

     </interceptors>

注意1:定义拦截器栈的时候,引用拦截器的顺序决定了创建拦截器对象的顺序。(先指定就先创建)

 

注意2: 当前有了拦截器栈(多个拦截器)的执行顺序:

启动:

1)创建拦截器inter1对象,调用init方法

2)创建拦截器inter2对象,调用init方法

 

访问:

3)执行inter1的interceptor方法前面代码

4)执行inter2的interceptor方法前面代码

5)Action的业务方法

6)执行inter2的interceptor方法后面代码

7)执行inter1的interceptor方法前面代码

 

注意3: 当我们的包下引用了自定以拦截器,则会把默认包下的default-stack拦截器给覆盖掉!!!

这时需要这么做:

 

<interceptor-stack name="myStack">

     <interceptor-ref name="defaultStack"></interceptor-ref><!-- 引入了默认的18个拦截器 -->

     <interceptor-ref name="interStack"></interceptor-ref><!-- 引入自定义的2个拦截器 -->

     </interceptor-stack>

 

struts2的核心流程图(关键):

 

2值栈

2.1 Ognl表达式简介

  1. OGNL表达式

       OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。

 

在struts2项目中导入ognl.jar  包来实现支持ognl表达式。

 

ognl表达式   vs   EL表达式

 

EL表达式: 获取域对象的数据。 不能存放数据,不能调用方法

Ognl表达式: 获取域对象的数据。  可以存放数据,可以调用方法。

 

OGNL的优势:

 

1、支持对象方法调用,如xxx.doSomeSpecial();

       2、支持类静态的方法调用和值访问,表达式的格式:

             @[类全名(包括包路径)]@[方法名 |  值名],例如:

             @java.lang.String@format('foo %s', 'bar')

             或@tutorial.MyConstant@APP_NAME;

       3、支持赋值操作和表达式串联,如price=100, discount=0.8,

             calculatePrice(),这个表达式会返回80;

       4、访问OGNL上下文(OGNL context)和ActionContext;

       5、操作集合对象。

 

 

2.2 Ognl表达式核心OgnlContext对象

 

//目标: 学习了解Ognl表达式的核心对象OgnlContext对象的使用

public class OgnlDemo {

 

@Test

public void test1(){

User user = new User();

user.setName("eric");

user.setAge(20);

 

//1)创建一个OgnlContext对象

OgnlContext context = new OgnlContext();

//2)把user对象存入OgnlContext对象

context.put("user", user);

//3)从OgnlContext对象取出数据

User user2 = (User)context.get("user");

System.out.println(user2.getName()+"\t"+user2.getAge());

}

 

//使用Ognl表达式取出OgnlContext的数据,如果是非根对象数据,那么使用#号去取

@Test

public void test2()throws Exception{

User user = new User();

user.setName("eric");

user.setAge(20);

 

//1)创建一个OgnlContext对象

OgnlContext context = new OgnlContext();

//2)把user对象存入OgnlContext对象

context.put("user", user);//往OgnlContext的非根对象 存数据

 

//使用Ognl表达式从OgnlContext对象取出数据

Object ognlObj = Ognl.parseExpression("#user.age");//表达式对象

Object result = Ognl.getValue(ognlObj, context, context.getRoot()); //获取数据方法

System.out.println(result);

 

 

}

 

//使用Ognl表达式取出OgnlContext的数据,如果是根对象数据,不需要使用#号,不需要key名称,直接写存入对象的属性即可!!!

@Test

public void test3()throws Exception{

User user = new User();

user.setName("eric");

user.setAge(20);

 

//1)创建一个OgnlContext对象

OgnlContext context = new OgnlContext();

//2)把user对象存入OgnlContext对象

context.setRoot(user);////往OgnlContext的根对象 存数据

 

//使用Ognl表达式从OgnlContext对象取出数据

Object ognlObj = Ognl.parseExpression("name");//表达式对象

Object result = Ognl.getValue(ognlObj, context, context.getRoot()); //获取数据方法

System.out.println(result);

 

 

}

 

/**

 * java.util.Math

 * @throws Exception

 */

//Ognl表达式调用静态方法

@Test

public void test4()throws Exception{

//Math.round(10.3);

 

//1)创建一个OgnlContext对象

OgnlContext context = new OgnlContext();

//使用Ognl表达式从OgnlContext对象取出数据

Object ognlObj = Ognl.parseExpression("@Math@round(10.5)");//表达式对象

Object result = Ognl.getValue(ognlObj, context, context.getRoot()); //获取数据方法

System.out.println(result);

 

 

}

}

 

结论:

1)从OgnlContext对象的根对象取出数据,不需要#号

2)从OgnlContext对象的非根对象取出数据,需要#号

2.3 struts2的值栈(ValueStack)对象(利用OgnContext对象)

ValueStack接口,最终在项目中存储数据的对象是ValueStack的实现类OgnlValueStack

 

 

ValueStack的数据存储结构:分为  List栈(根栈)  和  Map栈(非根栈)

 

1)List栈主要存储Action对象和Provider代理对象

2)Map栈主要存放各个域存放的数据和用户的参数信息

2.4页面获取值栈(ValueStack)数据

 

 

一、List栈的数据(不需要#号,不需要key)

 

输入Ognl: user

 

作用: 直接到List栈的每个对象去搜索对应的属性。

搜索规则:

    从List栈的栈顶开始搜素  ->  user  -> 返回,找不到继续向下找

    栈的第二个元素          ->  user  -> 返回,找不到继续向下找

    .......                 ->  user - > 空

     

 

注意:在List栈中尽量不要在两个栈对象中出现相应的属性名,如果出现相应的属性名,只获取第一个对象的属性。

 

使用struts2的标签结合Ognl表达式获取值栈数据:

 

<%-- 1)取出List栈的数据 --%>

  <s:property value="user.name"/> - <s:property value="user.age"/> <br/>

    <s:property value="book.user.name"/> - <s:property value="name"/>

    <%--查看值栈的所有数据 --%>

    <hr/>

    <%--2)取出Map栈的数据 --%>

    <s:property value="#request.request_data"/><br/>

    <%-- 因为值栈对象是通过request域专递到页面,所以可以直接忽略#request去取request域的数据 --%>

    <s:property value="#request_data"/><br/>

    <s:property value="#session.session_data"/><br/>

    <s:property value="#application.application_data"/><br/>

    <%-- #attr : 类似于findAttribute. 依次从小到大在三个域中搜索数据:  #request-> #session -> #application --%>

    <s:property value="#attr.session_data"/><br/>

    <s:property value="#parameters.name"/><br/>

    <hr/>

    ${session_data }

    <hr/>

    <%-- 遍历集合 :List--%>

    <s:iterator value="#request.userList" var="user">

     姓名: <s:property value="#user.name"/> - <s:property value="#user.age"/><br/>

    </s:iterator>

    <hr/>

     <%-- 遍历集合:Map --%>

    <s:iterator value="#request.userMap" var="entry">

     编号: <s:property value="#entry.key"/> - 姓名: <s:property value="#entry.value.name"/> - <s:property value="#entry.value.age"/><br/>

    </s:iterator>

    <s:debug></s:debug>

 

防止表单重复提交:

 

回顾重点内容:

 拦截器:是struts2核心业务功能实现的机制。

   1)自定义拦截器 : 只能拦截action资源

实现Interceptor接口

init()   :  在创建拦截器对象的时候,拦截器对象在加载web应用时创建。

interceptor()   : 每次访问action的业务方法的时候调用!!!!

destory();   拦截器对象销毁的时候调用。web应用重新部署或web服务器停止。

 

2)拦截器栈: 当前action同时被多个拦截器拦截,就使用拦截器栈。

<interceptor-stack>

<interceptot-ref name="拦截器1"/>

<interceptot-ref name="拦截器2"/>

........

</interceptor-stack>

注意:当使用了自己定义的拦截器(拦截器栈)的时候,记住在调用我们的拦截器之前加上struts提供的默认拦截器(defaultStack)

 

 值栈:是struts2的数据存取的核心!!!!!(重点)

 

1)Ognl表达式:存取数据

Ognl存取数据的核心 OgnlContext对象

OgnlContext对象数据结构:

Object root:   根对象          不用带#,直接访问属性

Map values:  非根对象        带#,根据key获取value

 

2)struts2的值栈对象: ValueStack(OgnlValueStack对象)

OgnlValueStack对象数据结构:

List<Objet> root:   根对象(List栈)

OgnlContext对象:

Object root:   根对象          不用带#,直接访问属性

Map values:  非根对象(Map栈)        带#,根据key获取value

 

OgnlValueStack对象分为两个部分存储数据:

List对象栈:Action对象,Provider对象,ValueStack.push(obj)

Ognl表达式访问List栈(不要#,直接写属性名):

  第一个对象: 找user,找到返回,找不到往下一个对象找。

  第二个对象: 找user,找到返回,找不到往下一个对象找。

  第三个对象: 找user,找到返回,找不到往下一个对象找。

  。。。。。。。所有对象找完,都没有,就返回空。

 

Map栈:request域的Map      

session域的Map

application域的Map,

attr的Map,

paramter参数的Map

 

Ognl表达式访问Map栈(必须要#,根据key找value):

request域的Map    : #request.user  

session域的Map    :   #session.user

application域的Map,:   #application.user

attr的Map,      :    #attr.uesr

paramter参数的Map  :  #parameter.user

 

注意:如果想使用Ognl表达式查找值栈的数据,必须结合struts2的标签

 

数据共享

请求参数封装

类型转换(自定义类转换)

文件上传和下载

大纲:

 

struts2核心业务功能:

国际化

数据验证

模型驱动

 

struts2的知识补充:

常用的struts2的标签(逻辑标签+UI标签)

数据回显

防止重复提交

1 国际化

1.1 简介

文字国家化

 

以前: ResourceBundle类

getBundle();  绑定指定国家的资源包。

资源包规则:

 包名_语言简写_国家简称.properties

e.g  中国: message_zh_CN.properties

美国: message_en_US.properties

英国:  message_en_GB.properties

jsp页面中:

<fmt:setBundle name="message"/>  绑定资源

<fmt:message key="user"/>   获取资源包的内容

 

1.2 struts2中简化国际化的使用

1)准备不同国家的资源包

中国: message_zh_CN.properties

user=用户名

美国: message_en_US.properties

英国:  message_en_GB.properties

 

2)在struts.xml文件中(修改)指定资源包加载路径的常量

struts.custom.i18n.resources=message

 

3)在页面上使用资源包的内容

   <s:text name="user"/>

2数据验证

struts2提供给开发者进行表单数据的后台数据验证的功能。

2.1 用代码方式对action的所有方法进行验证

分析:

前台:  注册表单    user_register.action

user.username

user.password

后台:

class UserAction extends ActionSupport{

private User user;

用于存储错误信息

private Map actionErrors;

public String validate(){

表单校验的逻辑(不好,影响当前业务逻辑)

if(user.getName()==null || user.getName().eqauls("")){

出现异常

保存错误信息

actionErrors.put("name","用户名不能为空");

转发到错误显示显示jsp

}

。。。。。。。

actionErrors.put("password","密码不能为空");

 

}

 

 //注册方法

public String register(){

//validate(); 这里不写这个方法调用,而把方法的调用交给拦截器去做!!!

具体的注册业务逻辑

}

}

 

struts2的数据验证的核心拦截器:

<interceptor name="validation" class="com.opensymphony.xwork2.validator.ValidationInterceptor"/>

 

开发步骤:

1)Action类继承ActionSupport(为了实现Valiateable接口)

2)Action类覆盖validate方法(验证所有方法)

 

public void validate() {

//在这里写表单数据验证的逻辑

//System.out.println("调用了validate方法");

if(user.getName()==null || user.getName().equals("")){

//用户名为空

//把错误信息放入错误信息Map集合

super.addFieldError("user.error.requried", "用户名不能为空!");

}

if(user.getPassword()==null || user.getPassword().equals("")){

//密码为空

//把错误信息放入错误信息Map集合

super.addFieldError("password.error.requried", "密码不能为空!");

}

 

}

3)在struts.xml文件中对应的action配置加上input视图,然后struts2就会自动把错误信息转发到input视图的页面上去

4)在input视图页面上,打印出错误信息

 

<s:fielderror></s:fielderror>

 

注意:

validate()方法对当前Action下的所有方法都会有效!!!!

2.2 用代码方式对action的指定方法进行验证

指定方法验证:

第二步骤的验证方法名称为  validate+需要验证的方法名称

例如: validateRegister()   ->  可以验证register()方法

2.3 用xml配置方式对action的所有方法进行验证

以上这两种方式都是使用代码在程序写死了!!!

希望更加灵活,扩展型更好!

 

xml配置数据验证的规则:

1)编写一个xml文件,名称:  Action文件名-validation.xml

2)该xml文件必须放在Action文件的同一目录

 

注意: 这种配置方式会对action下的所有方法都生效!!!

2.4 用xml配置方式对action的指定方法进行验证

xml配置数据验证的规则:

1)编写一个xml文件,名称: Action文件名-访问方法路径-validation.xml

例如: UserAction的register方法: user_register路径访问

文件名:   UserAction-user_register-validation.xml

2)该xml文件必须放在Action文件的同一目录

<validators>

  <!-- 验证用户名 -->

  <field name="user.name">

     <!-- type: 代表xwork中定义的可以使用的验证类型 -->

    <field-validator type="requiredstring">

     <!-- 当出现错误时,提示的错误信息 -->

     <message>用户名必填</message>

    </field-validator>

    <field-validator type="stringlength">

     <param name="minLength">6</param>

     <param name="maxLength">16</param>

     <message>用户名必须是6-16位</message>

    </field-validator>

  </field>

 

  </field>

  

</validators>

 

 

<validators>

    <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/>

    <validator name="requiredstring" class="com.opensymphony.xwork2.validator.validators.RequiredStringValidator"/>

    <validator name="int" class="com.opensymphony.xwork2.validator.validators.IntRangeFieldValidator"/>

    <validator name="long" class="com.opensymphony.xwork2.validator.validators.LongRangeFieldValidator"/>

    <validator name="short" class="com.opensymphony.xwork2.validator.validators.ShortRangeFieldValidator"/>

    <validator name="double" class="com.opensymphony.xwork2.validator.validators.DoubleRangeFieldValidator"/>

    <validator name="stringlength" class="com.opensymphony.xwork2.validator.validators.StringLengthFieldValidator"/>

    <validator name="regex" class="com.opensymphony.xwork2.validator.validators.RegexFieldValidator"/>

    <validator name="conditionalvisitor" class="com.opensymphony.xwork2.validator.validators.ConditionalVisitorFieldValidator"/>

</validators>

3 模型驱动

 请求数据封装:

方式一: 表单: name    -》  基本数据类型: String name

方式二: 表单: user.name - 》 javabean数据类型: User user     (User:  String name)

 

方式三: 表单: name  ->     javabean数据类型: User user     (User:  String name) (使用模型驱动方式)

 

 

public class UserAction extends ActionSupport implements ModelDriven<User>{

//注意:使用模型驱动的方式,存放数据的模型引用不能为空

private User user = new User();

 

/**

 * 该方法struts2可以把值栈中的请求参数封装到User对象

 */

public User getModel() {

return user;

}

 

}

 

4常用的struts2的标签

4.1 Ognl常用的符号

1) {   }   创建List集合

<%-- ognl表达式: 在jsp页面中创建List集合(不需要#) --%>

   <s:iterator value="{'eric','jacky','rose','lucy'}" var="name">

   <s:property value="#name"/><br/>

   </s:iterator>

2) #{   }   创建Map集合

 

    <%-- ognl表达式: 在jsp页面中创建Map集合(需要#号) --%>

    <s:iterator value="#{1:'eric',2:'jacky',3:'rose',4:'lucy'}" var="entry">

   编号: <s:property value="#entry.key"/>-姓名:<s:property value="#entry.value"/><br/>

   </s:iterator>  

    

 

  3)%{  }   把内容引入Ognl运行环境

 

<s:textfield name="userName" value="%{#request.userName}"></s:textfield>

 

4.2 常用的逻辑标签

4.3 表单数据回显

4.4 放在页面的重复提交

默认情况下,struts2不支持防止重复提交的

 

需要在struts.xml文件中打开功能:

 

1)

 

<interceptors>

<interceptor-stack name="myStack">

<interceptor-ref name="defaultStack"></interceptor-ref>

<interceptor-ref name="token"></interceptor-ref>

</interceptor-stack>

</interceptors>

2)在jsp页面指定一个标签

<s:token></s:token>

 

 

总结:

1)struts2基础:

struts2执行原理(理解)

2)struts2核心功能:(web开发常用的功能)

数据共享功能(三种方式)

请求数据封装(三种方式)

类型转换(自定义类型转换器)

文件上传和下载

国家化

数据验证

 

 

回顾:

核心业务:

一、国际化

1)写好资源包

2)在struts.xml配置国际化的资源包。 message_zh_CN.properties

3)使用:

jsp页面: <s:text name="user"/>

action:    ActinoSupport.getText("user")  

 

二、数据验证:后台数据验证

1)代码方式验证所有方法:

重写Validatable接口的方法:valiate()  写验证逻辑

2)代码方式验证指定的方法:

修改validate方法名:  validateRegister()    validate+方法名()

3)xml配置方式验证所有方法:(插拔式)

ActionName-validation.xml(和action方法在同一目录)

 

<validators>

<field name="user.name">

<field-validator type="requriredstring/int/regex...">

<message>错误提示信息</message>

<field-validator>

</field>

<validators>

4)xml配置方式验证指定方法

修改验证文件名称: ActionName-方法调用路径-validation.xml(和action方法在同一目录)

  UserAction-user_register-validation.xml

三、模型驱动

接口: ModelDriven<T>

<input type="text" name="name"/>    ->  UserAction      User user=new User();

四、struts2的标签:

<%@ taglib uri="/struts-tags" prefix="s"%>

 

 

逻辑标签:

迭代: <s:iterator value="ognl表达式" var="" status="">

赋值: <s:set var="" value="ognl表达式"/>

获取:  <s:property value="ognl表达式"/>

判断: <s:if/>  <s:elseif/>  <s:else/>

UI标签: 1)节省html代码编写  2)数据回显功能

<s:form/>  -> <form>

<s:textfield/>  -> <input type="text"/>

<s:password/>   -> <input type="password"/>

<s:checkbox/>  -> <input type="checkbox"/>

<s:checkboxlist  list="多个值"/>  -》  多个<input type="checkbox"/>

<s:radio list="多个值"/>   ->  多个<input type="radio"/>

<s:select list="多个值"/>  -》 <select>多个<option/></select/>

 

五、防止重复提交:

  1) 打开功能:  TokenIntecetpot拦截器

  2)在jsp页面上加入 <s:token/> 标签

 

 

 

今天目标: 改造之前的  《网上图书销售系统》

 

之前的架构:

  web层     -》    service层    -》 dao层    》 mysql数据层

servlet+jsp(jstl+el)      ( 普通java类 )  jdbc(dbutils)    

 (遵守MVC模式)

 

现在架构:

  web层     -》                  service层    -》 dao层    》 mysql数据层

struts2+jsp(struts标签)      ( 普通java类 )  jdbc(dbutils)    

 (遵守MVC模式)

 

 

1)项目的目录结构:

|-bookstore

|-gz.itcast.entity

|-gz.itcast.filter

|-gz.itcast.interceptor(拦截器包)

|-gz.itcast.utils

|-gz.itcast.biz

|-front

|-book

|-dao

|-service

|-web

|-action  (struts2的action类)

|-servlet  (写servlet)

|-admin

 

|-config (配置文件 struts2配置、hiberate配置文件、spring配置文件)

|-struts.xml

|-WebRoot(保持不变)

 

2)设计strut2的配置文件(config目录)

struts-constant.xml    存放struts框架的常量值

struts-front.xml      存放前台业务的action配置

 

<package namespace="/front">

e.g  模块: <action name="book_*" class="gz.itcast.biz.front.book.web.action.BookAction" method="{1}">

 

struts-admin.xml     存放后台业务的action配置

<package namespace="/admin">    

e.g  模块: <action name="book_*" class="gz.itcast.biz.admin.book.web.action.BookAction" method="{1}">

 

 

3)struts开发步骤:

3.1 导入jar包

3.2 配置全局过滤器

3.3 在src下放struts.xml文件

 

 

 

4)设计一个BaseAction公共Action类

 

============================================

hibernate01

Struts2:

1. 简化Servlet开发,用Action取代之前的Servlet

2. 开发流程

3. 请求数据自动封装  (params拦截器)

3. struts 数据处理

Map---》域对象

4. 文件上传/下载

5. 数据效验、国际化

6. Ognl表达式语言、Struts标签

(OgnlContext/ValueStack)

传统的开发模式:

基于MVC模式项目体系结构!

 

 

1. Hibernate框架

ORM 规则

ORM,  Object Relation Mapping 对象关系映射!

目标:

通过orm(对象关系映射), 可以做到:

a. 不写sql,包对象直接保存到数据库中

b. 不写sql, 从数据库中读取,直接获取的是封装好的对象!

 

ORM是一种思想,或者说是一种规则的定义, 基于orm的应用:

1. hibernate 框架

2. mybatis 框架

3. 自定义一套程序!

 

Hibernate框架

概念

基于ORM的持久层框架,对jdbc操作进行了封装!

Hibernate与具体数据库无关的技术,即可以框数据库平台!

 

 

Hibernate开发环境搭建

Hibernate版本: 3.6版本

 

整体步骤:

1. 下载源码,引入jar文件

2. 写配置

* hibernate.cfg.xml  主配置

* Users.hbm.xml    映射配置

3. Api

Configuration   

SessionFactory

Transaction

Session

Query

 

 

步骤实现:

1. 建库、建表

-- 删除数据库

DROP DATABASE hib_demo;

 

-- 创建数据库

CREATE DATABASE hib_demo DEFAULT CHARACTER SET utf8;

 

-- 建表

CREATE TABLE users(

   id INT PRIMARY KEY AUTO_INCREMENT,

   NAME VARCHAR(20),

   age INT

)

2. 引入hibernate核心jar文件

源码中:

hibernate3.jar   +   required 目录中所有  + jpa  + 数据库驱动包

 

antlr-2.7.6.jar

commons-collections-3.1.jar

dom4j-1.6.1.jar

hibernate-jpa-2.0-api-1.0.0.Final.jar

hibernate3.jar

javassist-3.12.0.GA.jar

jta-1.1.jar

mysql-connector-java-5.1.12-bin.jar

slf4j-api-1.6.1.jar

 

3. 主配置文件:  hibernate.cfg.xml

<!DOCTYPE hibernate-configuration PUBLIC

        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"

        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">

 

<hibernate-configuration>

    <session-factory>

     <!-- 数据库连接的参数配置 -->

     <property name="hibernate.connection.url">jdbc:mysql:///hib_demo</property>

     <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>

     <property name="hibernate.connection.username">root</property>

     <property name="hibernate.connection.password">root</property>

     <!-- 通过数据库方言,告诉hibernate如何生产sqlhibernate会根据配置的方言,生产符合当前数据库语言的SQL语句 -->

     <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

    </session-factory>

</hibernate-configuration>

4.  javabean/ 映射文件

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC 

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<!--

通过XML映射,把对象映射到数据库的表中!

 -->

<hibernate-mapping package="cn.itcast.a_config">

 

<class name="Users" table="users">

<id name="userId" column="id">

<generator class="native"></generator>

</id>

<property name="userName" column="name"></property>

<property name="age" column="age"></property>

</class>

 

</hibernate-mapping>

 

 

5.  App

 

// 测试类

public class App {

 

@Test

// 保存

public void testSave() throws Exception {

 

// 对象

Users users = new Users();

users.setUserName("Jack");

users.setAge(30);

 

// 1. 创建配置管理器对象

Configuration config = new Configuration();

// 2. 加载主配置文件, 默认加载src/hibernate.cfg.xml

config.configure();

// 3. 根据加载的主配置文件,创建对象

SessionFactory sf = config.buildSessionFactory();

// 4. 创建Session对象

Session session = sf.openSession();

// 5. 开启事务

Transaction tx = session.beginTransaction();

 

// --- 保存

session.save(users);

 

// 6. 提交事务/关闭session

tx.commit();

session.close();

 

}

 

@Test

// 获取对象

public void testGet() throws Exception {

 

 

// 1. 创建配置管理器对象

Configuration config = new Configuration();

// 2. 加载主配置文件, 默认加载src/hibernate.cfg.xml

config.configure();

// 3. 根据加载的主配置文件,创建对象

SessionFactory sf = config.buildSessionFactory();

// 4. 创建Session对象

Session session = sf.openSession();

// 5. 开启事务

Transaction tx = session.beginTransaction();

 

// --- 获取 (根据主键查询)

Users users = (Users) session.get(Users.class, 1);

 

System.out.println(users);

 

// 6. 提交事务/关闭session

tx.commit();

session.close();

 

}

}

 

 

 

 

2. Hibernate框架Api

 

|-- Session   一个与数据库连接的会话信息

 Sesison里面维护了一个连接对象,且对常用操作进行封装!

更新:

session.save(obj);    保存一个对象

session.update(obj)   更新一个对象, 注意修改对象的主键一定要在数据库存在!

session.saveOrUpdate(obj)  保存或更新

如果有设置主键且主键存在执行更新!

没有设置主键执行保存!

    session.delete(obj)     删除一个对象; 注意修改对象的主键一定要在数据库存在!

 

主键查询:

 Session.get(clazz,id);    根据主键查询

 Session.load(clazz,id);    根据主键查询

 

HQL查询:

Hibernate Query language

Hibernate提供的面向对象的查询语言!

查询的是对象、对象的属性!

 

HQL与SQL区别:

Hql 查询的是对象、对象的属性, 区分大小写!

    Hql查询的对象一定要有映射!

SQL 查询的是表、字段,不区分大小写!

 

 

 

3. Hibernate执行流程

 

4. hibernate.cfg.xml 配置详解

在主配置文件配置的时候,hibernate 前缀可以省略!

 

d

查看配置提示:

hibernate-distribution-3.6.0.Final\project\etc\hibernate.properties

 

里面有常用配置,如:

#hibernate.dialect org.hibernate.dialect.MySQLDialect

#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect

#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect

#hibernate.connection.driver_class com.mysql.jdbc.Driver

#hibernate.connection.url jdbc:mysql:///test

#hibernate.connection.username gavin

#hibernate.connection.password

 

自动建表:

 

#hibernate.hbm2ddl.auto create-drop    每次在创建sessionFactory的时候创建

   表;执行sf.close()删除表。

#hibernate.hbm2ddl.auto create    每次都先删除表,再创建新的表

#hibernate.hbm2ddl.auto update        如果表不存在则创建,存在就不创建!

#hibernate.hbm2ddl.auto validate       检查映射配置与数据库结构是否一致,不一致就报错!  (严格)

 

 

也可以通过代码的方式,自动建表:

/**

 * 代码方式自动建表

 * @param args

 */

public static void main(String[] args) {

// 创建配置管理器对象,加载主配置文件(会加载映射)

Configuration cfg = new Configuration().configure();

// 自动建表工具类

SchemaExport export = new SchemaExport(cfg);

// 创建表

// 第一个参数: 是否打印建表语句到控制台

// 第二个参数: 是否执行脚本,生成表

export.create(true, true);

}

 

5. 映射配置

映射文件,

命名: *.hbm.xml

作用: 描述“对象”与“表”的映射关系!

   通过映射文件可以描述一张完整的表!

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC 

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<!--

通过XML映射,把对象映射到数据库的表中!

 

package 表示包名; 可选,如果没有写,后面的类必须指定类的全名!

auto-import="true" 默认为true,即在写hql的时候,会自动引入包名;

       如为false,hql中对象要写上包名称

  Query q = session.createQuery("from Users");

 -->

<hibernate-mapping package="cn.itcast.b_api" auto-import="true">

<!--

class 表示映射的一个javabean对象

  (可以有多个class节点,但一般一个映射文件对应一个class)

  

name  表示映射的类的名称;

table (可选)类的名称,对应的表名, 如果不写默认与类名称一样

 

 -->

<class name="Users" table="t_users">

<!--

 

id  表示映射的是主键

            注意: 在hibernate的映射文件中,必须要有主键映射!

                         那就要求表必须要有主键!

                         

generator  表示的是主键生成策略  (Api : 5.1.2.2.1. Various additional generators)

      class

         

        identity  主键自增长, mysql/sqlservlet等数据库使用的自增长的方式

        sequence  以序列的方式实现自增长;

         native   表示主键自增长: 根据底层数据库的能力选择 identity、sequence等其中一个。

         

         assigned  手动指定主键的值  

         uuid      uuid的值作为主键,确保一定唯一

 -->

<id name="userId" column="id">

<generator class="native"></generator>

</id>

 

 

<!--

property 表示普通字段的映射

name 属性的名称

column 可选,如果没有指定,与属性名称一致

length 表示字符长度,只对字符类型有效

type 数据库中字段的类型  (如果没有指定,会匹配属性的类型)

hibernate中指定的类型:  小写开头

         java中类型:  写类的全名

    unique  设置为true,表示给当前列添加唯一约束

     (主键约束 = 唯一约束 + 非空)

 -->

<property name="userName" type="java.lang.String" column="username" length="50" unique="true"></property>

 

<property name="age" column="age" type="int"></property>

 

<!-- 注意:如果列名称对应的是数据库的关键字,需要处理 -->

<property name="desc" column="`desc`" length="200"></property>

</class>

 

 

</hibernate-mapping>

 

 

 

 

6. 联合主键映射

联合主键,

多列共同作为主键!

数据库,联合主键:

 

-- 联合主键  (hbm:   <composite-id></composite-id>   )

CREATE TABLE test(

  id1 INT,

  id2 INT,

  PRIMARY KEY(id1,id2)

);  

 

SELECT * FROM test;

-- 插入

INSERT INTO test VALUES(1,1);

INSERT INTO test VALUES(1,2);  

INSERT INTO test VALUES(1,2);  -- 错误

 

 

需求:

保存员工信息: 名称、地址、部门、年龄

(联合主键:名称、地址)

 

设计javabean:

写映射:

App:

 

/**

 * 联合主键对象, 必须要实现可课序列化标记!

 */

public class CompositeKeys implements Serializable{

 

private String name;

private String address;

   ..

}

// 员工

public class Employee {

 

 // 名称、地址、部门、年龄

 

// 联合主键对象

private CompositeKeys keys;

private String dept;

private Date birth;

..

}

 

Employee的映射:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE hibernate-mapping PUBLIC 

"-//Hibernate/Hibernate Mapping DTD 3.0//EN"

"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

 

<hibernate-mapping package="cn.itcast.c_composite">

<class name="Employee" table="t_employee">

<composite-id name="keys">

<key-property name="name"></key-property>

<key-property name="address"></key-property>

</composite-id>

 

<property name="dept" length="50"></property>

<property name="birth" type="date"></property>

</class>

 

 

</hibernate-mapping>

 

 

 

 

 

 

 

 

 

测试

 

public class App {

private static SessionFactory sf;

static {

sf = new Configuration().configure().buildSessionFactory();

}

 

@Test

public void testSave() throws Exception {

Session session = sf.openSession();

session.beginTransaction();

 

// 联合主键对象

CompositeKeys keys = new CompositeKeys();

keys.setName("Jack");

keys.setAddress("棠东...");

 

// 对象

Employee emp = new Employee();

emp.setKeys(keys);

emp.setDept("研发部");

emp.setBirth(new Date());

 

// 保存

session.save(emp);

 

 

session.getTransaction().commit();

session.close();

 

}

 

@Test

public void testGet() throws Exception {

Session session = sf.openSession();

session.beginTransaction();

 

// 联合主键对象

CompositeKeys keys = new CompositeKeys();

keys.setName("Jack");

keys.setAddress("棠东...");

 

Employee employee = (Employee) session.get(Employee.class, keys);

System.out.println(employee.getKeys().getName());

System.out.println(employee.getKeys().getAddress());

System.out.println(employee.getDept());

System.out.println(employee.getBirth());

 

session.getTransaction().commit();

session.close();

 

}

}

 

 

提问:

1. Hibernate与ORM 关系

2. Hibenate开发步骤、执行流程

3. Hibernate 中方言作用

4. 映射文件起什么作用?

5. 如何进行联合主键映射?

<composite-id>

 

执行流程

1. 创建Configuration对象

2. 加载主配置文件:hibernate.cfg.xml

3. 接着,创建SessionFactory对象

4. 创建Session

5. 开启事务

6. – 执行操作 –

7. 提交/关闭

 

目标:

1. hibernate对象状态

2. hibenate 一级缓存

3. 集合映射/多对一/一对多映射

 

1. hibernate对象状态

session.save(对象);

 

  • 临时状态

1 . 直接new出来的对象

2. 不处于session的管理(即没有与任何一个session关联)

3. 对象在数据库中没有对应的记录!

Employee  e  = new Employee();

e.setId(2);  只要主键在数据库中存在,就说这个对象在数据库中有对应记录!

 

  在数据库中叫主键!

 

OID, object identified 对象的唯一标识 (对应数据库中的主键)

 

  • 持久化状态

1. 处于session的管理范围

当执行session的方法如:save/update/saveOrUpdate/get/load

对象就会自动转变为持久化状态!

2. 在数据库中有对应的记录

3. 处于持久化状态的对象,当对对象属性进行更改的时候,提交事务更改会反映到数据库中!

 

  • 游离状态

1. 对象不处于session的管理范围;  通常指session关闭后对象的状态

2. 对象在数据库中有对应的记录

 

 

 

2. Session缓存

概念:

Session缓存,也叫做一级缓存!

当执行session的相关方法,如: save()/update()/get()/load()等方法的时候,对象会自动放入一级缓存中。

当Session关闭后,一级缓存内容失效!

特点:

1)缓存有效范围,只在当前session范围内有效! 缓存时间很短、作用范围小!

2)一级缓存,可以在短时间内多次操作数据库的时候,才会明显提升效率!

一级缓存的结构:Ma<主键,对象>

3)在提交事务时候,

  Hibernate会同步缓存数据到数据库中,会对比缓存数据与数据库数据是否一致,如果不一致,才提交更改到数据库(生成update)!

4) hibernate提供的一级缓存有hibernate自身维护,如果想操作一级缓存内容,必须通过hibernate提供的方法;

session.flush();       手动让让一级缓存内容与数据库同步

session.evict(emp1);   清空一级缓存中对象:  清除指定的对象

session.clear();       清空一级缓存中对象:  清除所有的对象

 

list()与iterator()查询区别

list:  (通常使用频率较高)

Query接口定义的list查询方法,

一次查询所有满足需要的数据!

 

iterator:

Query接口定义的iterator查询方法,

1. 先查询所有满足条件记录的主键   (查询1次)

2. 再根据每一个id,进行主键查询,有多少记录,查询多少次  (查询n次)

3. iterator查询:  N + 1

4. iterator查询,迭代数据的时候,只有用到数据的时候,才会查找数据库(懒加载)

 

区别:

1. 查询数据方式不同: 查询全部与查询N+1

2. 一级缓存

List查询,查询的结果会放入一级缓存,但不会从一级缓存中获取!

Iteraotro查询,会放入一级缓存,同时也会从一级缓存中获取!

 

 

3. lazy 属性

Hibernate为了提升程序运行效率,提供了懒加载!

lazy  属性表示懒加载!

true   支持懒加载

false   关闭懒加载

extra  (集合属性时候使用)

 

 

懒加载:  用到数据的时候,才向数据库发送查询的sql!

 

(1) 主键查询:

get/load

get:

及时加载, 只要get就立刻查询数据库

如果查询的主键不存在,返回null

Load:

懒加载, 只有在用到数据的时候,才向数据库发送sql语句!

如果查询的主键不存在,只要使用就报错!

 

(2) 懒加载作用位置

类级别,默认支持懒加载,但只有在使用load使用才会应用这个特性!

字段级别, 普通字段无效,大数据类型会有影响(long/longtext)

集合属性, 默认支持懒加载

 

(3) 懒加载异常

org.hibernate.LazyInitializationException: could not initialize proxy - no Session

解决思路:

在关闭后,不能能懒加载数据, 那么就要求关闭前把懒加载使用的数据先查询出来!

 

 

4.集合映射

1. 需求:购物填写地址,一个用户,对应多个地址!

2. 数据库设计:

 

 

3. 设计javabean封装数据

4. 写映射

5. App.java   测试

 

 

 

思考:

集合映射,如果保存的数据只有一个可以使使用List/Set集合!

           如果保存的数据有2个,使用Map集合

               如果保存的数据是2个以上,

  集合元素类型,能否为对象?

 

5.多对一、一对多映射

需求: 保存用户信息,用户对应的多个地址!

   周颖,年龄25, 广州天河,gzth,510000

   欧阳光,年龄25, 广州天河,gzth,510000

 

   用户与地址的关系:

一对多  【一个用户对应多个地址】

   地址与用户的关系

多对一   【多个地址对应一个用户】

 

数据库设计:

Javabean封装数据库数据:

映射:

App:

 

多对一, 实现   

目的:

通过多对一映射,能完全描述地址表、用户表的数据库的关系!

public class Address {

 

private int id;

private String name;

private String shortName;

private String code;

 

// 地址与用户, 是多对一的关系

private Users user;

  

}

多对一映射:

<!--

多对一的配置:

1.映射的对象

2.对象对应的外键字段

3.对象的类型

注意:

对象一定是有映射文件进行映射!  (cn.itcast.d_many2one.Users 对应有映射文件)

-->

 <many-to-one name="user" column="user_id" class="Users"></many-to-one>

 

 

 

 

一对多, 实现   

public class Users {

 

private int id;

private String name;

private int age;

// 用户与地址,是一对多的关系  【注意一定要用接口接收!】

private Set<Address> address = new HashSet<Address>();

}

一对多映射:

<set name="address" table="t_address">

   <key column="user_id"></key>

   <one-to-many class="Address"/>

 </set>

 

 

 

 

 

夜光总结:

一对多与多对一映射,

可以只配置多对一, 只能通过的多的一方维护关系!

可以只配置一对多,       只能通过一的一方维护关系

双向配置: 一对多与多对一,   可以通过双向维护关系!

 

 

 

 

 

 

 

 

作业:

一对多与多对一练习,需求自拟!

-à 用户与地址

à 用户与订单

à 老师与学员

à 部门/ 员工

 

 

再深化一下:不要嫌弃啰嗦~~

1. 关联映射中关联关系的维护

  •  需求: 部门与员工

关系:一对多与多对一的关系!

  • 数据库

主表: 部门表

外键表: 员工表 (部门的外键,引入部门的主键)

  • Javabean
  • 映射
  • 测试

关系维护:

A. 保存

B. 通过其中一方获取另外一方

C. 解除关系

D. 删除数据,对关系的影响!

  • Inverse属性

Inverse属性在维护关联关系的时候的作用!

Inverse属性,表示的是控制权是否转移!

Inverse属性, 在一的一方设置,如<set> 标签节点

 

Inverse  反转

true   反转,   控制权转移,当前方没有控制权

false  不反转,  控制权不转移,当前方有控制权!

 

2. 多对多映射

  1. 需求:

老师与学员

项目与开发人员

一个项目,对应多个开发人员

一个开发人员,参与多个项目

这种就是多对多关系!

 

  1. 设计数据库:
  2. Javabean / 映射
  3. 测试:
    1. 基本多对多映射,是否配置正确
    2. 关联关系的维护
    3. Inverse属性,在多对多种的影响

 

总结:

一对多与多对多种,inverse属性在维护关联关系时候作用的区别?

一对多, 是否设置外键的值!

多对多, 是否删除中间表数据!

 

 

3. 一对一

需求: 存储用户、身份证信息

   用户: 姓名、性别、年龄、身份证编号;

   身份证:身份证编号、签发地、有效日期;

 

他们的关系就是一对一的关系!

数据库:

  

 

3. 组件映射

对象之间的关系:

组合关系, 一个类中包含对另外一个类的引用,这2个类就是组合关系!

继承关系,一个类继承另外一个类!

映射,

组合关系的映射就是“组件映射”!

继承映射!

 

  1. 组件类和包含的组件类同时映射到一个表 

 

需求:

汽车与车轮

映射:

 

<component name="wheel" class="Wheel">

<property name="count"></property>

<property name="size"></property>

</component>

 

 

3. 继承映射

需求:

动物,猫,狗!

简单继承映射

特点:

父类、子类写到一个映射文件中!

有多少个子类,要写多少个映射文件.

 

总结:

缺点就是映射文件过多!

<hibernate-mapping package="cn.itcast.f_extends1">

<class name="Dog" table="t_dog">

<!-- 继承父类的属性,直接写 -->

<id name="id">

<generator class="native"></generator>

</id>

<property name="name" length="20"></property>

 

<!-- 子类属性 -->

<property name="play" length="20"></property>

 

</class>

</hibernate-mapping>

 

复杂继承映射

方式1:整个继承结构一张表

特点:

所有的子类都写到一个映射文件中!

用一张表存储所有的子类信息!

 

 

<subclass name="Cat" discriminator-value="cat_">

<property name="catching"></property>

</subclass>

 

总结:

生成的表,不符合数据库设计原则!

因为所有子类都用一张表存储,存在很大的冗余字段!

 

 

方式2:三张表

特点:

完全按照面向对象设计表结构!

<joined-subclass name="Cat" table="t_cat">

<key column="id"></key>

<property name="catching"></property>

</joined-subclass>

 

总结:

设计的表,是符合数据库设计原则(三大范式)!

但是,表结构、关系变得负责,影响数据访问效率!

 

 

方式3:每个子类用一张表

特点:

一个映射文件

有多少个子类对应多少个表,父类不对应表!

<!-- 注意:使用union-subclass要求主键不能自增长! -->

<!-- 子类:猫 -->

<union-subclass name="Cat" table="t_cat">

 <property name="catching"></property>

</union-subclass>

 

总结:

推荐使用!

注意:主键不能为自增长!

 

 

3. cascade 级联操作

cascade   表示级联操作,在一对多、多对一、一对一种都可以设置

save-update   级联保存或更新

delete        级联删除

 

save-update,delete   级联保存、更新、删除

all                同上

 

none           不级联(默认值)

 

 

未完成:

hibernate查询:

二级缓存/连接池支持

Hibernate对session管理(案例)

4. hibernate查询

Hibernate提供的查询:

  1. 主键查询

get/load

2) 对象导航方式

3) HQL查询

Hibernate提供的面向对象的查询方式!

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/weixin_41987706/article/details/84849103