struts2(2)
整理了从开始学习Java以来在纸质本上做的一些笔记,如有错误,恳请批评指正。
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的核心流程图(关键):
OGNL表达式:
参考:
el表达式跟ognl表达式的区别:http://www.cnblogs.com/ycxyyzw/p/3493513.html
Struts2学习笔记:http://www.cnblogs.com/Cratical/archive/2012/09/09/2677909.html
结论:
1)从OgnlContext对象的根对象取出数据,不需要#号
2)从OgnlContext对象的非根对象取出数据,需要#号
Ognl表达式核心—>OgnlContext对象(Map结构)
存数据:*OgnlContext context = new OgnlContext();
1. 往OgnlContext的非根对象存数据: context.put("key",value);
2. 往OgnlContext的根对象存储数据:context.setRoot(对象);
取数据:
1. 非根数据,取出用#加key。因为非根数据是map结构存储。
2. 根对象数据,不需#,不需要key,直接写存入对象的属性名即可。
struts2的值栈(ValueStack对象)利用了(OgnlContext对象)
ValueStack接口:实现类对象OgnlValueStack
创建action对象会同时创建值栈对象。
ValueStack的数据存储结构:List栈(根数据)、Map栈(非根)
1. List栈主要存储action对象和provider对象。
2. Map栈主要存放各个域存放的数据和用户的参数信息。
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>
因为值栈对象是通过request域传递到页面的,所以可以忽略#request直接从request域中取值。
思考:放在request中的值栈可以存储session和context域数据,显然request的作用域没这么大,威慑呢么?
值栈中的是引用,其生命周期贯穿Action对象始终。
当struts2接受到一个访问时,迅速创建ActionContext、ValueStack、和Action对象。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。
“#号的作用:除了用于查询非根数据外,还可以在JSP页面中构建Map集合。
%的作用:用于通知执行环境%{}里面的是OGNL表达式。为确保安全可在任何地方都使用%{}。
更多的使用参考:
Struts标签、Ognl表达式、el表达式、jstl标签库这四者之间的关系和各自作用:http://blog.youkuaiyun.com/love_you_99/article/details/8184797
OGNL表达式原理:http://developer.51cto.com/art/201203/322509.htm
2 数据验证
2.1 用代码方式对action的所有方法进行验证
struts2的数据验证的核心拦截器:
<interceptor name="validation" class="com.opensymphony.xwork2.validator.ValidationInterceptor"/>
开发步骤:
1)Action类继承ActionSupport(为了实现Valiateable接口)
2)Action类覆盖validate方法(验证所有方法)
3)在struts.xml文件中对应的action配置加上input视图,然后struts2就会自动把错误信息转发到input视图的页面上去
4)在input视图页面上,打印出错误信息
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", "密码不能为空!");
}
}
<s:fielderror></s:fielderror>
打印错信息
注意:
validate()方法对当前Action下的所有方法都会有效!!!!
2.2 用代码方式对action的指定方法进行验证
指定方法验证:
第二步骤的验证方法名称为 validate+需要验证的方法名称
例如: validateRegister() -> 可以验证register()方法
2.3 用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-validator type="email"/>
<field-validator type="regex"/>
</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;
}
}
注意:
1. 存放数据的模型引用不能为空,即必须new。
2. setter和getter不能少。
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 常用的逻辑标签
<body>
<s:set var="变量名" scope="放置的范围,接受application,session,page,action" value="值"></s:set>
<s:bean name="JavaBean全名" var="被赋值的对象名,不设置则放置在栈顶"></s:bean>
<!-- 逻辑标签 -->
迭代:<s:iterator value="ognl表达式"></s:iterator>
赋值:<s:set var="" value=""></s:set>
获取:<s:property value="ognl表达式"/>
判断:<s:if test=""></s:if>
<!-- UI标签 -->
<!-- 优点
1. 节省html代码
2. 数据回显功能!!!!!!!
-->
<s:form></s:form>
<s:text name=""></s:text>
<s:textfield></s:textfield>
<s:password></s:password>
<s:checkboxlist list=""></s:checkboxlist>
<s:radio list=""></s:radio>
<s:select list=""></s:select>
</body>
4.3 表单数据回显
struts2标签自带回显功能
4.4 放在页面的重复提交
默认情况下,struts2不支持防止重复提交的
1)需要在struts.xml文件中打开功能:
<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>
标记此页面不可重复提交。