Struts2使用重点笔记

Struts2使用笔记

  • 配置文件的加载顺序

    struts.xml -> struts.properties -> web.xml

    这三个文件都是可以修改 struts2常量的值,但是后面的重复的值会覆盖前面的值

  • 在上面三个文件中都是可以配置常量值的

  • 通常在struts.xml中配置常量或者其他的Action,项目比较大时,难免臃肿,此时可以使用include标签来引入其他的xml配置文件,其格式遵循struts.xml文件的格式

  • 在struts.xml中配置action的三种方式:

    • 指定method

    • 通过通配符”*”匹配

    • 动态方法访问,注意:struts2.5以后默认关闭,需要配置打开,同时在package中配置

      1
      <global-allowed-methods>regex:.*</global-allowed-methods>


  • 结果页面配置

    • 局部结果页面配置

      1
      2
      3
      4
      5
      6
      7
      8
      <action name="user_*" class="com.lee.struts2test.UserController" method="{1}">
      <result name="login_success">
      /index.jsp
      </result>
      <result name="regist_success">
      /login.jsp
      </result>
      </action>

      是在action中配置

    • 全局结果页面配置

      全局结果页面展示必须放在局部的action标签之前

    • result标签中的type属性

      • dispatcher:转发,默认
      • redirect:重定向
  • Action中常用的两个类

    • ActionContext
    • ServletActionContext
  • ServletRequestAware接口,在方法中获取HttpServletRequest对象

  • 表单数据的封装

    • 原始方法,得到request中的参数
    • 属性封装
      • 提供Entity中的属性和get/set方法,Action会自动调用给属性赋值(获取表单数据到成员变量里面,不能把数据直接封装到实体类里面)
      • 表达式封装,在页面通过使用user.userName分方式来设置表单的name属性(在Action中必须提供get方法,返回user为属性名的一个实体)
    • 模型驱动封装
      • 可以直接把表单数据封装到实体类里面,一个Action类中只能有一个实体类对象
  • 使用表达式封装,可以将数据封装到List或者Map中

1.配置的时候,Intellij自动生成了全局过滤器

1
2
3
4
5
6
7
8
<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>

其中

1
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter

爆红,原来如果jar包确认没问题的话,检查你的Struts2版本,如果是2.5版本以上的话,将.ng去掉,我的是2.5.14.1,修改成

1
2
3
4
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>

2.使用通配符”*”配置struts.xml中的action访问路径的时候,运行时出现异常,action映射的方法没有找到,解决办法:**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<action name="customer_*" class="com.lee.crm.customer.action.CustomerAction" method="{1}">
<!--添加客户-->
<result name="add_success">/jsp/success.jsp</result>
<result name="add_error">/jsp/customer/add.jsp</result>

<!--客户列表-->
<result name="list_success">/jsp/customer/list.jsp</result>
<result name="list_error">/jsp/error.jsp</result>
<!--更新客户-->
<result name="update_success">/jsp/customer/add.jsp</result>
<result name="update_error">/jsp/error.jsp</result>

<!--使用通配符匹配的时候,加上这一句-->
<allowed-methods>add,list,update</allowed-methods>
</action>

加上<allowed-methods>add,list,update</allowed-methods>

3.使用模型驱动封装表单数据,在需要对表单对应的实体进行更新的时候**

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class CustomerAction extends ActionSupport implements ModelDriven<Customer> {
private Customer customer = new Customer();
@Override
public Customer getModel() {
return customer;
}

public String preUpdate() {
// 获取custid
String custId = ServletActionContext.getRequest().getParameter("custId");
Customer customer = mCustomerService.findCustomerById(Long.parseLong(custId));

// 将customer对象设置到值栈中,更新model对象,回显
this.customer = customer;
// ActionContext.getContext().getValueStack().push(this.customer);
return "pre_update_success";
}
}

发现从ValueStack中获取的值依然是更新之前的值.这是由于action中的customer的确是更新了,但是valuestack中的值依然是旧值,而在页面中通过<s:property value='custId' />获取的也是旧值

解决办法有多种,这里介绍两种常用的方法:

  • 第一种:

    ActionContext.getContext().getValueStack().push(this.customer);

    将新的值压入栈顶,页面获取的就是新的对象的值了

  • 第二种:

    在相应的action标签中加入

    1
    2
    3
    4
    5
    6
    7
    8
    <action name="customer_*" class="com.lee.crm.customer.action.CustomerAction" method="{1}">

    <interceptor-ref name="defaultStack">
    <!-- 渲染页面前刷新model在ValueStack的root的引用 -->
    <!--这样在valuestack中会自动压入一个新的值,跟手动调用push方法是一样的-->
    <param name="modelDriven.refreshModelBeforeResult">true</param>
    </interceptor-ref>
    </action>

    同时在action中给对象赋上新的值

    1
    this.customer = customer;

4.ValueStack压入的对象是以对象的属性名作为key,属性值作为value存贮在map中的,所以在页面中取值的时候直接通过Property Name取值,具体可以多用用<s:debug><s:debug>标签看看Value Stack Contents中值的存放形式

  1. 在使用struts.xml文件时,经常因为格式导致不必要的错误。
    例:

    1
    2
    3
    4
    5
    <package name="default" extends="struts-default" namespace="/namespace1">
    <action name="initFStree" class="InitFStree">
    <result name="success">pages/initFStree.jsp</result>
    </action>
    </package>

5.struts2中%# 的使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
%和$符号在OGNL表达式中经常出现.

1.#符号的用途一般有三种。

1) 访问非根对象属性,例如示例中的#session.msg表达式,由于Struts 2中值栈被视为根对象,所以访问其他非根对象时,需要加#前缀。实际上,#相当于ActionContext. getContext();#session.msg表达式相当于ActionContext.getContext().getSession(). getAttribute(”msg”).

2) 用于过滤和投影(projecting)集合,如示例中的persons.{?#this.age>20}。

3) 用来构造Map,例如示例中的#{’foo1′:’bar1′, ’foo2′:’bar2′}。



2.%符号

1. %符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。如下面的代码所示:

构造Map

<s:set name=”foobar” value=”#{’foo1′:’bar1′,foo2:bar2′}” />

The value of key “foo1″ is <s:property value=”#foobar['foo1']” />

不使用%:<s:url value=”#foobar['foo1']” />

使用%:<s:url value=”%{#foobar['foo1']}” />说明:

"在标志的属性为字符串类型时":

如标志:s:url的属性value,其类型是字符串类型.

如标志:s:property的属性value,其类型是对象.

所以:

<s:url value=”%{#foobar['foo1']}” /> -->要使用%

否则,会直接显示成:#foobar['foo1']



<s:property value="#foobar['foo1']" /> -->不用使用% (3)

1. $符号:

$符号主要有两个方面的用途。

2.1

在国际化资源文件中,引用OGNL表达式.

在资源文件的国际化字符串中使用OGNL,格式为${表达式},例如:

validation.require=${getText(fileName)} is required在显示这些国际化字符时,同样有两种方法设置参数的值:

1. 使用标志的value0、value1...valueN的属性,如:
<s:text name="validation.required" value0="User Name"/>
2. 使用param子元素,这些param将按先后顺序,代入到国际化字符串的参数中,例如:
<s:text name="validation.required">
<s:param value="User Name"/>
/s:text2.2
在Struts 2框架的各种配置文件(validation.xml或struts.xml)中引用OGNL表达式,例如下面的代码片断所示:<validators>
<field name=”intb”>
<field-validator type=”int”>
<param name=”min”>10</param>
<param name=”max”>100</param>
<message>BAction-test校验:数字必须为{min}为{max}之间!</message> //其值则上面的参数
</field-validator>
</field>
</validators> (4) <h2><s:text name="HelloWorld"/></h2>
<h2><s:property value="%{getText('HelloWorld')}"/></h2>
上面的例子用了两种方法来显示国际化字符串,其输出是相同的。其实,这就是Struts 2.0的一个优势,因为它默认支持EL,所示我们可以用getText方法来简洁地取得国际化字符串。另外更普遍的情况——在使用UI表单标志时, getText可以用来设置label属性,例如:
<s:textfield name="name" label="%{getText('UserName')}"/> 即:<s:text name="HelloWorld"/>相当于:%{getText('UserName')}