拦截器的意义:
1、如果有一个比较复杂的逻辑,在没有拦截器的情况下,会把这些需求全部写在action的方法中
这样会导致方法的结构不好
2、会把一些重用性的内容写在拦截器中
3、要把这些重用性比较高的代码以很好的组织形式结合起来,一个拦截器是不够的,所以需要
拦截器栈
4、怎么样写一个拦截器
1、声明一个拦截器
<interceptors>
声明了一个拦截器
<interceptor name="imageInterceptor"class="cn.itheima03.struts2.interceptor.MyInterceptor"></interceptor>
声明了一个拦截器栈:可以放很多个拦截器
<interceptor-stack name="myInterceptor">
<interceptor-refname="imageInterceptor"></interceptor-ref>
为struts2默认执行的拦截器
interceptor-ref即能指向拦截器,也能指向拦截器栈
<interceptor-refname="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
2、使用拦截器
<default-interceptor-refname="myInterceptor"></default-interceptor-ref>
这样就可以覆盖struts-default.xml文件的内容了
3、写的拦截器类必须实现Interceptor接口
intercept(){
return invocation.invoke();//往下继续执行
}
说明:
从配置文件中可以看出,拦截器的声明只能放在包下,所以配置文件中的package可以选择性的使用拦截器(可以通过继承来实现)
把拦截器作为全局的(脱离package)内容,是不合适的,这样不能使package对拦截器有比较灵活的选择机制
拦截器的配置
1、interceptor只能配置在package中,所以不能配置全局的拦截器
2、struts2中关于interceptor有两个概念:interceptor,interceptors
这两个内容的声明都放在interceptors标签中
<interceptors>
//声明一个interceptor
<interceptor name="imageInterceptor" class="cn.itheima03.struts2.interceptor.MyInterceptor"></interceptor>
//声明一个interceptor stack
<interceptor-stack name="myInterceptor">
//自定义的interceptor
<interceptor-ref name="imageInterceptor"></interceptor-ref>
//struts2默认的执行的interceptor stack
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
//引用myInterceptor的interceptor stack
<default-interceptor-ref name="myInterceptor"></default-interceptor-ref>
3、从上述的配置可以说明:
1、在struts2内部有默认的执行的interceptor stack
<default-interceptor-ref name="defaultStack"/>
如果一个interceptor不在这个interceptor stack中,那么将不执行该interceptor
2、可以把默认的interceptor stack变成自己的interceptor stack
3、在interceptor stack中可以指向(ref)一个interceptor,也可以指向(ref)一个interceptor stack
4、如果一个package要用到另外一个package中的interceptor,只需要通过package的继承机制就可以了
在struts2中,如何获取表单元素的内容:
1、属性驱动
1、概念
可以利用属性驱动获取页面表单元素的内容
2、步骤
1、在action中声明属性,属性的名称和页面元素中name属性的值保持一致
2、action中的属性必须有set和get方法
4、模型驱动
1、如果页面上元素内容太多,用属性驱动实现,action中代码就会很庞大,这个时候可以考虑用模型驱动来实现
2、步骤
a、一个action必须实现一个接口ModelDriver<获取数据的bean>
b、该action中必须有一个方法getModel
c、bean中的属性和页面上name属性的值对应
d、在action中创建一个对象,用于getModel方法的返回值
public class UserAction implements ModelDriver<User>{
private User model = new User();
public User getModel(){
return this.model;
}
}
2、模型驱动
1、一个action必须实现一个接口ModelDriver<获取数据的bean>
2、该action中必须有一个方法getModel
3、在action中创建一个对象,用于getModel方法的返回值
4 、 bean 中的属性和页面上 name 属性的值对应
login.jsp
用户名:<inputtype="text" name="username">
密码 :<input type="password"name="password">
(模型驱动)
ModelDriverInterceptor{
interceptor(){
Object action= invocation.getAction();
if (actioninstanceof ModelDriven) {//该类必须实现ModelDriven
ModelDriven modelDriven = (ModelDriven) action;
ValueStackstack = invocation.getStack();
Objectmodel = modelDriven.getModel();
stack.push(model);//把模型驱动的对象放入到栈顶
}
}
(属性驱动)
ParametersInterceptor:
1、把页面上表单的元素获取,封装成了一个TreeMap
2、遍历TreeMap
for(Entry<String,Object[]> entry:treeMap){
valueStack.setValue(entry.getKey(),entry.getValue()[0]);
}
说明:
1、在执行该拦截器的时候,action已经在栈顶了,那么action的属性在对象栈中
2 、通过 valueStack.setValue 的方法可以改变对象栈的属性的值
LoginAction{
private Stringusername;
private Stringpassword;
//set和get方法
public String login(){
在执行该方法的时候,username和password已经有值了
}
用模型驱动 把对象放到栈顶 属性驱动利用valueStack.setValue()放法对属性进去赋值。从而得到表单内容。
在拦截器 启动过程中 模型驱动要在属性驱动前面 不能打乱顺序
struts2的校验机制
struts2提供了两种校验机制
代码校验
步骤:
1、在页面上
<s:textfield name="username" label="用户名"></s:textfield>
<s:textfield name="password" label="密码"></s:textfield>
<s:fielderror fieldName="username"></s:fielderror>
说明:
<s:fielderror fieldName="username"></s:fielderror>
在这里fileldName="username"会把后台username的报错信息显示到前台
<s:fielderror></s:fielderror>
把所有的字段的错误信息显示到前台的页面中
2、在action中(action必须继承ActionSupport类,该类实现了Validateable接口),可以有两种写法
1、重写validate方法就可以了
public void validate() {
/**
* 验证用户名和密码是否为空
*/
if("".equals(this.getUsername())){
this.addFieldError("username", "用户名不能为空");
}
if("".equals(this.getPassword())){
this.addFieldError("password", "密码不能为空");
}
}
2、如果action中的几个方法都需要校验,在action中必须写这样的方法
例如:对如下方法进行校验
public String testValidate(){
}
那么校验方法为:(validate+被校验的方法名称(方法的第一个字母大写))
public void validateTestValidate(){
//校验逻辑
}
说明:
this.addFieldError("username", "用户名不能为空");该方法中username和页面上的fieldName字段对应,而value的值就是报错信息
3、在struts2的配置文件中
如果校验没有通过,则指向input所指向的页面
<result name="input">validate/validate.jsp</result>
而在这个页面中,<s:fielderror fieldName="username"></s:fielderror>该标签将显示
this.addFieldError("username", "用户名不能为空");的错误信息
xml校验
步骤
1、在页面上
<s:textfield name="username" label="用户名"></s:textfield>
<s:textfield name="password" label="密码"></s:textfield>
<s:fielderror fieldName="username"></s:fielderror>
说明:
<s:fielderror fieldName="username"></s:fielderror>
在这里fileldName="username"会把后台username的报错信息显示到前台
<s:fielderror></s:fielderror>
把所有的字段的错误信息显示到前台的页面中
2、编写xml文件
xml文件的名称的命名规则为:
<ActionClassName>-<aliasName_methodName>-validation.xml
其中alias为配置文件中action元素name属性的值
例如:
1、在com.itheima.struts2.validate.action包中写了一个类ValidateAction
2、在配置文件中作为如下的配置
<action name="validateAction_*" method="{1}" class="cn.itheima03.struts2.validate.action.ValidateAction">
<result name="success">validate/success.jsp</result>
<result name="input">validate/validate.jsp</result>
</action>
3、在该类的相同路径下,写一个xml文件
ValidateAction-validateAction_testXMLValidate-validation.xml
该xml文件和类在同一个路径下
4、在该xml文件中,就可以进行属性的校验了
<validators>
//要验证的属性,和页面上name的属性的值对应
<field name="username">
//type为校验器,是struts2内置的
<field-validator type="requiredstring">
<param name="trim">true</param>
//如果验证不成功,则输出的内容
<message><![CDATA[用户名不能为空]]></message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message><![CDATA[密码不能为空]]></message>
</field-validator>
//正则表达式验证
<field-validator type="regex">
<param name="trim">true</param>
<param name="expression"><![CDATA[^[a-zA-Z0-9]{6,12}$]]></param>
<message><![CDATA[密码长度应该在6到12之间]]></message>
</field-validator>
</field>
</validators>
3、在struts2的配置文件中
input所指向的页面就是验证不成功,输出的验证信息的页面
<result name="input">validate/validate.jsp</result>