第1章Struts2
-
-
- 需求分析
-
Crm系统使用struts2架构实现web层,web层实现的功能是控制逻辑和视图。
整体调用流程如下:
1、用户请求至struts2
2、struts2调用service
3、service调用dao
4、dao持久化数据
-
- 相关知识点
- Struts2框架的概述
- 什么是Struts2
- Struts2框架的概述
- 相关知识点
Struts2是一个基于MVC设计模式的WEB层框架。
-
-
-
- Struts2和Struts1区别:
-
-
Struts2和Struts1没有任何联系.Struts2内核是webwork的内核.
-
-
-
- WEB层的框架都会基于前端控制器的模式:
-
-
-
-
- Struts2快速入门:
- 解压Struts2的开发包:
- Struts2快速入门:
-
* apps :Struts2提供一些案例
* docs :Struts2开发文档.
* lib :Struts2的开发的jar包
* src :Struts2的源码
-
-
-
- 创建一个web工程引入相应jar包:
-
-
D:\struts2\struts-2.3.24\apps\struts2-blank\WEB-INF\lib\*.jar
-
-
-
- 创建一个页面:放置一个链接.
-
-
<h1>Struts2的入门案例</h1>
<a href="${pageContext.request.contextPath }/strutsDemo1.action">访问Struts2的Action.</a>
-
-
-
- 编写一个Action:
-
-
public class StrutsDemo1 {
/**
* 提供一个默认的执行的方法:execute
*/
public String execute(){
System.out.println("StrutsDemo1中的execute执行了...");
return null;
}
}
-
-
-
- 完成Action的配置:
-
-
在src下引入一个struts.xml
<struts>
<!-- 配置一个包:package -->
<package name="demo1" extends="struts-default" namespace="/">
<!-- 配置Action -->
<action name="strutsDemo1" class="cn.it.struts2.action.StrutsDemo1">
</action>
</package>
</struts>
-
-
-
- 配置核心过滤器:
-
-
<!-- 配置Struts2的核心过滤器:前端控制器 -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
-
-
-
- 修改Action,将方法设置一个返回值:
-
-
public class StrutsDemo1 {
/**
* 提供一个默认的执行的方法:execute
*/
public String execute(){
System.out.println("StrutsDemo1中的execute执行了...");
return "success";
}
}
-
-
-
- 修改struts.xml
-
-
<struts>
<!-- 配置一个包:package -->
<package name="demo1" extends="struts-default" namespace="/">
<!-- 配置Action -->
<action name="strutsDemo1" class="cn.it.struts2.action.StrutsDemo1">
<!-- 配置结果页面的跳转 -->
<result name="success">/demo1/demo2.jsp</result>
</action>
</package>
</struts>
-
-
- Struts2开发流程分析
- Struts2的执行流程:
- Struts2开发流程分析
-
从客户端发送请求过来 先经过前端控制器(核心过滤器StrutsPrepareAndExecuteFilter)过滤器中执行一组拦截器(一组拦截器 就会完成部分功能代码)执行目标Action,在Action中返回一个结果视图,根据Result的配置进行页面的跳转.
-
-
-
- 配置struts.xml中的提示(在不联网情况下)
-
-
DTD存放的路径:src\core\src\main\resources\struts-2.3.dtd
Window--->Preferences--->在左侧搜索xml catalog--->add添加.
* 选择URI
* 文件系统 选择dtd路径
-
-
- Struts2的常见配置
- Struts2的配置文件的加载顺序:
- Struts2的常见配置
-
查看StrutsPrepareAndExecuteFilter:(核心过滤器)两个功能 :预处理 和 执行
在预处理功能中 init 方法中会有加载配置文件的代码:
dispatcher.init();
init_DefaultProperties(); // [1] ---- 加载org.apache.struts.default.properties.配置的是struts2的所有常量.
init_TraditionalXmlConfigurations(); // [2] ---- 加载struts-default.xml、struts-plugin.xml、struts.xml
init_LegacyStrutsProperties(); // [3] ---- 加载用户自定义struts.properties
init_CustomConfigurationProviders(); // [5] ---- 加载Struts2定义Bean.
init_FilterInitParameters() ; // [6] ---- 加载web.xml
init_AliasStandardObjects() ; // [7] ---- 用户自定义Bean
结论:
* default.properties
* struts-default.xml
* struts-plugin.xml
* struts.xml ---- 配置Action以及常量.(******)
* struts.properties ---- 配置常量
* web.xml ---- 配置核心过滤器及常量.
***** 后配置的常量 会 覆盖先配置的常量.
-
-
-
- Action的配置:
-
-
<package>的配置:
* package:包. 不是java中说那个包. Struts2中的包 管理<action>.
* 属性:
* name :包名.包名是唯一的不能重复的.
* extends :继承.继承struts-default.(struts-default包中定义结果类型和拦截器.)
* namespace :名称空间.与<action>标签中的name属性共同决定Action的访问路径.
* 写法:
* namespace有名称: namespace=”/aa”
* namespace只是一个/: namespance=”/”
* namespace默认的: namespace没写.
* abstract :抽象的.用于使其他的包可以继承的.
* <package name="struts-default" abstract="true"> . 所以可以继承struts-default.
<action>的配置:
* action:配置Action类的访问路径.
* 属性:
* name :名称.与<package>中的namespace属性共同决定访问路径.
* class :类的全路径.要执行的Action类的全路径.
* method :方法.用来指定Action中执行那个方法的方法名.(默认的值execute)
<result>的配置:
* result:配置Action执行后的页面跳转.
* 属性:
* name :逻辑视图名称.(不是真实的视图,为真实的视图起了一个别名,在Action中返回这个字符串的别名,从而找到具体页面.)
* type :跳转的类型.
-
-
-
- 默认的Action和Action的默认处理类:
-
-
默认的Action:
<!-- 配置默认的Action:Action的访问路径不存在的时候,执行一个默认的Action -->
<default-action-ref name="strutsDemo1"/>
Action的默认处理类:
<!-- Action的默认处理类:Action的访问路径配置正确了,但是没有配置class属性. -->
<default-class-ref class="com.opensymphony.xwork2.ActionSupport"/>
-
-
-
- Struts2常量的配置:
-
-
修改常量:
* struts.xml中修改常量(推荐使用)
<!-- 修改Struts2的常量的值 -->
<constant name="struts.action.extension" value="abc"/>
* struts.properties修改常量
struts.action.extension=xxx
* web.xml中修改常量
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>xyz</param-value>
</init-param>
</filter>
-
-
-
- 分模块开发的时候
-
-
<include file="cn/it/struts2/demo1/struts_demo1.xml"/> 整合其他的struts的配置文件.
-
-
- Struts2的Action的访问:
- Action的编写的方式:
- Struts2的Action的访问:
-
【Action的是一个POJO的类】
Action是简单的Java对象没有实现任何借口 和 继承任何类.
public class ActionDemo1 {
public String execute(){
System.out.println("执行Demo1");
return null;
}
}
【Action类实现一个Action的接口】
public class ActionDemo2 implements Action{
@Override
public String execute() throws Exception {
System.out.println("执行ActionDemo2");
return null;
}
}
Action接口中提供了5个已经定义好的视图名称:
* SUCCESS :success,代表成功.
* NONE :none,代表页面不跳转
* ERROR :error,代表跳转到错误页面.
* INPUT :input,数据校验的时候跳转的路径.
* LOGIN :login,用来跳转到登录页面.
【Action类继承ActionSupport类】
public class ActionDemo3 extends ActionSupport{
@Override
public String execute() throws Exception {
System.out.println("执行ActionDemo3");
return NONE;
}
}
ActionSupport中提供了一些功能,比如数据校验,比如国际化… 如果Action继承了ActionSupport,那么Action就会有这些功能.
-
-
-
- Action的访问:
-
-
Action的访问不是难题,因为之前已经访问过了,但是出现一个问题一次请求现在对应一个Action,那么如果请求很多对应很多个Action.现在要处理的问题就是要让一个模块的操作提交到一个Action中。
【解决Action的访问的问题的方式一:通过配置method属性完成】
页面:
<h3>客户的管理</h3>
<a href="${ pageContext.request.contextPath }/saveCustomerAction.action">添加客户</a> <br/>
<a href="${ pageContext.request.contextPath }/updateCustomerAction.action">修改客户</a> <br/>
<a href="${ pageContext.request.contextPath }/deleteCustomerAction.action">删除客户</a> <br/>
<a href="${ pageContext.request.contextPath }/findCustomerAction.action">查询客户</a> <br/>
编写Action:
public class CustomerAction extends ActionSupport{
public String save(){
System.out.println("执行CustomerAction中save方法);
return NONE;
}
public String update(){
System.out.println("执行CustomerAction中update方法");
return NONE;
}
public String delete(){
System.out.println("执行CustomerAction中delete方法");
return NONE;
}
public String find(){
System.out.println("执行CustomerAction中find方法");
return NONE;
}
}
配置Action:
<package name="demo3" extends="struts-default" namespace="/">
<action name="saveCustomerAction" class="cn.it.struts2.demo3.CustomerAction" method="save"></action>
<action name="updateCustomerAction" class="cn.it.struts2.demo3.CustomerAction" method="update"></action>
<action name="deleteCustomerAction" class="cn.it.struts2.demo3.CustomerAction" method="delete"></action>
<action name="findCustomerAction" class="cn.it.struts2.demo3.CustomerAction" method="find"></action>
</package>
【解决Action的访问的问题的方式二:通过通配符的配置完成】
第一种解决方案不是很优秀,因为在Action的配置中配置多条.能不能一个Class类只对应一个配置?
页面:
<h3>联系人的管理</h3>
<a href="${ pageContext.request.contextPath }/linkman_save.action">添加联系人</a> <br/>
<a href="${ pageContext.request.contextPath }/linkman_update.action">修改联系人</a> <br/>
<a href="${ pageContext.request.contextPath }/linkman_delete.action">删除联系人</a> <br/>
<a href="${ pageContext.request.contextPath }/linkman_find.action">查询联系人</a> <br/>
编写Action:
public class LinkManAction extends ActionSupport{
public String save(){
System.out.println("保存");
return NONE;
}
public String update(){
System.out.println("修改.");
return NONE;
}
public String delete(){
System.out.println("删除");
return NONE;
}
public String find(){
System.out.println("查询");
return NONE;
}
}
配置Action:
<!-- 通配符的配置 -->
<action name="linkman_*" class="cn.it.struts2.demo3.LinkManAction" method="{1}"></action>
【解决Action的访问的问题的方式三:动态方法访问】
开启一个常量:动态方法访问.
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
编写Action:
public class UserAction extends ActionSupport{
public String save(){
System.out.println("保存");
return NONE;
}
public String update(){
System.out.println("修改");
return NONE;
}
public String delete(){
System.out.println("删除");
return NONE;
}
public String find(){
System.out.println("查询用户");
return NONE;
}
}
配置Action:
<!-- 动态方法访问的配置 -->
<action name="userAction" class="cn.it.struts2.demo3.UserAction"></action>
页面路径写法:
<h3>用户的管理</h3>
<a href="${ pageContext.request.contextPath }/userAction!save.action">添加用户</a> <br/>
<a href="${ pageContext.request.contextPath }/userAction!update.action">修改用户</a> <br/>
<a href="${ pageContext.request.contextPath }/userAction!delete.action">删除用户</a> <br/>
<a href="${ pageContext.request.contextPath }/userAction!find.action">查询用户</a> <br/>
第2章Struts2
-
- 相关知识点
- Struts2访问Servlet的API:
- 可以使用完全解耦合的方式.
- Struts2访问Servlet的API:
- 相关知识点
public class RequestActionDemo1 extends ActionSupport{
@Override
public String execute() throws Exception {
// 接收表单的参数:
// 使用的是Struts2中的一个对象ActionContext对象.
ActionContext actionContext = ActionContext.getContext();
// 接收参数:
Map<String,Object> paramsMap = actionContext.getParameters();
for (String key : paramsMap.keySet()) {
String[] value = (String[]) paramsMap.get(key);
System.out.println(key+" "+value[0]);
}
// 向request中存入数据 request.setAttribute(String name,Object value);
actionContext.put("requestName", "张三");
// 向session中存入数据 request.getSession().setAttribute(String name,Object value);
actionContext.getSession().put("sessionName", "李四");
// 向application中存入数据 this.getServletContext().setAttribute(String name,Object value);
actionContext.getApplication().put("applicationName", "王五");
return SUCCESS;
}
}
-
-
-
- 使用原生的Servlet的API
-
-
public class RequestActionDemo2 extends ActionSupport{
@Override
public String execute() throws Exception {
// 接收参数:
HttpServletRequest req = ServletActionContext.getRequest();
Map<String,String[]> map = req.getParameterMap();
for (String key : map.keySet()) {
String[] value = map.get(key);
System.out.println(key+" "+value[0]);
}
// 向域中存入数据:
req.setAttribute("requestName", "张三");
// 向session中存入数据:
req.getSession().setAttribute("sessionName", "李四");
// 向application中保存:
ServletActionContext.getServletContext().setAttribute("applicationName", "王五");
return SUCCESS;
}
}
-
-
- 结果页面的配置:
- 全局结果页面
- 结果页面的配置:
-
<global-results>
<result name="success">/demo3/demo2.jsp</result>
</global-results>
-
-
-
- 局部结果页面
-
-
<action name="requestActionDemo2" class="cn.it.struts2.demo4.RequestActionDemo2">
<result name="success">/demo3/demo3.jsp</result>
</action>
<result>标签:
* name :返回一个逻辑视图名称.
* type : 跳转的采用的方式.
* dispatcher :默认值,转发. 转发到一个JSP页面
* redirect :重定向. 重定向到一个JSP页面
* chain :转发,转发到一个Action.
* redirectAction :重定向到另一个Action
-
-
- Struts的数据封装
-
实际开发的场景:页面提交参数,在Action中接收参数,需要进行数据的封装,封装到JavaBean中,将JavaBean传递给业务层.
-
-
-
- 属性驱动
-
-
- 编写属性的set方法的方式进行参数的封装】使用比较少.
页面:
<h1>Struts2的属性驱动中:set方法的方式</h1>
<form action="${ pageContext.request.contextPath }/strutsDemo1.action" method="post">
名称:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
生日:<input type="text" name="birthday"><br/>
<input type="submit" value="提交">
</form>
Action:
public class StrutsDemo1 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;
}
…
}
***** 这种方式还需要手动封装对象。
- 页面中使用表达式的方式进行参数的封装】
页面:
<h1>Struts2的属性驱动中:OGNL表达式的方式</h1>
<form action="${ pageContext.request.contextPath }/strutsDemo2.action" method="post">
名称:<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>
Action:
public class StrutsDemo2 extends ActionSupport{
private User user;
// 必须提供get方法.
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
…
}
-
-
-
- 模型驱动
-
-
- 使用模型驱动的方式进行参数的封装】(优先)
页面:
<h1>Struts2的模型驱动驱动中:模型驱动的方式</h1>
<form action="${ pageContext.request.contextPath }/strutsDemo3.action" method="post">
名称:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
生日:<input type="text" name="birthday"><br/>
<input type="submit" value="提交">
</form>
Action:
public class StrutsDemo3 extends ActionSupport implements ModelDriven<User>{
// 模型驱动使用的对象.
private User user = new User();// 必须手动new
@Override
public User getModel() {
return user;
}
…
}
-
-
- Struts2中封装复杂类型的数据:
- 封装到List集合中:
- Struts2中封装复杂类型的数据:
-
页面:
<form action="${ pageContext.request.contextPath }/strutsDemo4.action" method="post">
名称:<input type="text" name="list[0].name"><br/>
年龄:<input type="text" name="list[0].age"><br/>
生日:<input type="text" name="list[0].birthday"><br/>
名称:<input type="text" name="list[1].name"><br/>
年龄:<input type="text" name="list[1].age"><br/>
生日:<input type="text" name="list[1].birthday"><br/>
<input type="submit" value="提交">
</form>
Action:
public class StrutsDemo4 extends ActionSupport{
private List<User> list;
public List<User> getList() {
return list;
}
public void setList(List<User> list) {
this.list = list;
}
@Override
public String execute() throws Exception {
for (User user : list) {
System.out.println(user);
}
return NONE;
}
}
-
-
-
- 封装数据到Map集合:
-
-
页面:
<h1>批量插入用户:封装到Map集合</h1>
<form action="${ pageContext.request.contextPath }/strutsDemo5.action" method="post">
名称:<input type="text" name="map['one'].name"><br/>
年龄:<input type="text" name="map['one'].age"><br/>
生日:<input type="text" name="map['one'].birthday"><br/>
名称:<input type="text" name="map['two'].name"><br/>
年龄:<input type="text" name="map['two'].age"><br/>
生日:<input type="text" name="map['two'].birthday"><br/>
<input type="submit" value="提交">
</form>
Action:
public class StrutsDemo5 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()) {
User user = map.get(key);
System.out.println(key+" "+user);
}
return NONE;
}
}
-
- 总结:
- Struts2的拦截器:
- 拦截器的概述
- Struts2的拦截器:
- 总结:
拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。
谈到拦截器,还有一个词大家应该知道——拦截器链 (Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
-
-
-
- 拦截器的实现原理:
-
-
大部分时候,拦截器方法都是通过代理的方式来调用的。Struts 2的拦截器实现相对简单。当请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。
Struts2拦截器是可插拔的,拦截器是AOP的一种实现。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。
-
-
-
- Struts2的执行流程:
-
-
-
-
-
- 自定义拦截器及配置:
-
-
第一步: 自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。
第二步:在strutx.xml中注册上一步中定义的拦截器。
第三步:在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的Action都被这个拦截器拦截。
第3章Struts2
-
- 相关知识点
- OGNL的概述
- 什么是OGNL
- OGNL的概述
- 相关知识点
-
-
-
- OGNL的作用
-
-
1、支持对象方法调用,如xxx.doSomeSpecial();
2、支持类静态的方法调用和值访问,表达式的格式:
@[类全名(包括包路径)]@[方法名 | 值名],例如:
@java.lang.String@format('foo %s', 'bar')
或@tutorial.MyConstant@APP_NAME;
设置 struts.ognl.allowStaticMethodAccess=true
3、访问OGNL上下文(OGNL context)和ActionContext;访问值栈
4、支持赋值操作和表达式串联,如price=100, discount=0.8,
calculatePrice(),这个表达式会返回80;
5、操作集合对象。
-
-
-
- OGNL的入门:
-
-
@Test
// OGNL调用对象的方法:
public void demo1() throws OgnlException{
OgnlContext context = new OgnlContext();
Object obj = Ognl.getValue("'helloworld'.length()", context, context.getRoot());
System.out.println(obj);
}
@Test
// OGNL获取数据:
public void demo3() throws OgnlException{
OgnlContext context = new OgnlContext();
// 获取OgnlContext中的数据:
/*context.put("name", "张三");
String name = (String) Ognl.getValue("#name", context, context.getRoot());
System.out.println(name);*/
// 获得Root中的数据
User user = new User();
user.setName("李四");
context.setRoot(user);
String name = (String) Ognl.getValue("name", context, context.getRoot());
System.out.println(name);
}
-
-
- 值栈的概述
- 什么是值栈?
- 值栈的概述
-
ValueStack是Struts的一个接口,字面意义为值栈,OgnlValueStack是ValueStack的实现类,客户端发起一个请求struts2架构会创建一个action实例同时创建一个OgnlValueStack值栈实例,OgnlValueStack贯穿整个 Action 的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。
-
-
-
- 值栈的内部结构:
-
-
在 OnglValueStack 中包括两部分,值栈和map(即ognl上下文)
- Context: 即OgnlContext上下文,它是一个map结构,上下文中存储了一些引用,parameters、request、session、application等,上下文的Root为CompoundRoot。
OgnlContext中的一些引用:
parameters: 该 Map 中包含当前请求的请求参数
request: 该 Map 中包含当前 request 对象中的所有属性
session: 该 Map 中包含当前 session 对象中的所有属性
application:该 Map 中包含当前 application 对象中的所有属性
attr: 该 Map 按如下顺序来检索某个属性: request, session, application
- CompoundRoot:存储了action实例,它作为OgnlContext 的Root对象。
CompoundRoot 继承ArrayList实现压栈和出栈功能,拥有栈的特点,先进后出,后进先出,最后压进栈的数据在栈顶。我们把它称为对象栈。
struts2对原OGNL作出的改进就是Root使用CompoundRoot(自定义栈),使用OnglValueStack的findValue方法可以在CompoundRoot中从栈顶向栈底找查找的对象的属性值。
CompoundRoot作为OgnlContext 的Root对象,并且在CompoundRoot中action实例位于栈顶,当读取action的属性值时会先从栈顶对象中找对应的属性,如果找不到则继续找栈中的其它对象,如果找到则停止查找。
-
-
-
- ActionContext和ValueStack的关系:
-
-
通过源码查询:
public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
ActionContext ctx;
Integer counter = 1;
Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
if (oldCounter != null) {
counter = oldCounter + 1;
}
ActionContext oldContext = ActionContext.getContext();
if (oldContext != null) {
// detected existing context, so we are probably in a forward
ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
} else {
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
stack.getContext().putAll(dispatcher.createContextMap(request, response, null));
ctx = new ActionContext(stack.getContext());
}
request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
ActionContext.setContext(ctx);
return ctx;
}
* 在创建ActionContext的时候 创建ValueStack的对象,将ValueStack对象给ActionContext.
* ActionContext中有一个ValueStack的引用. ValueStack中也有一个ActionContext的引用.
* ActionContext获取ServletAPI的时候,依赖值栈了.
-
-
-
- 获取值栈对象:
-
-
【通过ActionContext对象获取值栈.】
ValueStack stack1 =ActionContext.getContext().getValueStack();
【通过request域获取值栈.】
ValueStack stack2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
-
-
-
- 操作值栈:
-
-
【对Action中的属性提供get方法的方式】
因为Action本身在值栈中,Action中的属性也就默认在值栈中了,所以我们可以通过对Action的属性提供get方法的方式来操作值栈。
【手动操作值栈】
调用值栈的push和set方法对值栈进行操作
-
-
-
- 从值栈中获取数据
-
-
-
-
-
- EL能够访问值栈
-
-
底层对Request对象的getAttribute方法进行增强:
public class StrutsRequestWrapper extends HttpServletRequestWrapper {
private static final String REQUEST_WRAPPER_GET_ATTRIBUTE = "__requestWrapper.getAttribute";
private final boolean disableRequestAttributeValueStackLookup;
/**
* The constructor
* @param req The request
*/
public StrutsRequestWrapper(HttpServletRequest req) {
this(req, false);
}
/**
* The constructor
* @param req The request
* @param disableRequestAttributeValueStackLookup flag for disabling request attribute value stack lookup (JSTL accessibility)
*/
public StrutsRequestWrapper(HttpServletRequest req, boolean disableRequestAttributeValueStackLookup) {
super(req);
this.disableRequestAttributeValueStackLookup = disableRequestAttributeValueStackLookup;
}
/**
* Gets the object, looking in the value stack if not found
*
* @param key The attribute key
*/
public Object getAttribute(String key) {
if (key == null) {
throw new NullPointerException("You must specify a key value");
}
if (disableRequestAttributeValueStackLookup || key.startsWith("javax.servlet")) {
// don't bother with the standard javax.servlet attributes, we can short-circuit this
// see WW-953 and the forums post linked in that issue for more info
return super.getAttribute(key);
}
ActionContext ctx = ActionContext.getContext();
Object attribute = super.getAttribute(key);
if (ctx != null && attribute == null) {
boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE));
// note: we don't let # come through or else a request for
// #attr.foo or #request.foo could cause an endless loop
if (!alreadyIn && !key.contains("#")) {
try {
// If not found, then try the ValueStack
ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE);
ValueStack stack = ctx.getValueStack();
if (stack != null) {
attribute = stack.findValue(key);
}
} finally {
ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE);
}
}
}
return attribute;
}
}
-
-
- EL的特殊字符的使用:
- #号的使用:
- EL的特殊字符的使用:
-
【获取context的数据】
<s:property value=”#request.name”/>
【用于构建一个Map集合】:使用struts的UI标签的时候.
<s:iterator value="#{'aaa':'111','bbb':'222','ccc':'333' }" var="entry">
<s:property value="key"/>---<s:property value="value"/><br/>
<s:property value="#entry.key"/>---<s:property value="#entry.value"/><br/>
</s:iterator>
<s:radio list="#{'1':'男','2':'女' }" name="sex"></s:radio>
-
-
-
- %号的使用:
-
-
【%强制解析OGNL表达式】
<s:textfield name="name" value="%{#request.name}"/>
【%强制不解析OGNL表达式】
<s:property value="%{'#request.name'}"/>
-
-
-
- $号的使用:
-
-
【在配置文件中使用OGNL表达式】
在struts的配置文件中使用.XML文件 或者 是属性文件.
说明:由于个人能力有限,所以有些地方借鉴了他人的经验,如有错误,或者涉及侵权等问题,请及时告知,我会立即修改或者删除。谢谢各位。