第一节、MVC以及Struts2简介
第二节、Action生命周期以及接收表单数据
第三节、Struts2配置以及Struts.xml详解
-
Struts2 主要配置文件
Web.xml 设置过滤器以及annotation初始化参数 Struts.xml 主配置文件 Struts.properties 默认属性文件 Struts-default.xml 默认配置文件 Struts-plugin.xml 插件配置文件
-
Struts2 主要配置加载次序
由上至下,以此为: Struts-default.xml Struts-plugin.xml Struts.xml Struts.properties Web.xml 如果在多个文件中配置了同一个Struts2常量,则后一个文件中的配置的常量值将覆盖前面文件中配置的常量值。在不同文件中配置常量的方式是不一样的,但不管哪个文件中,配置Struts2常量都要指定两个属性:常量name和常量value 推荐在struts.xml文件中配置Struts2常量
-
Struts-default.xml 配置信息
Bean元素属性 class:必选,指定了Bean实例的实现类 type:可选,通常是通过某个接口或者在此前定一个过的Bean name:可选,它指定的Bean实例的名字,对于有相同type的多个Bean,name必须唯一 scope:可选,指定Bean的作用域,只能是default、singleton、request、session和thread之一 static:可选,它指定Bean是否使用静态方法注入。通常而言,当指定了type属性时,该属性就不应该设置为true optional:可选,指定Bean是否是一个可选Bean
-
default.properties 默认属性信息
##字符集 struts.i18n.encoding=UTF-8 struts.objectFactory.spring.autoWire = name struts.objectFactory.spring.useClassCache = true struts.objectFactory.spring.autoWire.alwaysRespect = false struts.multipart.parser=jakartastruts.multipart.saveDir=struts.multipart.maxSize=2097152 ##请求后缀 struts.action.extension=action,, struts.serve.static=true struts.serve.static.browserCache=true struts.enable.DynamicMethodInvocation = false struts.enable.SlashesInActionNames = false struts.mapper.action.prefix.enabled = false struts.mapper.action.prefix.crossNamespaces = false struts.tag.altSyntax=true ##开发模式 struts.devMode = false struts.i18n.reload=false struts.ui.theme=xhtmlstruts.ui.templateDir=template struts.ui.theme.expansion.token=~~~struts.ui.templateSuffix=ftl struts.configuration.xml.reload=false struts.velocity.configfile = velocity.properties struts.velocity.contexts = struts.velocity.toolboxlocation= struts.url.http.port = 80struts.url.https.port = 443 struts.url.includeParams = none struts.dispatcher.parametersWorkaround = false struts.freemarker.templatesCache=false struts.freemarker.beanwrapperCache=false struts.freemarker.wrapper.altMap=true struts.freemarker.mru.max.strong.size=0 struts.xslt.nocache=false struts.mapper.alwaysSelectFullNamespace=false struts.ognl.allowStaticMethodAccess=false struts.el.throwExceptionOnFailure=false struts.ognl.logMissingProperties=false struts.ognl.enableExpressionCache=true struts.handle.exception=true
-
Struts.xml 配置信息
<struts> <!--重置属性—> <constant name="struts.devMode" value="true"> </constant> <constant name="struts.i18n.encoding" value="urf-8"></constant> <!--定义包—> <package name="default" namespace="/" extend="struts-default"> <!--动作—> <action name="" class=""> <result name="" class="" ></result> </action> </package> </struts>
Constant 常量 Package 包 解决Action重名,方便继承 -name 包名 -extends 父包名 -namespace 命名空间 Action -name 动作名 -class 实现类 global-results 全局结果 Result 局部结果
第四节、Action 高级
-
method 属性
<action name="admin" class="net.nw.action.AdminAction" method="add"> <result>result.jsp</result> </action>
-
DMI动态方法调用
<action name="admin" class="net.nw.action.AdminAction"> <result>result.jsp</result> </action> <a href="<%=path%>/admin/admin!add.action">添加</a>
-
Forword Action(页面跳转)
-
默认Action
<default-action-ref name="error"></default-action-ref> <action name="error"> <result>error.jsp</result> </action>
-
通配符映射
<action name="Student*" class="net.nw.struts2.action.StudentAction" method="{1}"> <result>/Student{1}_success.jsp</result> </action>
{0} 表示匹配所有内容 {1} 表示前面的第一个*的内容 * 0-N不包括 "/" ** 0-N包括 "/" 转义符
-
Zero Configuration (Annotation配置)
引入struts2-convention-plugin-2.2.1.jar包
//web.xml <filter> …… <init-param> <param-name>actionPackages</param-name> <param-value>net.nw.action</param-value> </init-param> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter>
//注解 @parentPackage(value="struts-default") @Namespace(value="/") @Result(name="login_success",location="/login_success.jsp") @Results({ @Result(name="login_success",location="/login_success.jsp","type="redirect"), @Result(name="login_failure",location="/login_failure.jsp","type="redirect") })
-
包含模块
<include file="admin.xml">
-
出错页面
<action name="**"> <result>error.jsp</result> </action>
第五节、访问Web元素以及Result类型
-
Action访问web对象四种方式:
1.创建request,session,application Map对象
Map request = (Map)ActionContext.getContext().get("request"); Map session = ActionContext.getContext().getsession(); Map application = ActionContext.getContext().getApplication();
2.实现RequestAware,SessionAware,ApplicationAware接口 Map对象(常用)
3.创建传统的HttpServletRequest、HttpSession、ServletContext对象
HttpServletReques request = ServletActionContext.getRequest(); HttpSession session = request.getSession(); ServletContext application = session.getServletContext();
4.实现ServletRequestAware、ServletContextAware接口
-
Result类型
Dispatcher:转发到URL,通常是JSP(服务器) Redirect:重定向到URL,通常是JSP(客户端) Chain:转发到一个Action(服务器) redirectAction:重定向到一个Action(客户端) freemarker:处理FreeMarker模型 Httpheader:控制特殊HTTP行为的结果类型 Stream:向浏览器发送InputSream对象,通常用来处理文件下载,还可用于返回AJAX数据 Velocity:处理Velocity模版 Xslt:处理XML/XLST模版 plainText:显示原始文件内容,例如文件源代码
第六节、Validation框架和i18n
-
Exception异常处理
<global-results> <result name = "error" > /error.jsp</result> </global-results> <global-exception-mappings> <exception-mapping result="error" exception="java.lang.Exception"></exception> </global-exception-mappings>
-
Validation框架
分为validate() / XML / Annotation 三种方式
重写validate() 方法,验证action中所有的方法。 @Override public void validate(){ if(! false){ this.addFieldError("validate_error","验证错误!"); } super.validate(); }
编写ActionName-validation.xml,验证action中所有的方法。 //Login-validation.xml <!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN" "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd"> <validators> <field name="username"> <field-validator type="requiredstring"> <message>用户名不能为空</message> </field-validator> <field-validator type="email"> <message>用户名必须为邮箱格式</message> </field-validator> </field> <field name="password"> <field-validator type="requiredstring"> <message>密码不能为空</message> </field-validator> <field-validator type="stringlength"> <param name="minLength">6</param> <param name="maxLength">20</param> <message>密码长度必须在 ${min} ~ ${max}之间</message> </field-validator> </field> </validators>
validateMethodName(), 验证指定方法 //User.java public void validateLogin(){ if(! false){ this.addFieldError("validate_error","验证错误!"); } }
Struts.xml配置, 验证指定方法 //User.java @Override public void validate(){ if(! false){ this.addFieldError("validate_error","验证错误!"); } super.validate(); } //Struts.xml <action> <interceptor name="defaultStack"> <param name="validation.includeMethods">add</param> </interceptor> </action>
Annotation注解 @Action(interceptorRefs=@InterceptorRef(value="defaultStack",params={"validation.includeMethod},"add")) @SkipValidation (推荐)
出错信息 <s:filederror cssStyle="color:red" />
-
i18n
i18n:Internationalization 国际化
L10n:localization 本地化
创建资源文件(包名_语言_国家.properties) App_en_US.properties App_zn_CN.properties
Struts.xml加载属性文件 <constant name="struts.custom.i18n.resources" value="APP"></constant> //.html <a href="<%=path%>"/language.action?request_local=en_US">英文</a> <s.property value="getText('label.username)" /> //Validation.xml <message> ${getText("login.field.isnull",{getText("label.username")})} </message>
第七节、OGNL(一)
-
OGNL简介
OGNL 是 Object-Graph Navigation Language 的缩写,它是一种功能强大的表达式语言(Expression Language,简称EL),通过它简单一致的表达式语法,可以存储对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。
-
对象导航图
-
方法调用
普通方法
//java public String method(){ return "aaaaa"; } //jsp <s:property value="obj.method()" />
Action普通方法
//jsp <s:property value="method()" />
静态方法
//struts.xml <constant name="struts.ognl.allowStaticMethodAcces" value="true"></constant> //jsp <s:property value="@package.ActionName@method()" />
静态属性(注意,必须是public)
//java public static Int num = 123; //jsp <s:property value="@package.ActionName@num" />
构造方法
<s:property value="new package.construct() " />
系统Math方法
<s:property value="@@random() " />
系统其他类方法
<s:property value="@java.util.Calendar@getInstance() " />
-
集合对象
List(有序,可重复)
Set(无序,不可重复)
Map(键值对)
获取集合长度 list.size();
//java private List<String> aaa = new ArrayList<String>(); private Set<String> bbb = new HashSet<String>(); private Map<Interget,String> ccc= new HashMap<interger String>(); public construct() { aaa.add("aaaaaa"); bbb.add("bbbbbb"); ccc.put("1","ccc"); } //jsp <s:property value="aaa" /> <!---List 集合 -> <s:property value="aaa[0]" /> <!---List 集合对象 -> <s:property value="aaa.{attr}" /> <!---List 集合属性 -> <s:property value="aaa.{attr}.[0]" /> <!---List 集合属性 -> <s:property value="bbb" /> <!---Set 集合 -> <s:property value="bbb[0]" /> <!---Set 集合对象 -> <s:property value="ccc" /> <!---Map 集合 -> <s:property value="ccc[1]" /> <!---Map 集合对象 -> <s:property value="ccc.keys" /> <!---Map 集合中key对象 -> <s:property value="ccc.values" /> <!---Map 集合中values对象 -> <s:property value="ccc.size()" /> <!---Map 集合中的长度 ->
第八节、OGNL(二)
-
投影和选择
#this 当前
? 所有
^ 第一个
$ 最后一个
//java private List<Students> stus = new ArrayList<Students>(); public construct() { stus.add(new Students("张三",18)); stus.add(new Students("李四",28)); stus.add(new Students("王五",38)); } //jsp <s:property value="stus.{?#this.age>=30}.{name}" /> <s:property value="stus.{^#this.age>=30}.{name}" /> <s:property value="stus.{$#this.age>=30}.{name}" />
-
#符号的使用
访问根对象
Struts2 中值栈为根对象,如ODNL上下文和Action上下文,#相当于ActionContext.getContext();
下面是几个ActionContext中有用的属性:
#parameters URL地址参数 #request 请求参数 #session SESSION参数 #application #attr 用于按request > session > application 顺序访问其属性(attribute)
用于选择和投影
构造Map
#{'foo1':'bar1','foo2':'bar2'}
-
$符号的使用
用于在国际化资源文件中,引用OGNL表达式
在Struts 2 配置文件中,引用OGNL表达式(不推荐)
-
值栈
Struts2 为每一次请求生成一个值栈,不同的请求对应不同的值栈
Struts2 接收到一个action请求,首先创建Action类的实例对象,把该对象压进值栈。此时action中的所有属性都是默认值。然后执行定义该action上的所有拦截器,最后执行action动作。
Action构造方法->拦截器->动作方法
注意:拦截器可以改变属性的值,当改变某个属性值后,Action类的相应属性值就会变成在拦截器中最后改变该属性的这个值。
两个action之间采用的是服务器跳转,如果两个action有名字相同的属性,则对后一个属性的修改是否会覆盖前一个action的属性。分以下两种情况:
如果具体相同名字的属性是引用类型,则会覆盖。
如果具体相同名字的属性是基本类型,则不会覆盖。
将对象压入值栈
ActionContext.getContext().getValueStack().push(obj);
访问值栈中的对象
[0].attr //从值栈第一个对象开始寻找 [1].method() //从值栈第二个对象开始寻找 <s:property value="[0]" /> <s:property value="[1]" /> <s:property value="[2]" />
第九节、Interceptor拦截器
-
拦截器原理
拦截器(Interceptor) 是Struts2框架的核心,Struts2中包括解析请求参数、将请求参数赋值给Action属性、执行数据校验、文件上传等工作都是通过拦截器实现的,Struts2设计的灵巧性,更大程度地得益于拦截器设计,当需要扩展Struts2功能时,只需要提供对应拦截器,并将它配置在Struts2容器中即可;如果不需要该功能时,也只需要取消该拦截器的配置即可。
Struts2 内建了大量的拦截器,这些拦截器以name-class对的形式配置在struts-default.xml文件中,其中name是拦截器的名字,就是以后使用该拦截器的唯一标识;class则指定了该拦截器的实现类,如果我们定义的package继承了Struts2的默认struts-default包,则可以自由使用下面定义的拦截器,否则必须自己定义这些拦截器。
-
常见的内置拦截器
chain:服务器内部跳转
execAndWait:等待执行拦截器
fileUpload:文件上传拦截器
timer:统计动作执行时间
token:表单令牌
token-session:表单令牌会话
-
拦截器与过滤器的区别
拦截器拦截的是动作(action),过滤器过滤的是请求(request),过滤器一般映射为 /* ,过滤所有请求。
拦截器是基于java反射机制的,而过滤器是基于函数回调的。
过滤器依赖于servlet容器,而拦截器不依赖于servlet容器。
拦截器可以访问Action上下文、值栈里的对象,而过滤器不能。
在Action的生命周期中,拦截器可以多次调用,而过滤器只能在容器初始化时被调用一次。
自定义拦截器
实现Interceptor接口(不推荐)
继承AbstractInterceptor抽象类,对所有方法进行拦截
//java class demoInterceptor extents AbstractInterceptor{ @Override public String intercept(ActionInvocation invocation) throws Exception{ //拦截之前 String result = invocation.invokde(); //拦截之后 return result; } } //struts.xml <package name="default" namespace="/" extends="struts-default"> <interoeptors> <interceptor name="demoInterceptor" class="package.demoInterceptor" /> <intorceptor-stack name="mydefaultStack"> <interceptor-rel name="demoInterceptor" ></interceptor-rel> <interceptor-rel name="defaultStack" ></interceptor-rel> </intorceptor-stack> </interoeptors> </package> <package name="user" namespace="/user" extends="default"> <action name="login" class="package.UserAction"> <interceptor-rel name="mydefaultStack" ></interceptor-rel> </action> </package>
MethodFilterInterceptor,对指定方法进行拦截
//java class demoInterceptor extents MethodFilterInterceptor{ @Override public String doIntercept(ActionInvocation invocation) throws Exception{ //拦截之前 String result = invocation.invokde(); //拦截之后 return result; } } //struts.xml <package name="default" namespace="/" extends="struts-default"> <interoeptors> <interceptor name="demoInterceptor" class="package.demoInterceptor" /> <intorceptor-stack name="mydefaultStack"> <interceptor-rel name="demoInterceptor" > <param name="excludeMethods">excludeFun</param> </interceptor-rel> <interceptor-rel name="defaultStack" ></interceptor-rel> </intorceptor-stack> </interoeptors> </package> <!--另一种方式--> <package name="user" namespace="/user" extends="default"> <action name="login" class="package.UserAction"> <interceptor-rel name="mydefaultStack" > <param name="demoInterceptor.excludeMethods">excludeFun</param> <param name="demoInterceptor.includeMethods">includeFun</param> </interceptor-rel> </action> </package>
PreResultListener 监听器 在返回结果集之前执行的方法
//java class BeforeResultInterceptor extents PreResultListener{ public void beforeResult(ActionInvocation invocation,String str){ //返回结果集之前执行 } } class demoInterceptor extents MethodFilterInterceptor{ @Override public String doIntercept(ActionInvocation invocation) throws Exception{ invocation.addPreResultListener(new BeforeResultInterceptor()); //拦截之前 String result = invocation.invokde(); //拦截之后 return result; } }
使用拦截器解决表单重复提交
//struts.xml <interceptor-ref name="token"> <!-- 显示重复提交出错页面--> </interceptor-ref> <interceptor-ref name="tokenSession"> <!-- 显示重复提交成功页面,但不执行重复提交动作--> </interceptor-ref> <result name="invalid.token">/tokenerror.jsp</result> //jsp <s:token></s:token>