[ SSH框架 ] Struts2框架学习之一
一、Struts2框架的概述
Struts2是一种基于MVC模式的轻量级Web框架,它自问世以来,就受到了广大Web开发者的关注,并广泛应用于各种企业系统的开发中。目前掌握 Struts2框架几乎成为Wcb开发者的必备技能之一。
接下来将针对 Struts2的特点、安装以及执行流程等内容进行详细的讲解。
1.1 什么是Struts2
Struts2是 Struts1的下一代产品,是在 Struts1和 WebWork技术的基础上进行合并后的全新框架( WebWork是由 OpenSymphony组织开发的,致力力于组件化和代码重用的J2 EE Web框架,它也是一个MVC框架)。虽然 Struts2的名字与 Struts1相似,但其设计思想却有很大不同。实质上,Struts2是以 WebWork为核心的,它采用拦截器的机制来处理用户的请求。这样的设计也使得业务逻辑控制器能够与 ServletAPI完全脱离开,所以 Struts2可以理解为 WebWork的更新产品。
Struts2拥有优良的设计和功能,其优势具体如下:
● 项目开源,使用及拓展方便,天生优势。
● 提供 Exception处理机制。
● Result方式的页面导航,通过 Result标签很方便的实现重定向和页面跳转。
● 通过简单、集中的配置来调度业务类,使得配置和修改都非常容易。
● 提供简单、统一的表达式语言来访问所有可供访问的数据。
● 提供标准、强大的验证框架和国际化框架。
● 提提供强大的、可以有效减少页面代码的标签。
● 提供良好的Ajax支持。
● 拥有简单的插件,只需放入相应的JAR包,任何人都可以扩展 Struts2框架,比如自定义拦截器。
● 自定义结果类型、自定义标签等,为 Struts2定制制需要的功能,不需要什么特殊配置,并且可以发布给其他人使用。
● 拥有智能的默认设置,不需要另外进行繁琐的设置。使用默认设置就可以完成大多数项目程序开发所需要的功能。
上面列举的就是 Struts2的一系列技术优势,只需对它们简单了解即可,在学习了后面的知识后,会慢慢对这些技术优势有更好的理解和体会。
那么除了 Struts2之外,还有那些优秀的WEB层框架呢?
了解了这些之后,让我们通过一个Struts2的快速入门,来感受一下Struts2。
二、Struts2快速入门
2.1 下载Struts2的开发包:
百度网盘链接:https://pan.baidu.com/s/1HeQLGcDaXdskUayFI-vGWw 密码:qyxp
2.2 解压Struts2的开发包
解压后的目录结构如下图:
● apps:该文件夹存用于存放官方提供的 Struts2示例程序,这些程序可以作为学习者的学习资料,可为学习者提供很好的参照。各示例均为war文件,可以通过zip方式进行解压。
● docs:该文件夹用于存放官方提供的 Struts2文档,包括 Struts2的快速入门、 Struts2的文档,以及API文档等内容
● lib:该文件夹用于存放 Struts2的核心类库,以及 Struts2的第三方插件类库。
有了 Struts2的开发环境,接下来我们亻可以进行 Struts2的开发了。
以上这些就是struts2基本的开发包了,那么这些包都有什么含义呢?说明如下图:
需要注意的是,通通常使用 Struts2的Web项目并不需要利用到 Struts2的全部JAR包,因此没有必要一次将 Struts2的lib目录下的全部JAR包复制到Web项目的WEB-INF/ib路径下,而是根据需要,再添加加相应的JAR包。
那么 Struts2的基本jar包已经引入完成了,我们使用用 Struts2都是是从页面发起请求到服务器,再由服务器处理请求,响应到页面的这个过程。接下来我们就从页面开发进行 Struts2的开发吧。
2.4 创建一个页面,放置一个连接
首先在WebContent下创建一个jsp文件,在jsp文件中编写一个Action的访问路径。如下图
<<h1>Struts2的入门案例</h1> <a herf="${pageContext.request.contextPath }/HelloAction.action">访问Struts2的Action</a>
2.5 编写一个Action
package com.Kevin.action; public class HelloAction { /** * 提供一个默认的执行的方法:execute * @return */ public String execute(){ System.out.println("HelloAction中的execute方法执行了------"); return null; } }
Action类编写好了以后,Struts2框架是如何识别它就是一个Action呢,我们需要对Action类进行配置。
2.6 完成Action配置
这个时候,我们还需要观察apps中的示例代码,在WEB-INF的 classes中,有一个名称为 struts.xml 的文件,这个文件就是 struts2的配置文件。
我们在开发中需要将 struts xml文件引入到工程的src下,因为src下内内容发布到web服务器中就是WEB-INF下的 classes中。将 struts.xml中的原有的内容删除掉,然后配置上自己编写的 Action类就可以了。
配置内容如下:里面的具体的标签,会在后面的地方详细介绍。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="hellodemo" extends="struts-default" namespace="/"> <!-- name:访问名称 class:action位置 --> <action name="HelloAction" class="com.Kevin.action.HelloAction"> </action> </package> </struts>
Action类已经配置好了,配置好了以后大家考虑一下,现在是否可以执行呢?其实现在还不行,因为之前我们介绍过,WEB层的框架都有一个特点就是基于前端控制器的模式,这个前端控制器是由过滤器实现的,所所以我们需要配置 Struts2的核心过滤器。这个过滤器的名称称是 StrutsPrepareAndExecuteFilter 。
2.7 配置核心过滤器
<?xml version="1.0" encoding="UTF-8"?> <web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <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> </web-app>
那么到这,我们程序就可以执行了,但是到了 Action以后,页面并没有跳转,只是会在控制台输出 Action中的内容,往往我们在实际的开发中,处理了请求以后,还需要进行页面的跳转,如何完成 Struts2的页面的跳转呢?
这个时候我们需要修改改 Action类中的 execute方法法的返回值了,这个方法返回了一个 String类型,这个 String类型的值就是一个逻辑视图(逻辑视图:相相当于对一个真实的页面,取了一个别名)。那么我们来修改一个 Action类。
2.8 修改Action,将方法设置一个返回值
修改Action中的execute方法的返回值,我们先任意给其返回一个字符串,比如返回一个 ok 的字符串。这个字符串就作为一个逻辑视图的名称。
package com.Kevin.action; public class HelloAction { /** * 提供一个默认的执行的方法:execute * @return */ public String execute(){ System.out.println("HelloAction中的execute方法执行了------"); return "ok"; } }
返回一个 ok 的字符串了,这个字符串如何代表一个页面呢?我们就需要对struts2进行配置了。这个时候需要修改struts.xml,对Action的配置进行完善。
2.9 修改struts.xml
打开struts.xml 文件,对action标签进行完善,在action标签中配置一个result标签,这个标签中的name属性就是之前方法返回的那个字符串的逻辑视图名称ok 。标签内部就是跳转的页面。
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "http://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="hellodemo" extends="struts-default" namespace="/"> <!-- name:访问名称 class:action位置 --> <action name="HelloAction" class="com.Kevin.action.HelloAction"> <!-- 配置方法的返回值到页面 --> <result name="ok">/hello.jsp</result> </action> </package> </struts>
到这里,我们的整个程序就执行完毕了,可以启动服务器并且测试项目。
打开页面:
页面跳转:
三、Struts2开发流程分析
3.1 Struts2的执行流程
四、Struts2的常见配置
4.1 Action的配置
【< package>的配置】
Struts2框架架的核心组件是 Action和拦截器,它使用包来管理 Action和拦截器。每个包就是多个Action、多个拦截器、多个拦截器引用的集合。在 struts.xml文件中,package元素用于定义包配置每个 package元素定义了一个包配置。 package元素的常用属性,如表所示。
在 package中还有 namespace的配置,namespace属性与 action标签的name属性共同决定了访问路径。namespace有如下三种配置:
● 跟名称空间:跟名称空间就是 namespace="/"
● 带名称的名称空间:带名称的名称空间就是 namespace="/demo1"
【 Action的配置】
Action映射是框架中的基本“工作单元”。 Action映射就是将一个请求的URL映射到一个 Action类,当一个请求匹配某个 Action名称时,框架就使用这个映射来确定如何处理请求。在 struts.xml文件中,通过< action>元素对请求的 Action和 Action类进行配置< action>元素中共有4个属性,这4个属性的说明如表所示。
< include>元素用来在一个 struts.xml 配置文件中包含其他的配置文件,包含配置体现的是软件工程中的“分而治之”原则。 Struts2允许将一个配置文件分解成多个配置文件,从而提高配置文件的可读性。 Struts2默认只加载WEB-INF/ classes下的 struts.xml文件,但一且通过多个xml文件来配置Action,就必须通过 struts.xml文件来包含其他配置文件
为了让大家更直观地理解如何在 struts.xml文件中进行包含配置,接下来通过一段示例代码来说明,具体如下
<struts> <!-- 包含了4个配置文件 --> <!-- 不指定路径,默认路径在src下的方式 --> <include file="struts-user.xml"></include> <include file="struts-customer.xml"></include> <include file="struts-book.xml"></include> <!-- 配置文件在具体包中时的方式 --> <include file="com.Kevin.action.hello.xml"></include> </struts>
需要注意的是,每一个被包含的配置文件都是标准的 Struts2配置文件,一样包含DTD信息Struts2配置文件的根元素等信息。通过将 Struts2的所有配置文件都放在Web项目的WEB- INF/classes路径下, struts.xml文件包含了其他的配置文件,在 Struts2框架自动加载 struts.xml文件时,完成加载所有的配置信息。
Action的基本配置以及熟悉了,那么通过配置 Struts2框架就可以找到具体的 Action类了,那么Action类又要如何编写呢?接下来学习 Action类的编写的方式。
在 Struts2中,Action可以不继承特殊的类或不实现任何特殊的接口,仅仅是一个POJO。POJO全称 Plain Ordinary Java Object(简单的Java对象),只要具有一部分 getter/ setter方法的那种类,就可以称作POJO。一般在这个POJO类中,要有一个公共的无参的构造方法(采用默认的构造方法就可以)和一个 execute方法。定义格式如下:
package com.Kevin.action; public class HelloAction { /** * 提供一个默认的执行的方法:execute * @return */ public String execute(){ System.out.println("HelloAction中的execute方法执行了------"); return "ok"; } }
● 方法的权限修饰符为 public。
● 返回一个字符串,就是指示的下一个页面的 Result。
● 方法没有参数。
也就是说,满足上述要求的POJO都可算作是 Struts2的 Action实现。
通常会让开发者自己编写 Action类或者者实现 Action接口或者继承 Actionsupport类。
为了让用户开发的 Action类更规范,Struts2提供一个 Action接口,用户在实现 Action控制制类时,可以实现 Struts2提提供的这个 Action接口。
Action接口定义了 Struts的的 Action处理理类应该实现的规范,Action接口中的具体代码如下所示。
package com.Kevin.action;
import com.opensymphony.xwork2.Action;
public class UserAction implements Action{ @Override public String execute() throws Exception { System.out.println("实现了Action接口----------"); return NONE; } }
Action接口中提供了5个已经定义的常量如下:
● SUCCESS:success,代表成功。
● NONE:none,代表页面不跳转。
● ERROR:error,代表跳转到到错误页面。
● INPUT:input,数据校验的时候跳转的路径。
● LOGIN:login,用来跳转到登录页面。
由于 Xwork的 Action接口简单,为开发者提供的帮助较小,所以在实际开发过程中,Action类很少直接实现Action接口,通常都是从ActionSupport类继承。
package com.Kevin.action; import com.opensymphony.xwork2.ActionSupport; public class PersonAction extends ActionSupport{ public String execute(){ System.out.println("继承ActionSupport类----------"); return NONE; } }
ActionSupport 类中提供了许多默认方法,这些默认方法包括获取国际化信息的方法、数据校验的方法、默认的处理用户请求的方法等。实际上,ActionSupport 类是 Struts2默认的 Action处理类。如果让开发者的 Action类继承该 ActionSupport 类,则会大大简化 Action的开发。
Action的类已经会编写了,如果要执行这个 Action,可以通过前面的配置来完成,但是之前的方式有一个缺点,就是多次请求不能对应同一个 Action,因为实际的开发中,一个模块的请求通常由一个 Action类处理就好了,否则则会造成 Action类过多。那么接下来我们讲一下 Action访问的一些细节。
其实我们学过在< action>的标签中有一个属性 method,通通过 method的配置来指定 Action中的某个方法执行。
【解决 Action的访问的问题的方式一:通通过配置 method属性完成】
编写测试代码如下:
BookAction类:
package com.Kevin.method; import com.opensymphony.xwork2.ActionSupport; public class BookAction extends ActionSupport{ public String add(){ System.out.println("add----"); return NONE; } public String update(){ System.out.println("update-----"); return NONE; } }
<!-- 配置method方法访问 --> <package name="methoddemo" extends="struts-default" namespace="/"> <action name="addAction" class="com.Kevin.method.BookAction" method="add"></action> <action name="updateAction" class="com.Kevin.method.BookAction" method="update"></action> </package>
【解决 Action的访问的问题的方式二:通过通配符的配置完成】
编写测试代码如下:
package com.Kevin.method; import com.opensymphony.xwork2.ActionSupport; public class BookAction extends ActionSupport{ public String add(){ System.out.println("add----"); return NONE; } public String update(){ System.out.println("update-----"); return NONE; } }
<!-- 通配符方式实现 --> <package name="methoddemo2" extends="struts-default" namespace="/"> <!-- name属性值里加符号 * 1.执行action中的add方法,访问book_add 2.执行actoin中的update方法,访问book_update 上述两个路径使用book_* 就可匹配到 --> <action name="book_*" class="com.Kevin.method.BookAction" method="{1}"></action> </package>
动态方法访问在 Struts2中默认是不开启的,如果想要使用需要先去开启一个常量。
<constant name="struts.enable.DynamicMethodInvocation" value=true"></constant>
六、简单区别Struts1和Struts2
● Struts1要求 Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。
● Struts2 Action类可以实现一个 Action接口,也可实现其他接口,使可选和定制的服务成为可能。 Struts2提供一个 Actionsupport基类去实现常用的接接口。 Action接口不是必须的,任何有 execute标识的POJO对象都可以用作 Struts2的 Action对象。
● Struts1 Action依赖于 Servlet Apl,因为当个 Action被调用时 Http Servletrequest和Http Servletresponse被传递给 execute方法
● Struts1 Action是单例模式并且必须是线程安全的,因为仅有 Action的一个实例来处理所有的请求。单例策略限制了 Struts1 Actior能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。
● Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)