请求-响应过程中struts功能详解
1. 接收请求
- 浏览器向服务器发送请求
- 服务器根据web.xml(核心过滤器)的配置将请求交给struts框架
- 但struts框架不一定所有的请求都处理。
- 默认:只接收处理 .action后缀的请求或没有后缀的请求
/test.action
/test - 可以重置struts.action.extension 属性改变处理请求的后缀
2. 映射请求
-
struts根据<action>配置,找到与此次请求对应的处理类
<action name="test" class="com.action.TestAction" method="t1"></action>- 注意:映射请求时,不再携带后缀匹配
- 发送的请求是test.do
- 映射的请求是test
- .do后缀在接收请求时起作用
- 注意:处理请求的action类就是一个普通pojo类,不需要任何继承(对比 servlet)
- 注意:<action method="">没有配置则默认调用execute方法,配置则调用指定方法。
- 注意:处理的请求方法不能有任何参数
如果有响应处理,设置String返回值,否则void。
- 注意:映射请求时,不再携带后缀匹配
有3种请求映射方式:
第1种:一个<action>配置对应一个请求
<action name="test1" class="com.action.TestAction" method="t1"></action>
<action name="test2" class="com.action.TestAction" method="t2"></action>
第2种:动态方法调用,一个<action>配置对应多个请求
- 浏览器发请求时要符合以下规则
/test!t3.do
/test!t4.do- 上述2个请求语法都表示发送test.do请求
- 后面的t3和t4表示处理请求的方法名
- 在struts.xml配置文件中重置属性,开启动态方法调用
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
- 配置<action>
<action name="test" class="com.action.TestAction"></action>
- 在struts.xml的<package>中,指定允许动态方法调用的方法名。
<global-allowed-methods>t3,t4</global-allowed-methods>
第3种: 通配符匹配,一个<action>配置对应多个请求
- 浏览器发送请求时要符合一定的规则(自定义)
/Test_t5.do
/Test_t6.do - 使用通配符配置<action>
<action name="Test_" class="com.action.TestAction" method="{1}"></action>
{1} 代表第1个*代表的位置
- 扩展:
/Test_User_t5.do
/Test_Book_t6.do
在struts.xml配置文件中
<action name="Test_*_*" class="com.action.{1}Action" method="{2}"></action>
等价于
<action name="Test_*_*" class="com.action.UserAction" method="t5"></action>
- 在struts.xml的<package>中,指定允许动态方法调用的方法名。
<global-allowed-methods>t3,t4</global-allowed-methods>
3. 请求处理
- 接收参数:
- 接收action对象的初始化参数
- 我们定义的action类,但由struts框架负责管理(创建,调用) (IOC 控制反转)
- 在struts.xml中,使用<action>的子标签<param> 指定初始化参数
<param name="size" >10</param>
- 在action类中定义与上述参数同名的属性,并实现set方法
- 属性类型与参数值匹配即可。
- 注意:struts在创建action时会自动调用set方法为action传递初始化参数 (DI 依赖注入)
- 接收请求传递的独立参数
- 在action中定义与请求参数同名的属性,并实现set方法
- 属性类型与参数值匹配即可。
- 接收传递的对象参数
- 传递了多个参数,且这些参数恰好可以组成一个对象。
- 在浏览器(网页)请求传参时,需要为每一个参数提供一个统一对象名前缀,如:
/test3.do?user.uname=dmc&user.upass=123&user.age=18&user.uno=1001
<input name="user.uname" />
- 定义装载参数的类(User)
- 隐藏条件:类属性名必须与请求的参数名一致
public class User implements Serializable {
private Integer uno ;
private String uname ;
private String upass ;
private Integer age ;
public Integer getUno() {
return uno;
}
public void setUno(Integer uno) {
this.uno = uno;
}
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getUpass() {
return upass;
}
public void setUpass(String upass) {
this.upass = upass;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public User(Integer uno, String uname, String upass, Integer age) {
this.uno = uno;
this.uname = uname;
this.upass = upass;
this.age = age;
}
public User() {
}
}
- 在action中定义User类型的属性,属性名就是参数的前缀名,并实现set/get方法
public class TestAction2 {
private String uname ;
private int age ;
public void setUname(String uname) {
this.uname = uname;
}
public void setAge(int age) {
this.age = age;
}
public void t2(){
//String uname = request.getParameter("uname");
System.out.println(uname+"--------------"+age);
}
}
- 扩展: 接收请求传递的对象参数 (模型驱动)
- 浏览器(网页) 正常传参, 参数不需要提供对象名前缀
/test4.do?uname=dmc&upass=123&age=18&uno=1001 - action类 实现 ModelDriven<User>接口,设置User泛型 , 重写方法(getModel)
- action类中定义User类型属性,并创建对象。
User user = new User(); - 在getModel()方法中,返回一个user属性值
public User getModel() {
return user;
} - 机制:
- struts框架创建action时
- 会通过检测机制(拦截器)发现action实现了ModelDriven接口
- 就会调用action的getModel方法获得一个返回的(user)对象
- 将获取的参数装载到(值栈顶)user对象中。
扩展:值栈
image.png在每次请求时,struts会根据请求映射的配置,创建action对象并调用方法
- 于此同时还会创建一个值栈对象
- 值栈用来存放请求响应过程中的一些数据内容,如:request,response,session,application等
- 值栈栈顶装载的就是action对象
- struts有一个params拦截器,负责接收参数
- 接收参数后,会获得值栈栈顶的对象(默认是action), 为其(根据set方法)传递参数
- 如果发现action实现了ModelDriven接口
- modelDriven拦截器会通过getModel()获得对象(user),将对象装入栈顶
- params再赋值时,就是为user对象赋值(通过set方法),获取servlet相关对象 request , response , session , application等
* 方式1:通过ActionContext获得一个具有session存储功能的Map对象
Map<String,Object> session = ActionContext.getContext().getSession();
session.put("uname",uname) ;//相当于session.setAttribute("uname",uname);
- 扩展:
ActionContext.getContext().put("k","v");//相当于request.setAttribute(k,v);
ActionContext.getContext().getApplication().put("k","v");//相当于application.setAttribute(k,v);
public class TestAction1 {
private String uname ;
public void setUname(String uname) {
this.uname = uname;
}
public void t1(){
System.out.println("----------------" + uname);
//将unmae参数值装入session对象
Map<String,Object> session = ActionContext.getContext().getSession();
session.put("uname",uname) ;//相当于session.setAttribute("uname",uname);
//ActionContext.getContext().put("k","v");//相当于request.setAttribute(k,v);
//ActionContext.getContext().getApplication().put("k","v");//相当于application.setAttribute(k,v)
}
}
* 方式2: 通过SerlvetActionCotnext获得原生servlet相关对象
HttpServletRequesst,HttpServletResponse,HttpSession
ServletActionContext.getRequest();
request.getSession(); //sessioin
request.getServletContext(); //application
ServletActionContext.getResponse();
public class TestAction2 {
private int age ;
public void setAge(int age) {
this.age = age;
}
public void t2(){
System.out.println("==============" + age );
//将action装入session
ServletActionContext.getRequest().getSession().setAttribute("age",age); ;
}
}
* 方式3:通过实现接口,配合拦截器,使用DI方式获得原生servlet相关对象
- action实现SessionAware接口,重写方法
- action中定义session属性
- set方法中赋值
private Map<String,Object> session ;
public void setSessioin(Map<String,Object> map){
this.session = map ;
}
public class TestAction3 implements SessionAware {
private String sex ;
public void setSex(String sex) {
this.sex = sex;
}
private Map<String,Object> session ;
public void t3(){
System.out.println("++++++++++++++++++++" + sex);
//将sex装入session
}
@Override
public void setSession(Map<String, Object> map) {
this.session = map ;
}
}
实现机制:
在struts的请求处理过程中,先通过拦截器(servletConfig)对action进行检测,如果发现该action实现了接口SessionAware
,struts就会根据set方法传入session对象(DI 依赖注入)
补充:
action实现了ServletRequestAware
接口 获得HttpServletRequest
action实现了ServletResponseAware
接口 获得HttpServletResponse
* 扩展:
通过上述3种方式的源码分析发现获取的所有对象最终都来自ActionContext
所以没有性能差别
网友评论