struts2框架

第1章Struts2

      1. 需求分析

       Crm系统使用struts2架构实现web层,web层实现的功能是控制逻辑和视图。

       整体调用流程如下:

       1、用户请求至struts2

       2、struts2调用service

       3、service调用dao

       4、dao持久化数据

 

    1. 相关知识点
      1. Struts2框架的概述
        1. 什么是Struts2

 

 

Struts2是一个基于MVC设计模式的WEB层框架。

        1. Struts2和Struts1区别:

Struts2和Struts1没有任何联系.Struts2内核是webwork的内核.

        1. WEB层的框架都会基于前端控制器的模式:

 

      1. Struts2快速入门:
        1. 解压Struts2的开发包:

 

* apps  :Struts2提供一些案例

* docs  :Struts2开发文档.

* lib   :Struts2的开发的jar包

* src   :Struts2的源码

        1. 创建一个web工程引入相应jar包:

D:\struts2\struts-2.3.24\apps\struts2-blank\WEB-INF\lib\*.jar

        1. 创建一个页面:放置一个链接.

<h1>Struts2的入门案例</h1>

<a href="${pageContext.request.contextPath }/strutsDemo1.action">访问Struts2的Action.</a>

        1. 编写一个Action:

public class StrutsDemo1 {

    /**

     * 提供一个默认的执行的方法:execute

     */

    public String execute(){

        System.out.println("StrutsDemo1中的execute执行了...");

        return null;

    }

}

        1. 完成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>

        1. 配置核心过滤器:

  <!-- 配置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>

        1. 修改Action,将方法设置一个返回值:

public class StrutsDemo1 {

 

    /**

     * 提供一个默认的执行的方法:execute

     */

    public String execute(){

        System.out.println("StrutsDemo1中的execute执行了...");

        return "success";

    }

}

        1. 修改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>

      1. Struts2开发流程分析
        1. Struts2的执行流程:

从客户端发送请求过来 先经过前端控制器(核心过滤器StrutsPrepareAndExecuteFilter)过滤器中执行一组拦截器(一组拦截器 就会完成部分功能代码)执行目标Action,在Action中返回一个结果视图,根据Result的配置进行页面的跳转.

 

 

        1. 配置struts.xml中的提示(在不联网情况下)

DTD存放的路径:src\core\src\main\resources\struts-2.3.dtd

Window--->Preferences--->在左侧搜索xml catalog--->add添加.

* 选择URI

* 文件系统 选择dtd路径

 

 

 

      1. Struts2的常见配置
        1. Struts2的配置文件的加载顺序:

查看StrutsPrepareAndExecuteFilter:(核心过滤器)两个功能 :预处理执行

在预处理功能中 init 方法中会有加载配置文件的代码:

dispatcher.init();

            init_DefaultProperties(); // [1]                  ---- 加载org.apache.struts.default.properties.配置的是struts2的所有常量.

            init_TraditionalXmlConfigurations(); // [2]       ---- 加载struts-default.xmlstruts-plugin.xmlstruts.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               ---- 配置核心过滤器及常量.

 

***** 后配置的常量 覆盖先配置的常量.

        1. 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  :跳转的类型.

        1. 默认的Action和Action的默认处理类:

默认的Action:

<!-- 配置默认的Action:Action的访问路径不存在的时候,执行一个默认的Action -->

<default-action-ref name="strutsDemo1"/>

 

Action的默认处理类:

<!-- Action的默认处理类:Action的访问路径配置正确了,但是没有配置class属性. -->

<default-class-ref class="com.opensymphony.xwork2.ActionSupport"/>

 

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

 

        1. 分模块开发的时候

<include file="cn/it/struts2/demo1/struts_demo1.xml"/>  整合其他的struts的配置文件.

      1. Struts2的Action的访问:
        1. 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就会有这些功能.

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

    1. 相关知识点
      1. Struts2访问Servlet的API:
        1. 可以使用完全解耦合的方式.

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;

    }

}

        1. 使用原生的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;

    }

}

      1. 结果页面的配置:
        1. 全局结果页面

<global-results>

    <result name="success">/demo3/demo2.jsp</result>

</global-results>

        1. 局部结果页面

        <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

 

      1. Struts的数据封装

实际开发的场景:页面提交参数,在Action中接收参数,需要进行数据的封装,封装到JavaBean中,将JavaBean传递给业务层.

        1. 属性驱动
  • 编写属性的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;

    }

}

        1. 模型驱动
  • 使用模型驱动的方式进行参数的封装】(优先)

页面:

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

    }


}

      1. Struts2中封装复杂类型的数据:
        1. 封装到List集合中:

页面:

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

    }

}

        1. 封装数据到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;

    }

}

    1. 总结:
      1. Struts2的拦截器:
        1. 拦截器的概述

拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。

在Webwork的中文文档的解释为——拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行。同时也是提供了一种可以提取action中可重用的部分的方式。

谈到拦截器,还有一个词大家应该知道——拦截器链 (Interceptor Chain,在Struts 2中称为拦截器栈Interceptor Stack)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

        1. 拦截器的实现原理:

大部分时候,拦截器方法都是通过代理的方式来调用的。Struts 2的拦截器实现相对简单。当请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。

Struts2拦截器是可插拔的,拦截器是AOP的一种实现。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。

        1. Struts2的执行流程:

 

        1. 自定义拦截器及配置:

第一步: 自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。

第二步:在strutx.xml中注册上一步中定义的拦截器。

第三步:在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的Action都被这个拦截器拦截。

 

 

第3章Struts2

    1. 相关知识点
      1. OGNL的概述
        1. 什么是OGNL

 

        1. 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、操作集合对象。

        1. 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);

    }

      1. 值栈的概述
        1. 什么是值栈?

       ValueStack是Struts的一个接口,字面意义为值栈,OgnlValueStack是ValueStack的实现类,客户端发起一个请求struts2架构会创建一个action实例同时创建一个OgnlValueStack值栈实例,OgnlValueStack贯穿整个 Action 的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。

        1. 值栈的内部结构:

 

在 OnglValueStack 中包括两部分,值栈和map(即ognl上下文)

 

 

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

 

  1. CompoundRoot:存储了action实例,它作为OgnlContext 的Root对象。

              CompoundRoot 继承ArrayList实现压栈和出栈功能,拥有栈的特点,先进后出,后进先出,最后压进栈的数据在栈顶。我们把它称为对象栈。

      

       struts2对原OGNL作出的改进就是Root使用CompoundRoot(自定义栈),使用OnglValueStack的findValue方法可以在CompoundRoot中从栈顶向栈底找查找的对象的属性值。

 

       CompoundRoot作为OgnlContext 的Root对象,并且在CompoundRoot中action实例位于栈顶,当读取action的属性值时会先从栈顶对象中找对应的属性,如果找不到则继续找栈中的其它对象,如果找到则停止查找。

 

        1. 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的时候,依赖值栈了.

        1. 获取值栈对象:

【通过ActionContext对象获取值栈.】

ValueStack stack1 =ActionContext.getContext().getValueStack();

 

【通过request域获取值栈.】

ValueStack stack2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);

        1. 操作值栈:

【对Action中的属性提供get方法的方式】

因为Action本身在值栈中,Action中的属性也就默认在值栈中了,所以我们可以通过对Action的属性提供get方法的方式来操作值栈。

【手动操作值栈】

调用值栈的push和set方法对值栈进行操作

        1. 从值栈中获取数据

 

        1. 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;

    }

}

      1. EL的特殊字符的使用:
        1. #号的使用:

【获取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>

        1. %号的使用:

【%强制解析OGNL表达式】

<s:textfield name="name" value="%{#request.name}"/>

【%强制不解析OGNL表达式】

<s:property value="%{'#request.name'}"/>

        1. $号的使用:

【在配置文件中使用OGNL表达式】

在struts的配置文件中使用.XML文件 或者 是属性文件.

说明:由于个人能力有限,所以有些地方借鉴了他人的经验,如有错误,或者涉及侵权等问题,请及时告知,我会立即修改或者删除。谢谢各位。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值