Fork me on GitHub

二.Struts2————跳转方式和访问Servlet的API以及如何获得参数和集合参数的封装

今天到了Struts2学习的第二天,今天总体内容来说比较少,所以博主能够好好休息一下,这篇写完还早,准备看个电影,哈哈哈哈;

Struts2的页面跳转方式(各种方式背后的源码其实还是我们在Servlet中写的):

    转发
> 根据前面学习,我们知道Struts2的页面跳转方式的配置在struts.xml中action配置中的result中的type属性,这次我们来具体看看:

测试代码:
1
2
3
4
5
6
7
8
9
10
public class Demo1Action extends ActionSupport{

@Override
public String execute() throws Exception {

System.out.println("Demo1Action.execute()");

return SUCCESS;
}
}


配置信息:
1
2
3
4
<!-- 转发 -->
<action name="Demo1Action" class="yp.itcast.a_result.Demo1Action" method="execute">
<result name="success" type="dispatcher">/hello.jsp</result>
</action>
    重定向


配置信息:(注意action中的name属性不同):

1
2
3
4
<!-- 重定向 -->
<action name="Demo2Action" class="yp.itcast.a_result.Demo2Action" method="execute">
<result name="success" type="redirect">/hello.jsp</result>
</action>


    转发到action(注意是转发到action)


测试代码:

1
2
3
4
5
6
7
8
9
10
11
12
public class Demo3Action extends ActionSupport{

@Override
public String execute() throws Exception {

System.out.println("Demo3Action.execute()");

return SUCCESS;
}


}


配置信息:
1
2
3
4
5
6
7
8
9
10
<!-- 转发到Action -->
<action name="Demo3Action" class="yp.itcast.a_result.Demo3Action" method="execute">
<result name="success" type="chain">
<!-- action的名字 -->
<param name="actionName">Demo1Action</param>
<!-- action所在命名空间 -->
<param name="namespace">/</param>
</result>

</action>
    重定向到action


配置信息:
1
2
3
4
5
6
7
8
9
<!-- 重定向到action -->
<action name="Demo4Action" class="yp.itcast.a_result.Demo4Action" method="execute">
<result name="success" type="redirectAction">
<!-- action的名字 -->
<param name="actionName">Demo1Action</param>
<!-- action所在命名空间 -->
<param name="namespace">/</param>
</result>
</action>

Struts2访问ServletAPI的方式:

之前我们是在Servlet中写代码,有requets,session……等对象,但是我们在action对象中如何去获取Servlet中的这些类呢?

    访问Servlet的原理

image

这是什么意思呢?

就是Struts2中有一个ActionContext对象,算是Struts2的上下文对象吧,它会帮你获取到原生的ServletAPI并且将其储存起来,你需要的时候就去创建ActionContext对象,从中获取Servlet的Api

注意:Struts2是线程安全的,它通过ThreadLocal类达到空间换取安全的目的,而synchranized(忘了咋写,尴尬)是通过时间换取安全的,两者目的相同,实现不同,具体可以百度ThreadLocal类看其原理,其次我们得知道,其实各个域对象其实是个map集合(点到这);

    ActionContext访问(推荐)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Demo5Action extends ActionSupport{

@Override
public String execute() throws Exception {

//request域对象=>map
//不推荐
Map<String, Object> request = (Map<String, Object>)ActionContext.getContext().get("request");
//推荐
ActionContext.getContext().put("name", "requestTom");

//session域=>map
Map<String, Object> session = ActionContext.getContext().getSession();
session.put("name", "sessionTom");

//application域(Context域)=>map
Map<String, Object> application = ActionContext.getContext().getApplication();
application.put("name", "applicationTom");


return SUCCESS;
}
}

让我们跟进ActionContext.getContext()的getContext()这段源码是这样:

1
2
3
public static ActionContext getContext() {
return actionContext.get();
}

再次跟进actionContext.get()的actionContext会看到:

1
static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();

是不是跟我说的一样:是使用ThreadLocal来获得Servlet的原生api

    通过ServletActionContext访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

public class Demo6Action extends ActionSupport{

//并不推荐
public String execute() throws Exception {
//原生request
HttpServletRequest request = ServletActionContext.getRequest();
//原生session
HttpSession session = request.getSession();
//原生response
HttpServletResponse response = ServletActionContext.getResponse();
//原生servletContext
ServletContext servletContext = ServletActionContext.getServletContext();

return SUCCESS;
}
}

这种其实没有价值,因为它需要去依赖Servlet的一些jar包,我们写代码讲究低耦合,高内聚,所以并不推荐

我们跟进ServletActionContext.getRequest()这段代码的getRequest()的源码:

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

我们又发现了ActionContext对象,所以这种方法的本质其实还是通过ActionContext来获取的,最后一种方法也是这样,说Struts2有三种访问Servlet的方式的人只不过是个初学者,本质都是这一个;

    通过实现接口的方式访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Demo7Action extends ActionSupport implements ServletRequestAware{

private HttpServletRequest request;

public String execute() throws Exception {

System.out.println("原生request对象:"+request);

return SUCCESS;
}

public void setServletRequest(HttpServletRequest request) {
// TODO Auto-generated method stub
this.request = request;
}
}

注意:这种方式实现的接口后缀都是Aware,需要实现一个方法,这个方法就一行代码,简单的一皮,只需设置就行,还需创建设置的本地变量

1
2
3
4
public void setServletRequest(HttpServletRequest request) {
// TODO Auto-generated method stub
this.request = request;
}

这个时候我们去到struts-default.xml文件中去找默认拦截器配置拦截器

找到这段:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
     <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>

<!-- The completeStack is here for backwards compatibility for
applications that still refer to the defaultStack by the
old name -->
<interceptor-stack name="completeStack">
<interceptor-ref name="defaultStack"/>
</interceptor-stack>

<!-- Sample execute and wait stack.
Note: execAndWait should always be the *last* interceptor. -->
<interceptor-stack name="executeAndWaitStack">
<interceptor-ref name="execAndWait">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
<interceptor-ref name="defaultStack"/>
<interceptor-ref name="execAndWait">
<param name="excludeMethods">input,back,cancel</param>
</interceptor-ref>
</interceptor-stack>

</interceptors>

其中有个: 这个
这个是声明,我们看上面有它的定义:

1
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>

复制后面的org.apache.struts2.interceptor.ServletConfigInterceptor,
然后Ctrl+Shift+T,查找这个类(注意关联源码)
进去后是这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/*
* $Id$
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.apache.struts2.interceptor;

import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.StrutsStatics;
import org.apache.struts2.servlet.interceptor.ServletPrincipalProxy;
import org.apache.struts2.util.ServletContextAware;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;


/**
* <!-- START SNIPPET: description -->
*
* An interceptor which sets action properties based on the interfaces an action implements. For example, if the action
* implements {@link ParameterAware} then the action context's parameter map will be set on it.
*
* <p/> This interceptor is designed to set all properties an action needs if it's aware of servlet parameters, the
* servlet context, the session, etc. Interfaces that it supports are:
*
* <ul>
*
* <li>{@link ServletContextAware}</li>
*
* <li>{@link ServletRequestAware}</li>
*
* <li>{@link ServletResponseAware}</li>
*
* <li>{@link ParameterAware}</li>
*
* <li>{@link RequestAware}</li>
*
* <li>{@link SessionAware}</li>
*
* <li>{@link ApplicationAware}</li>
*
* <li>{@link PrincipalAware}</li>
*
* </ul>
*
* <!-- END SNIPPET: description -->
*
* <p/> <u>Interceptor parameters:</u>
*
* <!-- START SNIPPET: parameters -->
*
* <ul>
*
* <li>None</li>
*
* </ul>
*
* <!-- END SNIPPET: parameters -->
*
* <p/> <u>Extending the interceptor:</u>
*
* <p/>
*
* <!-- START SNIPPET: extending -->
*
* There are no known extension points for this interceptor.
*
* <!-- END SNIPPET: extending -->
*
* <p/> <u>Example code:</u>
*
* <pre>
* <!-- START SNIPPET: example -->
* &lt;action name="someAction" class="com.examples.SomeAction"&gt;
* &lt;interceptor-ref name="servletConfig"/&gt;
* &lt;interceptor-ref name="basicStack"/&gt;
* &lt;result name="success"&gt;good_result.ftl&lt;/result&gt;
* &lt;/action&gt;
* <!-- END SNIPPET: example -->
* </pre>
*
* @see ServletContextAware
* @see ServletRequestAware
* @see ServletResponseAware
* @see ParameterAware
* @see SessionAware
* @see ApplicationAware
* @see PrincipalAware
*/
public class ServletConfigInterceptor extends AbstractInterceptor implements StrutsStatics {

private static final long serialVersionUID = 605261777858676638L;

/**
* Sets action properties based on the interfaces an action implements. Things like application properties,
* parameters, session attributes, etc are set based on the implementing interface.
*
* @param invocation an encapsulation of the action execution state.
* @throws Exception if an error occurs when setting action properties.
*/
public String intercept(ActionInvocation invocation) throws Exception {
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);
}

if (action instanceof ServletResponseAware) {
HttpServletResponse response = (HttpServletResponse) context.get(HTTP_RESPONSE);
((ServletResponseAware) action).setServletResponse(response);
}

if (action instanceof ParameterAware) {
((ParameterAware) action).setParameters((Map)context.getParameters());
}

if (action instanceof ApplicationAware) {
((ApplicationAware) action).setApplication(context.getApplication());
}

if (action instanceof SessionAware) {
((SessionAware) action).setSession(context.getSession());
}

if (action instanceof RequestAware) {
((RequestAware) action).setRequest((Map) context.get("request"));
}

if (action instanceof PrincipalAware) {
HttpServletRequest request = (HttpServletRequest) context.get(HTTP_REQUEST);
if(request != null) {
// We are in servtlet environment, so principal information resides in HttpServletRequest
((PrincipalAware) action).setPrincipalProxy(new ServletPrincipalProxy(request));
}
}
if (action instanceof ServletContextAware) {
ServletContext servletContext = (ServletContext) context.get(SERVLET_CONTEXT);
((ServletContextAware) action).setServletContext(servletContext);
}
return invocation.invoke();
}
}

看intercept方法,里面是不是又出现了ActionContext,还是通过ActionContext来获取Servlet的原生API的

Struts2获得参数的方式:

    扩展

分清MVC和三层架构,两个不一样
image
image

Action的生命周期:

1.每次请求到来时,都会创建一个新的Action实例

2.Action是线程安全的.可以使用成员变量接收参数

    属性驱动获得参数

表单:

1
2
3
4
5
6
<form action="${pageContext.request.contextPath}/Demo8Action">
用户名:<input type="text" name="name" /><br/>
年龄:<input type="text" name="age" /><br/>
生日:<input type="text" name="birthday" /><br/>
<input type="submit" value="提交"/>
</form>

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//struts2如何获得参数---方式一:
public class Demo8Action extends ActionSupport {

public Demo8Action() {
super();
System.out.println("Demo8Action.Demo8Action()");
}
//准备与参数键名称相同的属性
private String name;
//自动类型转换,只转换8大基本数据类型以及对应的包装类
private Integer age;
//支持特定类型字符串转换为Date类型,例如yyyy-MM-dd
private Date birthday;

public Date getBirthday() {
return birthday;
}

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

public Integer getAge() {
return age;
}

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

public String getName() {
return name;
}

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


public String execute() throws Exception {

System.out.println("name:"+name+",age:"+age+",birthday:"+birthday);

return SUCCESS;
}

}

注意:这种方式还行,每个属性都需要get和set方法;

    对象驱动获得参数

注意表单(name属性):

1
2
3
4
5
6
<form action="${pageContext.request.contextPath}/Demo9Action">
用户名:<input type="text" name="user.name" /><br/>
年龄:<input type="text" name="user.age" /><br/>
生日:<input type="text" name="user.birthday" /><br/>
<input type="submit" value="提交"/>
</form>

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Demo9Action extends ActionSupport {

//准备一个User对象
private User user;


public User getUser() {
return user;
}

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

public String execute() throws Exception {

System.out.println(user);

return SUCCESS;
}

}

    模型驱动获得参数

表单(这次表单没变):

1
2
3
4
5
6
<form action="${pageContext.request.contextPath}/Demo10Action">
用户名:<input type="text" name="name" /><br/>
年龄:<input type="text" name="age" /><br/>
生日:<input type="text" name="birthday" /><br/>
<input type="submit" value="提交"/>
</form>

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//struts2如何获得参数---方式三
//模型驱动
public class Demo10Action extends ActionSupport implements ModelDriven<User>{

//准备User:成员变量(一定要初始化了就是new了)
private User user = new User();

public String execute() throws Exception {

System.out.println("开始");
System.out.println(user);

return SUCCESS;
}

public User getModel() {
return user;
}

}

    封装集合类参数

表单:

1
2
3
4
5
6
<form action="${pageContext.request.contextPath}/Demo11Action" method="post">
list:<input type="text" name="list"/><br/>
list:<input type="text" name="list[3]"/><br/>
map:<input type="text" name="map['haha']"/><br/>
<input type="submit" value="提交"/>
</form>

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package yp.itcast.c_param;

import java.util.List;
import java.util.Map;

import com.opensymphony.xwork2.ActionSupport;

//struts2 封装集合类型参数
public class Demo11Action extends ActionSupport{

//List
private List<String> list;

//Map
private Map<String,String> map;

public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}

public String execute() throws Exception {

System.out.println("list:"+list);
System.out.println("map:"+map);

return SUCCESS;
}


}