• Struts2.0 封装请求数据和拦截器介绍


    1. Struts2 框架中使用 Servlet 的 API 来操作数据

    1.1 完全解耦合的方式

    1. Struts2 框架中提供了一个 ActionContext 类,该类中提供了一些方法:
      • static ActionContext getContext(): 获取 ActionContext 对象实例;
      • Map<Object> getParameters(): 获取请求参数, 相当于 request.getParameterMap();
      • Map<Object> getSession(): 获取代表 session 域的 Map 集合, 就相当于操作 session 域;
      • Map<Object> getApplication(): 获取代表 application 域的 Map 集合;
      • void put(String key, Object value): 向 request 域中存入值;

    1.2 使用原生 Servlet 的API方式

    1. Struts2 框架提供了一个 ServletActionContext 类,该类中提供了一些静态的方法:
      • static getPageContext()
      • static getRequest()
      • static getResponse()
      • static getServletContext()
    // 需求: 使用 Struts2 作为 Web 层完成客户的新增功能
    // regist.jsp
        <h1>注册</h1>
        <form action="{pageContext.request.contextPath}/registAction" method="post">
        用户名: <input type="text" name="username"/><br/>
        密  码: <input type="password" name="password"/><br/>
        <input type="submit" value="注册"/>
        </form>
    
    // 完全解耦合的方式,操作数据 com.opensymphony.xwork2.ActionContext 包
        ActionContext context = ActionContext.getContext();
        // 获取到请求参数
        Map<String,Object> map = context.getParameters();
        // 遍历map, 获取数据
        Set<String> keys = map.keySet();
        for(String key : keys){
            // Object 是数组
            String[] val = (String[])map.get(key);
            System.out.println(key+":"+Arrays.toString(val));
        }
    
        // 向 request 域中存入数据
        context.put("msg","request域中数据");
    
        // 向 session 域中存入数据
        context.getSession().put("msg","session域中数据");
    
        // 向 application 域中存入数据
        context.getApplication().put("msg","application域中数据");
    
    // 使用原生 Servlet 的 API 方式  org.apache.struts2.ServletActionContext 包
        // 获取 request 对象
        HttpServletRequest request = ServletActionContext.getRequest();
    

    2. 结果页面的跳转

    2.1 结果页面存在两种方式

    1. 全局结果页面
    • 如果 <package> 包中的一些action都返回 success,并且返回的页面都是同一个JSP页面,这样就可以配置全局的结果页面;
    • 全局结果页面针对当前包中的所有 Action, 如果局部还有结果页面,会优先局部的.
    <package name="demo" extends="struts-default" namespace="/">
    
        // 添加图书和删除图书成功后,都会跳转到 suc.jsp 页面
        <global-results>
            <result>/demo2/suc.jsp</result>
        </global-results>
    
        // 添加图书
        <action name="addBook" class="cn.itcast.demo2.BookAction" method="add"/>
    
        // 删除图书
        <action name="deleteBook" class="cn.itcast.demo2.BookAction" method="delete"/>
    </package>
    
    2. 局部结果页面
    • <result>/demo3/suc.jsp</result>

    2.2 结果页面的类型

    1. <result>标签包含两个属性:
      • name: 逻辑视图的名称;
      • type: 跳转的类型; 常见的结果类型,可以从 struts-default.xml中查找;
        • dispatcher: 转发, 默认值;
        • redirect: 重定向;
        • chain: 多个 action 之间跳转, 从一个 Action 转发到另一个 Action;
        • redirectAction: 多个 action 之间跳转,从一个 Action 重定向到另一个 Action;
        • stream: 文件下载时,使用;
    // 重定向到 Action
        // Action 类的编写
            public class Demo3Action extends ActionSupport{
    
                public String save(){
                    System.out.println("save....");
                    return SUCCESS;
                }
    
                public String update(){
                    System.out.println("update...");
                    return NONE;
                }
            }
    
    
        // struts.xml
            <action name="demo3Action_*" class="com.itheima.demo.Demo3Action" method="{1}">
                // 注意路径的编写方式
                <result name="success" type="redirectAction">demo3Action_update</result>
            </action>
    

    3. Struts 框架的数据封装

    3.1 概述

    1. Struts2 提供了两类数据封装的方式
      • 属性驱动;
      • 模型驱动(使用较多);

    3.2 属性驱动

    3.2.1 提供对应属性的 set 方法进行数据的封装(使用较多)
    1. 表单的哪些属性需要封装数据,那么在对应的 Action 类中提供该属性的 set 方法即可;
    2. 表单中提交的数据,最终调用 Action 类中的 setXxx 方法,赋值给全局变量;
    3. 注意点:
      • Struts2 的框架采用拦截器完成数据的封装;
      • 如果属性特别多,需要提供特别多的 set 方法,而且还需要手动将数据存入到对象中;
      • 这种情况下, Action 类就相当于一个 JavaBean. Action类既封装数据,又接收请求数据,耦合性较高,
        没有体现出 MVC 思想;
    3.2.2 在页面上,使用 OGNL 表达式进行数据封装
    1. 在页面中使用OGNL表达式进行数据的封装,就可以直接把属性封装到某一个 JavaBean 的对象中;
    2. 在页面中定义一个 JavaBean, 并且提供 set 方法;
    3. 表单的写法: <input type="text" name="user.username"/>
    4. 注意:
      • 只提供一个 set 方法还不够,还需要提供 user 属性的 get 方法;
      • 先调用 get 方法,判断一下是否有 user 对象的实例对象;如果没有,就先创建 user 对象,并封装一个数据,
        然后调用set方法把拦截器创建的对象注入进来; 再调用 getUser 来封装数据;

    3.3 模型驱动

    1. 手动实例化 JavaBean, 即: private User user = new User();
    2. 必须实现 ModelDriven 接口,实现 getModel() 的方法, 在 getModel() 方法中返回 user 即可!
    // 属性驱动
        // regist.jsp
        <form action="{pageContext.request.contextPath}/regist.action" method="post">
            用户名: <input type="text" name="username"/><br/>
            密  码: <input type="password" name="password"/><br/>
            <input type="submit" value="注册"/>
        </form>
    
        // 属性驱动方式一, Action 类中提供对应属性的 set 方法
        public class RegistAction extends ActionSupport{
    
            // 定义属性
            private String username;
            private String password;
    
            // 只需要提供对应属性的 set 方法
            // 拦截器调用 setXxx 方法,将属性封装,赋值给全局变量 username,password
            public void setUsername(String username){
                this.username = username;
            }
            public void setPassword(String password){
                this.password = password;
            }
    
            // regist 方法
            public String regist(){
    
                // 输出打印
                System.out.println(username+"::"+password);
                return NONE;
            }
        }
    
        // 属性驱动方式二, OGNL 表达式
        // regist.jsp, 页面中使用 OGNL 表达式
        <form action="{pageContext.request.contextPath}/regist.action" method="post">
    
            // 此处 user.username 与 Action 类中的属性 user 一致
            用户名: <input type="text" name="user.username"/><br/>
            密  码: <input type="password" name="user.password"/><br/>
            <input type="submit" value="注册"/>
        </form>
    
    
        // 需要提供 JavaBean
        // User.class
            public class User{
                private String username;
                private String password;
    
                // 提供 get 和 set 方法
                public String getUsername(){
                    return username;
                }   
                public void setUsername(String username){
                    this.username = username;
                }
    
                public String getPassword(){
                    return password;
                }
                public void setPassword(String password){
                    this.password = password;
                }
    
                public String toString(){
                    ....
                }
            }
    
        // Action 类
            public class RegistAction extends ActionSupport{
    
                // 定义属性
                private User user;
    
                // 提供 get 和 set 方法
                public User getUser(){
                    return user;
                }
                public void setUser(User user){
                    this.user = user;
                }
    
                public String regist(){
                    System.out.println(user);
                    return NONE;
                }
            }
    
    // 模型驱动
        // regist.jsp
        <form action="{pageContext.request.contextPath}/regist.action" method="post">
            用户名: <input type="text" name="username"/><br/>
            密  码: <input type="password" name="password"/><br/>
            <input type="submit" value="注册"/>
        </form>
    
        // User.class
         同上
    
    
        // Action 类, 需要实现 ModelDriven 接口
        public class RegistAction extends ActionSupport implements ModelDriven<User>{
    
            // 手动实例化
            private User user = new User();
    
            // 实现 getModel() 方法
            // 即获取模型对象
            public User getModel(){
                return user;
            }
    
            public String regist(){
                System.out.println(user);
                return NONE;
            }
        }
    

    3.4 Struts2 把数据封装到集合中

    1. 把数据封装到 Collection 中
      • 因为 Collection 接口都会有下标值,所有页面的写法会有一些区别,
        <input type="text" name="products[0].name"/>;
      • 在 Action 类中,需要提供 products 集合,并且提供 get 和 set 方法;
    2. 把数据封装到 Map 中
      • Map 集合是键值对的形式,页面的写法:
        <input type="text" name="map['one'].name"/>
      • Action 类中提供 map 集合,并且提供 get 和 set 方法;
    // 向 List 集合中封装数据 (默认情况下, 采用属性驱动的方式)
        // regist.jsp
        <form action="{pageContext.request.contextPath}/regist.action" method="post">
            用户名1: <input type="text" name="list[0].username"/><br/>
            密  码1: <input type="password" name="list[0].password"/><br/>
    
            用户名2: <input type="text" name="list[1].username"/><br/>
            密  码2: <input type="password" name="list[1].password"/><br/>
            <input type="submit" value="注册"/>
        </form>
    
        // User.class
        同上
    
        // Action 类
        public class RegistAction extends ActionSupport{
    
            // 定义属性
            private List<User> list;
    
            // 提供 get 和 set 方法
            public List<User> getList(){
                return list;
            }
            public void setList(List<User> list){
                this.list = list;
            }
    
            public String regist(){
                for(User user : list){
                    System.out.println(user);
                }
                return NONE;
            }
        }
    
    
    // 向 Map 集合中封装数据
        // regist.jsp
            <form action="{pageContext.request.contextPath}/regist.action" method="post">
                用户名1: <input type="text" name="map['one'].username"/><br/>
                密  码1: <input type="password" name="map['one'].password"/><br/>
    
                用户名2: <input type="text" name="map['two'].username"/><br/>
                密  码2: <input type="password" name="map['two'].password"/><br/>
                <input type="submit" value="注册"/>
            </form>
    
        // User.class
        同上
    
        // Action 类
        public class RegistAction extends ActionSupport{
    
            // 定义属性
            private Map<String,User> map;
    
            // 提供 get 和 set 方法
            public Map<String,User> getMap(){
                return map;
            }
            public void setMap(Map<String,User>  map){
                this.map = map;
            }
    
            public String regist(){
                System.out.println(map);
                return NONE;
            }
        }
    

    4. 拦截器技术

    4.1 拦截器的概述

    1. 拦截器就是 AOP(Aspect-Oriented Programming)的一种实现. AOP 是指用于在某个方法或字段被访问之前,
      进行拦截,然后在之前或之后加入某些操作;
    2. 拦截器采用"责任链"模式
      • 在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链;
      • 责任链中每一个节点,都可以继续调用下一个节点,也可以组织流程继续执行;
    3. Struts2 中可以定义很多个拦截器,将多个拦截器按照特定顺序组成拦截器栈.

    4.2 拦截器和过滤器的区别

    1. 拦截器是基于 java 反射机制的,而过滤器是基于函数回调的;
    2. 过滤器依赖于 Servlet 容器, 而拦截器不依赖于 Servlet 容器;
    3. 拦截器只能对 Action 请求起作用(即Action 中的方法),
      而过滤器是用于过滤从客户端发送到服务端请求的,其中包括CSS, JSP, JS等;

    4.3 自定义拦截器和配置

    4.3.1 自定义拦截器
    • 编写拦截器需要实现 interceptor 接口,实现接口中的三个方法;
    • 也可以继承 interceptor 接口的已知实现类 AbstractInterceptor;
    • 或者继承 interceptor 接口的已知实现类 MethodFilterInterceptor, 可以对指定方法放行;
    // 编写拦截器
        public String DemoInterceptor extends AbstractInterceptor {
    
            // intercept 方法: 在 action 执行之前,拦截
            public String intercept(ActionInvocation invocation) throws Exception{
    
                System.out.println("拦截器执行之前.....");
    
                // 执行下一个拦截器
                String result = invocation.invoke();
    
                System.out.println("拦截器执行之后....");
                return result;
            }
        }
    
    4.3.2 在 struts.xml 中配置拦截器
    // 第一种方式:
        // 在 <package> 包中定义拦截器,出现在 <package> 包的上方
        <interceptors>
            <interceptor name="loginInterceptor" class="cn.itcast.interceptor.LoginInterceptor"/>
        </interceptors>
    
        // 在某个 action 中引入拦截器
        <interceptor-ref name="loginInterceptor"/>
    
        // 注意:
        // 如果引入了自定义的拦截器,Struts2 框架默认的拦截器就不会再执行了,所以需要引入 Struts2 默认的拦截器
        <interceptor-ref name="defaultStack"/>
    
    // 第二种方式
        // 在 <package> 包中定义拦截器的时候,自己直接定义一个拦截器栈
        <interceptors>
            <interceptor name="loginInterceptor" class="cn.itcast.interceptor.LoginInterceptor"/>
            <interceptor-stack name="myStack">
                <interceptor-ref name="loginInterceptor"/>
                <interceptor-ref name="defaultStack"/>
            </interceptor-stack>
        </interceptors>
    
        // 在 action 中引入自定义拦截器栈
        <action name="book_*" class="cn.itcast.action.BookAction" method="{1}">
            <interceptor-ref name="myStack"/>
        </action>
    

    参考资料

  • 相关阅读:
    『实践』Yalmip建模+Cplex类求解(文末附程序、文章和算例)
    『实践』Matlab实现Flyod求最短距离及存储最优路径
    『转载』Matlab中fmincon函数获取乘子
    『实践』Yalmip获取对偶函数乘子
    『转载』hadoop 1.X到2.X的变化
    『转载』hadoop2.x常用端口、定义方法及默认端口
    『实践』VirtualBox 5.1.18+Centos 6.8+hadoop 2.7.3搭建hadoop完全分布式集群及基于HDFS的网盘实现
    C#设计模式学习笔记:(6)适配器模式
    ASP.NET 开源导入导出库Magicodes.IE 导出Pdf教程
    Rx基础
  • 原文地址:https://www.cnblogs.com/linkworld/p/7710560.html
Copyright © 2020-2023  润新知