1. struts2项目的基本结构:
(1)首先在web.xml中配置一个过滤器,struts2处理请求的核心,有多个过滤器时,struts2的过滤器要配在最后。
<filter>
<filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
(2)在classPath下建一个文件struts.xml,不用再web.xml中配置struts.xml的位置,再要放在calsspath下并叫struts.xml就行,struts2的过滤器就会自动读取到。Struts配置有包的概念,包还可以继承,每个包还可以配置一个nameSpace,访问这个包下的action时,URL要加上这个包的nameSpace。
<?xml version="1.0"encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTDStruts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<constantname="struts.enable.DynamicMethodInvocation" value="false"/>
<constantname="struts.devMode" value="false" />
<includefile="example.xml"/>
<package name="default"namespace="/" extends="struts-default">
<default-action-refname="index" />
<action name="index">
<result type="redirectAction">
<paramname="actionName">HelloWorld</param>
<paramname="namespace">/example</param>
</result>
</action>
</package>
</struts>
2. struts2处理请求的过程:
客户端发送请求,无论什么请求都会被struts2的过滤器拦截住,然后这个拦截器根据请求的URL和Struts.xml中的配置找到相应的Action,把请求传到相应的Action。
3. struts2 就是把请求和展示分开了。
4. Struts2的Action类,可以是普通的java类,也可以是实现了Action接口的类,也可以是继承自ActionSupport类的类(最好的方式),请求访问Action类时默认会执行Action类的excute()方法,可以在访问时加方法名来说明访问Action的哪个方法,如:/XXXAction!XXXMethod。也可以在Struts.xml时直接配置到方法。
5. Struts2每次请求都会新建一个Action的对象,所以不会有线程安全问题。Struts1一个Action就一个对象,线程不安全。
6. Struts标签中有一个很有用的标签是<s:debug></s:debug>,在页面上会展示一个Debug信息,包括两部分,一个值栈(value stack),一个stack context,如图:
7. 如何在Action中获取Web元素:request(HttpServletRequest),session(HttpSession),application(ServletContext)
(1) 方式一:用ActionContext类的静态方法:
private Map request;
private Map session;
private Map application;
public String add(){
request = (Map)ActionContext.getContext().get("request");
session = ActionContext.getContext().getSession();
application = ActionContext.getContext().getApplication();
return"success";
}
注意:
a)ActionContext.getContext()返回一个ActinContext对象,其实就是<s:debug></s:debug>标签中第二部分(stack context)的一个分装对象。
b)这种方式得到的是Map类型的request,session,applicatiob,不是真正的HttpServletRequest,HttpSession,servlcetContext对象,那在页面上能直接使用request,session,application对象吗,答案是能的,所以Struts2在内部实现了这三个Map和真正的request,seesion.application对象的关联,用的时候不用考虑不同。
c)<s:debug>中有两部分,第一部分值栈(value stack),在页面访问时直接用key访问就行,而第二部分Stack context也就是ActionContext的值,要用#+key来访问,<s:property value="name"/>,<s:propertyvalue="#request.r1"/>
(2)方式二(常用方式):Action类事项三个接口RequestAware,SessionAware,ApplicationAware
这种方式要Action类实现三个接口,并在Action中定义三个Map,并要有三个set方法,如下:
private Map request;
private Map session;
private Map application;
@Override
publicvoid setApplication(Map<String, Object> arg0) {
application=arg0;
}
@Override
publicvoid setSession(Map<String, Object> arg0) {
session=arg0;
}
@Override
publicvoid setRequest(Map<String, Object> arg0) {
request=arg0;
}
(3)方式3:用ServletActionContext取,前两种取到的都是Map类型的request,session,application, 这种方式取到的是真正的request,session,application,如下:
private HttpServletRequest request;
private HttpSession session;
private ServletContext application;
public String add(){
request = ServletActionContext.getRequest();
session = request.getSession();
application = session.getServletContext();
return"success";
}
(4)方式4:实现servletRequestAware
该方式和方式二类似,要实现一个接口,并定义一个HttpRequest属性,并有一个set方法。
总结:去web元素,本身很少,因为Action的属性基本完成了Request的功能,但有时要取得Session对象等情况,所以有需要获取web对象。方式一和二是取得Map类型的request,session,application,方式一是用ActionContext的静态方法,方式二是用实现接口的方式。方式三和四取得的是真正的request,session,application, 方式三是用ServletActionContext的静态方法,方式四是用实现接口的方式。
8. OGNL表达式能访问对象的属性,方法都可以,EL表达式只能访问属性。
9. 用OGNL表达式时要配合Struts的标签使用。不能再EL表达式中用。
10. Struts2的标签中的value值,默认被当做OGNL表达式来解析,要在加个‘’才会被当做字符串来解析。例:(1)<s:property value="name"/>,name当做OGNL表达式解析 (2)<s:property value="’name’"/>,’name’被当做字符串,标签展示的就是这个字符串了。
11. Struts2的异常处理:
(1)有异常只管往上抛,最终会被struts2处理。只要在配置Action时加下面的配置:
<action name="add" class="com.zhengjie.MyAction1">
<result>/index.jsp</result>
<exception-mapping result="error" exception="java.sql.SQLException"></exception-mapping>
<result name="error">/error.jsp</result>
</action>
配一个<exception-mapping>告诉struts2出相应错误时跳转到相关结果页面,并配一个结果<result>,只是配给某一个Action的异常处理。
(2)在(1)中异常处理只能每个Action都配置,很麻烦。所以写一个总的Package,让所有的package都继承总的package,总的package一定要继承自struts2的struts-default package,因为里面有一些struts2的一些默认的拦截器等,是struts2一些功能的前提,然后再总的package中定义一个<global-exception-mappings>和<global-results>:
<package name="base" namespace="/"extends="struts-default">
<global-results>
<result name="error">/error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="error" exception="java.sql.SQLException"></exception-mapping>
</global-exception-mappings>
</package>
注意:<global-results>一定要配在<global-exception-mappings>上面。
Struts2的异常处理机制,实际是通过拦截器实现的,这也是为什么自己定义的package一定要直接或间接继承struts默认的package:struts-default,struts-default里面有好多struts2默认的一些拦截器和其他东西。
12. struts2的拦截器和java EE规范的filter类似,只是filter是对请求的过滤(来回都过滤),而struts2的拦截器是在struts2的StrutsPrepareAndExecuteFilter在请求Action时拦截(来回都拦截)。拦截器就是在整个web项目的filter中,一个特殊filter(struts2的filiter)中的一个小范围的过滤器,只不过struts2称他为拦截器。
13. 自己写拦截器时,就是写一个类要实现Interceptor接口,写好类后还要配置,自定义的拦截器可以配置在摸个Action上如下:
<package name="default"namespace="/" extends="struts-default">
<interceptors>
<interceptor name="myInterceptor" class="xxx.xxx.xxx"></interceptor>
</interceptors>
<action name="add" class="com.zhengjie.MyAction1">
<result name="success">/index.jsp</result>
<interceptor-ref name="myInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
</package>
注意:给Action配置自定义的拦截器时,一定要配上struts2默认的拦截器,因为如果你配了拦截器后,默认的不配的话就是失效了。