文章目录
1. 什么是Struts2
我们来看下图,在图中传统方式的开发,有一次请求就会对应一个Servlet,这样会导致出现很多Servlet。而Struts2将所有的请求都先经过一个前端控制器,在前端控制器中实现框架的部分功能,剩下具体操作又提交到具体的Action中。那么所有的请求都会经过前端控制器,那用什么来实现前端控制器呢?过滤器就是最好的一个实现方式,因为需要所有的请求都可以被过滤器拦截,然后在过滤器中实现部分的功能。所以Struts2的前端控制器也是由过滤器来实现的。
2. Struts2快速入门
2.1 创建Action类
public class StrutsDemo {
//提供一个默认的执行的方法: execute
public String execute(){
system.out.print1n("StrutsDemo1中的execute执行了...");
return "success";
}
}
2.2 创建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="demo1" namespace="/hello" extends="struts-default" >
<!-- 配置 Action -->
<action name="strutsDemo" class="cn.joker.demo1.StrutsDemo" >
<!-- 配置结果页面的跳转 -->
<result name="success" >/hello.jsp</result>
</action>
</package>
</struts>
2.3 配置核心过滤器
<!-- web.xml中配置 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.4 测试
localhost:8080/struts_demo/hello/strutsDemo.action,即可跳转至我们编写的hello.jsp页面。
2.5 运行流程分析
3. Struts2的常见配置
3.1 核心过滤器的配置
Struts2框架要想执行,所有的请求都需要经过这个前端控制器(核心过滤器),所以需要配置这个核心过滤器,因为这个过滤器完成了框架的部分的功能,在web工程的web.xml中添加如下配置。
<!-- web.xml中配置 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>
3.2 Action的配置
Struts2框架的核心配置文件是struts.xml文件,该文件主要用来配置Action和请求的对应关系。
<struts>
<!-- package标签: 如果要配置 <Action>的标签,那么必须要先配置 <package>标签,代表的包的概念
name属性: 包的名称,要求是唯一的,管理 action配置
namespace属性: 名称空间,一般与 <action>标签中的 name属性共同决定访问路径(通俗话:怎么来访问 action)
extends属性: 继承,可以继承其他的包,只要继承了,那么该包就包含了其他包的功能,一般都是继承 struts-default
abstract属性: 这个属性基本很少使用,值如果是 true,那么编写的包是被继承的
-->
<package name="demo1" namespace="/hello" extends="struts-default" >
<!-- action标签: 配置 action类
name属性: 和 <package>标签的 namespace属性一起来决定访问路径的
class属性: 配置 Action类的全路径(默认值是 ActionSupport类)
method属性: Action类中执行的方法,如果不指定,默认值是 execute
-->
<action name="strutsDemo" class="cn.joker.demo1.StrutsDemo" >
<!-- result标签: action类中方法执行,返回的结果跳转的页面
name属性: 结果页面逻辑视图名称,与 action方法的返回值对应
type属性: 结果类型(默认值是转发,也可以设置其他的值)
-->
<result name="success" >/hello.jsp</result>
</action>
</package>
<!-- 引入其他 struts配置文件 -->
<include file="cn/joker/demo2/StrutsDemo2/struts.xml"></include>
</struts>
3.3 配置文件的加载顺序
每次从客户端发送请求到服务器都要先经过Struts2的核心过滤器StrutsPrepareAndExecuteFilter,这个过滤器有两个功能:预处理和执行。在预处理中主要就是来加载配置文件的,对应的是过滤器中的init方法。而执行是用来执行一组拦截器完成部分功能的,对应的是过滤器的doFilter方法。所以我们如果要去了解Struts2的配置文件的加载顺序,那么我们需要查询过滤器的init方法。
在init方法中,调用了init的initDispatcher的方法来加载配置文件,进入到该代码中:
我们会发现这个方法又调用了dispatcher的init方法。进入init方法内部:
//这一系列的代码就是用来加载 Struts2的配置文件的
init_DefaultProperties();//[1] 加载 org.apache.struts.default.properties。该文件配置的是 struts2的所有常量
init_TraditionalXmlConfigurations();//[2] 加载 struts-default.xml、struts-plugin.xml、struts.xml
init_LegacystrutsProperties();//[3] 加载用户自定义 struts.properties
init_CustomConfigurationProviders();//[5] 加载用户配置的提供对象
init_FilterInitParameters();//[6] 加载 web.xml
init_AliasStandardobjects();//[7] 加载标准对象
根据上面的代码我们可以得出配置文件的加载顺序如下:default.properties、struts-default.xml、struts-plugin.xml、struts.xml、struts.properties、web.xml。前三个配置文件我们不用关心,是Struts2内部的配置文件,我们无法修改,能修改的文件就是struts.xml、struts.properties、web.xml配置文件。这几个配置文件的加载是有一定的顺序的。这三个配置文件都可以修改Struts2的常量的值,要记住的是,后加载配置文件中常量的值会将先加载的配置文件中常量的值给覆盖。
4.4 常量的配置
- 在struts.xml文件中配置:
<struts> <!-- 设置默认编码集为 UTF-8 --> <constant name="struts.i18n.encoding" value="UTF-8"/> <!-- 设置使用开发模式 --> <constant name="struts.devMode" value="true"/> </struts>
- 在struts.properties文件中配置:
###设置默认编码集为UTE-8 struts.i18n.encoding=UTF-8 ###设置 action请求的扩展名为 action或者没有扩展名 struts.action.extension=action,, ###设置不使用开发模式 struts.devMode=false ###设置不开启动态方法调用 struts.enable.DynamicMethodInvocation=false
- 在web.xml文件中配置:
<!-- web.xml中配置 struts2核心过滤器 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> <init-param> <param-name>struts.i18n.encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
5. Action类详解
5.1 Action类的编写
-
Action类就是一个POJO类
在Struts2中,Action可以不继承特殊的类或不实现任何特殊的接口,仅仅是一个POJO。POJO全称Plain Ordinary Java Object(简单的Java对象),只要具有一部分getter/setter方法的那种类,就可以称作POJO。一般在这个POJO类中,要有一个公共的无参的构造方法(采用默认的构造方法就可以)和一个execute方法。execute方法的要求为(方法的权限修饰符为public。返回一个字符串,就是指示的下一个页面的result。方法没有参数)。也就是说,满足上述要求的POJO都可算作是Struts2的Action实现。 -
Action类可以实现Action接口
为了让用户开发的Action类更规范,Struts2提供一个Action接口,用户在编写Action控制类时,可以实现Struts2提供的这个Action接口。这个接口里只定义了一个execute方法,该接口的规范规定了Action处理类应该包含一个execute方法,该方法返回一个字符串。除此之外,该接口还定义了5个字符串常量,它们的作用是统一execute方法的返回值。5个已经定义的常量为(SUCCESS:成功。INPUT:用于数据表单校验,如果校验失败,跳转INPUT视图。LOGIN:跳转到登录页面。ERROR:跳转到错误页面。NONE:页面不跳转)。 -
Action类可以去继承ActionSupport类(常用的方式)
ActionSupport类本身实现了Action接口,是Struts2中默认的Action接口的实现类,所以继承ActionSupport就相当于实现了Action接口。ActionSupport 类还实现了Validateable、ValidationAware、TextProvider、LocaleProvider和Serializable等接口,来为用户提供更多的功能。ActionSupport类中提供了许多默认方法,这些默认方法包括获取国际化信息的方法、数据校验的方法、默认的处理用户请求的方法等。实际上,ActionSupport类是Struts2默认的Action处理类,如果让开发者的Action类继承该ActionSupport类,则会大大简化Action的开发。
5.2 Action的访问
-
通过<action>标签中的method属性,访问到Action中的具体的方法。
页面的代码:<a href="${pageContext.request.contextPath}/addBook.action">添加图书</a> <a href="${pageContext.request.contextPath}/updateBook.action">删除图书</a> <a href="${pageContext.request.contextPath}/deleteBook.action">删除图书</a> <a href="${pageContext.request.contextPath}/findBook.action">删除图书</a>
Action的代码:
public class BookAction extends ActionSupport { public String add(){ System.out.println("添加图书"); return NONE; } public String update(){ System.out.println("修改图书"); return NONE; } public String delete(){ System.out.println("删除图书"); return NONE; } public String find(){ System.out.println("查找图书"); return NONE; } }
配置文件的代码:
<package name="demo2" extends="struts-default" namespace="/"> <action name="addBook" class="cn.joker.demo2.BookAction" method="add"></action> <action name="updateBook" class="cn.joker.demo2.BookAction" method="update"></action> <action name="deleteBook" class="cn.joker.demo2.BookAction" method="delete"></action> <action name="findBook" class="cn.joker.demo2.BookAction" method="find"></action> </package>
-
通配符的访问方式
通过上面的方式我们会发现,同一个Action类就被配置了很多次,只是修改了后面的method的值。那么能不能配置简单化呢?也就是一个Action类,只配置一次就好了,这个时候我们就需要使用通配符的配置方式了,如下所示:<!-- 在 action的 name属性中使用的 *代表任意字符,method中的 {1}代表 name属性中的出现的第一个 *所代替的字符 --> <package name="demo2" extends="struts-default" namespace="/"> <action name="*Book" class="cn.joker.demo2.BookAction" method="{1}"></action> </package>
-
动态方法访问的方式
动态方法访问在Struts2中默认是不开启的,如果想要使用需要先去开启一个常量:<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
配置文件代码:
<package name="demo2" extends="struts-default" namespace="/"> <action name="bookAction" class="cn.joker.demo2.BookAction"></action> </package>
页面的代码:
<a href="${pageContext.request.contextPath}/bookAction!add.action">添加图书</a> <a href="${pageContext.request.contextPath}/bookAction!update.action">修改图书</a> <a href="${pageContext.request.contextPath}/bookAction!delete.action">删除图书</a> <a href="${pageContext.request.contextPath}/bookAction!find.action">查找图示</a>