1、1为什么要使用框架?回忆基于 Servlet 的 MVC 框架:Struts2 是以上模式的进化版本,也是以控制器为核心。 框架将经常使用的程序模块和设计模式包装成可复用的设计构件,强调软件设计的重用性和系统的可扩充性, 缩短大型应用软件系统的开发周期,提高开发质量。第 1 节 Struts2 简介2006 年,WebWork 与 Struts 这两个优秀的 Java Web 框架开发团队,决定合作共同开发一个新的、整合了 WebWork 与 Struts 的优点,并且更加优雅、扩展性更强的框架,命名为“Struts 2”,原先 Struts 的 1.x 版本产品称为“Struts 1” 。S
2、truts 2 以 WebWork 为核心,是一个 MVC 框架。用 Struts 1 架构的系统并不能升级为 Struts 2 架构,除非完全重新实现。因此 Struts 2 的体系结构与 Struts 1 的差别非常巨大,但相对于WebWork,Struts 2 只有很小的变化。Struts 2 框架由 3 个部分组成:核心控制器 FilterDispatcher、业务控制器和用户实现的业务逻辑组件。在这 3 个部分里,Struts 2 框架提供了核心控制器 FilterDispatcher,而用户需要实现业务控制器和业务逻辑组件。同时采用拦截器的机制来处理用户的请求,使得业务逻辑控制器能
3、够与 Servlet API 完全的脱离。2第 2 节 快速搭建 Struts2 框架2.1 下载 Struts2 框架Struts 2 框架由 Apache 开源组织开发并负责维护的,可以登录 Struts 的官方站点http:/struts.apache.org/download.cgi#struts221Full Distribution:下载 Struts 2 的完整版。通常建议下载该选项。Example Applications:下载 Struts 2 的示例应用,这些示例应用对于学习 Struts 2 有很大的帮助,下载 Struts 2 的完整版时已经包含了该选项下全部应用。Es
4、sential Dependencies:仅仅下载 Struts 2 的核心库,下载 Struts 2 的完整版时将包括该选项下的全部内容。Documentation:仅仅下载 Struts 2 的相关文档,包含 Struts 2 的使用文档、参考手册和 API 文档等。下载 Struts 2 的完整版时将包括该选项下的全部内容。Source:下载 Struts 2 的全部源代码,下载 Struts 2 的完整版时将包括该选项下的全部内容。下载完成,解压之后出现以下四个文件夹:apps:包含了基于 Struts 2 的示例应用,这些示例应用对于学习者是非常有用的资料。docs:包含了 Stru
5、ts 2 的相关文档,包括 Struts 2 的快速入门、Struts 2 的文档,以及 API 文档等内容。lib:包含了 Struts 2 框架的核心类库,以及 Struts 2 的第三方插件类库。src:包含了 Struts 2 框架的全部源代码。32.2 在 Eclipse 中创建 struts2 项目第一步:将 struts2 的 jar 包拷贝到项目的 lib 目录下下面是构建 Struts 2 应用的必须 jar 包: commons-fileupload-1.2.1.jar 实现文件上传的工具包 commons-io-1.3.2.jar 处理输入输出的工具包 commons-l
6、ogging-1.0.4.jar 日志记录工具包 freemarker-2.3.16.jar 模板引擎,Struts2 标签模板都是用 FreeMarker 编写的 ognl-3.0.jar Struts2 表达式的基础 struts2-core-2.2.1.jar Struts2 框架核心类库 xwork-core-2.2.1.jar XWork 类库,Struts2 是基于 XWork 的 javassist-3.7.ga.jar注意:在使用 struts-2.2.1 时,需要引入 javassist-3.7.ga.jar,而这个在 struts-2.2.1lib 下是没有的,需要在 st
7、ruts-2.2.1appsstruts2-blank-2.2.1.war 下的 lib 中找。第二步:在 web.xml 中配置 struts2 的核心过滤器Struts 2 框架是基于 MVC 模式开发的,它提供了一个核心过滤器,用于对所有的请求进行统一拦截处理,这个控制器是由一个名为 FilterDispatcher 的 Servlet 过滤器来充当的。当用户请求到达时,该 Filter 会过滤用户请求,并转发到合适的 Action 类。只要Web应用加载FilterDispatcher,FilterDispatcher将会加载Struts2框架。是的属性,用来定义 Filter 的名称
8、。是 的属性,用来指定 Filter 的具体实现类 org.apache.struts2.dispatcher.FilterDispatcher。用来指定访问 Filter 时的 URL。用来定义 Filter 的名称,和前面 中定义的名称相对应。指定访问 Filter 时 URL 的相对路径。4第三步:添加 struts 的配置文件 struts.xml 文件应在 WEB-INF/classes 目录下,添加 struts.xml(注:在 Eclipse 项目中,向 src 目录下直接添加 struts.xml,即是将 struts.xml 文件添加到 WEB-INF/classes 目录下
9、) 。说明:struts.enable.DynamicMethodInvocation :设置 Struts 2 是否支持动态方法调用,默认值是true。如果需要关闭动态方法调用,则可设置该属性为 false。struts.devMode:设置 Struts 2 应用是否使用开发模式。如果设置为 true,则可以在应用出错时显示更多、更友好的出错提示。默认值是 false。通常,应用在开发阶段设置为 true,当进入产品发布阶段后,则该属性设置为 false。第 3 节 简单登陆示例客户浏览器F i l t e r D i s p a t c h e rL o g i n A c t i o
10、nl o g i n _ f a i l u r e . j s pl o g i n _ s u c c e s s . j s p发送请求请求转发返回 s u c c e s s返回 f a i l u r e53.1 JSP 页面登录页面 login.jsp 用户登录 用户名:密码:说明:请求-响应周期的起始点和结束点都在用户的 Web 浏览器端。代表 action 的 URL 可以在提交表单时指定,也可在用户点击链接或直接在浏览器的地址栏输入。例如:直接进入直接进入登录成功页面 login_success.jsp登录成功登录失败页面 login_failure.jsp登录失败63.2
11、控制器 ActionMVC 框架的核心就是控制器。Action 是 Struts2 的基本“程序单位” 。在 struts2 框架中每一个Action 是一个工作单元。当用户通过页面提交用户请求时,该请求需要提交给控制器处理。控制器根据处理结果,决定将哪个页面呈现给客户端。Struts2 下的控制器不同于 Struts1 的控制器,不需要继承任何父类,也无需实现任何接口,是一个普通的 POJO 类(普通、传统的 Java 对象) 。Action 中包含一个 execute 方法,用来调用业务逻辑组件进行判断,并返回字符串(逻辑视图名),通过该字符串,Struts2 会跳转到指定的视图资源。控制
12、器 LoginAction.javapackage com.struts2.action;import com.struts2.service.LoginCheck;public class LoginAction private String username;private String password;/ 获得username 值public String getUsername() return username;/ 设置username 值public void setUsername(String username) this.username = username;/ 获得pa
13、ssword 值public String getPassword() return password;/ 设置password 值public void setPassword(String password) this.password = password;public String execute() throws Exception / new一个LoginCheck对象LoginCheck lc = new LoginCheck();/ 调用业务逻辑组件的判断功能来判断if (lc.isLogin(getUsername(), getPassword() return “succe
14、ss“; else return “error“;说明:getXXX()和 setXXX()中的 XXX 必须和表单参数的名字一样 ,这样 Struts 2 框架就可以把表单的值赋给这些属性,并且表单也可以获取该类的属性值。7业务逻辑类 LoginCheck.java业务逻辑组件实际上就是 MVC 模式中的 Model 组件,负责实现系统业务逻辑方法。此处的业务逻辑组件只是模拟实现业务逻辑方法,并未真正调用持久层组件来获取数据库信息。package com.struts2.service;public class LoginCheck / 判断是否为合法用户public boolean isL
15、ogin(String name, String password) if (“admin“.equals(name) else return false;3.3 配置 struts.xml在 struts.xml 中指定该 Action 的实现类,并定义该 Action 处理结果与视图资源之间的映射关系。/login_success.jsp/login_failure.jsp说明: package 代表一个独立的模块,类似于 package。Struts2 使用 package 来组织 Action,将多个 action 元素组织为一个逻辑单元。name 属性指定包的名字,extends 属
16、性指定要继承的包。struts-default 包定义在 struts-default.xml 文件中,该文件已经包含在 Struts 2 的核心 JAR 包中了,可以直接继承该包的所有配置。 Struts2 以 namespace(命名空间)的方式来管理 Action,同一个命名空间中不能有同名的Action,不同的命名空间中可以有同名的 Action。命名空间将 Action 分成逻辑上的不同模块,每一个模块都有自己独立的前缀。使用 namespace 可以有效地避免 Action 重名的冲突,“/“表示根 Namespace,所有直接在应用程序上下文环境下的请求都在这个 Package
17、中查找。 当某个包指定了命名空间后,该包下所有的Action处理的URL应该是命名空间+Action名。例如:请求 action 时:注意: namespace 与 WebRoot 中的目录无关,namespace 完全是逻辑上的模块概念。 action 元素用于对 action 进行配置。name 属性为 action 指定一个名字,这个名字即用户访问的 URL,class 属性指定 action 的完整类名。8 action 执行的结果(成功或者失败)通常都对应着一个要呈现给用户的 result。 result 元素指定 execute 方法返回值(逻辑视图)和视图资源之间的映射关系。Fi
18、lterDispatcher 根据action 返回的结果字符串来选择对应的 result 显示给用户。 如果 result 的名字是 success,可以省略 name 属性。第 4 节 处理流程核心控制器:org.apache.struts2.dispatcher.FilterDispatcherFilterDispatcher是Struts2框架的核心控制器,该控制器作为一个Filter运行在Web应用中,它负责拦截所有用户请求,当用户请求到达时,该Filter会过滤用户请求。业务(流程)控制器组件:用户Action业务控制器组件就是用户实现Action类的实例,Action类里通常包含
19、了一个execute方法,该方法返回一个字符串-该字符串就是一个逻辑视图名,每个字符串对应一个视图名。每个Action都要处理一个用户请求,而用户请求总是包含了指定URL。当FilterDispatcher拦截到用户请求后,根据请求的URL和Action处理URL之间的对应关系来处理转发。模型组件Java EE应用里的模型组件,通常指系统的业务逻辑组件(service)以及隐藏其下的DAO、领域对象等组件。模型组件已经超出了MVC框架的覆盖范围。对于Struts2框架而言,通常没有为模型组件的实现提供太多的帮助。通常,MVC框架里的业务控制器会调用模型组件的方法来处理用户请求。也就是说,业务逻
20、辑控制器不会对用户请求进行任何实际处理,用户请求最终由模型组件负责处理。业务控制器只是间接负责调度的调试器,这也是称Action为控制器的原因。视图组件Struts2允许使用各种视图技术。当Struts2的控制器返回逻辑视图名时,逻辑视图并未与任何的视图技术关联,仅仅是返回一个字符串,该字符器作为逻辑视图名。当在struts.xml文件中配置Action时,不仅需要指定Action的name属性和class属性,还要为Action元素指定系列result了元素,每个result子元素定义一个逻辑视图和物理视图之间的映射。当没有在result子元素中指定type属性时,默认使用JSP作为视图资源
21、。总的工作流程:用户请求-FilterDispatcher-Action-业务逻辑组件(URL) (核心控制器) (业务控制器)1,浏览器发送请求,例如请求/login.action。2,核心控制器FilterDispatcher根据请求决定调用合适的Action(代替了Servlet)。3,WebWork的拦截器链自动寻找请求应用通用功能。例如validation、编码转换或文件上传等功能。4,调用Action的execute方法,该execute方法先获取用户请求参数,然后执行某种数据操作,既可以是将数据保存到数据库,也可以从数据库中检索信息。实际上,因为Action只是一个控制器,它会调
22、用业务逻辑组件来处理用户的请求。5,Action 的 execute 方法处理结果信息将被输出到浏览器中,可以是 HTML 页面、图像、也可以是 PDF 文档或其他文档。9第 5 节 改进控制器前面的应用中,Action 代码中都是直接返回的字符串。不过有时候由于输入的错误,如把“success”输入成了“succeess”,这样项目就无法找到对应的视图资源了。要找出这类的错误也是非常麻烦的。所以 Struts 2 提供了一个 Action 接口,通过该接口就可以很好的避免这类问题了。Action 接口的源代码public interface Action public static fina
23、l String SUCCESS = “success“;public static final String NONE = “none“;public static final String ERROR = “error“;public static final String INPUT = “input“;public static final String LOGIN = “login“;public String execute() throws Exception;通过 Action 接口改进登陆控制器package com.struts2.action;import com.str
24、uts2.service.LoginCheck;import com.opensymphony.xwork2.Action;public class LoginAction2 implements Action private String username;private String password;/ 获得username 值public String getUsername() return username;/ 设置username 值public void setUsername(String username) this.username = username;/ 获得pass
25、word 值public String getPassword() return password;/ 设置password 值public void setPassword(String password) this.password = password;public String execute() throws Exception / new一个LoginCheck对象LoginCheck lc = new LoginCheck();/ 调用业务逻辑组件的判断功能来判断if (lc.isLogin(getUsername(), getPassword() return SUCCESS;
26、 else 10return ERROR;修改 struts.xml 配置即可:/login_success.jsp/login_failure.jsp第 6 节 获取 ServletAPI 对象在传统的 Web 开发中,经常会用到 Servlet API 中的 HttpServletRequest、HttpSession 和ServletContext。由于 Struts2 可以直接访问和设置 action 及模型对象的数据,所以降低了对ServletAPI 对象的使用需求。但在某些应用中可能需要在 action 中去访问它们,例如用户登录成功后,将用户信息保存到 Session 中。Str
27、uts2 提供了多种方式来访问上述的三种对象,归结起来,可以划分为两大类: 与 Servlet API 解耦的访问方式 与 Servlet API 耦合的访问方式。6.1 与 Servlet API 解耦的访问方式为了避免与 Servlet API 耦合在一起,方便 Action 类做单元测试,Struts 2 对HttpServletRequest、HttpSession 和 ServletContext 进行了封装,构造了三个 Map 对象来替代这三种对象,在 Action 中,直接使用 HttpServletRequest、HttpSession 和ServletContext 对应的
28、Map 对象来保存和读取数据。要获取这三个 Map 对象,可以使用 com.opensymphony.xwork2.ActionContext 类。ActionContext 是 action 执行的上下文,在 ActionContext 中保存了 action 执行所需的一组对象, ActionContext 类定义了如下方法,用于获取 HttpServletRequest、HttpSession 和ServletContext 对应的 Map 对象。获取 HttpServletRequest 的 Map 对象:public Object get(“request“)获取 HttpSessi
29、on 的 Map 对象:public Map getSession()获取 ServletContext 的 Map 对象:public Map getApplication()示例:访问 ServletAPI 的 loginAction.javapackage com.struts2.action;import java.util.Map;import com.opensymphony.xwork2.Action;import com.opensymphony.xwork2.ActionContext;import com.struts2.service.LoginCheck;public
30、class LoginAction implements Action11private String username;private String password;/ 获得username 值public String getUsername() return username;/ 设置username 值public void setUsername(String username) this.username = username;/ 获得password 值public String getPassword() return password;/ 设置password 值publi
31、c void setPassword(String password) this.password = password;public String execute() throws Exception / new一个LoginCheck对象LoginCheck lc = new LoginCheck();/ 调用业务逻辑组件的判断功能来判断if (lc.isLogin(getUsername(), getPassword() ActionContext context = ActionContext.getContext(); Map request = (Map)context.get(“
32、request“);Map session = context.getSession();Map application = context.getApplication();request.put(“username“, getUsername();session.put(“username“, getUsername();Integer count = (Integer)application.get(“counter“);if(null = count)count=1;elsecount+;application.put(“counter“, count);return SUCCESS;
33、 else return ERROR;登陆成功页面 login_success.jsp登录成功 12欢迎$sessionScope.username访问!欢迎$requestScope.username访问!本站的访问量是: $applicationScope.counter除了利用 ActionContext 来获取 request、session 和 application 对象这种方式外,Action类还可以实现某些特定的接口,让 Struts 2 框架在运行时向 Action 实例注入request、session 和 application 对象。这种方式称为“注射方式”。与之对应的
34、三个接口及其方法如下所示:1. org.apache.struts2.interceptor.RequestAware 接口向 Action 实例注入 request Map 对象。该接口只有一个方法,如下:public void setRequest(Map request)2. org.apache.struts2.interceptor.SessionAware 接口向 Action 实例注入 session Map 对象。该接口只有一个方法,如下:void setSession(Map session)3. org.apache.struts2.interceptor.Applicat
35、ionAware 接口向 Action 实例注入 application Map 对象。该接口只有一个方法,如下:void setApplication(Map application)Aware 接口实际是一种拦截器,拦截器代码会在执行 Action 之前执行,将相关的 Servlet 对象设置进来。示例:通过接口注入来获取 request、session 和 application 对象的 LoginAction2package com.struts2.action;import java.util.Map;import com.opensymphony.xwork2.Action;imp
36、ort org.apache.struts2.interceptor.ApplicationAware;import org.apache.struts2.interceptor.RequestAware;import org.apache.struts2.interceptor.SessionAware;import com.struts2.service.LoginCheck;public class LoginAction2 implements Action, RequestAware, SessionAware,ApplicationAware private String user
37、name;private String password;private Map request;private Map session;private Map application;/ 获得username 值public String getUsername() return username;/ 设置username 值public void setUsername(String username) this.username = username;13/ 获得password 值public String getPassword() return password;/ 设置passw
38、ord 值public void setPassword(String password) this.password = password;Overridepublic void setRequest(Map request) this.request = request;Overridepublic void setSession(Map session) this.session = session;Overridepublic void setApplication(Map application) this.application = application;public Strin
39、g execute() throws Exception / new一个LoginCheck对象LoginCheck lc = new LoginCheck();/ 调用业务逻辑组件的判断功能来判断if (lc.isLogin(getUsername(), getPassword() request.put(“username“, getUsername();session.put(“username“, getUsername();Integer count = (Integer) application.get(“counter“);if (null = count)count = 1;e
40、lsecount+;application.put(“counter“, count);return SUCCESS; else return ERROR;146.2 与 Servlet API 耦合的访问方式若需要直接访问 ServletAPI 对象,可以使用 org.apache.struts2. ServletActionContext 类,该类是 ActionContext 的子类,在这个类中定义下面两个静态方法:得到 HttpServletRequest 对象:public static HttpServletRequest getRequest()得到 ServletContext
41、 对象:public static ServletContext getServletContext()ServletActionContext 类还给出了获取 HttpServletResponse 对象的方法:public static HttpServletResponse getResponse()*ServletActionContext 类并没有给出直接得到 HttpSession 对象的方法,HttpSession 对象可以通过 HttpServletRequest 对象来得到。示例:通过 ServletActionContext 来获取 HttpServletRequest 和
42、 ServletContext 对象的LoginAction3.javapackage com.struts2.action;import com.opensymphony.xwork2.Action;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import javax.servlet.ServletContext;import org.apache.struts2.ServletActionContext;import com.struts2.service.LoginC
43、heck;public class LoginAction3 implements Actionprivate String username;private String password;/ 获得username 值public String getUsername() return username;/ 设置username 值public void setUsername(String username) this.username = username;/ 获得password 值public String getPassword() return password;/ 设置pass
44、word 值public void setPassword(String password) this.password = password;public String execute() throws Exception / new一个LoginCheck对象LoginCheck lc = new LoginCheck();/ 调用业务逻辑组件的判断功能来判断15if (lc.isLogin(getUsername(), getPassword() HttpServletRequest request = ServletActionContext.getRequest(); HttpSes
45、sion session = request.getSession();ServletContext context = ServletActionContext.getServletContext();request.setAttribute(“username“, getUsername();session.setAttribute(“username“, getUsername();Integer count = (Integer)context.getAttribute(“counter“);if(null = count)count=1;elsecount+;context.setA
46、ttribute(“counter“, count);return SUCCESS; else return ERROR;除了利用 ServletActionContext 来获取 HttpServletRequest 对象和 ServletContext 对象这种方式外,Action 类还可以实现 ServletRequestAware 和 ServletContextAware 接口,由 Struts 2 框架向 Action 实例注入 HttpServletRequest 和 ServletContext 对象。org.apache.struts2.interceptor.Servlet
47、RequestAware 接口只有一个方法:void setServletRequest(HttpServletRequest request)org.apache.struts2.util.ServletContextAware 接口也只有一个方法:void setServletContext(ServletContext context)ServletRequestAware 接口和 ServletContextAware 接口不属于同一个包,前者在org.apache.struts2.interceptor 包中,后者在 org.apache.struts2.util 包中。示例:pac
48、kage com.struts2.action;import java.util.Map;import com.opensymphony.xwork2.Action;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpSession;import org.apache.struts2.interceptor.ServletRequestAware;import org.apache.struts2.util.ServletCo
49、ntextAware;import com.struts2.service.LoginCheck;public class LoginAction4 implements Action, ServletRequestAware,ServletContextAware private String username;private String password;private HttpServletRequest request;private ServletContext context;16/ 获得username 值public String getUsername() return username;/ 设置username 值public void setUsername(String username) this.username = user