简介

以后如果没有特殊的要说,就在简介中介绍一下大概的知识点。今天主要学习封装请求参数及类型转换、用户输入校验、国际化、拦截器

 

Struts2封装请求参数的方式

方式一:
	Action 本身作为model对象,通过成员setter封装(一个名字为params的拦截器实现的)
	产生疑问:使用第一种数据封装方式,数据封装到Action属性中,不可能将Action对象传递给 业务层 
  * 需要再定义单独JavaBean ,将Action属性封装到 JavaBean,得出第二种方式
方式二:
	动作类和模型分开,在Action中创建Model对象,页面通过ognl表达式封装 (属性驱动)
方式三:
	模型驱动
	模型驱动实际上是由一个拦截器来做的。modelDriven拦截器来做。把getModel方法返回的对象,压入一个叫做ValueStack的栈顶。struts框架就会根据表单的name属性,调用对应栈顶对象的setter方法,从而把请求参数封装进来

封装复杂类型参数(集合类型 Collection 、 Map)

1. 封装数据到Collection 对象
页面:
	产品名称 <input type="text" name="products[0].name" /><br/>--->注意这里的名字要和Action中的一致
Action :
	public class ProductAction extends ActionSupport {
		private List<Product> products;
		
		public List<Product> getProducts() {
			return products;
		}

		public void setProducts(List<Product> products) {
			this.products = products;
		}
	}
2. 封装数据到Map 对象 
页面:
	产品名称 <input type="text" name="map['one'].name" /><br/>  =======  one是map的键值
Action :
	public class ProductAction2 extends ActionSupport {
		private Map<String, Product> map;

		public Map<String, Product> getMap() {
			return map;
		}

		public void setMap(Map<String, Product> map) {
			this.map = map;
		}
	}

 

封装参数--类型转换

1. 显示或者是数据回显:其他类型----->String
基本类型自动转换
	boolean 和 Boolean
	char和 Character
	int 和 Integer
	long 和 Long
	float 和 Float
	double 和 Double
	java.util.Date<-------->String(中国:Struts2默认按照yyyy-MM-dd本地格式进行自动转换)
# 数组  可以将多个同名参数,转换到数组中
# 集合  支持将数据保存到 List 或者 Map 集合

总结:在使用Struts2时,基本上不用写任何类型转换器。内置的完全够用

2. 自定义类型转换器
	a). 实现方式
	第一种 实现TypeConverter接口
	第二种 继承 DefaultTypeConverter
	第三种 继承 StrutsTypeConverter
	
	b). 类型转换器 一直都是双向转换 
		页面提交请求参数,封装到model --- 需要转换
		model数据 需要在页面 回显  ---- 需要转换
	c). 注册类型转换器 
		局部注册 : 只对当前Action有效 (针对属性) 
		全局注册 : 针对所有Action的日期类型有效 (针对类型 )
	
	局部注册 : 在Action类所在包 创建 Action类名-conversion.properties , 格式 : 属性名称=类型转换器的全类名 
	全局注册 : 在src下创建 xwork-conversion.properties ,格式 : 待转换的类型=类型转换器的全类名
	
3. 转换失败时的页面转向和错误消息提示
	a、配置一个name=”input”的结果视图,一般指向用户输入数据的那个页面
	b、在jsp中使用struts2的标签显示字段有关的错误
		<%@ taglib uri="/struts-tags" prefix="s"%>
		<s:fielderror/>
	c、配置提示信息为中文的,在动作类所在的包中,建立一个名称为:动作类名.properties的配置文件

 

用户输入数据的校验

1. 校验方式:
	a:客户端校验。(防君子不防小人)在页面中写js脚本。
	输入错误的话提醒比较及时
	减轻服务器的压力
	b、服务器端校验
	数据安全
	***开发中使用:a+b
	
2. 服务器端校验
	# 编程式校验(代码校验):自己编写一个校验代码(缺点:验证规则都写在了代码中)
		a). 覆盖validate方法,完成对Action的业务方法 数据校验,在jsp中 通过 <s:fieldError/> 显示错误信息 
			通过代码逻辑判断参数是否有效,如果参数非法 , this.addFieldError (ActionSupport提供)
			workflow拦截器 跳转回 input页面
		b). 针对指定的动作进行校验
			方式一:写了一个validate方法,可以在不需要验证的动作方法前,使用@SkipValidation带有此注解的表示会被忽略验证
			方式二:validate方法有一定的书写规范。public void validate动作方法名(首字母大写)
		总结:所有验证不通过或转换不同的过的,框架都会转向name=”input”的结果视图。要显示错误提示,使用<s:fieldError/>,显示字段有关的错误提示
		
	# 声明式校验:通过xml配置文件
		a). 针对动作类中的所有动作进行校验
			在动作类所在的包中,建立一个名称为:”动作类名-validation.xml”配置文件
			**引入DTD--xwork-core-2.3.7.jar 中 /com/opensymphony/xwork2/validator/validators/default.xml
		b). 针对指定的动作进行校验
			方式一:使用@SkipValidation
			方式二:声明文件遵循一定的书写规范:
				动作类名-动作名(struts.xml配置文件中的)-validation.xml
		c). struts2框架内置的声明式类型验证器
			* 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指定最大值)
			
3. 自定义声明式校验
	a). 编写一个类:实现Validator接口或者继承ValidatorSupport。如果是验证表单字段有关,建议继承FieldValidatorSuppor
	b). 要注册校验器,在WEB-INF\classes目录下,建立一个固定名称为validators.xml的配置文件
	c). 使用校验器在Action所在包 创建Action类名-validation.xml
	**** 实际开发中很少用到自定义校验器 

 

Struts2的国际化

1. 配置全局国际化消息资源包
	在struts.xml中
		添加<constant name="struts.custom.i18n.resources" value="messages"></constant>   messages.properties 在src根目录
		<constant name="struts.custom.i18n.resources" value="cn.itcast.resources.messages"></constant>   messages.properties 在 cn.itcast.resources 包中
	在Action动作类中:
		前提,动作类继承ActionSuppor/this.getText("msg"); 
	在jsp中使用  :<s:text name="msg" />
	在配置文件中(校验xml) : <message key="agemsg"></message>
	
2. 配置局部消息资源包
	数据只能在对应Action中使用,在Action类所在包 创建 Action类名.properties  --------- 无需配置
	局部的比全局的优先级高

3. 包范围的消息资源包
	数据对包 (包括子包)中的所有Action 都有效 , 在包中创建 package.properties ----- 无需配置 
	书写有规范的,名称为package_zh_CN.properties,放在类的包中。可以被包中及子包的所有动作类来访问
4. 临时信息文件 (主要在jsp中 引入国际化信息 )
	在jsp指定读取 哪个properties文件 
	<s:i18n name="cn.itcast.struts2.demo7.package">
		<s:text name="customer"></s:text>
	</s:i18n>
	向信息中传递参数  {0} {1} ------------ MessageFormat 动态消息文本 
	this.getText("required", new String[] { "用户名" });

 

struts2中的拦截器(框架功能核心)

拦截器 的使用 ,源自Spring AOP(面向切面编程)思想 
	拦截器 采用 责任链 模式 
	*  在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链。
	*  责任链每一个节点,都可以继续调用下一个节点,也可以阻止流程继续执行 
		
在struts2 中可以定义很多个拦截器,将多个拦截器按照特定顺序 组成拦截器栈 (顺序调用 栈中的每一个拦截器 )

1、 struts2 所有拦截器 都必须实现 Interceptor 接口 
2、 AbstractInterceptor 类实现了 Interceptor 接口. 并为 init, destroy 提供了一个空白的实现

所有实际开发中,自定义拦截器 只需要 继承 AbstractInterceptor类, 提供 intercept 方法实现 

3、 常用struts2 拦截器
	<interceptor-ref name="modelDriven"/> 模型驱动
	<interceptor-ref name="fileUpload"/> 文件上传
	<interceptor-ref name="params"> 参数解析封装 
	<interceptor-ref name="conversionError"/> 类型转换错误
	<interceptor-ref name="validation"> 请求参数校验
	<interceptor-ref name="workflow"> 拦截跳转 input 视图

综合案例

案例 : 登陆,对其它Action访问  通过自定义拦截器 进行权限控制 
	导入jar包 (struts2 jar、c3p0、 dbutils、 mysql驱动)
	web.xml 
	struts.xml
	JDBCUtils 工具类

第一步 : 编写index.jsp 提供 图书增删改查 四个功能 
   编写BookAction ,提供四个业务方法 
   
第二步: 完成登陆功能    

第三步 :必须要登陆 才能进行图书管理 
	使用Filter 进行权限控制 ---- 过滤所有web请求 (所有web资源访问)
	使用拦截器 进行权限控制 ---- 主要拦截对Action访问  (不能拦截JSP)

定义拦截器 继承AbstractInterceptor 

配置拦截器 
	方式一
		<!-- 注册拦截器 -->
		<interceptors>
			<interceptor name="privilege" class="cn.itcast.interceptor.PrivilegeInterceptor"></interceptor>
		</interceptors>
		<action name="book_*" class="cn.itcast.action.BookAction" method="{1}" >
			<!-- 使用拦截器 -->
			<!-- 当使用自定义拦截器 后,默认拦截器 就会失效  -->
			<interceptor-ref name="defaultStack"></interceptor-ref>
			<interceptor-ref name="privilege"></interceptor-ref>
		</action>
	方式二
		<!-- 注册拦截器 -->
		<interceptors>
			<interceptor name="privilege" class="cn.itcast.interceptor.PrivilegeInterceptor"></interceptor>
			<!-- 自定义拦截器栈 -->
			<interceptor-stack name="privilegeStack">
				<interceptor-ref name="defaultStack"></interceptor-ref>
				<interceptor-ref name="privilege"></interceptor-ref>
			</interceptor-stack>
		</interceptors>
		
		<!-- 设置当前包 所有Action 都使用 自定义拦截器栈 -->
		<default-interceptor-ref name="privilegeStack"></default-interceptor-ref>