结果处理方式、在Action中获取原生ServletAPI、获取前端参数

结果跳转方式

在struts.xml文件中,配置result标签的type类就可以选择处理结果的方式,struts2提供了如下处理结果的方式,可以在struts2核心包 --> struts-default.xml文件中找到

<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>

这里介绍四种,分别是转发、重定向、转发到Action、重定向到Action,如果不对type属性进行配置,会默认type属性为转发

转发dispatcher(默认)

<action name="helloAction" class="com.jinxin.action.HelloAction" method="hello">
    <result name="success" type="dispatcher">/hello.jsp</result>
</action>

由struts-default.xml文件中的配置可知,转发是交给 org.apache.struts2.dispatcher.ServletDispatcherResult 类处理的,进入这个类,有一个 doExecute() 方法,这就是处理转发的方法,在该方法中,有如下几条代码

HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
dispatcher.forward(request, response);

分别是获取request对象,获取response对象,获取转发对象,转发,这很显然就是在Servlet中实现的转发的代码,只是struts2已经将它们封装好了,提高了代码的重用性

重定向redirect

<action name="helloAction" class="com.jinxin.action.HelloAction" method="hello">
    <result name="success" type="redirect">/hello.jsp</result>
</action>

同样,可以进redirect的处理类 org.apache.struts2.dispatcher.ServletRedirectResult 看看它是怎样实现重定向的

同样,在该类中也有一个 doExecute() 方法,很显然,这个方法就是处理重定向的,在这个方法中,先是获取了request跟response对象,然后进行了一些判断跟路径的拼接处理,最后将拼接好的路径和response对象传进了一个 sendRedirect() 方法,其中核心的代码如下

HttpServletRequest request = (HttpServletRequest) ctx.get(ServletActionContext.HTTP_REQUEST);
HttpServletResponse response = (HttpServletResponse) ctx.get(ServletActionContext.HTTP_RESPONSE);
sendRedirect(response, finalLocation);

进入这个 sendRedirect() 方法,发现该方法执行了 response.sendRedirect(finalLocation); ,显然,这同样也是Servlet中重定向的代码。。。

转发到Action

<action name="helloAction" class="com.jinxin.action.HelloAction" method="hello">
    <result name="success" type="chain">
        <param name="actionName">Demo1Action</param>
        <param name="namespace">/</param>
    </result>
</action>

actionName表示转发到哪个Action类,namespace表示那个Action所在的命名空间

重定向到Action

<action name="helloAction" class="com.jinxin.action.HelloAction" method="hello">
    <result name="success" type="redirectAction">
        <param name="actionName">Demo1Action</param>
        <param name="namespace">/</param>
    </result>
</action>

actionName表示重定向到哪个Action类,namespace表示那个Action所在的命名空间

在Action中获取ServletAPI

在Action中获取ServletAPI主要通过一个数据中心ActionContext,这个ActionContext的生命周期与request一致,每次请求时,都会创建一个与请求对应的ActionContext对象,请求处理完ActionContext销毁

那么,如何去获取这个数据中心呢?struts2的设计是,将ActionContext对象创建好后,将ActionContext与当前线程绑定,当需要获取ActionContext时,只需要从ThreadLocal中获取即可

其实ActionContext是一个Map,它通过键值对存放内容,其中存放的request域,application域跟session域同样也是Map,那么下面就三种方式讨论如何获取这些域

通过ActionContext获得(常用)

获取session域

Map<String, Object> sessionScope = ActionContext.getContext().getSession();

获取application域

Map<String, Object> applicationScope = ActionContext.getContext().getApplication();

获取request域

获取request域不能像上面那样通过 getRequest() 方法获取,在ActionContext中并没有提供这个方法,那么用该如何去获取呢?很简单,上面有说过ActionContext是一个Map映射,那么自然就可以通过键名去获取值了,下面就是通过request键名去获取的request域

Map<String, Object> requestScope = ActionContext().getContext().get("request");

虽然获取了request域,但是并不推荐使用,上面提到过ActionContext的生命周期与request中的一致,因此将数据存在ActionContext域中与request域中是一样的,所以更推荐使用ActionContext域

ActionContext.getContext().put("name", "Scarlett");

那么,既然存储的地方变了,自然就会有这样一种担心——在取值的时候应该怎么办?其实并不需要有这种担心,因为在取值的时候会先到request原生域中找,如果没有找到就会继续到ActionContext域中查找,即取值的方式不会改变

同ServletContext(为了跟Servlet解耦,所以不推荐使用)

获取原生的request

HttpServletRequest hr = ServletActionContext.getRequest();

获取原生的response

HttpServletResponse hp = ServletActionContext.getResponse();

获取原生的ServletContext

ServletContext sc = ServletActionContext.getServletContext();

获取原生的session

HttpSession session = request.getSession();

这看似是一种新的方式,但实则跟上一种没什么区别,何出此言,我们可以进入到 ServletActionContext 类中,查看其中的某一个方法,这里以 getRequest() 方法为例

1 public static HttpServletRequest getRequest() {
2     return (HttpServletRequest) ActionContext.getContext().get(HTTP_REQUEST);
3 }

可以看到,上面的 getRequest() 方法正是通过键名向ActionContext中取值的方式获取的request对象,这与第一种方式难道不是一致的吗

通过接口获得

第三种方法是通过实现相关的 xxxAware 接口来获得的,比如想要获取request对象可以实现 ServletRequestAware 接口

public class GetAPI extends ActionSupport implements ServletRequestAware{
	private HttpServletRequest request;
	
	
	@Override
	public void setServletRequest(HttpServletRequest request) {
		// TODO Auto-generated method stub
		this.request = request;
	}

}

上述代码就获取一个request对象,若想要获取其他对象,以相同的方法实现对应的Aware接口即可

那么,如此神奇的方式怎样实现呢?正是通过struts2的核心拦截器实现的,同样可以进入到 struts-default.xml 文件中,找到设置拦截器的部分

<interceptor name="alias" class="com.opensymphony.xwork2.interceptor.AliasInterceptor"/>
<interceptor name="autowiring" class="com.opensymphony.xwork2.spring.interceptor.ActionAutowiringInterceptor"/>
<interceptor name="chain" class="com.opensymphony.xwork2.interceptor.ChainingInterceptor"/>
<interceptor name="conversionError" class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>
<interceptor name="cookie" class="org.apache.struts2.interceptor.CookieInterceptor"/>
<interceptor name="cookieProvider" class="org.apache.struts2.interceptor.CookieProviderInterceptor"/>
<interceptor name="clearSession" class="org.apache.struts2.interceptor.ClearSessionInterceptor" />
<interceptor name="createSession" class="org.apache.struts2.interceptor.CreateSessionInterceptor" />
<interceptor name="debugging" class="org.apache.struts2.interceptor.debugging.DebuggingInterceptor" />
<interceptor name="execAndWait" class="org.apache.struts2.interceptor.ExecuteAndWaitInterceptor"/>
<interceptor name="exception" class="com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor"/>
<interceptor name="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor name="i18n" class="com.opensymphony.xwork2.interceptor.I18nInterceptor"/>
<interceptor name="logger" class="com.opensymphony.xwork2.interceptor.LoggingInterceptor"/>
<interceptor name="modelDriven" class="com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor"/>
<interceptor name="scopedModelDriven" class="com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor"/>
<interceptor name="params" class="com.opensymphony.xwork2.interceptor.ParametersInterceptor"/>
<interceptor name="actionMappingParams" class="org.apache.struts2.interceptor.ActionMappingParametersInteceptor"/>
<interceptor name="prepare" class="com.opensymphony.xwork2.interceptor.PrepareInterceptor"/>
<interceptor name="staticParams" class="com.opensymphony.xwork2.interceptor.StaticParametersInterceptor"/>
<interceptor name="scope" class="org.apache.struts2.interceptor.ScopeInterceptor"/>
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
<interceptor name="timer" class="com.opensymphony.xwork2.interceptor.TimerInterceptor"/>
<interceptor name="token" class="org.apache.struts2.interceptor.TokenInterceptor"/>
<interceptor name="tokenSession" class="org.apache.struts2.interceptor.TokenSessionStoreInterceptor"/>
<interceptor name="validation" class="org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor"/>
<interceptor name="workflow" class="com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor"/>
<interceptor name="store" class="org.apache.struts2.interceptor.MessageStoreInterceptor" />
<interceptor name="checkbox" class="org.apache.struts2.interceptor.CheckboxInterceptor" />
<interceptor name="datetime" class="org.apache.struts2.interceptor.DateTextFieldInterceptor" />
<interceptor name="profiling" class="org.apache.struts2.interceptor.ProfilingActivationInterceptor" />
<interceptor name="roles" class="org.apache.struts2.interceptor.RolesInterceptor" />
<interceptor name="annotationWorkflow" class="com.opensymphony.xwork2.interceptor.annotations.AnnotationWorkflowInterceptor" />
<interceptor name="multiselect" class="org.apache.struts2.interceptor.MultiselectInterceptor" />
<interceptor name="deprecation" class="org.apache.struts2.interceptor.DeprecationInterceptor" />

其中name属性为 servletConfig 的,就是实现获取这些对象的拦截器,进入到相应的class属性指定的类中,可以看到一个 intercept() 方法,就是用来获取这些对象的,以request为例

final Object action = invocation.getAction();
final ActionContext context = invocation.getInvocationContext();

if (action instanceof ServletRequestAware) {
    HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
    ((ServletRequestAware) action).setServletRequest(request);
}

在 intercept() 方法中,先通过 invocation 获取了本次请求的Action以及ActionContext,然后判断该Action是否实现了ServletRequestAware接口,如果实现了,就通过键名从ActionContext中取出request对象,通过 setServletRequest() 方法设置request,而这个 setServletRequest() 方法不正是先前实现ServletRequestAware接口重写的方法吗,而request也就自然而然的设置给了该Action类中的 this.request 

总结:其实虽然是分了三种方式去获取ServletAPI,但是当研究了底层的代码后,发现,这三种获取的方式最终都是通过键名去ActionContext中取值的,实际上可以看做是一种方式,只是外表不一样罢了,但是这三种方式任然各有优劣,比如第二种与Servlet耦合太深,第三种在笔者看来太过麻烦,因此更推荐使用第一种方式。。。

获取前端参数

一个网站,经常会免不了用户登录、用户注册,那么这时候就需要从前端获取到用户填写的数据,那么在struts2中如何去获取呢?下面分别介绍四种方式获取这些参数

属性驱动获取参数

顾名思义,属性驱动获取参数就是在Action中准备与input标签中name属性同名的一个属性去接收参数,具体代码如下

jsp页面

<body>
	<form action="${pageContext.request.contextPath}/hello/paramAction.do" method="post">
		<input type="text" name="name" />
		<input type="submit" value="提交" />
	</form>
</body>

在Action类中

public class ParamAction extends ActionSupport{
	private String name;   // 添加一个与前端input标签name属性同名的属性即可
	
	
	
	public String test() {
		System.out.println(name);    // 打印属性
		return "success";
	}
	
	

	public String getName() {
		return name;
	}

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

在上面的Action类中,接受参数使用了成员变量,但是这在Servlet中是不允许的,因为Servlet是线程不安全的,就这么一个成员变量,而用户却有很多人,除非能保证同一时间只有一个用户去使用这个变量,不然,当多个用户同时使用就会乱套。而为什么在Action中又能使用了呢?原因就是Action是线程安全的,每次请求Action时,都会新建Action的实例对象,这就相当于每个用户都有自己的成员变量,互不干扰。

对象驱动获得参数

像上面那样将属性都放到Action类中,属性跟业务写在一块儿让笔者觉得非常的乱,看起来不舒服,影响体验,甚至可能因此出错,那么,很自然的就会想到,能不能将这些属性单独的放到一个类中,而在Action类中只需要实例化这个类就可以了呢?当然是有的,这就是对象驱动获取参数

User类

将属性都放在一个类中,这个类取名为User

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;
	}
	
	
	public String toString() {
        return name + "===>" + age + "===>" + birthday;
    }
}

Action类

在Action类中只需要准备一个User类型的属性即可

public class ParamAction extends ActionSupport{
	private User user;
	

	public String test() {
		System.out.println(user);     // 打印获取的参数
		return "success";
	}


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

jsp页面

在jsp页面中的input标签的name属性同样要与User类中的各个属性名称相同,但是这次需要在它们前面加上Action中的user属性名,在将它们通过句点符连接起来

<body>
	<form action="${pageContext.request.contextPath}/hello/paramAction.do" method="post">
		<input type="text" name="user.name" />   <!-- 这里是 对象名.对象的属性名 -->
		<input type="text" name="user.age" />
		<input type="text" name="user.birthday" />
		<input type="submit" value="提交" />
	</form>
</body>

模型驱动获取参数

上面通过对象驱动获取参数显然方便多了,但是在input标签中的name属性的写法显然跟平时的习惯不太一样,那么怎样才能不写前面的user呢?这就需要用到模型驱动获取参数

User类

User类的写法同对象获取参数一样,不做赘述

Action类

在Action类中需要实现ModelDriven接口,然后实现一个 getModel() 方法,方法中返回user对象,由于此时的user不是一个属性,没有get、set方法,所以需要手动去实例化,即 private User user = new User(); 

public class ParamAction extends ActionSupport implements ModelDriven<User>{     // 实现ModelDriven接口,这里的泛型写User类
    private User user = new User();
    
    
    public String test() {
        System.out.println(user);
        return "success";
    }

        // 实现getModel()方法,返回user对象
    @Override
    public User getModel() {
        // TODO Auto-generated method stub
        return user;
    }
}

 

jsp页面

在使用了模型驱动后,此时在input标签中就不需要写user了

<body>
    <form action="${pageContext.request.contextPath}/hello/paramAction.do" method="post">
        <input type="text" name="name" />   <!-- 这里是 对象名.对象的属性名 -->
        <input type="text" name="age" />
        <input type="text" name="birthday" />
        <input type="submit" value="提交" />
    </form>
</body>

集合类型封装参数

除了上面的通过属性获取参数以外,还可以使用集合获取参数,可以用List和Map获取

使用List获取

使用集合获取跟使用属性获取其实是差不多的,同样是在Action类中准备一个List类型的属性存放参数即可

Action类
public class ParamAction extends ActionSupport{
	private List<String> list;
	
	
	
	public String test() {
		System.out.println(list);
		return "success";
	}
	
	public List<String> getList() {
		return list;
	}

	public void setList(List<String> list) {
		this.list = list;
	}
}
jsp页面
<body>
	<form action="${pageContext.request.contextPath}/hello/paramAction.do" method="post">
		<input type="text" name="list" />
		<input type="text" name="list" />
		<input type="text" name="list" />
		<input type="submit" value="提交" />
	</form>
</body>

如果在name中直接填写list,那么获取的参数会按照默认的顺序存放,当然,也可以指定参数存放的位置,比如 list[5] 就是将该参数存放到索引为5的位置,前面没有参数的位置以null填充

使用Map获取

使用Map获取跟使用list获取是一样的

Action类
public class ParamAction extends ActionSupport{
	private Map<String, String> map;
	
	
	public String test() {
		System.out.println(map);
		return "success";
	}



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

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

在input标签的name属性中,需要写键名,比如键名为name,那么应该写 map['name'] 

<body>
	<form action="${pageContext.request.contextPath}/hello/paramAction.do" method="post">
		<input type="text" name="map['name']" />
		<input type="text" name="map['age']" />
		<input type="text" name="map['birthday']" />
		<input type="submit" value="提交" />
	</form>
</body>

 

posted @ 2018-07-10 11:56  Jin同学  阅读(231)  评论(0)    收藏  举报