struts2学习笔记(三)—— struts2的常见配置

时间:2022-05-22 14:48:19

一、配置文件的加载顺序

  每次从客户端发送请求到服务器都要先经过Struts2的核心过滤器StrutsPrepareAndExecuteFilter,这个过滤器有两个功能:预处理和执行。在预处理中主要就是来加载配置文件的。对应的是过滤器中的init方法,而执行是用来执行一组拦截器完成部分功能的,对应的是过滤器的doFilter方法。所以我们如果要去了解Struts2的配置文件的加载顺序,那么我们需要查询过滤器的init方法。

  struts2学习笔记(三)—— struts2的常见配置

  在init方法中,调用了init的initDispatcher方法来加载配置文件,进入到该代码中:

  struts2学习笔记(三)—— struts2的常见配置

  我们发现这个方法又调用了dispatcher的init方法,进入init方法内部:

  struts2学习笔记(三)—— struts2的常见配置

  这一系列代码就是用来加载Struts2的配置文件的

 init_DefaultProperties(); // 加载org.apache.struts.default.properties,里面配置的是struts2的所有常量
init_TraditionalXmlConfigurations(); // 加载struts-default.xml、struts-plugin.xml、struts.xml
init_LegacyStrutsProperties(); // 加载用户自定义的struts.properties
init_CustomConfigurationProviders(); // 加载用户配置的提供对象
init_FilterInitParameters() ; // 加载web.xml
init_AliasStandardObjects() ; // 加载标准对象

  根据上面的代码我们可以得出配置的加载顺序为

* default.properties
* struts-default.xml
* struts-plugin.xml
* struts.xml --- 配置Action以及常量(******)
* struts.properties --- 配置常量
* web.xml --- 配置核心过滤器及常量

  前三个配置文件我们不用关心,是Struts2内部的配置文件,我们无法修改,能修改的文件就是struts.xml,struts.properties,web.xml。这几个配置文件的加载是有一定顺序的。这三个配置文件都可以修改Struts2的常量的值,要记住的是,后加载配置文件中常量的值会将先加载的配置文件中常量的值给覆盖。

二、struts.xml配置

  struts.xml是struts2的核心配置文件,该文件主要用来配置Action和请求的对应关系。

<!-- package:将Action配置封装.就是可以在Package中配置很多action.
name属性: 给包起个名字,起到标识作用.随便起.不能其他包名重复.
namespace属性:给action的访问路径中定义一个命名空间
extends属性: 继承一个指定包,通常都设置为struts-default,这样该包中的Action就具有了Struts2框架默认的拦截器等功能了
abstract属性:包是否为抽象的; 标识性属性.标识该包不能独立运行.专门被继承
-->
<package name="hello" namespace="/hello" extends="struts-default" >
<!-- action元素:配置action类
name属性: 决定了Action访问资源名.(name属性和namespace属性共同决定了访问路径)
class属性: action的完整类名
method属性: 指定调用Action中的哪个方法来处理请求,默认是execute方法
-->
<action name="HelloAction" class="cn.itheima.a_hello.HelloAction" method="hello" >
<!-- result元素:结果配置
name属性: 标识结果处理的名称.与action方法的返回值对应.
type属性: 指定调用哪一个result类来处理结果,默认使用转发.
标签体:填写页面的相对路径
-->
<result name="success" type="dispatcher" >/hello.jsp</result>
</action>
</package>
<!-- 引入其他struts配置文件 -->
<include file="cn/itheima/b_dynamic/struts.xml"></include>

三、struts2常量配置

3.1 struts2默认常量配置位置

  struts2学习笔记(三)—— struts2的常见配置

3.2 常量配置的方式

  • 在struts.xml文件中通过<constant>元素配置常量最常用
    <!-- i18n:国际化. 解决post提交乱码 -->
    <constant name="struts.i18n.encoding" value="UTF-8"></constant>
    <!-- 指定访问action时的后缀名
    http://localhost:8080/struts2_day01/hello/HelloAction.do
    -->
    <constant name="struts.action.extension" value="action"></constant>
    <!-- 指定struts2是否以开发模式运行
    1.热加载主配置.(不需要重启即可生效)
    2.提供更多错误信息输出,方便开发时的调试
    -->
    <constant name="struts.devMode" value="true"></constant>

    struts.properties文件能配置的常量都可以在struts.xml中用<constant>元素来配置

  • 在struts.properties文件中配置常量

    struts2学习笔记(三)—— struts2的常见配置

  注意:和struts.xml一样,struts.properties文件也应该放在src目录下

  • 在web.xml中通过初始化参数配置常量
    <!-- 配置常量 -->
    <context-param>
    <param-name>struts.i18n.encoding</param-name>
    <param-value>UTF-8</param-value>
    </context-param>

  之前我们介绍过Struts2配置文件的加载顺序(struts.xml>struts.properties>web.xml),后加载的配置文件的常量的值会覆盖先加载的配置文件中常量的值。所以这个地方要注意。

四、分模块开发的配置

  在实际开发中我们更习惯使用struts.xml修改struts2的常量。但是这样就会有一个问题,如果一个项目是团队开发的,也就是很多人开发的,那么团队中的很多人就都需要去修改同一个struts.xml,因为这个文件是Struts2的核心配置文件。而这个文件一旦改错了一点,就会导致整个项目都会出现问题,所以struts2也支持分模块开发的配置,它提供了<include>标签来解决这个问题。

  <include>元素用来在一个struts.xml配置文件中包含其他的配置文件,包含配置体现的是软件工程中的“分而治之”原则。Struts2允许将一个配置文件分解成多个配置文件,从而提高配置文件的可读性。

  <!-- 包含了3个配置文件 -->
<!-- 不指定路径,默认在src下 -->
<include file="struts-shop.xml"/>
<include file="struts-user.xml"/>
<!-- 配置文件在具体包中 -->
<include file="cn/itcast/action/struts-product.xml"/>

  上面的3个配置文件中,前两个没有指定文件的所在路径,表示该文件在项目的src路径下,如果配置文件在具体的包中,那么引入配置文件时,需要包含文件所在包的路径。

  需要注意的是,每一个被包含的配置文件都是标准的Struts2配置文件,一样包含DTD信息、Struts2配置文件的根元素信息等。通过将Struts2的所有配置文件都放在web项目的WEB-INF/classes路径下,struts.xml文件包含了其他的配置文件,在Struts2框架自动加载struts.xml文件时,完成加载所有的配置信息。

五、Action类的配置

  在Struts2的应用开发中,Action作为框架的核心类,实现对用户请求的处理,Action类被称为业务逻辑控制器。一个Action类代表一次请求或调用,每个请求的动作都对应一个响应的Action类,一个Action类是一个独立的工作单元。也就是说,用户的每次请求,都会转到一个响应的Action类里面,由这个Action类来进行处理。简而言之,Action就是用来处理一次用户请求的对象

5.1 Action的编写方式

【Action是一个POJO类】

  在Struts2中,Action可以不继承特殊的类或不实现任何特殊的接口,仅仅是一个POJO。POJO全称Plain Ordinary Java Object(简单的Java对象),只要具有一部分getter/setter方法的那种类,就可以称作POJO。一般在这个POJO类中,要有一个公共的无参的构造方法(采用默认的构造方法就可以)和一个execute()方法。定义格式如下:

public class ActionDemo1 {

    public String execute() {
System.out.println("ActionDemo1执行了。。。");
return null;
}
}

  execute()方法的要求如下:

    • 方法的权限修饰符为public
    • 返回一个字符串,就是指示的下一个页面的Result
    • 方法没有参数

  也就是说,满足上述要求的POJO都可算作是Struts2的Action实现。

【Action类实现一个Action的接口】 

  为了让用户开发的Action类更规范,Struts2提供一个Action接口,用户在实现Action控制类时,可以实现Struts2提供的这个Action接口。

  Action接口定义了Struts的Action处理类应该实现的规范,Action接口中的具体代码如下所示。

public class ActionDemo2 implements Action{

    public String execute() {
System.out.println("ActionDemo2执行了。。。");
return null;
}
}

  从上述代码中可以看出,Action接口位于com.opensymphony.xwork2包中。这个接口里只定义了一个execute()方法,该方法返回一个字符串。除此之外,该接口还定义了5个字符串常量,它们的作用是统一execute()方法的返回值。

    struts2学习笔记(三)—— struts2的常见配置

  由于Xwork的Action接口简单,为开发者提供的帮助较小,所以在实际开发过程中,Action类很少直接实现Action接口。

【Action类继承ActionSupport类】(推荐)

public class ActionDemo3 extends ActionSupport{

    public String execute() {
System.out.println("ActionDemo3执行了。。。");
return null;
}
}

  ActionSupport类本身实现了Action接口,是Struts2中默认的Action接口实现类,所以继承ActionSupport就相当于实现了Action接口。ActionSupport类还实现了Validateable、ValidationAware、TextProvider、LocaleProvider和Serializable等接口,为用户提供更多的功能。

  ActionSupport类提供了许多默认方法,这些默认方法包括获取国际化信息的方法、数据校验的方法、默认的处理用户请求的方法等。实际上,ActionSupport类是Struts2默认的Action处理类,如果让开发者的Action类继承该ActionSupport类,则会大大简化Action的开发。

5.2 Action的访问

  Action的访问不是难题,因为之前已经访问过了,但是出现一个问题:一次请求现在对应一个Action,那么如果请求很多就会对应多个Action。现在要处理的问题就是要让一个模块的操作提交到一个Action中。我们可以通过<action>标签中的method属性来指定Action中某个方法的执行。

【方式一:通过配置method属性完成】

  • 编写页面:
    <h2>客户的管理</h2>
    <a href="${pageContext.request.contextPath }/saveCustomerAction.action">添加客户</a><br>
    <a href="${pageContext.request.contextPath }/updateCustomerAction.action">修改客户</a><br>
    <a href="${pageContext.request.contextPath }/deleteCustomerAction.action">删除客户</a><br>
    <a href="${pageContext.request.contextPath }/findCustomerAction.action">查询客户</a><br>
  • 编写Action:
    public class CustomerAction extends ActionSupport{
    public String save(){
    System.out.println("CustomerAction中的save方法执行了...");
    return NONE;
    } public String delete(){
    System.out.println("CustomerAction中的delete方法执行了...");
    return NONE;
    }
    public String update(){
    System.out.println("CustomerAction中的update方法执行了...");
    return NONE;
    }
    public String find(){
    System.out.println("CustomerAction中的find方法执行了...");
    return NONE;
    }
    }
  • 配置Action:
    <package name="demo3" namespace="/" extends="struts-default">
    <action name="saveCustomerAction" class="cn.itcast.struts2.action.CustomerAction" method="save"></action>
      <action name="deleteCustomerAction" class="cn.itcast.struts2.action.CustomerAction" method="delete"></action>
    <action name="updateCustomerAction" class="cn.itcast.struts2.action.CustomerAction" method="update"></action>
    <action name="findCustomerAction" class="cn.itcast.struts2.action.CustomerAction" method="find"></action>
    </package>

    但是这种方法我们发现,同一个Action类被配置了很多次,只是修改了后面的method的值。那么能不能配置简单化呢?也就是一个Action类,只配置一次就好?这个时候我们就需要使用通配符的配置方式了。

【方式二:通过通配符的配置完成】(开发中常用)

  • 编写页面
    <h2>联系人的管理</h2>
    <a href="${pageContext.request.contextPath }/linkMan_save.action">添加联系人</a><br>
    <a href="${pageContext.request.contextPath }/linkMan_update.action">修改联系人</a><br>
    <a href="${pageContext.request.contextPath }/linkMan_delete.action">删除联系人</a><br>
    <a href="${pageContext.request.contextPath }/linkMan_find.action">查询联系人</a><br>
  • 编写Action
    public class LinkManAction extends ActionSupport {
    public String save(){
    System.out.println("保存联系人...");
    return NONE;
    } public String delete(){
    System.out.println("删除联系人...");
    return NONE;
    } public String update(){
    System.out.println("修改联系人...");
    return NONE;
    } public String find(){
    System.out.println("查询联系人...");
    return NONE;
    }
    }
  • 配置Action
    <!-- 通配符的配置 -->
    <action name="linkman_*" class="cn.itcast.struts2.action.LinkManAction" method="{1}"></action>

  在<action>的name属性中使用的*代表任意字符,method中的{1}代表name属性中出现的第一个*所代替的字符。

  这个时候我们就只配置一个就可以了,在上述代码中,当客户端发送/linkman_save.action这样的请求时,action元素的name属性就被设置成linkman_save,method属性就被设置成save。当客户端发送/linkman_update.action这样的请求是,action元素的name属性就被设置为linkman_update,method属性也被设置成update。

【方式三:动态方法访问】(了解)

  动态方法访问在Struts2中默认是不开启的,如果想要使用,需要先去struts.xml中开启一个常量。

<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

  动态方法访问主要的控制是在页面端,所以编写Action和配置Action都很简单,关键是访问路径的编写。

  • 编写Action
    public class UserAction extends ActionSupport {
    public String save(){
    System.out.println("保存用户...");
    return NONE;
    } public String delete(){
    System.out.println("删除用户...");
    return NONE;
    } public String update(){
    System.out.println("修改用户...");
    return NONE;
    } public String find(){
    System.out.println("查询用户...");
    return NONE;
    }
    }
  • 配置Action
    <!-- 动态方法访问的配置 -->
    <action name="userAction" class="cn.itcast.struts2.action.UserAction"></action>
  • 页面路径的写法
    <h2>用户的管理</h2>
    <a href="${pageContext.request.contextPath }/userAction!save.action">添加用户</a><br>
    <a href="${pageContext.request.contextPath }/userAction!update.action">修改用户</a><br>
    <a href="${pageContext.request.contextPath }/userAction!delete.action">删除用户</a><br>
    <a href="${pageContext.request.contextPath }/userAction!find.action">查询用户</a><br>