六个基本包
struts2-core-2.1.6.jar :开发的核心类库
freemarker-2.3.13.jar :struts2的UI标签的模板使用freemarker编写
commons-logging-1.0.4.jar :日志包
ognl-2.6.11.jar :对象图导航语言,通过它来读写对象属性
xwork-2.1.2.jar :xwork类库,struts2在其上进行构建
commons-fileupload-1.2.1.jar:文件上传组件,2.1.6版本后必须加入此jar包
web.xml文件
主要完成对StrutsPrepareAndExecuteFilter的配置(在以前的版本中是对FilterDispatcher配置,新版本同样支持用FilterDispatcher配置),它的实质是一个过滤器,它负责初始化整个Struts框架并且处理所有的请求。这个过滤器可以包括一些初始化参数,有的参数指定了要加载哪些额外的xml配置文件,还有的会影响struts框架的行为。除了trutsPrepareAndExecuteFilter外,Struts还提供了一个ActionContexCleanUp类,它的主要任务是当有其它一些过滤器要访问一个初始化好了的struts框架的时候,负责处理一些特殊的清除任务。
<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>
struts.xml文件
框架的核心配置文件就是这个默认的struts.xml文件,在这个默认的配置文件里面我们可以根据需要再包括其它一些配置文件。在通常的应用开发中,我们可能想为每个不同的模块单独配置一个struts.xml文件,这样也利于管理和维护。这也是我们要配置的主要文件。
struts-default.xml
此文件是struts2框架默认加载的配置文件,它定义了struts2一些核心bean和拦截器,它会自动包含(included)到struts.xml文件中(实质是通过<package extends="struts-default">),并为我们提供了一些标准的配置。我们可以在struts2-core.jar中找到这个文件。
开启struts2自带的开发模式常量
在以前的开发中,当修改一些配置时总是不能及时地更新到服务器,我们总会重新部署或重启来更新改变的内容,在struts2中可以通过一个常量来达到此目的。即在struts.xml中的<struts>元素下增加如下内容:
<constant name="struts.configuration.xml.reload" value="true" /> 这样配置后,当配置文件修改保存时就会及时更新到服务器中。其它一些常量:
<!-- 指定WEB应用的编码集,相当于调用HttpServletRequest.setCharacterEncodint方法,如果使用了velocity或freemarker,它也用于指定输出的编码格式 -->
<constant name="struts.i18n.encoding" value="UTF-8" />
<!-- 指定请求后缀为.action,指定多个请求后缀用逗号分隔 -->
<constant name="struts.action.extension" value="action" />
<!--设置浏览器是否缓存静态内容,建议:开发阶段关闭,运行时开启 -->
<constant name="struts.serve.static.browserCache" value="false" />
<!--当struts.xml配置文件修改后,系统是否重新加载该文件,开发阶段打开此功能 -->
<constant name="struts.configuration.xml.reload" value="true" />
<!-- 开发提示:出错时打印更详细的信息-->
<constant name="struts.devMode" value="true" />
<!-- 指定请求的后缀可以是.do或.action -->
<constant name="struts.action.extension" value="do,action" />
注意:在struts2.1.6版本中存在一个bug:即配置了struts.i18n.encoding常量也不能解决中文乱码问题,原因是此版本在获取请求参数后才调用了setCharacterEncoding()方法进行编码设置。解决此bug的方法是配置一个filter,并在doFilter方法中增加如下代码:request.setCharacterEncoa2.1.8版本中解决了此问题及2.1.6中存在的其它bug,建议新项目使用2.1.8版本
为什么要使用struts2代替struts1.x
(1)struts2的execute方法中的参数不会依赖于servletAPI,实现了也servlet解耦,是一种无侵入式的设计。
(2)struts2提供了拦截器,利用拦截器可以进行AOP编程,实现权限拦截等功能。
(3)struts2提供了类型转换器,我们可以很容易地对请求参数转换成需要的类型。
(4)提供了同种表现层技术支持,如JSP、freeMarker、velocity等
(5)可以对指定的方法进行校验,可以轻松地实现表单校验功能
(6)提供了全局范围、包范围和action范围的国际化资源文件管理实现。
namespace默认值“”,即不配置namespace属性。它的意思是:如果action不能进行完整路径匹配,则会来此namespace下进行匹配,比如:.../test/test/test.action,如果参照namespace及action的name不能找到也之完全对应的action,它会再到依次追溯到上级目录中查找,即是说它会以„/test/test.action这样的路径来对应namespace和action的name进行查找。如果返回到最终的目录仍找不到,它就会到namespace="/"对应的包下查找名为test的action,如果仍找不到,它就会去默认的namespace下查找名为test的action,如果找到则执行此action。另外,namespace也可以配置成namespace="/"。它代表配置为项目的根。 总结action的名称探索顺序:完全对应、逐步追溯到上级目录查找、"/"下查找、默认namespace下查找。
为什么要提出namespace,主要是避免多人共同开发项目出现名字冲突。如果不使用namespace,多个人所写的action中可能出现重名的现象,这样当项目合并时就会出现冲突。而有了namespace可以在项目开发时由项目经理给每一个人分不同的namespace,这样每个开发人员只需要保证自己所写的action不同名即可。
namespace引发的链接问题:
当我们为action配置了namespace时,访问此action的形式总会是如下形式:.../webappname/xxx/yyy/ActionName.action 而当此action成功执行跳转到某个jsp页面时,如想在此jsp页面写链接,一定要写绝对路径,因为相对路径是相对.../webappname/xxx/yyy/,而如果以后我们修改了action的namespace时,相对路径又要变,所以链接不能写成相对路径。 以下介绍绝对路径的写法:通常用myeclipse开发时建立一个jsp文件,默认总会有如下内容:
<% String path = request.getContextPath(); String basePath =
request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %>
我们写绝对路径可以参此内容。还可以参<head>下的<base href="<%=basePath%>"> 来完成绝对路径的书写。
拦截器:
拦截器能在action被调用之前和被调用之后执行一些“代码”。Struts2框架的大部分核心功能都是通过拦截器来实现的,如防止重复提交、类型转换、对象封装、校验、文件上传、页面预装载等等,都是在拦截器的帮助下实现的。每一个拦截器都是独立装载的(pluggable),我们可以根据实际的需要为每一个action配置它所需要的拦截器。
<package name="myFirst" namespace="/" extends="struts-default">
<interceptors>
<interceptor name="timer"class="com.opensymphony.xwork2.interceptor.TimerInterceptor" />
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor" />
</interceptors>
<action name="login" class="com.asm.LoginAction">
<interceptor-ref name="timer"></interceptor-ref>
<interceptor-ref name="params"></interceptor-ref>
<result name="loginSuccess">/success.jsp</result>
<result name="loginFailure">/failure.jsp</result>
</action>
</package>
使用ForwardAction实现页面屏蔽。
我们在jsp页面之间写链接总会是.../xxx.jsp,而如果我们想屏蔽掉具体的jsp,只需要所jsp页面配置成一个ForwardAction即可实现。示例如下:在根目录下有一个index.jsp主页,我们strtus.xml 中作如下配置:
<package name="def" extends="struts-default">
<action name="forward">
<result >/index.jsp</result>
</action>
</package>
说明:如果没有未action指定class,默认就是ActionSupport类,如果没有为action指定method属性,则默认执行execute方法,如果没有指定result的name属性,默认值为success。知道了这些
再结合ActionSupport的源码就不难理解实现转发的原理了。
使用default-Action配置统一访问
default-action-ref,当访问没有找到对应的action时,默认就会调用default-action-ref指定的action.同样在上面的package中增加如下内容:
<default-action-ref name="error"></default-action-ref>
<action name="error">
<result>/other/error.jsp</result>
</action>
上面一段内容就是说当我们访问的action不能被找到时便指向名为error的action中去,接着我们在下面配置了这个error Action。但是要注意,一个package内只配置一个<default-action-ref>,如果配置多个,就无法预测结果了. 此时我们只要输入.../myStruts2/luanFangWen.action这样的形式,它就会去访问这个默认的<default-action-ref>,通常我们会为它配置一个错误页面,以提示用户访问的页面不存在。 在web开发中,我们还可以把这个默认的action访问配置成主页,这样当用户访问一些不存在的action时,总会跳到主页上去。 通过此配置,只要是访问一个不存在的action便会转向到.../other目录下的error.jsp页面。但是如果访问是其它的不存在资源则仍是报tomcat所标识的404错误,我们可以在web.xml中作如下配置:
<error-page>
<error-code>404</error-code>
<location>/other/404error.jsp</location>
</error-page>
这样配置后,访问错误页面将跳到.../other/404error.jsp页面中去。
通配符:
原理:当有.../addUser.action请求时,如果不能在当前应用中找到完全相同的addUser名字的Action时,通配符配置这时就起作用了,按通配原则,它便和上面的name="*User"相配成功,这里不难明了*此时代指的内容是add,再来看method恰恰是引用第一个*的内容,所以它的method此时的完整名为addUser,它刚好和com.asmUserAction中的addUser方法相对,所以它会去addUser方法,再来看下面的result配置所指代的页面,它也用到了{1},所以它的完整页面是/addUser.jsp。其实如果我们有良好的编程命名习惯,所有的Action我们都只需要进行一次配置。举例:规定所有的Action类都用XXXAction来命名,类中所有的CRUD方法都用add/del/update/query。Jsp页面也用add/del/update/query_XXX.jsp这样的形式。即配置文件可以写成如下形式:
<action name="*_*" class="com.asm.{2}Action" method="{1}">
<result name="success">.../{1}_{2}.jsp</result>
</action>
Name中第一个*代表CRUD操作的名字,第二个*代表类的名字。所以访问链接地址举例如下: .../del_User.action将访问到User类的del方法,成功后跳到del_User.jsp页面。补充说明{0}是代表name中所有的*组合。