准备

为后面测试示例编写代码及配置如下:

package com.zze.bean;

import java.util.Date;

public class User {
    private String name;
    private Integer age;
    private Date birthday;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Date getBirthday() {
        return birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", birthday=" + birthday +
                '}';
    }
}

com.zze.bean.User

<?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>
    <constant name="struts.devMode" value="true"/>
    <package name="test" extends="struts-default" namespace="/">
        <action name="*" class="com.zze.action.{1}Action">
            <result>/show.jsp</result>
        </action>
    </package>
</struts>

struts.xml

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
v1:${requestScope.key}
v2:${sessionScope.key}
v3:${applicationScope.key}

show.jsp

Servlet API的访问

在使用 Struts2 的过程中,会发现 Struts2 和 Servlet 的 API 是解耦合的。在实际开发中,经常用到 Servlet 的 API,比如将信息保存到 Session 中、使用 response 响应一些内容等等..,这些都涉及到对 Servlet 的 API 的访问。

解耦合方式

package com.zze.action;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

import java.util.Arrays;
import java.util.Map;

public class Test1Action extends ActionSupport {

    /**
     * 解耦合方式
     */
    @Override
    public String execute() {
        ActionContext context = ActionContext.getContext();
        // 获取请求参数
        Map<String, Object> parameters = context.getParameters();
        for (String key : parameters.keySet()) {
            String[] values = (String[]) parameters.get(key);
            System.out.println(String.format("key:%s value:%s", key, Arrays.toString(values)));
        }
        // 存放参数到域对象
        context.put("key", "value from context.put"); // request.setAttribute("key","value from context.put")
        context.getSession().put("key", "value from context.getSession().put"); // session.setAttribute("key","value from context.getSession().put")
        context.getApplication().put("key", "value from context.getApplication().put"); // application.setAttribute("key","value from context.getApplication().put")
        return SUCCESS;
    }
}

com.zze.action.Test1Action

原生Servlet的API

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.Map;

public class Test2Action extends ActionSupport {

    @Override
    public String execute() throws Exception {
        // 获取原生 request 对象
        HttpServletRequest request = ServletActionContext.getRequest();
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (String key : parameterMap.keySet()) {
            String[] values = (String[]) parameterMap.get(key);
            System.out.println(String.format("key:%s value:%s", key, Arrays.toString(values)));
        }
        // 存放数据到域对象
        request.setAttribute("key","value from request.setAttribute");
        request.getSession().setAttribute("key","value from request.getSession().setAttribute");
        // ServletActionContext.getServletContext()
        request.getServletContext().setAttribute("key","value from request.getServletContext().setAttribute");
        return super.execute();
    }
}

com.zze.action.Test2Action

接口注入

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.util.ServletContextAware;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Map;

/**
 * 接口注入的方式需要实现相应接口
 */
public class Test3Action extends ActionSupport implements ServletRequestAware, ServletResponseAware, ServletContextAware {
    private HttpServletRequest request;  // 接收注入的原生 request
    private HttpServletResponse response; // 接收注入的原生 response
    private ServletContext servletContext; // 接收注入的原生 servletContext

    @Override
    public String execute() throws Exception {
        // 接收请求参数
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (String key : parameterMap.keySet()) {
            String[] values = (String[]) parameterMap.get(key);
            System.out.println(String.format("key:%s value:%s", key, Arrays.toString(values)));
        }
        // 存放数据到域对象
        request.setAttribute("key", "value from request.setAttribute");
        request.getSession().setAttribute("key", "value from request.getSession().setAttribute");
        servletContext.setAttribute("key", "value from servletContext.setAttribute");
        return super.execute();
    }

    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }

    @Override
    public void setServletResponse(HttpServletResponse response) {
        this.response = response;
    }

    @Override
    public void setServletContext(ServletContext context) {
        this.servletContext = context;
    }
}

com.zze.action.Test3Action

请求数据封装

Struts2 是一个 web 层框架,提供了请求数据封装的功能。而它的提供了如下两种方式进行请求数据的封装:

属性驱动

提供set方法

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;

import java.util.Date;

public class Test4Action extends ActionSupport {
    private String name;
    private Integer age;
    private Date birthday;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(name);
        System.out.println(age);
        System.out.println(birthday);
        return NONE;
    }
}

com.zze.action.Test4Action

表达式方式

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;
import com.zze.bean.User;

/**
 * 请求参数的参数名需按指定格式
 */
public class Test5Action extends ActionSupport {
    // 给接收参数的对象提供 get 方法
    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(user);
        return NONE;
    }
}

com.zze.action.Test5Action : 封装到 JavaBean

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;

import java.util.Arrays;
import java.util.List;

/**
 * 请求参数的参数名需按指定格式
 */
public class Test6Action extends ActionSupport {
    public List<String> names;

    public List<String> getNames() {
        return names;
    }

    public void setNames(List<String> names) {
        this.names = names;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(Arrays.toString(names.toArray()));
        return NONE;
    }
}

com.zze.action.Test6Action : 封装到 List<String>

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;
import com.zze.bean.User;

import java.util.List;

public class Test7Action extends ActionSupport {
    private List<User> users;

    public List<User> getUsers() {
        return users;
    }

    public void setUsers(List<User> users) {
        this.users = users;
    }

    @Override
    public String execute() throws Exception {
        for (User user : users) {
            System.out.println(user);
        }
        return NONE;
    }
}

com.zze.action.Test7Action : 封装到 List<JavaBean>

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;

import java.util.Arrays;
import java.util.Map;

public class Test8Action extends ActionSupport {
    private Map<String,Object> map;

    public Map<String, Object> getMap() {
        return map;
    }

    public void setMap(Map<String, Object> map) {
        this.map = map;
    }

    @Override
    public String execute() throws Exception {
        for (String key : map.keySet()) {
            String valStr=  Arrays.toString((String[])map.get(key));
            System.out.println(String.format("%s:%s",key,valStr));
        }
        return NONE;
    }
}

com.zze.action.Test8Action : 封装到 Map<String,String[]>

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;
import com.zze.bean.User;

import java.util.Map;

public class Test9Action extends ActionSupport {
    private Map<String, User> map;

    public Map<String, User> getMap() {
        return map;
    }

    public void setMap(Map<String, User> map) {
        this.map = map;
    }

    @Override
    public String execute() throws Exception {
        for (String key : map.keySet()) {
            System.out.println(String.format("%s : %s", key, map.get(key)));
        }
        return NONE;
    }
}

com.zze.action.Test9Action : 封装到 Map<String,JavaBean>

模型驱动

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;
import com.opensymphony.xwork2.ModelDriven;
import com.zze.bean.User;

/**
 * 实现 ModelDriven 接口
 */
public class Test10Action extends ActionSupport implements ModelDriven<User> {
    private User user = new User();

    @Override
    public User getModel() {
        return user;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(user);
        return NONE;
    }
}

com.zze.action.Test10Action

补充

结果页配置

全局结果页

全局结果页指的是:在包中配置一次,其它在这个包中所有 action 只要返回了对应 name 值,就都可以跳转到全局结果页配置的页面。

在 struts.xml 的 package 标签下添加如下节点即可配置全局结果页:

<!--全局结果页配置-->
<global-results>
    <result name="success">/success.jsp</result>
</global-results>

局部结果页

局部结果页指的是:所配置的结果只对当前所在 action 有效。

在 struts.xml 的 package>aciton 下配置:

<!--局部结果页配置-->
<action name="*" class="com.zze.action.{1}Action">
    <result>/show.jsp</result>
</action>

result标签配置

result 标签用于配置页面的跳转。

属性:

  • name:逻辑视图名称,与 action 返回值对应。
  • type:页面跳转类型。
    type 的取值有很多,在 struts2-core-2.3.37.jar!/struts-default.xml 的 package 下有定义:

    <result-types>
        <result-type name="chain" class="com.opensymphony.xwork2.ActionChainResult"/>
        <result-type name="dispatcher" class="org.apache.struts2.dispatcher.ServletDispatcherResult" default="true"/>
        <result-type name="freemarker" class="org.apache.struts2.views.freemarker.FreemarkerResult"/>
        <result-type name="httpheader" class="org.apache.struts2.dispatcher.HttpHeaderResult"/>
        <result-type name="redirect" class="org.apache.struts2.dispatcher.ServletRedirectResult"/>
        <result-type name="redirectAction" class="org.apache.struts2.dispatcher.ServletActionRedirectResult"/>
        <result-type name="stream" class="org.apache.struts2.dispatcher.StreamResult"/>
        <result-type name="velocity" class="org.apache.struts2.dispatcher.VelocityResult"/>
        <result-type name="xslt" class="org.apache.struts2.views.xslt.XSLTResult"/>
        <result-type name="plainText" class="org.apache.struts2.dispatcher.PlainTextResult" />
        <result-type name="postback" class="org.apache.struts2.dispatcher.PostbackResult" />
    </result-types>

    struts-default.xml > package > result-types

    常用类型有如下几个:

    dispatcher:默认值,请求转发,从 当前 action 到 jsp。

    redirect:从当前 action 重定向到 jsp。

    chain:请求转发,从当前 action 转发到另一个 action。

    redirectAction:从当前 action 重定向到另一个 action。

    stream:返回流,文件下载。

INPUT逻辑视图

在 Action 接口中提供了 5 个静态字段,如下:

public static final String SUCCESS = "success"; // 操作成功
public static final String NONE = "none"; // 操作成功不跳转
public static final String ERROR = "error"; // 操作失败
public static final String INPUT = "input"; // 通常在表单提交请求参数验证失败时返回,标识需重新输入提交
public static final String LOGIN = "login"; // 返回到登录页

"input" 返回值在 Struts2 内置拦截器中就有用到,先看如下情况:

package com.zze.action;

import com.opensymphony.xwork2.ActionSupport;

public class Test11Action extends ActionSupport {
    private Integer age;

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(age);
        return NONE;
    }
}

com.zze.action.Test11Action

在上述 action 中使用属性驱动的方式接受一个 Integer 类型的年龄字段,而参数提交时提交的是 "aa","aa" 明显是不可以转成 Integer 类型的,此时 Struts2 就会返回错误如下:

No result defined for action com.zze.action.Test11Action and result input - action - file:/WEB-INF/classes/struts.xml:13:51

即:没有为 action 定义一个 name="input" 的 result 。为什么 Struts2 会返回这个结果呢?

首先我们知道 Struts2 内部默认是有一个拦截器栈的,在 struts2-core-2.3.37.jar!/struts-default.xml 中可以看到,如下:

<interceptor-stack name="defaultStack">
<interceptor-ref name="exception"/>
<interceptor-ref name="alias"/>
<interceptor-ref name="servletConfig"/>
<interceptor-ref name="i18n"/>
<interceptor-ref name="prepare"/>
<interceptor-ref name="chain"/>
<interceptor-ref name="scopedModelDriven"/>
<interceptor-ref name="modelDriven"/>
<interceptor-ref name="fileUpload"/>
<interceptor-ref name="checkbox"/>
<interceptor-ref name="datetime"/>
<interceptor-ref name="multiselect"/>
<interceptor-ref name="staticParams"/>
<interceptor-ref name="actionMappingParams"/>
<!--接收参数-->
<interceptor-ref name="params"/>
<!--类型转换-->
<interceptor-ref name="conversionError"/>
<!--数据校验-->
<interceptor-ref name="validation">
    <param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="workflow">
    <param name="excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
<interceptor-ref name="debugging"/>
<interceptor-ref name="deprecation"/>
</interceptor-stack>

在请求 action 时该栈下的拦截器会依次执行,而每个拦截器都有它自身的功能。如 params 拦截器用来接收参数、conversionError 拦截器用来类型转换、validation 拦截器用来数据校验。

而 Struts2 有一个专门存放错误的区域,当这几个操作出错时,Struts2 就会将对应错误信息存到该错误区域。接着在 workflow 拦截器中就会检查错误区域是否有错误,如果有,则返回 "input" 逻辑视图,如果没有则继续执行后续拦截器及 action。workflow 对应拦截器部分源码如下:

@Override
protected String doIntercept(ActionInvocation invocation) throws Exception {
    Object action = invocation.getAction();

    if (action instanceof ValidationAware) {
        ValidationAware validationAwareAction = (ValidationAware) action;
        // 如果错误区有错误
        if (validationAwareAction.hasErrors()) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Errors on action [#0], returning result name [#1]", validationAwareAction, inputResultName);
            }

            String resultName = inputResultName; // "input"
            resultName = processValidationWorkflowAware(action, resultName);
            resultName = processInputConfig(action, invocation.getProxy().getMethod(), resultName);
            resultName = processValidationErrorAware(action, resultName);

            return resultName;
        }
    }

    return invocation.invoke();
}

com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor#doIntercept

了解了拦截器返回 "input" 逻辑视图的原因,我们就可以对症下药了,在 struts.xml 中 action 标签下添加一个 "input" 的结果:

<result name="input">/input.jsp</result>

而在 jsp 中我们可以通过 Struts2 提供的标签输出错误信息:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<s:fielderror/>
</body>
</html>

input.jsp

再次请求,结果如下:

java框架之Struts2(2)-访问Servlet API及请求数据封装的更多相关文章

  1. Struts2(八)访问Servlet API

    一.Struts2中的Servlet API 1.1.struts2的Action实现了MVC中C层的作用 针对请求用户显示不同的信息 登录后段保存用户信息 ----session 保存当前在线人数等 ...

  2. struts2中访问servlet API

    Struts2中的Action没有与任何Servlet API耦合,,但对于WEB应用的控制器而言,不访问Servlet API几乎是不可能的,例如需要跟踪HTTP Session状态等.Struts ...

  3. struts2的action访问servlet API的三种方法

    学IT技术,就是要学习... 今天无聊看看struts2,发现struts2的action访问servlet API的三种方法: 1.Struts2提供的ActionContext类 Object g ...

  4. struts2 笔记01 登录、常用配置参数、Action访问Servlet API 和设置Action中对象的值、命名空间和乱码处理、Action中包含多个方法如何调用

    Struts2登录 1. 需要注意:Struts2需要运行在JRE1.5及以上版本 2. 在web.xml配置文件中,配置StrutsPrepareAndExecuteFilter或FilterDis ...

  5. 配置Struts2及Struts2访问servlet api的方式

    Struts2的起源与背景 在很长的一段时间内,在所有的MVC框架中,Struts1处于绝对的统治地位,无论是从市场的普及范围,还是具体的使用者数量. 其他MVC框架都无 法与其相比,作为一一款优秀的 ...

  6. struts2访问servlet API

    搭建环境: 引入jar包,src下建立struts.xml文件 项目配置文件web.xml. web.xml: <?xml version="1.0" encoding=&q ...

  7. Struts2框架(4)---Action类访问servlet

    Action类访问servlet Action类有三种方式servlet: (1)间接的方式访问Servlet API  ---使用ActionContext对象 (2)  实现接口,访问Action ...

  8. Struts2学习二----------访问Servlet API

    © 版权声明:本文为博主原创文章,转载请注明出处 Struts2提供了三种方式去访问Servlet API -ActionContext -实现*Aware接口 -ServletActionConte ...

  9. Struts2访问Servlet API的三种方式

    有时我们需要用到Request, Response, Session,Page, ServletContext这些我们以前常用的对象,那么在Struts2中怎么样使用到这些对象呢,通常有三种方式. * ...

随机推荐

  1. Java基础(四)线程快速了解

    开始整理线程之前,之前有个命令忘记整理了,先整理一下jar命令的使用 Jar包 其实可以理解是java的压缩包方便使用,只要在classpath设置jar路径即可数据库驱动,ssh框架等都是以jar包 ...

  2. ftp软件中保持连接命令CWD、PWD、LIST、NOOP四个操作命令解析

    转自:http://www.aspjzy.com/A/148.html 各位站长都知道,我们在维护网站的时候,经常需要一直保持ftp连接状态,这个时候在很多ftp客户端软件中都有一个保持全局连接的选项 ...

  3. plsql 通过修改配置文件的方式实现数据库的连接

    查看oracle的安装位置: XP系统: 开始>>所有程序>>>Oracle-OraDb10g_home1>>>配置和移植工具>>>右 ...

  4. 对世界首款“人工智能”ERP系统HUE的初步了解 - AI ERP - WAP - 万革始

    偶然的机会,刚好在查找机器人王国[奇妙的餐厅]的时候,看到开发[光的王国],[奇妙的宾馆],[奇妙的餐厅]等豪斯登堡集团在3月17日采用了这个传说中的世界首款人工智能ERP系统AI WORKS的下面4 ...

  5. Canvas组件:画布,可以实现动画操作。

    Module  10 Canvas组件:画布,可以实现动画操作. TextArea:文本域. 在单行文本域中回车会激发ActionEvent. 用CheckBoxGroup实现单选框功能. Java中 ...

  6. Nginx+Keepalived+Tomcat高可用负载均衡,Zookeeper集群配置,Mysql(MariaDB)搭建,Redis安装,FTP配置

    JDK 安装步骤 下载 http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html rpm ...

  7. 项目中phpexcel的基本用法

    前提:要下载PHPEXCEL库文件 如:phpexcel官方下载    ,本人使用下载 情形一:对于将数据写入EXCEL表中的用法 header("content-type:text/htm ...

  8. Kafka中bootstrap-server、broker-list和zookeeper的区别

    参考 Kafka bootstrap-servers vs zookeeper in kafka-console-consumer  中说建议使用新版(新版本指的是kafka 0.8.0之后的版本)的 ...

  9. Mybatis常考面试题汇总(附答案)

    1.#{}和${}的区别是什么? #{}和${}的区别是什么? 在Mybatis中,有两种占位符 #{}解析传递进来的参数数据 ${}对传递进来的参数原样拼接在SQL中 #{}是预编译处理,${}是字 ...

  10. 如何优雅的选择字体(font-family)

    大家都知道,在不同操作系统.不同游览器里面默认显示的字体是不一样的,并且相同字体在不同操作系统里面渲染的效果也不尽相同,那么如何设置字体显示效果会比较好呢?下面我们逐步的分析一下: 一.首先我们看看各 ...