深入了解Struts2

    |     2016年12月28日   |   struts2   |     0 条评论   |    1688

把 Struts2 用熟练,日常围着两份文件转:struts.properties 管常量,struts.xml 管 package / action / result。这两份读明白,动态方法调用和参数绑定才不会晕。

下面按原笔记往下走:核心文件 → Action 按命名空间往上搜的顺序 → 三种动态方法调用 → 三种收参数方式。

一、struts 核心文件

1. struts.properties 常量

开发期常用的常量可以写在 struts.properties,也可以用 <constant> 写进 struts.xml,效果一样。

#是否开启开发模式
struts.devMode=true
#所有匹配 *.action 的请求都由 struts2 处理
struts.action.extension=do
#struts 配置文件改动后,是否重新加载
struts.configuration.xml.reload=true
#请求参数的编码方式
struts.i18n.encoding=UTF-8
#每次 HTTP 请求系统都重新加载资源文件,有助于开发
struts.i18n.reload=true
#文件上传最大值
struts.multipart.maxSize=102400
#设置上传文件临时目录
struts.multipart.saveDir=d:/temp
#让 struts2 支持动态方法调用
struts.enable.DynamicMethodInvocation=true
#允许标签中使用表达式语法
struts.tag.altSyntax=true

2. struts.xml 核心结构

<?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="packageName" namespace="/test" extends="struts-default">
        <action name="actionName" class="com.ittx.struts.action.UserAction" method="methodName">
            <result>/sucess.jsp</result>
            <result name="ADD">/result.jsp</result>
        </action>
    </package>
</struts>
标签 作用 关键属性
package 把多个 Action 组织成一个模块 name、extends、namespace。namespace=/test 时访问地址是 http://localhost:8080/struts2/test/actionName.action
action 定义访问名、类、方法及返回页 name、class、method
result 指定响应类型和响应页面 name 对应 Action 返回值;type 不写则用父 package 默认 dispatcher

更完整的 struts.xml 示例(include、拦截器栈、全局 result、param):

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
    <!-- include 是组件化方式:每个功能模块独立 xml,再用 include 引用 -->
    <include file="struts-default.xml"></include>

    <!--
        package 的名字必须唯一;可以 extends 父 package,父 package 必须写在子 package 前面
        abstract=true 时不能定义 action
        namespace 影响 URL,例如 /test 对应 http://localhost:8080/struts2/test/XX.action
    -->
    <package name="com.kay.struts2" extends="struts-default" namespace="/test">
        <interceptors>
            <interceptor name="timer" class="com.kay.timer"></interceptor>
            <interceptor name="logger" class="com.kay.logger"></interceptor>
            <interceptor-stack name="mystack">
                <interceptor-ref name="timer"></interceptor-ref>
                <interceptor-ref name="logger"></interceptor-ref>
            </interceptor-stack>
        </interceptors>

        <!-- 默认拦截器:每个 Action 自动引用;Action 里若另引拦截器,默认拦截器失效 -->
        <default-interceptor-ref name="mystack"></default-interceptor-ref>

        <global-results>
            <result name="input">/error.jsp</result>
        </global-results>

        <!-- 一个 Action 可多次映射,只要 name 不同 -->
        <action name="hello" class="com.kay.struts2.Action.LoginAction">
            <interceptor-ref name="timer"></interceptor-ref>
            <result name="success" type="dispatcher">/talk.jsp</result>
            <!-- name 对应 Action 中的 get/set -->
            <param name="url">http://www.sina.com</param>
        </action>
    </package>
</struts>

二、Action 搜索顺序

新建项目命名为 struts2,按下面配置一个 Action:

<package name="hello" namespace="/test" extends="struts-default">
    <action name="helloworld" class="com.ittx.struts.action.HelloWorldAction" method="execute">
        <result name="success">/hello.jsp</result>
    </action>
</package>

部署后访问 http://localhost:8080/struts2/test/sdf/dsf/32/d/helloworld.action 依然能打到这个 Action。Struts2 会按命名空间逐级往上截来搜:

  • 先找 namespace 为 /test/sdf/dsf/32/d 的包里有没有 helloworld
  • 再找 /test/sdf/dsf/32
  • 再找 /test/sdf/dsf
  • 再找 /test/sdf
  • 再找 /test —— 这里能搜到,于是命中

如果一路截完都不存在,就会到 namespace 为 ""(默认命名空间)的包里继续找 helloworld。

三、动态方法调用

一个 Action 要对应多个请求时,不必拆成一堆 Action 类。动态方法调用常见三种:method 属性、感叹号 !、通配符。

第一种:Action 的 method 属性

在 Action 里加 add()、update(),再在 xml 里用 method 指过去:

public class UserAction extends ActionSupport {
    public String add() {
        log.debug("执行add添加用户操作 >>>>>>");
        return "ADD";
    }

    public String update() {
        log.debug("执行update用户操作 >>>>>>");
        return "UPDATE";
    }
}
<action name="userAdd" class="com.ittx.strutsproject.action.UserAction" method="add">
    <result name="ADD">/add_student.jsp</result>
</action>
<action name="userUpdate" class="com.ittx.strutsproject.action.UserAction" method="update">
    <result name="UPDATE">/update_student.jsp</result>
</action>
  • 添加:http://localhost:8080/struts2/userAdd.action
  • 修改:http://localhost:8080/struts2/userUpdate.action

第二种:感叹号方式 !

方法不多时,method 属性还好写。若有上百个方法,xml 会膨胀。这时可以用 actionName!methodName:

<action name="user" class="com.ittx.strutsproject.action.UserAction">
    <result>/sucess.jsp</result>
    <result name="ADD">/add_student.jsp</result>
    <result name="UPDATE">/update_student.jsp</result>
</action>
  • 添加:http://localhost:8080/struts2/user!add.action
  • 修改:http://localhost:8080/struts2/user!update.action

必须开启动态方法调用。Struts 2.5 还要在 package 下放开方法:

<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<!-- Struts 2.5 感叹号 / 通配符无效时,在 package 下加: -->
<global-allowed-methods>regex:.*</global-allowed-methods>

第三种:通配符方式

<package name="student" namespace="/student" extends="struts-default">
    <!-- 解决 struts2.5 通配符调用无效 -->
    <global-allowed-methods>regex:.*</global-allowed-methods>
    <action name="user_*" class="com.ittx.strutsproject.action.UserAction" method="{1}">
        <result>/sucess.jsp</result>
        <result name="ADD">/add_student.jsp</result>
        <result name="UPDATE">/update_student.jsp</result>
    </action>
</package>
  • 添加:http://localhost:8080/struts2/user_add.action
  • 修改:http://localhost:8080/struts2/user_update.action

user_* 里的 {1} 会替换成第一段通配内容,于是 user_add 调 add()。

四、struts2 接收参数的几种形式

1. 用 Action 的属性

在 Action 里定义要接收的字段,提供 setter / getter,名称和提交参数一致,不用自己做类型转换。GET、POST 都可以,例如 testAction?name=admin。

<form action="./user_add.do" method="post">
    姓名:<input type="text" name="username"/><br>
    密码:<input type="text" name="password"/><br>
    <input type="submit" value="提交"/><br>
</form>
public class TestAction extends ActionSupport {
    private String username;
    private String password;

    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}

2. 使用 DomainModel

Action 里不必堆很多属性,改为持有一个 Model 对象。表单字段写成 对象名.属性名。注意:不要自己 new,Struts 会自动实例化。

<form action="./user_add.do" method="post">
    姓名:<input type="text" name="user.username"/><br>
    密码:<input type="text" name="user.password"/><br>
    <input type="submit" value="提交"/><br>
</form>
public class TestAction extends ActionSupport {
    // 错误写法:不能自己实例化,struts 会自动实例化
    // private Users users = new Users();
    private Users users;
    public Users getUsers() { return users; }
    public void setUsers(Users users) { this.users = users; }
}
public class User {
    private String username;
    private String password;
    public String getUsername() { return username; }
    public void setUsername(String username) { this.username = username; }
    public String getPassword() { return password; }
    public void setPassword(String password) { this.password = password; }
}

3. 使用 ModelDriven

Action 实现 ModelDriven,框架调用 getModel() 拿到对象。表单字段名直接写属性名,不必加对象前缀。这里要手动 new 模型。

<form action="./user_add.do" method="post">
    姓名:<input type="text" name="username"/><br>
    密码:<input type="text" name="password"/><br>
    <input type="submit" value="提交"/><br>
</form>
public class sysAction extends ActionSupport implements ModelDriven<User> {
    private User user = new User(); // 手动实例化

    public User getModel() {
        return user; // 返回实例
    }
}

一句话总结:struts.xml 把 URL 指到 Action;动态方法优先用通配符 user_* + method=”{1}”;收参数三种:Action 属性、DomainModel(别自己 new)、ModelDriven(要自己 new)。

转载请注明来源:深入了解Struts2
本文链接地址:https://ai.zhousir.top/?p=1846

上一篇:

下一篇:

回复 取消