四、Struts程序详解

从上一节课的第一个Struts程序的执行过程可知:Struts 的中心控制器接受所有来自客户端的请求,并根据系统的配置(struts.xml)路由HTTP请求到其它Action对象。在这些Action对象中会完成所有的业务操作,比如用户登录验证等。处理完毕后,由再由Struts的Controller Servlet根据配置转向到适当的JSP页面,将处理结果显示给用户。
因此,这过程中有两个节点是非常重要的:
一个是:struts.xml的配置文件;
另一个:Action控制类实现业务;
因此,我们本章重点来说说这两个部分。并通过例子,实现一个基于MVC模式的用户登录功能。

  • 1.struts.xml
    1.1.标签:定义常量;(建议:在struts.xml中定义常量)
    1.2.标签:使用包配置来声明Action和拦截器;
    1.3.标签:按功能拆分structs.xml配置文件;
  • 2.Action控制类的实现
    2.1.action控制器的实现(建议:继承ActionSupport类)
    2.2.action控制器在structs.xml中的声明;
    2.5.action返回的结果类型(dispatcher表示转发到;redirect表示重定向到)
    2.3.action访问Servlet API(即:获取上下文数据)(建议:通过ActionContext类访问Servlet)
    2.4.action如何从View中获取参数
  • 3.案例:基于MVC模式的用户登录功能实现

1.struts.xml配置文件

struts.xml是Struts2的核心配置文件,主要用来配置Action和请求的对应关系,以及配置逻辑视图和物理视图资源的对应关系。
通常放在项目的WEB-INF/classes目录下,可以被Struts2框架自动加载。

1.1.定义常量

在写程序时,有些变量是基本不会变且需要经常使用,此时我们就把它们统一成为常量,方便项目中的各个地方使用,例如:链接字符串、PI值等。
在Struts中要定义常量有三种方法,具体如下:

  • [v] 在struts.xml文件中,通过元素来配置常量;
  • [ ] 在struts.properties文件中,通过key-value键值对配置常量;
  • [ ] 在web.xml文件中,通过元素的子元素指定一个Struts2常量。

1.2.包配置

Struts框架的核心组件是由Action和拦截器组成,为了有效和组织管理,Struts引入了包配置标签来进行声明和管理所有的Action和拦截器。
其主要的属性如下:

标签的主要属性

1.3.包含配置

由于Struts框架是通过配置文件的形式来定义路由,一旦项目规模较大,所涉及对象就会很多,为了更好的进行组织和管理这些路由,Struts允许把配置文件进行拆分,即:将一个配置文件按业务或模块可分解成多个配置文件。
但Struts2默认只加载WEB-INF/classes下的struts.xml文件,因此,我们需要在struts.xml文件中通过标签引入所有子配置文件。如下图所示:

分解成多个配置文件

2.Action控制类

2.1.Action控制类的实现方式

Action实现对用户请求的处理,因此也被称为:业务逻辑控制器
在Struts2中,提供了3种方式实现Action控制类:

方式一:POJO(自定义简单的Java对象)

  • POJO,直接自定义一个简单的Java对象进行实现,这是最原始的方式。编写Action类需要提供getter/getter方法和公共的默认无参数构造方法以及一个execute()方法。

方式二:实现Action接口

  • 实现Action接口,通过编写Action类实现Action接口,复写execute()方法。Action接口定义了5个字符串常量,它的作用是统一excecute()方法的返回值。

方式三:继承ActionSupport类 (推荐)

  • 实现Action接口,通过继承ActionSupport类,重写execute()方法。ActionSupport实现Action等多个接口。所以提供了许多默认的方法,如国际化、数据校验、参数封装等。
import com.opensymphony.xwork2.ActionSupport;

public class UserLoginAction extends ActionSupport {
public String execute() throws Exception {
            return super.execute();
        }
    }
}

2.2.action控制器在structs.xml中的声明;

实现了Action后,就要告诉Web项目,怎么样的请求该丢给哪个Action来处理,这就是需要Struts.xml中对Action进行配置声明了。
配置Action映射将一个请求的URL映射到一个Action类,即把一个URL请求对应到一个Action类,以便在Action类中实现请求的业务处理。
在struts.xml文件中,通过标签进行声明,其属性如下:

标签的主要属性

struts.xml的例子::




    
    
    
    
    
    
        
        
            
            /success.jsp
            /error.jsp
        
        
            /message.jsp
        
        
            /message.jsp
        
    

2.5.action返回的结果类型

在struts.xml文件中,使用元素来配置Result逻辑视图与物理视图之间的映射。例如:


     
            /success.jsp
     

也可简化为:


     /success.jsp

注意:在Result配置中,
使用绝对地址:使用斜杠 / 开头,例如:/success.jsp,表示当前Web项目的上下文路径。
使用相对地址:不使用 / 开头,例如:success.jsp,表示当前Action同级目录下的。
Struts2中预定义了一些常用的ResultType,如下图所示:

Struts2中预定义的ResultType类型

其中,
dispatcher结果类型用于表示转发,因此在用户的整个请求/响应过程中,都会保持是同一个请求对象。反映为:URL地址不跳转到JSP页面。
redirect结果类型用于重定向到指定的结果资源(可以是JSP,也可以是另一个Action)。反映为:URL地址跳转到新的URL上。

2.3.action访问Servlet API(即:获取上下文数据)

在Struts2中,Action不直接访问Servlet API,这为前后端解耦合,实现分工带来很大好处,例如:前后段独立开发,可以对单个Action进行单元测试等。

如果想获取上下文数据(例如:Session),那该如何处理呢?

方法一:通过ActionContext上下文对象(推荐)

通过实例化ActionContext对象,可以实现包括parameter、request、session、application的获取。其常用方法如下图所示:


ActionContext上下文对象常用方法

例如,使用ActionContext对象向请求request、session、Application中都分别写入一个name参数,代码如下:

import com.opensymphony.xwork2.ActionContext;
public class UserLoginAction extends ActionSupport {
    public String execute() throws Exception {
        //获取Context对象
        ActionContext context = ActionContext.getContext();
        //将姓名name作为参数写入request请求中
        context.put("name", "用户1");
        //将姓名name作为参数写入session中
        context.getSession().put("name", "用户1");
        //将姓名name作为参数写入Application中
        context.getApplication().put("name", "用户1");
        return 0;
    }
}

方法二:实现特定接口,从而获取Servlet API的实例

Struts2中还提供了一系列接口,通过实现这些接口从而获取Servlet API实例,如:

(1)ServletRequestAware:实现该接口的Action可以直接访问Web应用的HttpServletRequest实例。
(2)ServletResponseAware:实现该接口的Action可以直接访问Web应用的HttpServletResponse实例。
(3)SessionAware:实现该接口的Action可以直接访问Web应用的HttpSession实例。
(4)ServletContextAware:实现该接口的Action可以直接访问Web应用的ServletContext实例。

方法三:ServletActionContext类的静态方法直接获取

Struts2框架还提供了ServletActionContext类实现直接访问Servlet API的直接访问,其提供的主要几个静态方法如下:

  • static HttpServletRequest getRequest():获取Web应用的HttpServletRequest对象。
  • static HttpServletResponse getResponse():获取Web应用的HttpServletResponse对象。
  • static ServletContext getServletContext():获取Web应用的ServletContext对象。
  • static PageContext getPageContext():获取Web应用的PageContext对象。

2.4.action如何从View中获取参数

JSP页面发送请求,经过struts.xml中的配置信息,把URL映射到对应的Action对象中进行处理。

那么Action对象如何获取从JSP页面中传来的参数呢?
Struts框架为我们提供了两种方式获取JSP页面传来的参数:

方法一:字段驱动(属性驱动)的方式:

在Action类定义时,在其内部定义与JSP页面参数对应的名称的属性成员。当请求匹配到该Action时,会自动把JSP页面参数自动匹配到对应名称的属性成员中。因此,属性成员的数据类型必须与JSP页面参数的数据类型一致。例如:

import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
    //与表单中传输参数同名的username
    private String username;   
    //与表单中传输参数同名的password
    private String password;
    @Override
    public String execute() throws Exception {
        return 0;
    }
}

方法二(改良版):JavaBean驱动

既然Action中的属性成员与JSP页面中的传输参数一一对应,能否再进一步,把这些对应的数据封装称为一个实体类对象,专门用来作为传输数据的载体,这就是属性驱动的改良版——JavaBean驱动。

以JavaBean来实现,所封装的属性和表单的属性一一对应,JavaBean将成为数据传递的载体来进行数据的传递。
跟上面方法一一样,我们需要传输登录时用户所输入的用户名username和密码password两个参数,为此我们定义一个实体类对象User,专门用于存储传输的数据。具体如下:
User实体类:

package cn.demo.domain;
public class User {
    private String username;
    private String password;
    // username的getter和setter方法
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    // password的getter和setter方法
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

Action中访问实体类对象,从而获取页面传来的数据:

import cn.demo.domain.User;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
public class UserLoginAction extends ActionSupport {
    private User user; //定义User实体类对象
    // user属性的getter和setter方法
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
    public String execute() throws Exception {
        //获取Context对象
        ActionContext context = ActionContext.getContext();
        if ("itcast".equals(user.getUsername())
                && "123".equals(user.getPassword())) {
            //将用户名和密码放入session中
            context.getSession().put("username", user.getUsername());
            context.getSession().put("password", user.getPassword());
            return SUCCESS;
        } else {
            context.getSession().put("error", "用户登录失败!");
            return ERROR;
        }
    }
}

方法三:模型驱动(通过接口,实现泛化的模型)

实现ModelDriven接口来接收请求参数,Action类必须实现ModelDriven接口,并且要重写getModel()方法,这个方法返回的就是Action所使用的数据模型对象。
模型驱动方式通过JavaBean模型进行数据传递。只要是普通的JavaBean,就可以充当模型部分。
采用这种方式,JavaBean所封装的属性与表单的属性一一对应,JavaBean将成为数据传递的载体。Action类通过get()的方法来获取模型,其中“”代表具体的模型对象。


作者: 肖sir@ZHBIT
2018 年 09月 27日


你可能感兴趣的:(四、Struts程序详解)