Struts2 是一种基于MVC模式的轻量级Web框架,它自问世以来,就受到了广大Web 开发者的关注,并广泛应用于各种企业系统的开发中。目前掌握Struts2 框架几乎成为Web开发者的必备技能之一。接下来将针对Struts2 的特点、安装以及执行流程等内容进行详细的讲解。
1.1 Struts2 简介
Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构差别巨大。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts 2可以理解为WebWork的更新产品。虽然从Struts 1到Struts 2有着太大的变化,但是相对于WebWork,Struts 2的变化很小。
1.2 其它WEB层框架
那么,除了Strut2之外,还有哪些优秀的Web层框架呢?常见的WEB层的框架还有Struts1、Webwork、SpringMVC。WEB层框架都有一个特点,就是基于前端控制器模式实现的。
2.1 搭建Struts2 框架
先搭建一个简单的Struts2 框架,具体步骤如下:
2.1.1 导包
1)下载Struts2 的开发包
Struts2 的官网:https://struts.apache.org/ 链接
2)解压Struts2 的开发包
3) 创建一个WEB工程,引入相关jar 包
导包,最简单的方法,是找到apps文件夹下后缀为 .war的例子,它们是Struts2的例子,肯定包含Struts2需要的jar 包。比如,将struts2-blank解压,打开解压之后的文件夹找到WEB-INF/lib ,这里面的所有的jar 包就是我们需要导入的包。直接将它们全部复制到我们自己新建的web工程下的lib 目录下就可以了。
2.1.2 书写Action类
在src 下创建一个包cn.itcast.struts2.action,在该包下创建一个Action类,名称为HelloAction 。在这个类中编写一个公有的,返回值为String类型的方法,这个方法的名称叫做execute(),且该方法没有任何参数,因为这个方法最终要被反射执行。
public class HelloAction {
/**
* 提供一个默认的执行方法:execute()
*/
public String execute(){
System.out.println("hello world!");
return "success";
}
}
对于execute()方法,先任意给其一个字符串返回值,比如返回一个success的字符串。这个字符串就作为一个逻辑视图名称。
Action类编写好之后,Struts2 框架需要识别出这个类是一个Action,就需要对Action类进行配置。比如上面步骤中的execute()方法返回一个字符串,这个success字符串又怎么能够代表一个页面呢?这时候就需要配置struts.xml对Action进行配置。
2.1.3 在src/struts.xml中配置Action类
接下来,我们需要观察apps 中的示例代码,在WEB-INF的classes 中,有一个名称为struts.xml的文件,这个文件就是Struts2的配置文件。开发中我们需要将struts.xml 文件引入到工程的 src 下,因为 src 下的内容发布到web 服务器中的就是WEB-INF 下的classes 中。将struts.xml 中原有的内容删除掉,再配置上自己编写的Action类就可以了。也可以自己在src下新建一个struts.xml文件,需要自己手动导入约束。导入约束:打开Web App libraries下的strut2-core-2_3_24.jar包,找到dtd后缀的文件,即为约束。打开dtd后缀的文件,比如struts-2.3.dtd,把里面的内容复制到记事本中,再将记事本重命名为struts-2.3.dtd。再在Eclipse中复制一下导包的路径,具体步骤如下面三张图片所示。
需要注意的是,到了Action之后,只会在控制台中输出Action中的内容,而没有实现页面的跳转。而在实际的开发中是需要实现页面跳转的,Action类中的execute()方法中返回了一个字符串类型的返回值,它是一个逻辑视图(逻辑视图:相当于一个真实的页面,只是取了一个别名而已)。所以在配置Action类的时候,也需要对页面的跳转进行配置。然后在相关位置新建一个.jsp页面。代码如下所示,里面具体的标签,会在后面的章节中做具体介绍。
/hello.jsp
这时,需要手动在WEB-INF下新建一个hello.jsp。代码如下:
Action类就已经配置好了。配置好之后还是不能执行的,因为之前我们介绍过,WEB 层的框架都有一个特点就是基于前端控制器的模式,这个前端控制器是由过滤器来实现的,所以我们需要配饰Struts2 的核心过滤器。这个核心过滤器的名称是StrutsPrepareAndExecuteFilter。
2.1.4 将Struts2核心过滤器配置到web.xml
Struts2框架要想执行,所有的请求都需要经过这个前端控制器(核心过滤器),所以需要配置这个核心过滤器。因为这个过滤器完成了框架的部分功能。打开web.xml,在web.xml 中进行如配置,代码如下:
struts2
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
struts2
/*
那么到这,完成了以上的步骤之后,程序就可以执行了。
2.1.5 测试
在地址栏中输入http://localhost8080/struts2_day01/hello/HelloAction,其中前面部分http://localhost8080/是tomcat默认的地址信息,.../struts2_day01是web工程名,.../hello是struts.xml中的namespace值,.../HelloAction是struts.xml中的Action name值
从结果我们可以看到,在下面的打印台上输出了 hello world! 说明Action已经执行到了。上面也输出了页面的信息,说明成功跳转到了hello.jsp页面 。
2.2 Struts2 的访问流程
当服务器启动,加载web.xml 文件,就会加载一个过滤器Filter,StrutsPrepareAndExecuteFilter这个过滤器加载后,Struts2框架就可以使用。StrutsPrepareAndExecuteFilter这个过滤器会拦截所有请求,我们的/hello访问请求也会被拦截下来,会使用/hello,去struts.xml 文件中查找指定的Action类。
下面是Struts2官网上给出的全图:
其中,橙色蓝色的StrutsPrepareAndExecuteFilter、ActionMapper、ActionProxy、ConfigurationManager、Result,是Struts2已经定义好而不需要我们程序员去处理的部分。绿色的Interceptor拦截器,可以用Struts2中现成的,也可以我们程序员自己重新自定义。黄色的struts.xml、Template中的JSP等、Action,是需要我们程序员自己动手的。
一个请求在Struts2框架中的处理大概分为以下几个步骤:
1) struts2的整个生命周期开始于来自客户端的request请求, 客户端初始化一个指向Servlet容器(例如Tomcat)的请求。
2) 这个请求经过一系列的过滤器(Filter)(这些过滤器中有一个叫做ActionContextCleanUp的可选过滤器,这个过滤器对于Struts2和其他框架的集成很有帮助,例如:SiteMesh Plugin)。
3) 接着FilterDispatcher被调用,FilterDispatcher询问ActionMapper来决定这个请求是否需要调用某个Action。
4) 如果ActionMapper决定需要调用某个Action,FilterDispatcher把请求的处理交给ActionProxy。
5) ActionProxy通过Configuration Manager询问框架的配置文件,找到需要调用的Action类。
6) ActionProxy创建一个ActionInvocation的实例。
7) ActionInvocation实例使用命名模式来调用,回调Action的execute()方法,该execute()方法先获取用户请求参数,然后它会调用业务逻辑组件来处理用户的请求。在调用Action的过程前后,涉及到相关拦截器(Intercepter)的调用。
8) 一旦Action执行完毕,ActionInvocation负责根据struts.xml中的配置找到对应的返回结果。返回结果通常是(但不总是,也可能是另外的一个Action链)一个需要被表示的JSP或者FreeMarker的模版。在表示的过程中可以使用Struts2 框架中继承的标签。在这个过程中需要涉及到ActionMapper。
在上述过程中所有的对象(Action,Results,Interceptors,等)都是通过ObjectFactory来创建的。
1) 客户端(Client)向服务器发送一个请求(request)
2) 客器(Container)通过web.xml映射请求,并获得控制器(Controller)的名字。
3) 容器(Container)调用过滤器(StrutsPrepareAndExecuteFilter或FilterDispatcher)。在Struts2.1以前调用FilterDispatcher,Struts2.1之后调用StrutsPrepareAndExecuteFilter。
4) 控制器(Controller)通过ActionMapper获得Action的信息。
5) 控制器(Controller)调用ActionProxy。
6) ActionProxy读取struts.xml文件读取相应的action和interceptor stack的信息。
7) ActionProxy把request请求传递给ActionInvocation。
8) ActionInvocation依次调用interceptor拦截器和action。
9) 根据action执行结果,产生result。
10) Result信息,经过interceptor拦截器返回给ActionInvocation。
11) 产生一个HttpServletResponse响应。
12) 将产生的响应返回给客户端。
Struts2 六大核心组件
AOP思想,面向切面编程
4.1 Action类详解
4.2 Strut2 配置详解
通过前面的学习,我们已经对Struts2 框架有了一定的了解,但是对于各知识点的细节,还需要进一步地学习。接下来,将针对Struts2中struts.xml 文件的配置等内容进行详细的讲解。在学习具体详细的配置之前,要对Struts2的配置文件的加载顺序有一定的了解,这样对后面学习Struts2 的配置都是有帮助的。
4.2.1 配置文件的加载顺序
每次从客户端发送请求到服务器端都要先经过Struts2的核心过滤器StrutsPrepareAndExecuteFilter,这个过滤器有两个功能:预处理和执行。在预处理中主要是加载配置文件,对应的是过滤器中的init()方法;而执行是用来执行一组拦截器完成部分功能,对应的是过滤器的doFilter()方法。所以我们如果想要了解Struts2的配置文件的加载顺序,就要查询过滤器的init()方法。
4.2.2 Action的配置中各个元素与属性
4.2.3 Struts2常量配置
在企业开发中,还有一个问题,就是如果一个团队协同开发一个项目,而团队中的很多人都需要去修改struts.xml,那么最后在项目整合的时候就会很麻烦。所以Struts2 中也支持分模块开发的配置。
4.2.4 分模块开发的配置
其中,每一个被包含的配置文件必须是标准的Struts2 配置文件,一样包含DTD信息、Struts2 配置文件的根元素等信息。
4.2.5 动态方法调用
方式一,配置动态方法是否开启的常量
1) 创建一个Action类,此类中包含了不止一个方法。
2) 通过设置动态方法调用是否开启的常量,
实现动态配置上面Action中四个方法。
3) 在地址栏中输入:
http://localhost8080/struts2_day01/dynamic/Demo1Action!delete.action
进行访问。其中调用方法的访问格式是 !方法名。因为在此案例中指定了访问action时的后缀名常量
重启服务器后,在地址栏中输入访问路径,结果如下图所示:
方式二,通配符 * 方法
1) 创建一个Action类,此类中包含了不止一个方法。
2) 使用 * 通配符,<action name="Demo1Action_*" class="cn.itheima.b_dynamic.Demo1Action" method="{1}">
3) 在地址栏中输入
http://localhost8080/struts2_day01/dynamic/Demo1Action_add.action
4.2.6 Struts2 中的默认方法配置
4.3 页面结果的配置(结果跳转方式)
4.4 Struts2访问servlet的API
前面已经对Struts2的流程执行完成了,但是如果表单中有参数,如何进行接收?又或者我们需要向页面保存一些数据,又要如何完成?我们可以通过学习Struts2 访问Servlet的API 来实现这样的功能。【 Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet 】
在Struts2中,Action 并没有直接和Servlet API 进行耦合,也就是说在Struts2的Action中不能直接访问Servlet API。虽然Struts2中的Action访问Servlet API 麻烦一些,但是这却是Struts2中Action的重要改良之一,方便Action进行单元测试。
尽管Action和Servlet API 解耦会带来很多的好处,然而在Action中完全不访问Servlet API 几乎是不可能的,在实现业务逻辑是,经常要访问Servlet 中的对象,如 session、 request 、application 等。
Struts2访问Servlet的API,就是要了解Struts2如何从 ActionContext 中取值。原理如下图:
Struts2访问servlet的API 的方式有 3 种,通过ActionContext 类访问Servlet的API,具体如下:
4.4.1 通过ActionContext 类访问Servlet的API
建议:在开发中优先使用方式一,通过ActionContext 类访问Servlet的API 。
4.4.2 通过ServletActionContext 类访问Servlet的API
4.4.3 通过特定接口访问Servlet的API
4.5 封装Struts2中的数据
在很多的实际开发场景中,页面提交请求到Action,在Action中接收参数并且需要对请求参数进行数据的封装。封装到一个JavaBean中,然后将JavaBean 传递给业务层。那么这些操作,Struts2 已经替我们都想好的。Struts2 将数据的封装分成两大类:一类被称为属性驱动,一类被称为模型驱动。
4.5.1 属性驱动
4.5.2 模型驱动
4.6 Struts2 中封装复杂类型的数据
在实际开发中,有些时候我们需要批量插入用户或批量插入其它的对象,在Action中需要接收到这多个Action 中封装的对象,然后传递给业务层。那么这个时候就需要将表单的数据封装到集合中。一般我们通常使用的集合无非是List或Map集合,下面就以这两种集合进行数据的封装示例演示。
4.6.1 封装到List 集合中
4.6.2 封装到Map 集合中
××××××××××××××××××××××××××看到这×××××××××××××××××××
5.1 OGNL 概念
OGNL是Object-Graph Navigation Language的缩写,对象视图导航语言。它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。如果把表达式看作是一个带有语义的字符串,那么OGNL 无疑成为了这个语义字符串与Java对象之间沟通的桥梁。
OGNL:对象视图导航语言。${user.addr.name},这种写法就叫做对象视图导航。OGNL不仅仅可以视图导航,还支持比EL表达式更加丰富的功能。
5.2 OGNL 的作用
5.3 OGNL 的要素
5.4 OGNL 案例
下面结合具体的例子,熟悉OGNL 是如何进行代码编码的。
6.1 结合的原理
6.2 值栈
6.2.1 值栈相关概念
扩展知识:
request.getAttribute() 方法的查找顺序
1. 原生request 域
2. 查找ValueStack的栈(Root)部分
3. 查找ValueStack的Context部分(ActionContext)
6.3 Struts2 和 OGNL 结合的体现
6.3.1 Struts2参数接收时,所体现出的OGNL
获得值栈,代码如下:
6.3.2 Struts2配置文件中,所体现出的OGNL
6.3.3 Struts2 的标签,所体现出的OGNL(了解即可)
标签体系:
Struts2 的标签的使用
7.1 拦截器的相关概念
7.2 拦截器的创建方式
拦截器的创建,有3 中常见方式:
7.3 自定义拦截器与拦截器的配置
注意:自定义拦截器要放在默认拦截器之前。
其中,指定哪些方法拦截与哪些方法不拦截不能同时出现。
7.4 拦截器和过滤器的区别
过滤器包裹住servlet,servlet包裹住拦截器。如下图所示:
1.过滤器和拦截器“触发时机(触发时间和地点)”不一样:
过滤器是在请求进入容器后,但请求进入servlet之前进行预处理的。请求结束返回也是,是在servlet处理完后,返回给前端之前。
2.过滤器的触发时机是容器后,servlet之前,所以过滤器的doFilter(ServletRequest request, ServletResponse response, FilterChain chain)的入参是ServletRequest ,而不是httpservletrequest。因为过滤器是在httpservlet之前。
过滤器和拦截器的区别:
①拦截器是基于Java的反射机制的,而过滤器是基于函数回调。
②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service(),可以调用业务逻辑。
---------------------------------------- 我是低调的分隔线 ----------------------------------------
易百教程:https://www.yiibai.com/struts_2/ 链接