Struts2入门第三讲——Struts2访问Servlet的API
发布日期:2021-06-30 18:00:18 浏览次数:4 分类:技术文章

本文共 11663 字,大约阅读时间需要 38 分钟。

前言:不知你有没想过这个问题,如果表单中有参数,那么如何接收这些参数呢?又或者我们需要向页面传递过去一些数据,要该如何完成呢?这些问题都涉及到了在Struts2的Action中访问Servlet API,本讲将是围绕这个问题而展开的。

在使用Struts2框架的过程中,发现Action并没有直接和Servlet API进行耦合,也就是说在Struts2的Action中不能直接访问Servlet API。但是,在实际开发中,又要经常使用到Servlet的API,比如进行登录时,要将用户的信息保存到Session中,或者使用response对象向页面输出一些内容的时候,这都涉及到要在Struts2中访问Servlet的API。虽然Struts2中的Action访问Servlet API麻烦一些,但是这却是Struts2中Action的重要改良之一,因为这能方便Action进行单元测试。

尽管Action和Servlet API解耦会带来很多好处,然而在Action中完全不访问Servlet API几乎是不可能的,在实现业务逻辑时,经常要访问Servlet中的对象,如session、request以及application等。在Struts2中,访问Servlet API有三种方式,下面我会一一介绍。

通过ActionContext类访问

Struts2框架提供了ActionContext类来访问Servlet API,ActionContext是Action执行的上下文对象,在ActionContext中保存了Action执行所需要的所有对象,包括parameters,request,session以及application等。下面列举了ActionContext类访问Servlet API的几个常用方法。

在这里插入图片描述
要在Action中访问Servlet API,可以通过如下方式进行。
在这里插入图片描述
在上述示例代码中,通过ActionContext类中的方法调用,分别在request、application和session中放入了键值对的数据。可以看到,通过ActionContext类可以非常简单地访问JSP内置对象的属性。
为了让大家更好地掌握如何通过ActionContext类来访问Servlet API,接下来通过两个具体的案例来演示ActionContext的使用。

  • 第一个案例。首先,在Eclipse中创建一个名称为struts2_demo02的web项目,将Struts2所需的jar包复制到项目的lin目录中,并发布到类路径下,再在WEB-INF目录下的web.xml文件中配置好Struts2的核心控制器。

    在这里插入图片描述
    然后,在WebContent目录下新建一个demo01目录,在该目录中创建一个简单的demo01.jsp页面。

    <%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%>
    Insert title here

    Struts2访问Servlet的API

    方式一:完全解耦合的方式

    姓名:
    密码:

    接着,在src目录下新建一个com.meimeixia.struts2.demo01包,并在该包中创建一个Action类(RequestDemo01.java),进行业务逻辑处理,如下所示:

    package com.meimeixia.struts2.demo01;import java.util.Arrays;import java.util.Map;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 访问Servlet的API方式一:完全解耦合的方式 * @author liayun * */public class RequestDemo01 extends ActionSupport {
    @Override public String execute() throws Exception {
    //一、接收参数 //利用Struts2中的对象——ActionContext对象 ActionContext context = ActionContext.getContext(); //调用ActionContext对象中的方法 //这个方法有点类似于Map
    request.getParameterMap(); Map
    map = context.getParameters(); for (String key : map.keySet()) {
    String[] values = (String[]) map.get(key); System.out.println(key + "\t" + Arrays.toString(values)); } return SUCCESS; }}

    紧接着,就要在struts.xml文件中配置以上Action类了,这里我们采用Struts2中分模块开发的配置。

    • struts.xml

    • struts-demo01.xml

      /demo01/demo02.jsp

      看来,咱又得在WebContent/demo01目录下新建一个demo02.jsp页面了,内容简简单单就好。

      <%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%>
      Insert title here

      成功跳转的页面,在这个页面显示数据

    最后 ,运行效果如下图所示。

    在这里插入图片描述
    可以发现使用表单post方式提交,在Struts2框架的Action中获取数据时不会有乱码问题,这是因为Struts2框架有一个常量设置,如下:
    在这里插入图片描述
    至于若采用表单的get方式提交,你也只能手动解决了。

  • 第二个案例。如果我们想要在页面跳转的时候,向demo02.jsp页面传递过去一些数据并显示,那么又该如何完成呢?可以将RequestDemo01类中的代码修改成下面的样子。

    package com.meimeixia.struts2.demo01;import java.util.Arrays;import java.util.Map;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 访问Servlet的API方式一:完全解耦合的方式 * @author liayun * */public class RequestDemo01 extends ActionSupport {
    @Override public String execute() throws Exception {
    //一、接收参数 //利用Struts2中的对象——ActionContext对象 ActionContext context = ActionContext.getContext(); //调用ActionContext对象中的方法 //这个方法有点类似于Map
    request.getParameterMap(); Map
    map = context.getParameters(); for (String key : map.keySet()) {
    String[] values = (String[]) map.get(key); System.out.println(key + "\t" + Arrays.toString(values)); } //二、向域对象中存入数据 context.put("reqName", "reqValue");//相当于调用了request.setAttribute("reqName", "reqValue"); context.getSession().put("sessName", "sessValue");//相当于调用了session.setAttribute("reqName", "reqValue"); context.getApplication().put("appName", "appValue");//相当于调用了application.setAttribute("reqName", "reqValue"); return SUCCESS; }}

    然后,修改demo02.jsp页面,在该页面中显示相应的数据。

    <%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%>
    Insert title here

    成功跳转的页面,在这个页面显示数据

    ${reqName }
    ${sessName }
    ${appName }

    最后,运行效果如下图所示。

    在这里插入图片描述

小结

这种方式只能操作request、session、application这些域对象中的数据(也即Map集合),不能操作这些对象本身上的方法,也就是说不能获得request、session、application这些真实对象。

通过ServletActionContext类访问

为了直接访问Servlet API,Struts2框架还提供了ServletActionContext类,该类包含了几个常用的静态方法。

在这里插入图片描述
接下来,我也是通过两个具体的案例来讲解如何通过ServletActionContext访问Servlet API。

  • 第一个案例。首先,将WebContent/demo01目录下的demo01.jsp页面修改成下面这样子。

    在这里插入图片描述
    然后,在com.meimeixia.struts2.demo01包中创建一个Action类(RequestDemo02.java),进行业务逻辑处理,如下所示:

    package com.meimeixia.struts2.demo01;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.catalina.tribes.util.Arrays;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 访问Servlet的API的方式二:原生的方式 * @author liayun * */public class RequestDemo02 extends ActionSupport {
    @Override public String execute() throws Exception {
    //一、接收数据 //直接获得request对象,通过ServletActionContext对象 HttpServletRequest request = ServletActionContext.getRequest(); Map
    map = request.getParameterMap(); for (String key : map.keySet()) {
    String[] values = map.get(key); System.out.println(key + "\t" + Arrays.toString(values)); } return SUCCESS; }}

    接着,就要在struts.xml文件中配置以上Action类了,这里我们采用Struts2中分模块开发的配置。

    • struts.xml

    • struts-demo01.xml

      /demo01/demo02.jsp
      /demo01/demo02.jsp

    最后 ,运行效果如下图所示。

    在这里插入图片描述

  • 第二个案例。如果我们想要在页面跳转的时候,向demo02.jsp页面传递过去一些数据并显示,那么又该如何完成呢?可以将RequestDemo02类中的代码修改成下面的样子。

    package com.meimeixia.struts2.demo01;import java.util.Map;import javax.servlet.http.HttpServletRequest;import org.apache.catalina.tribes.util.Arrays;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 访问Servlet的API的方式二:原生的方式 * @author liayun * */public class RequestDemo02 extends ActionSupport {
    @Override public String execute() throws Exception {
    //一、接收数据 //直接获得request对象,通过ServletActionContext对象 HttpServletRequest request = ServletActionContext.getRequest(); Map
    map = request.getParameterMap(); for (String key : map.keySet()) {
    String[] values = map.get(key); System.out.println(key + "\t" + Arrays.toString(values)); } //二、向域对象中保存数据 //向request中保存数据 request.setAttribute("reqName", "reqValue"); //向session中保存数据 request.getSession().setAttribute("sessName", "sessValue"); //向application中保存数据 ServletActionContext.getServletContext().setAttribute("appName", "appValue"); return SUCCESS; }}

    然后,修改demo02.jsp页面,在该页面中显示相应的数据。

    <%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%>
    Insert title here

    成功跳转的页面,在这个页面显示数据

    ${reqName }
    ${sessName }
    ${appName }

    最后,运行效果如下图所示。

    在这里插入图片描述

小结

这种方式不仅可以操作域对象的数据,而且也可以获得对象的方法,即操作真实对象上的方法。开发者借助于ServletActionContext类的帮助,可以在Action中直接访问Servlet API,避免了Action类实现ServletRequestAware、ServletResponseAware、SessionAware和ServletContextAware等XxxAware接口。虽然如此,该Action依然与Servlet API直接耦合,一样不利于程序解耦。综上,建议在开发中优先使用ActionContext,以避免和Servlet API耦合。

通过特定接口访问

Struts2框架提供了ActionContext类来访问Servlet API,虽然这种方法可以访问Servlet API,但是无法直接获得Servlet API实例。为了在Action中直接访问Servlet API,Struts2还提供了一系列接口。

  • ServletRequestAware:实现该接口的Action可以直接访问web应用的HttpServletRequest实例;
  • ServletResponseAware:实现该接口的Action可以直接访问web应用的HttpServletResponse实例;
  • SessionAware:实现该接口的Action可以直接访问web应用的HttpSession实例;
  • ServletContextAware:实现该接口的Action可以直接访问web应用的ServletContext实例。

接下来,我也是通过两个具体的案例来讲解如何通过这种方式在Action中访问Servlet API。

  • 第一个案例。首先,将WebContent/demo01目录下的demo01.jsp页面修改成下面这样子。

    在这里插入图片描述
    然后,在com.meimeixia.struts2.demo01包中创建一个Action类(RequestDemo03.java),进行业务逻辑处理,如下所示:

    package com.meimeixia.struts2.demo01;import java.util.Arrays;import java.util.Map;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import org.apache.struts2.interceptor.ServletRequestAware;import org.apache.struts2.util.ServletContextAware;import com.opensymphony.xwork2.ActionSupport;/** * 访问Servlet的API的方式三:接口注入的方式 * @author liayun * */public class RequestDemo03 extends ActionSupport implements ServletRequestAware, ServletContextAware {
    private HttpServletRequest request; private ServletContext context; public RequestDemo03() {
    super(); System.out.println("RequestDemo03被创建了......"); } @Override public String execute() throws Exception {
    //一、接收参数 //通过接口注入的方式获得request对象 Map
    map = request.getParameterMap(); for (String key : map.keySet()) {
    String[] values = map.get(key); System.out.println(key + "\t" + Arrays.toString(values)); } return super.execute(); } @Override public void setServletRequest(HttpServletRequest request) {
    this.request = request; } @Override public void setServletContext(ServletContext context) {
    this.context = context; } }

    自定义的RequestDemo03类实现了Action的ServletRequestAware和ServletContextAware这俩接口。需要注意的是,RequestDemo03类中必须实现setServletRequest()方法、setServletContext()方法以及execute()方法,通过setServletRequest()和setServletContext()这俩方法,可以得到HttpServletRequest和ServletContext的实例,这是在调用execute()方法或者其他自定义的方法之前就调用的,然后在execute()方法中,就可以访问HttpServletRequest和ServletContext的属性内容了。

    接着,就要在struts.xml文件中配置以上Action类了,这里我们采用Struts2中分模块开发的配置。

    • struts.xml

    • struts-demo01.xml

      /demo01/demo02.jsp
      /demo01/demo02.jsp
      /demo01/demo02.jsp

    最后 ,运行效果如下图所示。

    在这里插入图片描述
    从上图可以看出,使用Action的ServletRequestAware和ServletContextAware这俩接口顺利访问了Servlet API。

  • 第二个案例。如果我们想要在页面跳转的时候,向demo02.jsp页面传递过去一些数据并显示,那么又该如何完成呢?可以将RequestDemo03类中的代码修改成下面的样子。

    package com.meimeixia.struts2.demo01;import java.util.Arrays;import java.util.Map;import javax.servlet.ServletContext;import javax.servlet.http.HttpServletRequest;import org.apache.struts2.interceptor.ServletRequestAware;import org.apache.struts2.util.ServletContextAware;import com.opensymphony.xwork2.ActionSupport;/** * 访问Servlet的API的方式三:接口注入的方式 * @author liayun * */public class RequestDemo03 extends ActionSupport implements ServletRequestAware, ServletContextAware {
    private HttpServletRequest request; private ServletContext context; public RequestDemo03() {
    super(); System.out.println("RequestDemo03被创建了......"); } @Override public String execute() throws Exception {
    //一、接收参数 //通过接口注入的方式获得request对象 Map
    map = request.getParameterMap(); for (String key : map.keySet()) {
    String[] values = map.get(key); System.out.println(key + "\t" + Arrays.toString(values)); } //二、向域对象中保存数据 //向request中保存数据 request.setAttribute("reqName", "reqValue"); //向session中保存数据 request.getSession().setAttribute("sessName", "sessValue"); //向application中保存数据 context.setAttribute("appName", "appValue"); return super.execute(); } @Override public void setServletRequest(HttpServletRequest request) {
    this.request = request; } @Override public void setServletContext(ServletContext context) {
    this.context = context; } }

    然后,修改demo02.jsp页面,在该页面中显示相应的数据。

    <%@ page language="java" contentType="text/html; charset=UTF-8"    pageEncoding="UTF-8"%>
    Insert title here

    成功跳转的页面,在这个页面显示数据

    ${reqName }
    ${sessName }
    ${appName }

    最后,运行效果如下图所示。

    在这里插入图片描述

小结

之前学习Servlet时,我们应该知道Servlet是单例的,也就是说多个程序访问同一个Servlet只会创建一个Servlet的实例。但是,Struts2框架中的Action是多例的,即有一次请求,就会创建一个Action的实例,这样子的话,在Action中定义成员变量,是不会出现线程安全问题的。

转载地址:https://liayun.blog.csdn.net/article/details/67315598 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Struts2入门第七讲——OGNL
下一篇:Struts2入门第一讲——Struts2框架的快速入门

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年05月01日 01时16分13秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章