Java网课基础笔记(36)19-08-18

 

模型驱动的原理(了解)

【问题】为什么在赋值的时候,模型驱动的属性会优先赋值?模型驱动是如何具备更高的优先级别?

【示例】新增user数据模型,使用模型驱动

编写valuestack2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 <%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>s:debug标签可以在html页面上查看值栈内容</h3>
<s:debug></s:debug>
</body>
</html>

编写ValueStackAction6.java

public class ValueStackAction6  extends ActionSupport implements ModelDriven<User>{
	//通过模型驱动
			private User user= new  User();
		@Override
		public User getModel() {
			// TODO Auto-generated method stub
			return user;
		}
	//通过属性驱动
	private String username;
	
	public User getUser() {
		return user;
	}

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

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	@Override
	public String execute() throws Exception {
		
		// TODO Auto-generated method stub
		return SUCCESS;
	}

	

}

配置struts.xml

<!-- 开启struts的debug模式才可以在页面上查看debug信息 -->
<constant name="struts.devMode" value="true"></constant>
	<package name="default" extends="struts-default" namespace="/">
		<action name="vs6" class="struts2_03.valueStack.ValueStackAction6">
		<result>/stack/valuestack2.jsp</result></action>
	</package>

测试结果,输入http://localhost:8080/struts2_03/vs6.action?username=chen&password=123。 点击debug

【运行结果分析】系统在运行的时候,调用值栈的默认搜索,先找到模型驱动的username,然后直接赋值。即模型驱动优先于属性驱动。

注意:值栈在使用过程中要注意同名覆盖的问题。 

值栈的创建过程源代码分析(了解)

ValueStack对象的创建过程


  • StrutsPrepareAndExecuteFilter

         doFilter方法

        prepare.createActionContext(request,response);

        创建ActionContext和ValueStack

        ctx=new ActionContext(stack.getContext());

         ActionContext引用ValueStack对象

  • Dispatcher

       serviceAction方法

      request.setAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY,stack);

      将ValueStack对象保存到request范围

【值栈的运行流程源码详解】

  1. 访问Action,创建一个值栈,有一个元素,放了国际化信息
  2. init方法时,把当前执行的Action放入值栈
  3. 当执行模型驱动的拦截器时,把模型也放入值栈

1.访问action的时候,走过滤器,StrutsPrepareAndExecuteFilter中创建了值栈(ValueStack<--OgnlValueStack),并将常用web对象保存到OgnlContext的Map中。

注意:此时root栈为空

2.当访问Action的时候,过滤器会通过ActionProxy代理对象来执行。通过ActionProxyFactory的createActionProxy方法来得到代理对象。在获取代理对象的时候,需要创建一个ActionInvocation接口的默认实现类DefaultActionInvocation的对象,该默认对象在创建的时候会自动调用init方法来初始化,在初始化方法中会自动调用stack.push(action)方法,将当前Action对象,压入Root栈的顶部。

注意:再通过debug调试发现,默认情况下ValueStack的root栈存在2个对象,ValueStackAction(Action在栈顶)和DefaultTextProvider(用来初始化获取国际话资源信息)。

3.在初始化Action代理对象后,会自动调用拦截器(增强),而执行默认拦截器栈中的ModelDriven拦截器,struts2会判断该Action是否实现了ModelDriven接口,如果实现了,则会调用ModelDrivenInterceptor拦截器中的intercept方法,在该方法在会调用stack.push(model),将model压入root栈顶。

注意:此时root栈就有了3个对象,栈顶时model。

原理目的:

  • 知道栈顶的初始化时机,访问action的时候,才创建(这个过程会创建actionProxy对象,并且同时创建值栈,并且,将一些对象放入值栈。)
  • 值栈初始化之后,里面注意默认有,root栈(model(user),action类对象、DefaultTextProvider),map栈(servlet相关对象、action对象一个引用)
  • 要了解,哪些对象在栈顶!因为后面我们从值栈取值,都从栈顶往下取。所以,一个要知道哪个对象在栈上面。

值栈的生命周期

【分析】

  • 贯穿整个Action的生命周期,每个Action类的对象实例都拥有一个ValueStack对象。
  • Struts2框架价格ValueStack对象保存在名为“struts-valueStack”的(request)请求属性中,即值栈时request中的一个对象,一个请求对应一个Action实例和一个值栈对象

值栈的以线程安全的方式为每个请求提供公共的数据存取服务。当有请求到达的时候,Struts2会为每个请求创建一个新的值栈。也就是说,值栈和请求是一一对应的,不同的请求,值栈也会不一样,而值栈封装了一次请求所有需要操作的数据。

因此,值栈的生命周期,就是request生命周期,也就是Action的生命周期

【示例】通过重定向跳转项目时,目标页面无法获取到Action中放入值栈的值。

证明值栈的生命周期是与request一致的(下面是一个完整的例子测试值栈的生命周期)

编写ValueStackAction7.java

public class ValueStackAction7 extends ActionSupport{
	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		ActionContext.getContext().getValueStack().set("name", "feng");
		return SUCCESS;
	}

}

编写valuestack3.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 <%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<s:property value="name"/> 
</body>
</html>

配置struts.xml

<action name="vs7" class="struts2_03.valueStack.ValueStackAction7">
		<result>/stack/valuestack3.jsp</result></action>

测试结果 

先修改struts.xml的跳转方式,默认是请求跳转,现在改为重定向

<action name="vs7" class="struts2_03.valueStack.ValueStackAction7">
		<result type="redirect">/stack/valuestack3.jsp</result></action>

测试结果

发现获取不到数据,表明值栈的生命周期和request一致的。

Struts2支持的表达式语言

Struts2支持一下几种表达式语言:

  • OGNL,可以方便地操作对象属性的开源表达式语言;
  • EL,可以方便的操作就是jsp页面四个域范围数据(page、request、session、application);
  • JSTL,jsp 2.0集成的标准的表达式语言
  • Groovy基于Java平台的动态语言,它具有时下比较流行的动态语言(如python、Ruby和Smarttalk等)的一些特性;
  • Velocity,严格来说不是表达式语言,它是一种基于Java的模版匹配引擎,据说性能要比jsp好

Struts2默认的表达式语言是OGNL,原因是它相对其他表达式语言更简单、强大,最重要的是可以直接操作值栈。

OGNL对Struts2的值栈的操作方式

明确一点,OGNL表达式对值栈的操作,必须依赖Struts2的标签,所有每个jsp页面都需要引入Struts2的标签库。

Struts2通过值栈存放数据,那如何取数据呢?通过Ognl表达式访问值栈中的数据在Struts2中,OGNL表达式三种特殊符号的使用方式:

  • #号用法
  • %号用法
  • $号用法

#号的使用

访问Map栈中常用对象,包括wen对象(request/response/session/application..),添加#进行访问。

提示:#atrr按照page--request-session-application的顺序依次进行

【示例】在action中添加代码,想request、session、application域中放入对象,然后在页面通过ognl表达式获取。

编写ognl1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>OGNL表达式获取request域中的数据|EL表达式取数据</h3>
<s:property value="#request.name"/> | ${requestScope.name}
<h3>OGNL表达式获取session域中的数据</h3>
<s:property value="#session.name"/> | ${sessionScope.name}
<h3>OGNL表达式获取application域中的数据</h3>
<s:property value="#application.name"/> | ${applicationScope.name}
<h3>如何往page域放数据,在当前页面放入</h3>
<%
pageContext.setAttribute("name", "page数据");
%>
<s:property value="#attr.name"/> | ${name }
<h3>如何获取地址栏传过来的参数呢?</h3>
地址栏的信息:<s:property value="#parameters.name"/>
</body>
</html>

编写OgnlAction1.java

public class OgnlAction1 extends ActionSupport{
@Override
public String execute() throws Exception {
	// TODO Auto-generated method stub
	//把数据放入request、session、application3个域中
	ServletActionContext.getRequest().setAttribute("name", "request数据");
	ServletActionContext.getRequest().getSession().setAttribute("name", "session数据");
	ServletActionContext.getServletContext().setAttribute("name", "application数据");
	return SUCCESS;
}
}

配置struts.xml

<!-- ognl表达式#的作用 -->
		<action name="ognl1" class="struts2_03.ongl.OgnlAction1">
		<result>/ognl/ognl1.jsp</result></action>

测试结果 输入http://localhost:8080/struts2_03/ognl1.action?name=chen(如果session数据没出来,请再重新页面)

%的使用

主要作用:强制解析

【示例】

编写OgnlAction2.java

public class OgnlAction2 extends ActionSupport{
@Override
public String execute() throws Exception {
	// TODO Auto-generated method stub
ActionContext.getContext().getValueStack().set("name", "fenger");	
	return SUCCESS;
}
}

编写ognl2.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>文本框获取值栈中的值,使用%{}强制解析中的值</h3>
<h3>默认不解析</h3>
<s:textfield value="name"></s:textfield>
<h3>强制解析</h3>
<s:textfield value="%{name}"></s:textfield>
<h3>强制不解析</h3>
<s:property value="%{'name'}"/>
</body>
</html>

配置struts.xml

<!-- ognl表达式%的作用 -->
		<action name="ognl2" class="struts2_03.ongl.OgnlAction2">
		<result>/ognl/ognl2.jsp</result></action>

测试结果

$号的使用

此处的$不能理解为el表达式,因此此处的$必须用在struts特有的文件中,只能用在struts2点文件中

用法:是用在strust2特有点文件中的

$的主要作用:允许我们在配置文件中使用OGNL表达式,(换句话说,$可以在xml文件中获取值栈的值。)

配置文件主要指:struts.xml、国际化的文件(xxx.properties)、校验配置文件(xxx-validation.xml)

【示例1】在资源文件中使用,在页面读取携带参数--国际化文件中使用

编写OgnlAction3.java

public class OgnlAction3 extends ActionSupport {
	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		// 如果要在xml或属性properties文件中获取值栈的值,值不能是中文
		ServletActionContext.getContext().getValueStack().set("productName", "iphone");
		return SUCCESS;
	}
}

编写ognl3.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>通过键获取国际化资源文件中的内容</h3>
<s:text name="productInfo"></s:text>

</body>
</html>

编写属性文件messages.properties

<!--欢迎使用${productName}产品-->
productInfo=\u6B22\u8FCE\u4F7F\u7528${productName}\u4EA7\u54C1

测试结果

【说明】通过上述证明,表明在资源文件中可以通过${productName}的方式获取值栈中的内容

【示例2】struts.xml中使用$的方式获取值栈中的值,url请求重定向时,携带参数

编写OgnlAction4.java

public class OgnlAction4 extends ActionSupport {
	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		// 如果要在xml或属性properties文件中获取值栈的值,值不能是中文
		ServletActionContext.getContext().getValueStack().set("productName", "iphone");
		return SUCCESS;
	}
}

配置struts.xml

<action name="ognl4" class="struts2_03.ongl.OgnlAction4">
		<!-- 获取值栈中当产品名称,当作参数传给页面 -->
		<result type="redirect">/ognl/ognl4.jsp?productName=${productName}</result></action>

编写ognl4.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@taglib uri="/struts-tags" prefix="s" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>重定向时,值传不过来,这个时候,这个页面还必须要使用那个productName,那怎么办?</h3>
<h3>如何获取这个参数呢?</h3>
<s:property value="#parameters.productName"/>
</body>
</html>

测试结果

在#号的使用示例中,也表明通过el表达式可以获取值栈中的内容

【原理分析】EL表达式原理,在page、request、session、apllication四个范围,调用getAttribute获取数据,为什么也可以获取值栈的值呢?

Struts2对request进行包装了,对request的getAttribute方法增强

Struts2提供StrutsRequestWrapper包装类,如果request中存在值,就直接去request中查找,如果不存在key,就去值栈中搜素。优先使用request.getAttribute取值,如果取不到,执行vlaueStack到findValue方法,因此,request到个体Attribute方法被覆写。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值