i18n ... ****5.作用:指挥控制器的运作: C 6.默认需要在应用的classpath中建立一个struts.xml的配置文件 2. struts2的开发步骤. 要点(图解理解): 1、创建流程:创建动作action、创建视图jsp、配置文件struts.xml 2、执行流程:看图一条线(生活案例的理解) 请求action————>核心过滤器————判断————>执行哪个action,的哪个方法,return 到哪个jsp , ===>在struts.xml中配置 3、方法的要求 public String 方法名(){} 3.配置文件没有提示问题:struts2-core-2.3.15.3.jar 中找到 struts-2.3.dtd 中,配置 // dtd ———— URI xsd ————— Schema location (最好新建一个java项目,全部放到其中) // 在 XML Catalog中配置 4.具体执行过程: 从两个角度考虑: 1、启动服务器: // tomcat容器 加载项目————>加载web.xml————>实例化(web.xml中的配置类 eg;核心过滤器类)————>初始化(web.xml中的配置类的初始化参数...)————>在初始化过滤器时,加载了struts.xml文件 2、执行请求: http://localhost:8080/zjs_bos/userAction_login.action ——————> 通过核心过滤器 获取到请求动作: userAction_login.action // (请求信息封装到了核心过滤器中,由它负责 过滤 + 请求 + 响应) ——————> 在已加载的struts.xml中找到
——————> 找到 class="cn.it.bos.web.action.UserAction"(spring容器中略写为:class="userAction"),并实例化UserAction类 ——————> 调用方法 : login() (找到 method = "login") ——————> 返回值 return = "home" ——————> 找到结果集配置:
/WEB-INF/pages/common/index.jsp
——————> 跳转到结果视图: /WEB-INF/pages/common/index.jsp页面 5.Struts2的配置文件简介: 1. 1) 在核心控制器初始化的时候加载的 // web.xml 初始化的时候 2) 加载是有顺序的,后面覆盖前面的 // default.properties > struts-default.xml > struts.xml 查看源码: StrutsPrepareAndExecuteFilter 核心类中的 init(FilterConfig filterConfig)方法中 ————调用了初始化方法—————> init.initDispatcher(config); ————查看————> initDispatcher( HostConfig filterConfig )方法, 执行了初始化方法 dispatcher.init(); ————查看————> init() , 初始化顺序如下: init_FileManager(); init_DefaultProperties(); // [1] ——————> org/apache/struts2/default.properties init_TraditionalXmlConfigurations(); // [2] ——————> DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml"; init_LegacyStrutsProperties(); // [3] init_CustomConfigurationProviders(); // [5] init_FilterInitParameters() ; // [6] init_AliasStandardObjects() ; // [7] 2.default.properties , struts-default.xml , ( struts-plugin.xml ), struts.xml 的三个配置文件: 配置文件的名称 位置 存储的内容 说明 default.properties struts2-core-2.3.15.3.jar\org\apache\struts2\default.properties 参数配置 程序员不能修改 struts-default.xml struts2-core-2.3.15.3.jar\struts2-default.xml Struts2核心配置 程序员不能修改 struts.xml 在 classpath 中 用户配置 程序员使用 // ,以上配置文件在应用被启动的时候就完成了加载;而且有加载的顺序要求。后面的配置会覆盖掉前面配置文件中相同的信息。 2.1.default.properties 1、 参数的含义 // 做了很多 初始化过滤 设置 eg:过滤 URL后缀 、 编码方式 、 国际化 、 开发者模式... 2、 如何修改参数 // (struts.xml中修改) 后加载的覆盖先加载的 参数名称 默认值 说明 struts.i18n.encoding UTF-8 编码方式 struts.action.extension action,, 进入框架核心的url的后缀名 // xxx.action 或者 无后缀名 ———过滤———>进入到struts的核心内部 其他后缀,放行!!! // 无论什么 请求 都要进入 核心过滤器类, 经过过滤器过滤 , 根据后缀名 判断 是否放行!!! eg: .jsp / .html ... struts.devMode false 开发阶段设置为true //
struts.custom.i18n.resources 关闭 国际化 //注册国际化:
struts.serve.static.browserCache true 告诉客户端要不要缓存静态的资源 struts.configuration.xml.reload 被注释掉了:建议true 每当xml配置文件被修改后,不需要重新加载应用就能够使配置生效。适合开发阶段 3.如何修改他们的默认值: struts.xml:通过该文件来进行修改 (覆盖) 2.2.struts-default.xml简介
1、
2、
// 给定包名name
abstract:抽象包T/F 只能被继承,不能直接使用 1)结果类型 // 应用在
中 // stream:文件上传和下载 chain:转发到一个动作———> 配置两个参数:setNamespace() 和 setActionName()
// 结果类型
// 指定 dispatcher 为默认结果类型 ...
2)拦截器、拦截器栈(放入很多拦截器) ****C
***A 拦截器:
// 拦截器 : 定义拦截器 给定 name 和 class 拦截器都放入拦截器栈中!!! ... // n个拦截器 ***B 拦截器栈:
// 拦截器栈 : 给拦截器栈 声明一个 name // 拦截器栈 就是 一个拦截器集合 , 里面通过 拦截器name 引用了很多 拦截器 // 既然 拦截器栈里面包含的就是多个拦截器 , 那么 拦截器栈 也可以 直接引用拦截器栈 ——————> 即:直接引用 拦截器集合 *A
// 拦截器引用 : 拦截器栈 中 全部是引入的上面定义的 拦截器(栈)———> 根据拦截器(栈)name 引入 *A/B ... // n个拦截器(栈)引用 //
和
两个拦截器栈 有被其他 拦截器栈引用
... // n个拦截器栈 (每个栈里引用了 n个拦截器/栈)
3)默认引用
// 默认 拦截器栈 的引用
// 默认 类 的引用
2.3.配置文件package元素:// 作用:希望程序员能够 按照 分包的思想 , 管理你的动作配置 // 子包能够继承父包中的所有配置。自己写的包一般情况下要继承一个name=struts-default的包(它在struts-default.xml中) 1.Package:name 包的名称唯一 extends:extends="struts-default" // package 继承的是 内置配置文件 struts-default.xml 中的
不要搞错了! abstract="true" 抽象包概念: 没有任何action的子元素的包就是抽象包 // 包中不存在
即为抽象包 功能: 这个包 不能直接使用,只能被继承 namespace: 命名空间 默认值是 "" // 访问路径:命名空间的名称+动作的名称 方便管理 // 注意:There is no Action mapped for namespace [/] and action name [helloAction] /** 2.namespace的搜索顺序 例如:user/a/b 总结:1) 先找命名空间,再找action名称 2) 当前包找不到,向前找,最后找/,都找不到报错 案例:http://localhost:8088/struts2_04_namespace/user/a/b/helloAction http://localhost:8088/struts2_04_namespace/user/a1/b/helloAction http://localhost:8088/struts2_04_namespace/user1/a1/b/helloAction 3) 如果包存在,找action,如果这个包中没有action到默认的包中找action (注意:默认包是namespace=””) 找不到报错 namespace=””和namespace=”/”不同 案例:localhost:8088/struts2_04_namespace/user/helloAction1 */ 6.动作类Action的编写和配置: 1、实现action的三种方式 /** 方式一、动作类继承com.opensymphony.xwork2.ActionSupport (推荐) 方式二、动作类 实现 com.opensymphony.xwork2.Action接口 方法返回值的常量,返回值也可以自己定义 SUCCESS 一切成功 NONE/null 没有任何跳转 (eg:区域设置中的 导入 、 ajax请求响应回:json数据 、xml数据 、 自定义状态码...) INPUT 回显 LOGIN 用户登录 ERROR 报错 public String execute() throws Exception; 动作方法 方式三、动作类就是POJO(Plain Old Java Object最为普通的JavaBean)。 */ 2、动作类Action的配置 (和Servlet对比) //
必须出现
元素内部 name: 动作名称,就是url ——————对应servlet名 class: 动作类的全路径 没有定义,默认到struts-default.xml中找
method: 执行动作类中的方法 默认的是public String execute(); 3、生命周期: Action在用户访问action的时候创建的,是多例的(每次访问都会实例化) // Action ———————— 多例的!!! 诞生:每次用户访问时。 活着:动作没有响应结束。 死亡:响应结束。 多例的;没有线程安全问题。(与struts1所不同的)。 因为动作类是一个非常普通的Java类,创建它需要消耗的资源可以省略不计。 3、动作的访问 /** 通配符的使用 * 案例:增删改查 案例1)一个*号
/{1}.jsp
http://localhost:8088/struts2_01/addUser * 通配符 代表addUser {1} 第一个*代表的值 案例2)两个* http://localhost:8088/struts2_01/add_User
/{1}{2}.jsp
案例3) DMI:Dynamic Method Invocation: Struts2框架默认不允许动态方法调用的,不安全。 覆盖一个常量:struts.enable.DynamicMethodInvocation=true才能使用 !的使用 ——————此时不再是使用method去调用action的方法 http://localhost:8088/struts2_01!add_User 1) 配置文件
// 注册开启 使用!的方式 调用action中的方法 2) 不安全 、 */ 4、访问动作前的拦截器 // 动作执行前有很多拦截器在工作。 1、 Struts中有很多功能在拦截器中实现的 2、 Action执行之前 ,先要执行拦截器 3、
5、结果视图配置
name:字符串,逻辑视图名称, 默认值 Success 一、结果类型 dispatcher 转发到一个jsp视图 // 转发 到 : jsp chain 转发到一个动作Action // Action redirect 重定向到一个jsp视图 // 重定向 到 : jsp redirectAction 重定向到一个动作Action // Action 二、两个动作不在一个包中 6、结果的配置 struts.xml:
元素配置:配置结果视图。 属性: name:字符串。逻辑视图。对应当前动作的动作方法的返回值。默认值就是success字符串。 type:结果视图的类型 默认值是 dispatcher 请求转发到一个jsp页面。 //
struts2中的结果类型: struts-default.xml中做出的定义。 7、局部逻辑视图和全局逻辑视图 局部逻辑视图:定义在
元素内部,为当前动作服务的。 全局逻辑视图:在某个动作中找不到对应的逻辑视图,框架会从全局视图中找。 7、配置多个struts配置文件 // 使用多个struts配置文件,方便模块开发。 // 在struts.xml中: 使用
9、动作类中获取Servlet的API // Struts2的优点:与Servlet API进行了解耦 第一种方式: HttpServletRequest request = ServletActionContext.getRequest(); // HttpSession session = request.getSession(); HttpServletResponse response = ServletActionContext.getResponse(); ServletContext servletContext = ServletActionContext.getServletContext(); // servletContext.getRealPath(""); 得到绝对路径 第二种方式: // DemoAction extends ActionSupport implements ServletRequestAware , ServletResponseAware, ServletContextAware{ 构造...注入...} 原理: // 由一个叫做servletConfig的拦截器给你注入进来的。
10.封装请求参数: // 非常重要 依靠struts2的拦截器完成参数封装 : params(封装动态参数)、staticParams(静态参数封装) modelDrivern(模型驱动) 1、封装静态参数 运行期间一般不会发生变化的数据;通过配置文件设置的。 是由一个叫做 staticParams拦截器 负责注入的参数。 2、封装动态参数 运行期间由用户输入的数据;通过表单输入的。 2.1.动作类充当模型对象 // 由一个叫做 params的拦截器 完成的。 使用:模型对象xxx中没有的字段 , 我们一般会在 xxxAction中 声明该字段 , 并提供 set 方法 来获取到页面上 该字段的值!!! //同 2.2.属性注入(动作类和模型对象分开):推荐 // 根据 name="user.username" ——————> set数据到 user对象的username属性中 细粒度开发:设计越精细,可重用性就越高。 表单: name="user.usernmae" name="模型对象.属性" name="user.password" 动作类: 不需要提供 模型对象 模型: 2.3.模型驱动(动作类和模型对象分开):推荐 // 模型驱动是一个由叫做 modelDrivern的拦截器 负责的。 表单: name="usernmae" name="属性" name="password" 动作类: BaseAction
extends ActionSupport implements ModelDriven
1.实现 ModelDriven 接口 2.定义模型对象的引用,一定要实例化 // 作用: 声明的 模型对象的 引用model(代理对象) , ModelDriven拦截器 会把参数自动注入到 model对象中 , 3.实现接口的getModel() // 而 model = User(真实的模型类) public T getModel() { return model; } 12.类型转换: 1、认知: 用户的输入都是String类型; 而JavaBean中的属性有可能是 其他类型的。 —————————— 类型转换 读操作: 查询; 其他类型---------------> java.lang.String 写操作: 添加、修改、删除; java.lang.String---------------> 其他类型 2、Struts2的类型转换 使用频率较高: java.lang.String<----------------->java.util.Date 互转 struts2默认使用本地(操作系统)默认的日期格式进行自动转换。yyyy-MM-dd ,默认使用该格式进行转换。 // 默认支持 yyyy-MM-dd格式 , 其他格式,需手动提供转换方法 // 当然,你也可以修改 本地操作系统的日期格式. 额..这.. /** 3、自定义类型转换器 // 实际开发基本上 用不到自定义 类型转换器 MM/dd/yyyy (String)<------------------>java.util.Date 互转 a、自定义类型转换器 编写一个类, 继承StrutsTypeConverter, 实现两个抽象方法 // MyDateConverter extends StrutsTypeConverter { convertFromString() convertToString() } b、注册类型转换器 方式一:局部类型转换器 服务于当前的动作类;按照属性进行注册的形式; // 模型类的某个属性 在属性所在类的包中,建立名称为 “类名-conversion.properties” 的文件 // User-conversion.properties ——————> birthday=cn.it.struts.converter.MyDateConverter // 放在 cn.it.struts.domain 包下 ——————> 和 模型类User 放在一起 局部 仅UserAction可用 方式二:全局类型转换器 服务于整个所有动作类;按照类型进行注册的形式; // 按照java类中的 Type类型 在构建路径中,建立一个固定名称为 “xwork-conversion.properties” 的文件 // 固定名称: xwork-conversion.properties ————————> java.util.Date=cn.it.struts.converter.MyDateConverter // 放在 构建路径下: src下面 ———————> 全局 所有Action可用 c、转换出错时的问题解决 a、类型转换失败后,会自动转向一个 name="input" 的逻辑视图 b、显示错误消息
c、把错误提示改为中文的 // 由一个叫做 conversionError的拦截器 完成的 在Action所在的包中,建立名称为 “类名xxxAction.properties” 的文件 // UserAction.properties ———————> invalid.fieldvalue.birthday=\u751F\u65E5\u683C\u5F0F\u5FC5\u987B\u4E3Ayyyy-MM-dd // 放在 cn.it.struts.action 包下 ————————> 和 UserAction放在一起 数据回显使用 OGNL / EL */ 4、总结Struts2的类型转换器 boolean Boolean char Character int Integer long Long float Float double Double Date yyyy-MM-dd(支持) 数组 可将多个同名参数,转换到数组中 集合 支持将数据保存到 List 或者 Map集合 13.用户输入验证 1、概述 // 实际开发:客户端验证+服务器端验证 方式一: 客户端验证。 使用 JavaScript // eg:EasyUI的 $(this).form('validate'); ... 方式二: 服务器端验证。 使用 服务器的java代码 // .. 2、struts2中的服务器端验证 // 前提: extends ActionSupport 前提:动作类要继承ActionSupport类。 2.1编程式验证: // 就是在你的 java代码中 编写验证的逻辑 1—核心API:addFieldError() // 从ActionSupport 中继承过来的 API a、针对动作类中的所有动作方法进行验证 // 所有 动作类继承ActionSupport,覆盖 public void validate(){ addFieldError(fieldName, errorMessage) // 验证失败,封装信息到一个Map("错误字段","错误信息"); } // 如果Map中没有任何元素,说明验证通过. 否则,不通过. b、针对动作类中的某个/些动作方法进行验证 // 部分 1.不需要验证的方法数量少: 在不需要验证的方法上面使用 @SkipValidation 注解 2.需要验证的方法数量少:validate方法名() // validateRegist() 2.2声明式验证 // 通过 配置文件 制定验证规则 ——————全局: UserAction-validation.xml 局部: UserAction-xxx-validation.xml --->仅对xxx方法验证 eg: regist xml的dtd声明在: xwork-core-2.3.15.3.jar\xwork-validator-1.0.3.dtd // tips:这里的xxx:是
不是动作类中方法名 // class-name-validation.xml所以: 根据method ——找到对应——>name a、针对动作类中的所有动作方法进行验证 // 所有 // 约定大于编码!!! 此种写法下:我们100%会保持method和name值一直的!!! 在动作类所在的包中,建立一个名称为“动作类名-validation.xml”的配置文件 b、针对动作类中的某个/些动作方法进行验证 // 部分 1.不需要验证的方法数量少: 在不需要验证的方法上面使用@SkipValidation注解 2.需要验证的方法数量少: // class-name-validation.xml 配置文件的命名:动作类名-动作名-validation.xml // 若仅有一个方法需要验证 ,还可以考虑考虑此方法 其他就没卵用╮(╯_╰)╭ 动作名:指struts.xml中<action元素的name值,不是动作类中的动作方法的名字。 // 有点蛋疼 eg;我想验证 UserAction 中的regist方法 // 正常情况下的命名规范 :
... ——————这才是实际应用中 // 要对add()方法实施验证,校验文件的取名为: UserAction-user_add-validation.xml // 要对update()方法实施验证,校验文件的取名为: UserAction-user_update-validation.xml //
...——————这时我们前面学的 最原始的的方式 // 此处: name是可以随便写的,并没有要求必须和 method一直, 所有我们要注意了: name值的对应关系为action——name 可不是 action——method // ...写了这么一大堆,都没啥卵用... 实际根本用不着 ╮(╯_╰)╭ 格式: // 根元素 ————> 要验证的字段 ————> 内置验证器类型的引用 ————> 传参(当然,部分类型是没有参数的) /**
—————————— type 对应 default.xml 内置验证器配置文件中的
true
必须输入名字
您输入的用户名只能是字母和数字 ,且长度必须在4到25之间
true
必须输入密码
您输入的密码只能是字母和数字 ,且长度必须在4到25之间
1
150
年纪必须在1到150之间
1900-01-01
2050-02-21
生日必须在${min}到${max}之间
*/ 2.3验证失败的处理 失败后会自动转向一个 name="input" 的逻辑视图; //
error.jsp
错误消息的显示:
标签 2.4struts2提供的一些内置验证器 // default.xml 1、内置验证器在何处定义的 xwork-core-2.3.15.3.jar\com\opensymphony\xwork2\validator\validators\default.xml /** * validators : 根目录 * validator : 声明验证规则 ————————表明此标签代表的是:验证规则 * name : 验证规则的 唯一名称 * class : 验证规则 对应的完整路径 */
系统提供的校验器如下: required (必填校验器,要求被校验的属性值不能为null) requiredstring (必填字符串校验器,要求被校验的属性值不能为null,并且长度大于0,默认情况下会对字符串去前后空格) stringlength (字符串长度校验器,要求被校验的属性值必须在指定的范围内,否则校验失败: minLength参数指定最小长度, maxLength参数指定最大长度, trim参数指定校验field之前是否去除字符串前后的空格) regex (正则表达式校验器,检查被校验的属性值是否匹配一个正则表达式,expression参数指定正则表达式, caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true) int (整数校验器,要求field的整数值必须在指定范围内,min指定最小值,max指定最大值) double (双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值) fieldexpression (字段OGNL表达式校验器,要求field满足一个ognl表达式, expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过) email (邮件地址校验器,要求如果被校验的属性值非空,则必须是合法的邮件地址) url (网址校验器,要求如果被校验的属性值非空,则必须是合法的url地址) date (日期校验器,要求field的日期值必须在指定范围内,min指定最小值,max指定最大值) conversion (转换校验器,指定在类型转换失败时,提示的错误信息) visitor (用于校验action中复合类型的属性,它指定一个校验文件用于校验复合类型属性中的属性) expression (OGNL表达式校验器,它是一个非字段校验器, expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值, 返回true时校验通过,否则不通过,该校验器不可用在字段校验器风格的配置中) 14.struts2中对于国际化的支持 // 大前提:动作类必须 继承ActionSupport !!! 1、定义消息资源包——————————后面我们就可以在JSP页面或action类中访问国际化信息 a、定义全局消息资源包 // 项目级别 // 在struts.xml中通过 为struts.custom.i18n.resources常量 赋值, 把资源文件 定义为 全局资源文件
// message为资源文件的基本名 message.properties —————— 后缀略
// msg_en_US.properties —————— 省略 _en_US.properties b、定义包范围的资源包 // 包级别 package开头 ———————— package_zh_CN.properties 资源文件的开头,固定位 package 本包中的动作类,及子包下的动作类都能访问包范围的消息资源文件。 当查找指定key的消息时,系统会先从package资源文件查找,当找不到对应的key时,才会从常量struts.custom.i18n.resources指定的资源文件中寻找。 c、定义局部消息资源包 // 类级别 xxxAction开头 ———————— Demo1Action_zh_CN.properties 在动作类所在的包中,建立固定名称 "动作类名_语言代码_国家代码.properties" 2、如何获取资源包中的内容 a、在动作类中使用 // getText("key") 在Action类中,可以继承ActionSupport 使用其API: getText("key") getText("key") ———————— 获取值 b、在JSP页面中使用 //
name为 message.properties 中的key loginError=\u7528\u6237\u540D
———————— 输出显示 c、在表单标签中,通过key属性指定资源文件中的key
// 获取值 为表单 name字段 赋值! d、自由选择消息资源包——————————直接指定访问 哪个资源文件
// 直接访问 cn.it.action包下 基本 名为package 的资源文件
// key=welcome
小张
// 这里表示 我们可以在 资源包中 用通配符的方式 传参! eg:资源文件中的内容: welcome= {0},欢迎来到{1}
东京
// 在Action类中获取带占位符的国际化信息,可以使用getText(String key, String[] args)或getText(String aTextName, List args)方法。 3、资源文件的搜索顺序 有小到大 ..... 15.拦截器 1、拦截器简介 struts2中很多的核心功能都是拦截器完成的 比如:params(封装动态参数)、staticParams(静态参数封装)、i18n(国际化)、modelDrivern(模型驱动)、servletConfig(注入servletAPI)等 作用:在执行动作 前或后 进行拦截 2、struts2的运作全图 结论: 动作方法执行前:拦截器会 按照顺序依次进行拦截 执行动作方法 返回结果视图 拦截器会按照原来的顺序的 相反顺序再次进行拦截 执行过程中:ActionInvocation 保存了 需要用到的数据 < 自定义拦截器A > <~B> <~C> ... // 放行的过程 —————就是————— 调用下一个方法的过程 A———>B———>C———>D———>E ...———>...调用下一个拦截器(放行)... ———> xxxAction // Action 执行完 return "success"; Action永远都在 拦截器中间执行 ↓ jsp // 执行完Action 就会根据 结果集 ————>跳转到 jsp视图页面 ↓ A<———B<———C<———D<———E ...<———...传递返回值: success ... <——— // 然后 将Action的 结果集 继续逐层 往回传递到 第一个拦截器 ————————— 反向回传的过程 // 拦截器 反向执行的过程 // 拦截器 与 Filter 不同点: doFilter(ServletRequest request, ServletResponse response,FilterChain chain); // 核心对象:FilterChain API(放行): chain.doFilter(request, response); intercept(ActionInvocation invocation) // 核心对象:ActionInvocation API(放行): invocation.invoke(); service(ServletRequest req, ServletResponse res); 3、自定义拦截器 熟悉拦截器的体系:所有的拦截器都直接或间接的实现了Interceptor接口 interface Interceptor extends Serializable // init(); intercept(ActionInvocation invocation) destroy(); abstract class AbstractInterceptor implements Interceptor // 实现了 init()/destroy()————>为空方法 , 继承 抽象方法 intercept(ActionInvocation invocation); abstract class MethodFilterInterceptor extends AbstractInterceptor // 实现了 intercept(ActionInvocation invocation); 调用了 抽象方法 doIntercept(invocation); // 其 子类 必须重写 doIntercept(invocation); a、编写一个类,继承AbstractInterceptor或实现Interceptor接口 b、配置拦截器:声明拦截器 // 格式:仿照 struts-default.xml 配置文件来就OK了! // 全局
// 声明 自定义拦截器
// 声明 自定义拦截器栈
// 引用默认拦截器栈
// 引用自定义拦截器
c、使用已经声明的拦截器 d、调用过程 // 见 上2 4、执行动作前检查用户是否登陆的拦截器 5、MethodFilterInterceptor 是AbstractInterceptor的子类: setIncludeMethods(String includeMethods) : 设置 需要拦截 的方法, 多个方法用逗号分隔 setExcludeMethods(String excludeMethods) : 设置 不需要拦截 的方法, 多个方法用逗号分隔 6、配置拦截器的参数: 1.方式一: // 在自定义栈中 直接设置 同上 3.b、略 ....
login
.... 2.方式二: // 在 具体某个action内部 引用过来再设置
// 引用自定义拦截器栈
// 给栈中的 某个拦截器 设置参数
login
7、Interceptor接口: Struts 会依次调用程序员为某个 Action 而注册的每一个拦截器的 interecept 方法. 每次调用 interecept 方法时, Struts 会传递一个 ActionInvocation 接口的实例. ActionInvocation: 代表一个给定动作的执行状态, 拦截器可以从该类的对象里获得与该动作相关联的 Action 对象和 Result 对象. 在完成拦截器自己的任务之后, 拦截器将调用 ActionInvocation 对象的 invoke 方法前进到 Action 处理流程的下一个环节. 还可以调用 ActionInvocation 对象的 addPreResultListener 方法给 ActionInvocation 对象 “挂” 上一个或多个 PreResultListener 监听器. 该监听器对象可以在动作执行完毕之后, 开始执行动作结果之前做些事情. AbstractInterceptor 类实现了 Interceptor 接口. 并为 init, destroy 提供了一个空白的实现 16、文件的上传和下载 // fileUpload拦截器 底层:fileupload组件 1、文件的上传 1.1文件上传简介 前提: 表单写法有要求: a、表单的method必须是POST方式提交 b、表单的enctype属性必须是multipart/form-data c、表单提供
类型的输入域 struts2中如何实现文件上传的: a、借助一个fileUpload拦截器完成的; b、最底层的还是借助的commons-fileupload这个组件; 1.2单文件上传 a、编码步骤: 准备的表单页面:
struts.xml
动作类 //按照框架要求编写即可 public class UploadAction extends ActionSupport { private String name; // 普通文本字段,可不用管它 private File upload; //动作类上传的属性必须是File类型 字段名和
保持一致 private String uploadFileName;//上传的文件的文件名。 上传字段+FileName, FileName固定写法 private String uploadContentType;//上传文件的MIME类型。 上传字段+ContentType, ContentType固定写法 public String execute() throws Exception { System.out.println(name); //封装到upload字段中 //服务器建立一个保存文件的目录:WEB-INF/files目录,存放文件的地方 ServletContext sc = ServletActionContext.getServletContext(); String realStorePath = sc.getRealPath("/WEB-INF/files"); File rootDirectory = new File(realStorePath); if(!rootDirectory.exists()){ rootDirectory.mkdirs();//如果目录不存在,创建目录 } //实现上传:IO流 InputStream in = new FileInputStream(upload); OutputStream out = new FileOutputStream(new File(rootDirectory, uploadFileName)); int len = -1; byte[] b = new byte[1024]; while((len=in.read(b))!=-1){ out.write(b, 0, len); } in.close(); out.close(); return null; } public String getName() { return name; } public void setName(String name) { this.name = name; } public File getUpload() { return upload; } public void setUpload(File upload) { this.upload = upload; } public String getUploadFileName() { return uploadFileName; } public void setUploadFileName(String uploadFileName) { this.uploadFileName = uploadFileName; } public String getUploadContentType() { return uploadContentType; } public void setUploadContentType(String uploadContentType) { this.uploadContentType = uploadContentType; } } b、代码改进 1.动作类实现上传部分的代码: // 对 流对接 做了一个简单封装 //实现上传:IO流 FileUtils.copyFile(upload, new File(rootDirectory, uploadFileName)); //拷贝文件 FileUtils.moveFile(upload, new File(rootDirectory, uploadFileName)); //剪切文件 return null; 2.文件上传的一些限制:文件的大小(总文件大小);文件的类型等 默认值是2M, 在struts.xml 中覆盖原始参数
并在src 下创建资源文件 : msg_zh_CN.properties // 内容: struts.messages.upload.error.SizeLimitExceededException=\u6587\u4EF6\u6700\u5927\u5141\u8BB8{0},\u60A8\u7684\u6587\u4EF6\u5927\u5C0F{1} /**
// 注册国际化 资源文件 引用自定义文件, 覆盖部分原始参数的值 eg:下4.中文提示
// 覆盖 文件上传大小 原始参数设置
// 允许上传的文件的扩展名,多个扩展名用逗号分隔 ————————————给fileUpload拦截器 传入 文件扩展名参数
.doc,.txt // allowedTypes
text/plain,application/msword //允许上传的文件的最大字节数据:此参数设置无效
5242880 —————————— 此处设置 文件大小参数 , 无效!!! 只能在上面设置
/upload1.jsp
*/ 3.遇到的问题及解决办法: 上传时遇到问题,fileUpload拦截器会自动转向一个name=input的逻辑视图 // 在
中配置一个结果集
uploadError.jsp
jsp页面显示原始错误信息:
显示原始错误信息 // eg: 在 uploadError.jsp 页面 上写
展示 原始错误信息! // 一般我们会 采取自定义的 错误提示! 提高用户体验度! 真实错误信息,会打印到日志! 4.中文提示: // struts-message.properties struts2中的文字提示是基于国际化的。有内置的默认提示信息(struts2-core.jar\org\apache\struts\struts-message.properties) 覆盖其中有关文件上传的key的value即可 // (注意:使用全局消息资源包的形式) /** 具体步骤: // 覆盖步骤 第一步:创建新的资源文件 例如 fileuploadmessage.properties, 放置在 src 下 在该资源文件中增加如下信息: struts.messages.error.uploading=上传错误: {0} struts.messages.error.file.too.large=上传文件太大: {0} "{1}" "{2}" {3} struts.messages.error.content.type.not.allowed=上传文件的类型不允许: {0} "{1}" "{2}" {3} struts.messages.error.file.extension.not.allowed=上传文件的后缀名不允许: {0} "{1}" "{2}" {3} 第二步:在struts.xml文件加载该资源文件
// 此处value 一般要求配置全局的 直接src下 ,写文件名简称即可 */ /** struts-message.properties 配置如下: struts.messages.error.uploading=Error uploading: {0} struts.messages.error.file.too.large=File too large: {0} "{1}" "{2}" {3} struts.messages.error.content.type.not.allowed=Content-Type not allowed: {0} "{1}" "{2}" {3} struts.messages.error.file.extension.not.allowed=File extension not allowed: {0} "{1}" "{2}" {3} {0}:
中name属性的值 {1}:上传文件的真实名称 {2}:上传文件保存到临时目录的名称 {3}:上传文件的类型(对struts.messages.error.file.too.large是上传文件的大小) */ /** 5.upload拦截器 FileUpload 拦截器负责处理文件的上传操作, 它是默认的 defaultStack 拦截器栈的一员. FileUpload 拦截器有 3 个属性可以设置. maximumSize: 上传文件的最大长度(以字节为单位), 默认值为 2 MB allowedTypes: 允许上传文件的类型, 各类型之间以逗号分隔 allowedExtensions: 允许上传文件扩展名, 各扩展名之间以逗号分隔 可以在 struts.xml 文件中覆盖这 3 个属性 若用户上传的文件大小大于给定的最大长度或其内容类型没有被列在 allowedTypes, allowedExtensions 参数里, 将会显示一条出错消息. 在struts-messages.properties 文件里预定义. (org.apache.struts2包下) 可以在文件上传 Action 相对应的资源文件中重新定义错误消息, 但需要在 struts.xml 文件中配置使用 action 的消息: */ 1.3多文件上传 // name 保持一致 数组接收——————File[] / String[] 表单:提供多个
类型的上传输入域, name保持一致 /** 动作类: // 数组接收 private File[] upload;//动作类上传的属性必须是File类型 .List或数组 private String[] uploadFileName;//上传的文件的文件名。 上传字段+FileName,FileName固定写法 private String[] uploadContentType;//上传文件的MIME类型。 上传字段+ContentType,ContentType固定写法 */ //实现上传:IO流 if( upload!=null && upload.length!=0 ){ for(int i=0;i<upload.length;i++){ // FileUtils.copyFile(upload[i], new File(rootDirectory, uploadFileName[i]));//拷贝文件 FileUtils.moveFile(upload[i], new File(rootDirectory, uploadFileName[i]));//剪切文件 } } 2、文件的下载 // type="stream" —————————— 是一个结果类型:stream,实现文件的下载的 下载交给它就OK了,我们提供一个 InputStream 参数即可!!! // 查看 此结果类型的源码 发现 其doExecute()方法, 封装了文件下载功能 只需要我们为其提供 该类中声明的一个 成员变量inputName 的参数值即可 : // protected String inputName = "inputStream"; struts2提供了stream结果类型,该结果类型就是专门用于支持文件下载功能的 指定stream结果类型 需要指定一个 inputName参数,该参数指定一个输入流,提供被下载文件的入口 // 最主要的参数 :InputStream inputStream输入流对象 // 通过 struts.xml 配置给 stream即可 动作类编写: //写法也是固定的 public class Download1Action extends ActionSupport { //提供一个InputStream类型的属性 private InputStream inputStream; // 仅提供此 输入流对象 就可以实现下载 // 下面的是我们 配置的几个参数 是保证浏览器获取到 文件名 和 文件大小的 private int filelength;//要下载的文件的大小 private String name;//下载的文件的文件名 public String execute() throws Exception { //把inputStream赋值即可 //文件的真实路径 ServletContext sc = ServletActionContext.getServletContext(); String realPath = sc.getRealPath("/WEB-INF/files/美女.jpg"); inputStream = new FileInputStream(realPath); //设定大小 filelength = inputStream.available(); //设置文件名 name = FilenameUtils.getName(realPath);//要进行URL编码,火狐浏览器除外 ———————— 火狐 用Base64编码即可 //在动作中进行编码 name = URLEncoder.encode(name, "UTF-8"); return SUCCESS; } public int getFilelength() { return filelength; } public void setFilelength(int filelength) { this.filelength = filelength; } public InputStream getInputStream() { return inputStream; } public void setInputStream(InputStream inputStream) { this.inputStream = inputStream; } public String getName() { return name; } public void setName(String name) { this.name = name; } } struts.xml配置:主要配置stream结果类型的参数 // StreamResult类有 7 个set方法 setAllowCaching() 默认false:不使用缓存 setContentCharSet()默认系统本地utf-8 //我们尽量都把它需要的参数,手动设置进去 /**
// 结果类型 type="stream"
inputStream // 就是我们 Action类中 提供的 输入流对象
// 告诉浏览器 以下载的方式 打开
attachment;filename=${name} // attachment:附件
// 告诉浏览器, 我给你响应回来的是什么类型的文件 图片/html/json/二进制/...
application/octet-stream // 指定MIME类型 八位字节的二进制
1024 //单位 自然是字节
${filelength} //不设置 也可自动获取 没啥卵用 可忽略
*/ *********************第三篇 数据篇************************************** 17、OGNL表达式 // Ognl 有一个上下文(Context)概念,说白了上下文就是一个MAP结构,它实现了java.utils.Map的接口 OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。 能够:获取JavaBean的属性;List或数组的元素;Map根据key获取value的值;执行逻辑运算; OGNL其他功能: 前提:在struts2中使用OGNL表达式,必须把表达式写到struts2的自定义的标签中。 1、支持对象的普通方法调用 2、访问类的静态方法和静态变量 3、contextMap:(非常重要) 1.contextMap:是整个动作访问的数据中心。即每一次动作请求所有的数据都放在这里。 2.contextMap就是一个Map结构 key value 说 明 root java.util.List contextMap中的根,是一个List结构 栈结构 request java.util.Map 对应的是请求范围中的所有属性(Attributes) session java.util.Map 对应的是会话范围中的所有属性(Attributes) application java.util.Map 对应的是应用范围中的所有属性(Attributes) parameters java.util.Map 所有的请求参数 action java.lang.Object 当前动作对象 attr java.util.Map 依次从页面、请求、会话、应用范围搜索 3.cotextMap何时被创建的 // 每次动作访问,都会创建一个新的contextMap,保持本次访问用到的数据。 当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。 注意: Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:
4.ActionContext和ValueStack: ActionContext<---------- ----------="">ValueStack 创建ActionContext后,会绑定到当前线程上(ThreadLocal) 5.contextMap中的数据操作 // 我们可以把 contextMap 想象成一个数据库 它分为两张表:OGNL Context = ActionContext + ValueStack // ActionContext中存放的 HTTP请求信息 action对象存放在ValueStack 1.contextMap是动作访问的数据中心,本质是一个ActionContext类,这个类有一个Map.可以操作 _root 和 _values class ActionContext{ private Map
context;// 此 context —————— contextMap = _root(action) + _values(request、session、application、parameters、attr) } 2.其子类: class ServletActionContext extends ActionContext implements StrutsStatics ValueStack(值栈): 贯穿整个 Action 的生命周期(每个 Action 类的对象实例都拥有一个 ValueStack 对象). 相当于一个数据的中转站. 在其中保存当前 Action 对象和其他相关对象. @scope("prototype") // 多例的 class Action{ ValueStack; // 数据 存取 中转站 ———————————— Action + Http ActionContext; } interface ValueStack { // 在 ValueStack 对象的内部有两个逻辑部分: List ObjectStack; // ObjectStack: Struts 把动作和相关对象 压入 ObjectStack 中-----List // 相关对象 :在Action中 声明过的 对象 Map ContextMap; // ContextMap: Struts 把各种各样的 映射关系(一些 Map 类型的对象) 压入 ContextMap 中 } // Http请求 :Request + Request + Application + Attribute + parameters class OgnlValueStack implements ValueStack{ // Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中,request中 /** 断点执行如下代码: Object ctx = ServletActionContext.getRequest().getAttribute("struts.valueStack"); 通过断点,我们发现 ctx = root + context ; context = _root + _values ; 且对比发现: _root = root ; _values 中自然封装的 http对象的Map映射 */ // ObjectStack: private CompoundRoot root; // CompoundRoot extends ArrayList // ObjectStack: Struts 把 动作和相关对象 压入 ObjectStack 中 // ContextMap: private OgnlContext context; // ContextMap : Struts 把各种各样的 映射关系(一些 Map 类型的对象) 压入 ContextMap 中 root(Action);// root中保存着调用Action的实例 } class OgnlContext implements Map { // ObjectStack: private Object _root; // OgnlContext 中默认的顶层对象 _root = OgnlValueStack.root(action) // ContextMap: private hashMap _values; // Http请求 :Request + Request + Application + Attribute + parameters —————————————— ... _root = root; // Struts2将 OgnlValueStack的root对象 赋值给了 OgnlContext 中的_root对象 , // 在OgnlValueStack的root对象中,保存着调用Action的实例, // 因此,在页面上通过Struts2标签访问Action 的属性时,就不需要通过#号来引用 } /** ognl Context 包含 ObjectStack属性 和 ContextMap属性 ognl上下文 = root + context (context = _root + _values) */ 1.存数据:(实际使用中由框架为我们存数据) ActionContext的API // ActionContext提供了对ognl上下文对象中数据操作的方法. get/setServletContext(); get/setRequest(); get/setResponse(); getPageContext(); getContext(); ServletActionContext.getContext().getValueStack(); ... ValueStack的API 获取整个contextMap: Map
getContext(); // 获取 ValueStack的上下文(Map类型的context), 保存了ValueStack 所有的信息 和 环境 ———————— Map context // _root(action) + _values 只获取root: CompoundRoot getRoot(); // 获取 root ————————保存了 压入栈顶中的所有 Object findValue(String s); // 等同于 域对象的getAttribute() ————————————只不过此处是在 ValueStack中查找属性值 peek(); // 获取 栈顶对象 ——————仅获取,不做修改 pop(); // 获取 栈顶对象 ——————获取, 并从栈顶 remove push(Object o); // 将对象 压入栈顶 set(String key, Object o); // 如果栈顶存在 此Map,存入. 不存在,创建再存入. ... 2.取数据:OGNL表达式 为何使用EL表达式能够访问valueStack中对象的属性:原因是Struts2对HttpServletRequest作了进一步的封装。 3.#号的用法 # 相当于 ActionContext.getContext() // ActionContext ac = ActionContext.getContext(); 获取一个ActionContext实例 // OGNL会设定一个根对象(root对象),在Struts2中根对象就是ValueStack(值栈) 。 // 如果要访问根对象(即ValueStack)中对象的属性,则可以省略#命名对象,直接访问该对象的属性即可。 在OgnlValueStack类里有一个List类型的root变量,他存放了一组对象,处于第一位的对象叫栈顶对象。通常我们在OGNL表达式里直接写上属性的名称即可访问root变量里对象的属性, 搜索顺序是从栈顶对象开始寻找,如果栈顶对象不存在该属性,就会从第二个对象寻找,如果没有找到就从第三个对象寻找,依次往下访问,直到找到为止。 总结: 访问contextMap中的数据,使用# 访问root中的数据,直接写属性或者key值即可 小问题:不建议这么做
:从root找对象的name属性,如果找不到,会作为key到contextMap中去找。 18、Struts2的标签库 1、通用标签库 // 在OGNL表达式中, 字符串要使用 "" 引起来 双重 ""时, 默认 外层单引,内层双引 test='#grade=="A"' 控制标签: /** if elseif else
优秀
// 在OGNL表达式中:字符串要使用双引号引起来
良好
尚需努力
*/ /** iterator: //
作用:实现遍历迭代,类似JSTL中的c:forEach value: OGNL表达式 var: 指定一个key值。遍历过程中,会把当前元素以var指定的key存放到contextMap中. 可以不指定。会把当前遍历的元素存放到root中。(ValueStack.push(元素)) status: 指定一个key值,引用一个对象,放在了contextMap中。该对象记录着当前遍历的元素的属性 int getIndex() :当前对象的索引。从0开始 int getCount() :当前对象的顺序。从1开始 boolean isFirst() :是否是第一个元素 boolean isLast() :是否是最后一个元素 boolean isOdd() :是否是奇数 boolean isEven() :是否是偶数 begin: 从哪个开始 end: 结束索引 step: 步长。默认1 */ property:value不指定,默认输出栈顶对象 /**
// var 和 value 若指定了key, 均放入contextMap 取值就需要带# var若不指定,自动放入栈顶! // 用 奇偶设置 颜色
// 索引
// 序号
// 第一个
// 最后一个
// 奇数
// 偶数
// 姓名
// 性别
// 城市
// 生日
*/ 数据标签: property: //
作用: 输出表达式的值到页面上 属性: value:是一个OGNL表达式.如果没有指定该属性,则默认输出ValueStack栈顶的值. default:指定一个默认值, 如果需要输出的属性值为null,则显示该属性指定的值. escapeHtml:是否忽略HTML标签 date: //
功能:日期类型格式化 属性: name : OGNL表达式 format : SimpleDateFormat action: //
——————————执行 ognlAction_test.action 通过指定命名空间和action名称,该标签允许在jsp页面直接调用Action 在页面显示一个动作的执行结果. a:超链接 子标签 param : 属性: name : 参数名 value :OGNL
点我
url:该标签用于创建url地址,可以通过"param"标签提供request参数. action:用来生成url的action动作名称,如果没有则使用value namespace :命名空间 var:起一个临时的名称 放在了contextMap . value:如果不提供就用当前action,使用value后缀必须加.action
">hello /** 表单标签
s:radio list OGNL:创建list和map对象 创建list:{元素1,元素2,....} 创建map:#{key:value,key:value,}; key:value(传递值,页面显示值) value:指定默认值:value(指定的是key的值) name:注意一定要有name属性 // 不然,你把值赋给谁 -->
*/ 2、Struts2中的EL表达式 普通EL表达式: ${name}:相当于调用pageContext.findAttribute("name"),从 页面、请求、会话、应用 范围查找key=name对应的value的值。 Struts2中的EL表达式: // struts2框架对服务器原有的request对象的getAttribute()方法,进行了重写. ———————————— 会在 root 、 contextMap中 也查找 顺序如下: ${name}: 页面范围、请求范围、 root中对象的属性、contextMap中的key、 会话范围、应用范围 3、struts2UI标签中的表单标签 使用Struts2表单标签的优势: 1、错误回显 2、便于布局和排版 OGNL操作集合: list:{a,b,c,...} map:#{"key1":"value1", "key2":"value2","key3":"value3",...}
正确写法:
requiredLabel属性: 显示*号 // 用在 必填项中
// 用户名 * : 布局模板:默认的模板xhtml;经常使用的模板:simple //
统一更改表单标签的模板 // 覆盖 default.properties参数配置文件中 常量的值 4.OGNL其他细节 不使用任何符号: 比如:name,从root中取对象的属性。如果没有任何的属性,变为key到contextMap中找 使用#: 1、#name:从contextMap中找key=name对应的value的值 2、#{key1:value1,key2:value2,...}:创建一个Map对象 字符串直接量: 使用双引号引起来:比如,"abcdef" 使用%: 通用标签:value属性一般取值是一个 OGNL表达式 表单标签:value属性一般取值是一个 普通字符串 %可以强制变为OGNL表达式使用 $符号的使用: 在struts.xml或*.properties配置文件中使用OGNL表达式,使用${OGNL} 5.防止表单重复提交
...
struts.xml中配置自定义 name="token"拦截器 30.struts2中内置配置文件 default.properties 参数配置文件 struts.action.extension=action,, struts-default.xml 结果集 + 拦截器(栈)
、
+ 两个默认引用
配置文件
default.xml 内置验证器配置文件
// 校验配置文件的DTD信息 ————> xwork-validator-1.0.3.dtd struts-messages.properties 文件上传有关的出错消息 31.所谓通配符访问action // userAction_save.action name = " userAction_save " method = "save" class = userAction 就是把 同一个Action类 中的 method 集中处理. 方式为:将 name 以统一的xxxAction开头 , 再拼接上 通配符 _* ——————> name = " xxxAction_* " method 也统一以 占位符{0} 、 {1} ...获取 * 的值 ——————> method = {0} 1.一个通配符:(常用)
// 在 spring 容器中 class简写. 2.两个以上通配符的使用: // 页面跳转用 // 需要进行权限控制的页面访问 执行默认的ActionSupport类的execute() ———— execute()方法 返回值为: return SUCCESS;
/WEB-INF/pages/{1}/{2}.jsp
32.所谓栈:先进后出 33.struts.xml中的几个继承,到底继承的是谁?
// 此处 继承自 struts-default.xml 中的
————————————
// 注册自定义 拦截器栈
// 此处 继承自 struts-default.xml 中的 拦截器栈:
也是struts2的默认拦截器栈
34.namespace="/"的名称空间 和 默认的名称空间(namespace不写或者值为"") 的区别到底在哪??? 35注解. @Controller @Scope("prototype") @Resource @Service @Transactional @Repository ========================================== Hibernate =========================================================================================================================== 1.Hibernate框架简介【了解】 1.定义:Hibernate是一个基于Java的轻量级的ORM框架 基于Java:底层是Java语言实现的 轻量级:内存消耗比较少,运行速度比较快,性能稍高 ORM(Object Relation Mapping): Object: 对象 类 属性 数据类型 对象 Relation: 关系型数据库表 表名 字段 数据类型 表 Mapping: 映射 将具有对应关系的模型关联起来,操作对象,即操作数据库表 2.Hibernate实质:自动完成JDBC + 自动生成SQL语句 说明:自动生成的SQL语句是一种匹配所有格式的语句,因此该语句不能根据用户需要进行优化,因此生成的SQL语句是一种最差实践,性能较低 3.Hibernate是一种数据层解决方案,用于进行数据层开发,制作DAO 4.常见的数据层解决方案 JDBC // sun 规范 最原始的的方式 , 也是最高效(运行高效——编程低效) 简单封装JDBCUtils————开源工具————DBCP、C3P0进一步优化改造JDBCUtils Hibernate 市场占有率: ORM:非ORM 9:1 ORM市场: 开源:收费 9:1 开源ORM市场: Hibernate:iBatis:其他 6:3:1 JPA(Java Persistence API ) iBatis/MyBatis Apache DBUtils // QueryRunner update(增删改) / query(查) Spring JDBCTemplate、HibernateTemplate、等等 2.Hibernate系统架构【理解】 图的分类:系统架构图、技术架构图 系统架构图:描述系统中的重要模块以及模块与模块之间的关系【上层依赖于下层】 Application ↓ persistent Objects(中间连接量) ↓ hibernate(hibernate.properties + XML Mapping) ↓ Database 1.包含内容:应用程序、Hibernate、数据库 2.Hibernate位于APP与DB之间 3.APP依赖Hibernate,Hibernate依赖DB 4.Hibernate中有两种配置文件 5.映射使用XML格式完成 6.持久化对象出现在APP与Hibernate间,起桥梁的作用,连接APP与Hibernate。Hibernate与APP间使用持久化对象进行数据交换 技术架构图: Application (Transient Object) ↓ persistent Objects(中间连接量) ↓ Session //持久化对象传递给hibernate的Session SessionFactory + JDBC + JNDI + JTA ↓ Database 1.Hibernate裂变成5块 JDBC JNDI JTA SessionFactory Session 2.APP需要操作的数据通过 持久化对象交给Hibernate的Session对象完成 3.APP中包含一种瞬时对象 4.SessionFactory用于创建Session 5.JDBC,JNDI,JTA作用未知 Application (Transient Object) ↓ persistent Objects(中间连接量) ↓ Session Transaction + SessionFactory + TransactionFactory + ConnectionProvider ↓ JDBC + JNDI + JTA ↓ Database 1.Hibernate依赖由第三方厂商实现 JDBC,JTA,JNDI技术完成任务,而非Hibernate自身实现 2.Hibernate存在有事务及事务工厂 3.Hibernate的连接需要由第三方提供 4.SessionFactory依赖 连接供应商 和 事务工厂 来工作 /**3.Hiberante资源下载与介绍【了解】【操作】 1.下载Hibernate Hibernate 最高版本4.3,本课程基于Hibernate3.6.10学习 下载地址:http://sourceforge.net/projects/hibernate/files/hibernate3/ 2.厂商介绍JBOSS JBOSS服务器 Web服务器:内置WEB容器(TOMCAT) 应用服务器:内置WEB容器+EJB容器(JBOSS、Weblogic) Hibernate JBPM 3.资源包目录层次 documentation:帮助文档 lib:开发使用jar包 bytecode:字节码实现(代理对象相关) jpa:JPA规范包 optional:可选包,包含开发Hibernate常用可选技术jar包 required:必选包,包含开发Hibernate必须使用的jar包 project:源码 hibernate3.jar:核心jar包 hibernate-testing.jar:测试包 4.开发所使用的jar包: 必选:(9个) 1.核心jar包:hibernate3.jar (1个) 2.lib//required/*.jar (6个) 3.lib/jpa/hibernate-jpa-2.0-api-1.0.1.Final.jar (1个) 4.DB驱动包:mysql的驱动jar包 (1个) 可选:(2个)如果不使用,则无法查看Hibernate的运行日志 5.log4j的jar包:log4j-1.2.16.jar(1个) 6.slf4j整合log4j的jar包:slf4j-log4j12-1.7.2.jar(1个) 5.【扩展】slf4j(简单日志门面技术) 不同的日志记录技术,全部是自己的记录方式,规范不统一, slf4j提供一种标准的记录日志方式,整合不同的日志技术, slf4j本身不提供具体日志记录实现 5.log4j技术————————————————slf4j的实现之一 参看《log4j快速入门手册》 */ 4.Hibernate基础实例 1.基础实例制作分析: O:Object 对象(开发者完成) R:Relation 关系型数据库表(开发者完成) M:Mapping 对象与表间的对应关系(开发者完成) JDBC:Hibernate自动完成 SQL: Hibernate自动完成 2.步骤: 1.创建工程(标准java工程) 2.导入jar包(9个) /** 3.制作R,创建表结构 CREATE TABLE `tbl_user` ( `uuid` varchar(32) NOT NULL, `userName` varchar(30) NOT NULL, `age` int(3) NOT NULL, `address` varchar(30) NOT NULL, PRIMARY KEY (`uuid`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 */ 4.制作O,创建Java中的对象 /** 提供一个无参的构造方法(可以使用默认无参构造方法) 提供一个主键属性(uuid) 私有化其他的属性(userName,age,addres…) 封装所有属性(提供getter与setter方法) *不要声明为final类(与后期优化有关) *使当前类实现序列化接口(与后期服务器数据检测有关,目前可忽略) */ 5.制作M,创建表与对象间的映射关系 // xxxModel.hbm.xml A.在创建的对象(Model)同层目录下创建与类名相同的xml文件,名称:UserModel.hbm.xml ———————— 放在 cn.it.hibernate.domain包下 B.从资源包中搜索*.hbm.xml(User.hbm.xml) // xxxModel.hbm.xml C.将资源包中查找的信息复制过来,描述具体的对应关系: 类与表的映射 // class ——————————
主键的映射 // id ——————————
属性与字段的映射 // property ——————————
/**
*/ 6.制作系统配置文件,用于描述连接的数据库相关信息及Hibernate的基本配置信息 A. 在src目录中创建XML文件 // hibernate.hbm.xml B.从资源包中搜索hibernate.cfg.xml文件 C.将资源包中查找的信息复制过来,描述具体数据连接信息 数据库连接的配置 可选配置 // 方言 、 show_sql 资源注册 // xxxModel.hbm.xml /**
com.mysql.jdbc.Driver
jdbc:mysql://localhost:3306/hibernate
root
root
org.hibernate.dialect.MySQLDialect
true
*/ 7.制作客户端程序,运行Hibernate 范例如下: /** UserModel um = new UserModel(); //1.创建一个要保存的数据 —————— 瞬时 um.setUuid(1L); um.setUserName("传智"); um.setAge(8); um.setAddress("双元课堂"); //2.加载配置信息 Configuration conf = new Configuration().configure(); //3.基于配置信息,创建SessionFactory对象 SessionFactory sf = conf.buildSessionFactory(); //4.打开一个与数据库相关的Session对象 Session session = sf.openSession(); //5.开启事务,基于Session得到 Transaction t = session.beginTransaction(); //6.通过session保存数据 —————————————————————————————— 持久化 到DB session.save(um); //7.提交事务 t.commit(); //8.操作完毕后,关闭session连接对象 session.close(); */ 5.映射模型类制作规范: // 对象id OID ———————— hibernate 据此 区分不同的 对象 1.提供可访问的公共无参构造方法(可使用自动生成的) // DB ——————> Object 构造 Hibernate在读取数据时,将读取的数据转换成一个对象,该对象的创建需要使用该构造方法 2.提供一个标识属性,作为对象的主键,映射数据库表主键,通常使用uuid属性作为主键 // 主键 该属性用于Hibernate内部区分对象使用,Hibernate无法使用内存地址比对对象是否相同,Hibernate依赖该属性对对象进行区分, 如果该属性值相同,Hibernate则认为是同一个对象 3.对所有属性进行私有化声明,并进行标准封装 // 私有化 Integer:√ int:× 注意:属性声明时使用封装类模型,避免使用基本数据类型 4.不要使用final修饰符(否则将无法生成代理对象进行优化,一级缓存中学习) // 对象id OID ———————— hibernate 据此 区分不同的 对象 OID:Hibernate对于对象的管理标识,用于区分对象,对应数据库中的主键 OID选取规则:优先考虑代理主键 属性:身份证号具有业务含义,称为自然主键 属性:uuid不具有任何业务含义,称为代理主键 对象的属性选择:优先使用封装类,避免使用基本数据类型 A.使用基本数据类型,对于没有输入值的数据,采用实际数据作为默认值 B.使用封装类类型,对于米有输入值的数据,采用null作为默认值 基本数据类型无法区分默认值是用户输入的还是没有输入产生的默认值,具有一定的安全隐患,因此放弃使用,改由封装类类型 6.映射配置文件 // xxxModel.hbm.xml 详解 /** 1.映射文件中包含内容: 类与表的映射 // class 主键的映射 // id 属性与字段的映射 // property 关系的映射(后期) // many-to-one 、 many-to-many ... 2.命名规范: 模型类名.hbm.xml 可以写成任意的名称a.xml,此格式不满足规范,但是可以使用(Hibernate低版本格式严格) 3.class元素用于指定对象关系映射中的类与表的关系 name:模型类的全路径名格式 table:数据库表名 schema:数据库名 4.id元素用于声明主键映射 name: 数据模型中的OID,通常使用uuid属性(必须) column: 数据库表的主键,通常使用uuid字段(可选) 如省略column配置,则默认column值与name值相同 id元素的选择字段一定是作为对象的OID的字段 5.property元素用于声明属性与字段的对应关系 name:数据模型中的属性名,也就是Java字段名(必须) column:数据库表的字段名(可选) 如省略column配置,则默认column值与name值相同 三种声明格式: 使用空标记(常用)
使用非空标记
使用子元素声明数据库字段名
6.范例
*/ 7.OID——主键生成策略: // 持久化时,以配置文件 的主键生成策略为准!!! eg:
user.setId("001"); save(user) // 此时设定的 OID="001" 无效, 系统会按配置的生成策略 自动生成32位随机字符串!!! 1.generator // 描述的是OID的生成策略 1.手工控制策略: assigned: 程序员手工控制生成策略 // 手动设置 OID 2.自动生成策略: // 自动生成 OID uuid (字符串类型:32位及以上) // 服务端 随机生成32位字符串 increment (整型数值类型) 通过获取max的值,执行SQL语句 // 服务端 SQL命令:max+1 identity (整型数值类型) 通过数据库端实现,要求设置自增 ———— MySQL可用 // 数据库自增 MySQL sequence (整型数值类型) 通过数据库端实现,要求设置自增 ———— Oracle可用 // 数据库自增 Oracle native (整型数值类型) 根据数据库的实现 自动选择identity/ sequence // 数据库自增 自动选择 /** 2.联合主键/复合主键 为兼容早期遗留系统而设计,目前几乎不采用该配置
【常见面试题】: 请列举Hibernate的主键生成策略 */ 8.系统配置文件: // hibernate.cfg.xml ————————> 代替了 早期的 hibernate.properties(此方式以被淘汰) /** 1.系统配置文件中包含内容: 数据库连接的配置 可选配置 资源注册 二级缓存(后期) 2.命名规范: hibernate.cfg.xml // Use the mappings and properties specified in an application resource named
hibernate.cfg.xml. 可以写成任意的名称a.xml,此格式不满足规范,参看Configuration对象 // 源码:configure( "/hibernate.cfg.xml" ); 3.数据库连接的配置: hibernate.connection.driver_class JDBC驱动类类名 hibernate.connection.url JDBC连接字符串 hibernate.connection.username JDBC连接用户名 hibernate.connection.password JDBC连接用户名对应的密码 4.可选配置 1.必选:方言配置 用于设置生成的SQL语句的格式
org.hibernate.dialect.MySQLDialect
2.其他可选配置 hibernate.show_sql 设置是否将执行过程中运行的SQL语句输出到控制台 开发阶段开启此属性,上线阶段关闭此属性 hibernate.format_sql 设置show_sql属性打印出的SQL语句以分行的格式进行显示 hibernate.connection.pool_size 设置Hibernate模型连接池最大连接数量 使用c3p0连接池 步骤: 1.导入c3p0连接池jar包 lib/optional/c3p0/*.jar 2.cfg.xml中配置下列配置属性 开启任意一句与c3p0有关的配置,即开启使用c3p0连接池
21
721
3091
hibernate.hbm2ddl 设置是否根据hbm文件格式生成表结构,需要配合hbm.xml文件中对于属性类型与长度相关的配置使用 connection.autocommit 设置是否自动提交事务 5.资源注册 将Hibernate的映射文件加入到系统配置中,否则将无法操作该模型 注意:目录层次结构间使用/符号描述
*/ 9.Configuration // 封装 Hibernate 系统配置信息 的对象 两种格式: 常用格式: Configuration conf = new Configuration().configure(); // 不写 默认读取 hibernate.cfg.xml Configuration conf = new Configuration().configure(“配置文件名”); // 读取指定的配置文件 /** 早期格式介绍: 早期格式:Configuration conf = new Configuration(); // 读取 hibernate.properties 早期格式读取properties格式配置文件,无法进行资源注册的信息配置,需要使用下列格式进行资源注册: Configuration conf = new Configuration(); //格式一:手动添加映射配置文件,操作量较大 conf.addResource("cn/it/api/UserModel.hbm.xml"); //格式二:手动添加映射类,由类名自动查找该类同包结构下的类名.hbm.xml文件 conf.addClass(UserModel.class); */ 10.SessionFactory // 线程安全 创建Session对象的工厂类,通过加载Configuration对象中封装的配置信息得到 Configuration conf = new Configuration().configure(); // 加载 hibernate.cfg.xml SessionFactory sf = conf.buildSessionFactory(); // 用获取到的 配置对象 创建SessionFactory 注意: 1.由于每次加载配置信息,均要读取XML文件,需要浪费大量时间,因此同一项目中,Configuration对象只会加载一次,SessionFactory对象也只加载一次 2.对于同一个工程,连接数据库的信息唯一,基于加载的配置信息Configuration对象所创建的SessionFactory对象用于创建连接数据库的对象, 不同的连接对象使用的连接信息是相同的,因此SessionFactory对象是线程安全的 11.Session: // 不安全 同 Connection 与DB交互数据 功能更强大!!! 1.描述单次应用程序与数据库间进行数据交换的对象,作用相当于Connection,但是其功能远远超过普通的JDBC连接对象 2.Session对象基于SessionFactory对象获取 Session s = sf.openSession(); 3.Session对象操作完成后要进行关闭,否则将一直占用该连接对象 s.close(); 说明: Session对象由SessionFactory创建,每次创建并不是new出一个全新的Session对象,而是从数据库连接池中获取一个闲置的连接对象, 使用完毕后,关闭Session对象也不是将该对象销毁,而是清空本次操作过程中所有的数据痕迹后,将该对象交还给连接池。 如果使用同一个Session连续执行若干次任务,前一次执行任务所操作的数据痕迹没有及时清除,会影响下一次的操作,因此Session是线程不安全的。 13.工具类H3Util制作: public class H3Util { private static Configuration conf = null; //静态的SessionFactory private static SessionFactory sf = null; //使用静态代码块初始化对象 static{ conf = new Configuration().configure(); sf = conf.buildSessionFactory(); } public static SessionFactory getSf(){ return sf; } /** * 获取Session对象 * @return 全新的Session对象 */ public static Session getSession(){ return sf.openSession(); } } 14.Transaction: 1.描述Hibernate操作过程中,绑定当前Session对象的事务控制对象 2.获取事务对象:通过使用Session中的beginTransaction()方法获取 Transaction t = session.beginTransaction(); 3.事务回滚: t.rollback(); 4.事务提交: t.commit(); 15.Session API: 1.插入数据 save(Object) // Serializable oid = s.save(user); 1.如果配置信息提供了OID生成策略,那么对象携带的OID将失效 2.该操作返回的是添加的对象对应的OID 注意:如果对象保存时,不能获取到OID的值,将抛出异常 persist(Object) 1.该操作可以保存对象 // 仅保存 无返回值! 2.如果手工给出了OID,并且又使用了自动生成OID,该操作将抛出异常 // OID 自动生成 和 手动 不能同时使用!!! 2.删除数据 delete(Object); 1.删除时提供的对象必须拥有OID,否则不做任何操作 // s.delete(user) ———————— user中必须封装 有OID , 否则等于没操作! 2.删除一个不存在的OID对象时,抛出异常 // 且提供的 OID有误时, 报错! 3.修改数据 update(Object) // s.update(user) ———————— 必须提供 OID 1.修改时提供的对象必须拥有OID,否则抛出异常 2.在一个Session内对同一个执行修改操作多次,只会执行对应SQL语句一次(一级缓存中详解) // 4.添加/修改数据 saveOrUpdate(Object) 该方法可以完成修改和添加操作,取决于是否提供OID 判断是否提供OID的策略 1.OID是否为null 2.OID的值是否与配置中 unsaved-value 是否冲突 5.查询单条数据 get(Class, Serializable) load(Class, Serializable) 1.查询时只能查询1条数据,并且需要提供OID,根据OID进行查询 2.查询时必须指定查询数据模型,Hibernate根据模型查找对应映射文件,找到查询数据对应的表,查询完毕后将数据按照模型格式进行封装 // xxxModel——————> xxxModel.hbm.xml ——————> 表 ↓ // xxxModel(查询到的数据封装到模型类中) 16.HQL语句书写规范: 1.HQL(Hibernate Query Language)语言:Hibernate专用的查询语言 2.HQL与SQL语言对比: SQL语法中使用表与字段描述查询 // 表 ———— 字段 HQL语法中使用类与属性描述查询,由SQL衍生而来,具有SQL语言不具有的特殊语法 // 类 ———— 属性 例一: SQL: select * from tbl_user HQL: from UserModel HQL: select um from UserModel um 例二: SQL: select userName,age from tbl_user // 表的 字段 HQL: select userName,age from UserModel // 类的 属性 例三: SQL: select u.userName,u.age from tbl_user u HQL: select um.userName,um.age from UserModel um 例四: HQL: select um.userName from UserModel 错误 HQL: select userName from UserModel um 正确 HQL: select userName from UserModel as um 正确 17.Query: // HQL查询 —————————— 自定义HQL语句 ———————————— session.createQuery("手写HQL语句"); 1.Query对象用于进行查询操作,使用HQL语法完成 2.Query对象由Session对象创建,传入字符串HQL参数 Query q = session.createQuery("from UserModel"); 3.获取查询结果信息,如果查询的是映射的模型对象,根据配置信息封装为对应对象 使用list()获取结果为列表信息 // List list = q.list(); 0——N 将查询结果包装成对象,并将对象组装成一个List集合 可以用于获取0到多条数据,如果是0条数据,返回的集合中没有数据 使用uniqueResut()获取结果为单一信息 // Object obj = q.uniqueResult(); 0——1 若结果超过1条,报错! 将查询结果包装成对象,直接返回 用于获取0到1条数据,如果是0条数据,返回null 注意:uniqueResut()返回结果不能超过1条,否则抛出异常 4.投影查询 // 查询 部分属性(字段) 或 单个对象 通过设置HQL语句中select的内容进行的查询即为投影查询 例如: select um from UserModel um (查询结果为单一项) // 单一 List
模型对象 select userName from UserModel (查询结果为单一项) // 单一 List
仅查询一个属性(只获取userName列数据) select userName,age from UserModel (查询结果为多项) // 多项 List
java学习笔记————SSH
最新推荐文章于 2024-08-15 17:43:43 发布