• Struts2框架入门


    Struts2框架

    一、什么是Struts2

      Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中,Struts2作为控制器(Controller)来建立模型与视图的数据交互。Struts 2是Struts的下一代产品,是在 struts 1和WebWork的技术基础上进行了合并的全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构差别巨大。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与ServletAPI完全脱离开,所以Struts 2可以理解为WebWork的更新产品。虽然从Struts 1到Struts 2有着太大的变化,但是相对于WebWork,Struts 2的变化很小。

                                                

      -------------百度百科

    二、快速搭建环境

      1、下载官方的jar包
        官网:
    https://struts.apache.org/

      2、将其中核心j包中app文件中的struts-blank后缀名改为zip,并进行解压其中的lib文件夹中的jar包为运行struts2的基本jar包

      3、创建新工程,将基本jar包拷入新建工程中的lib文件夹

      

      4、在web.xml文件中配置核心过滤器

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

      其中<filter-class>中过滤器名是根据StrutsPrepareAndExecuteFilter类所在路径来配置的

      

      5、配置用于跳转的页面,此页面是用于跳转到Action中

    <body>
           <h3>快速入门</h3>
           <a href="${pageContext.request.contextPath}/hello.action">跳转</a>
      </body>

      6、编写Action

    package com.clj.action;
    /**
     * Struts框架都使用Action类处理用户的请求
     * @author Administrator
     *
     */
    public class HelloAction {    
        /**
         * Action类中的方法签名有要求,必须这么做
         * public 公共的
         * 必须有返回值,必须String类型
         * 方法名称可以是任意的,但是不能有参数列表
         * 页面的跳转:1.return 字符串 2.需要在struts.xml配置文件中,配置跳转的页面
         */
        public String sayHello(){
            //编写代码接收请求的参数
            System.out.println("Hello Struts2!");
            return "success";
        }
        /**
         * 演示的method方法的默认值
         * 当配置文件中没有配置指定的method方法,他会默认执行Action中的execute方法
         * @return
         */
        public String execute(){
            System.out.println("method方法的默认值是execute");
            return null;
        }
    }

      7、设置Action配置文件

          配置文件是一个xml文件,命名强制为struts2.xml,否则当服务器开启时无法识别不是该文件名的配置文件,该文件建立在src下

          其中,其约束条件可以在struts2-blankWEB-INFsrcjava的struts2.xml文件中可以找到

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">
    
    <struts>
        <!-- 包结构 ,包名不能重复 -->
        <package name="default" namespace="/" extends="struts-default">
            <!-- 配置Action -->
            <action name="hello" class="com.clj.action.HelloAction" method="sayHello">
                <!-- 配置跳转的页面,路经的写法:在Struts2框架中,不管是转发还是重定向,都不需要加项目名 
                    name表示结果页面逻辑视图名称
                     type 结果类型(转发类型,默认值是转发,也可以设置其他的值)
                -->    
                <result name="success">/jsp/success.jsp</result>
            </action>
         </package>
    </struts>

      8、此时访问跳转页面,即可执行execute方法

      总结:这里当执行跳转页面时,会根据配置文件中的action 中的 name属性进行匹配,找到有name为hello 匹配到HelloAction类中的sayHello方法,通过方法反射等进行解析,根据方法的返回值“success”进行页面的跳转,过渡到success.jsp中。值得注意的是,其package包名不能重复!

    三、struts2执行流程为:

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

    四、Action书写方式

      方式一:POJO类

    /**
     * 三种action书写方式之POJO类
     * 没有任何继承和实现
     * @author Administrator
     *
     */
    public class Demo1Action {
        /**
         * execute是默认方法
         * return null:他不会跳转
         * @return
         */
        public String execute(){
            System.out.println("Demo1Action就是一个POJO类");
            return null;
        }
    }

      方式二:实现Action的接口

    import com.opensymphony.xwork2.Action;
    
    /**
     * 三种action书写方式之实现Action的接口,Action是框架提供的接口
     * @author Administrator
     *
     */
    public class Demo2Action implements Action{
    
        @Override
        public String execute() throws Exception {
            // TODO Auto-generated method stub
            System.out.println("Demo2Actions实现了Action的接口");
            //Action接口中定义了 public static final String SUCCESS = "success";
            return SUCCESS;
        }
        
    }

      其中Action有自定义的字符串常量,实现Action的接口返回值就可调用它的常量

      方式三:继承ActionSupport类

    import com.opensymphony.xwork2.ActionSupport;
    
    /**
     *  三种action书写方式之编写ActionSupport类
     *  ActionSupport类已经实现了Action和一些其他接口
     * @author Administrator
     *
     */
    public class Demo3Action extends ActionSupport{
    
        
        public String execute() throws Exception {
            System.out.println("Demo3Action继承了ActionSupport类。。");
            //不跳转
            return NONE;
        }
         
    }

    五、struts2中常量的配置

      1.这里先看看当框架执行时配置文件加载的顺序

      查看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文件,在org/apache/struts2/default.properties文件,都是常量。

           * 又加载struts-default.xml配置文件,在核心的jar包最下方,struts2框架的核心功能都是在该配置文件中配置的。

           * 再加载struts.xml的配置文件,在src的目录下,代表用户自己配置的配置文件

              * 最后加载web.xml的配置文件

     

        * 后加载的配置文件会覆盖掉之前加载的配置文件(在这些配置文件中可以配置常量)

                因此: 后配置的常量 覆盖先配置的常量.

           2、查看常量

      

      3、修改常量

      注意:修改常量不能在default.properties文件中修改,可以在struts.xml或者web.xml文件中

       1)在struts.xml中

      <!-- 编写常量 -->
        <constant name="struts.action.extension" value="action,,"></constant>

      struts2中访问action默认后缀为action或者不写,这个配置可以进行更改

       2)在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>action,,</param-value>
          </init-param>
      </filter>

    六、Action的访问方式

      1、传统方式:配置method属性

        1)Action类代码

    import com.opensymphony.xwork2.ActionSupport;
    
    /**
     * 编写的客户的Action的类
     * @author Administrator
     *
     */
    public class CustomerAction extends ActionSupport {
        //保存客户
        public String save(){
            System.out.println("保存客户");
            return NONE;
        }
        //删除客户
        public String delete(){
            System.out.println("删除客户");
            return NONE;
        }
    }    

       2)配置文件配置

     <!-- 演示Action的访问,传统方式 -->
         <package name="demo2" namespace="/" extends="struts-default">
             <action name="saveCust" class="com.clj.action2.CustomerAction" method="save"/>
             <action name="delCust" class="com.clj.action2.CustomerAction" method="delete"/>    
         </package>

      2、通配符的配置

       1)Action类

    import com.opensymphony.xwork2.ActionSupport;
    /**
     * 通配符的方式
     * @author Administrator
     *
     */
    public class LinkmanAction extends ActionSupport{
        //保存客户
        public String save(){
            System.out.println("保存联系人。。");
            return "saveOk";
        }
        //删除客户
        public String delete(){
            System.out.println("删除联系人。。");
            return "delOk";
        }
    }

       2)配置文件

     <!-- 演示Action的访问,通配符方式 -->
         <package name="demo3" namespace="/" extends="struts-default">

       <!--这里的{1}代表统配第一个*;name=linkman_*_*...methd=”{1}”{1}表示匹配第一个*{2}表示通配第二个*,即数字表示*的位置,通过通配符调用指定方法-->

             <action name="linkman_*" class="com.clj.action2.LinkmanAction" method="{1}">
                 <result name="saveOk">/jsp/success.jsp</result>
                 <result name="delOk">/jsp/success.jsp</result>
             </action>
         </package>

       3、动态方法访问

       1)开启动态访问常量(注意:常量的配置都是定义在包外)

    <!-- 开启动态方法访问 -->
        <constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>

       2)Action类

    import com.opensymphony.xwork2.ActionSupport;
    
    /**
     * 动态方法访问
     * @author Administrator
     *
     */
    public class UserAction extends ActionSupport{
        //保存客户
            public String save(){
                System.out.println("保存用户。。");
                return NONE;
            }
            //删除客户
            public String delete(){
                System.out.println("删除用户。。");
                return NONE;
            }
    }

       3)配置文件

     <!-- 演示Action的访问,动态方法访问方式 -->
         <package name="demo4" namespace="/" extends="struts-default">
             <action name="user" class="com.clj.action2.UserAction"/>
         </package>

       4)域名书写方式

    <h3>动态方法访问</h3>
         <a href="${pageContext.request.contextPath}/user!save.action">保存联系人</a></br>
         <a href="${pageContext.request.contextPath}/user!delete.action">删除联系人</a></br>

     七、struts2中数据的之接收数据

      struts2怎么传值呢,这里由两种种方式

      1.定义一个jsp,利用表单进行数据传输

              <form action="${pageContext.request.contextPath}/demo1Action.action" method="post">
                  姓名:<input type="text" name="username"/></br>
                  密码:<input type="password" name="psssword"/></br>
                  <input type="submit" value="注册"/>
              </form></br>

      2.编写Action

       1)方式一:完全解耦合的方式

    package com.clj.demo1;
    
    import java.util.Arrays;
    import java.util.Map;
    import java.util.Set;
    
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ActionSupport;
    /**
     * 完全解耦合的方式,使用Servlet的API
     * 通过操作ActionContexte类的方法来获取Servlet API
     * @author Administrator
     *
     */
    public class demo1Action extends ActionSupport{
        public String execute() throws Exception{
            //完全解耦合的方式
            ActionContext context=ActionContext.getContext();
            //获取到请求的参数,获取到所有请求的参数
            Map<String,Object> map=context.getParameters();
            //遍历获取数据
            Set<String> keys=map.keySet();
            for(String key:keys){
                //通过key获取到值
                String[] values=(String[]) map.get(key);
                //默认情况下,struts已经将字符编码转成了UTF-8,无需考虑中文乱码
                System.out.println(key+":"+Arrays.toString(values));
            }
            //如果向request对象中存入值
            context.put("msg","小东东");
            //获取其他map集合
            context.getSession().put("msg","小苍");
            context.getApplication().put("msg","小泽");
            return SUCCESS;
            
        }
    }

      2)方式二:原生的Servlet API

    package com.clj.demo1;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    /**
     * 原生的Servlet API
     * @author Administrator
     *
     */
    public class demo2Action extends ActionSupport{
        public String execute() throws Exception{
            //获取到request对象
            HttpServletRequest request=ServletActionContext.getRequest();
            request.setAttribute("msg","小东东");
            request.getSession().setAttribute("msg","美美");
            ServletActionContext.getServletContext().setAttribute("msg", "小风");     
            return SUCCESS;
        }
    }

    八、结果视图处理

      1、关于全局页面

           为什么要设置全局页面?因为在同一个包下,有时候多个action中所获得的结果视图是同一个,这要每个action配置会觉得冗余,此时可以配置个全局页面来共用

        列子:假如当action中方法返回值是success,此时就可无需配置<result>标签,它会自动跳转到success.jsp中

    <!-- 配置全局的结果页面,必须定义在当前包下 -->
        <global-results>
            <!-- type:转发类型 
                     dispatcher:转发,默认值,Action->jsp
                     redirect:  重定向,Action->jsp
                     chain:     多个action之间跳转,Action->Action(转发)
                     redirectAction:多个action之间跳转,Action->Action(重定向)
                     stream:文件下载
            -->
            <result name="success" type="dispatcher">/jsp/success.jsp</result>
        </global-results>

      2.、结果页面的类型

            * 结果页面使用<result>标签进行配置,包含两个属性

            > name  -- 逻辑视图的名称

            > type  -- 跳转的类型,值一些,需要掌握一些常用的类型。常见的结果类型去struts-default.xml中查找。

                * dispatcher        -- 转发.type的默认值.Action--->JSP

                * redirect          -- 重定向. Action--->JSP

                * chain             -- 多个action之间跳转.从一个Action转发到另一个Action.  Action---Action

                * redirectAction    -- 多个action之间跳转.从一个Action重定向到另一个Action. Action---Action

                * stream            -- 文件下载时候使用的

         演示重定向

        action

    package com.clj.demo1;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    /**
     * 演示重定向
     * @author Administrator
     *
     */
    public class demo3Action extends ActionSupport{
        public String save(){
            System.out.println("保存");
            return SUCCESS;
        }
        public String update(){
            System.out.println("更新成功");
            return NONE;
        }
    }

       配置文件

    <!-- 演示重定向到Action -->
            <action name="demo3Action_*" class="com.clj.demo1.demo3Action" method="{1}">
                <result name="success" type="redirectAction">demo3Action_update</result>
            </action>

    九、关于struts2框架数据的封装

      封装数据是为了便于开发,降低维护成本,这里有两种方式进行数据的封装。

      > 提供对应属性的set方法进行数据的封装。

                * 表单的哪些属性需要封装数据,那么在对应的Action类中提供该属性的set方法即可。

                * 表单中的数据提交,最终找到Action类中的setXxx的方法,最后赋值给全局变量。

      1、方式一:属性驱动

           1)属性驱动写法方式一:在action类中直接写从页面中提交的属性数据

             jsp:

     <h3>属性驱动的方式(直接在Action中编写属性)</h3>
             <!-- aciton接收表单值时属性要提供set方法 -->
             <form action="${pageContext.request.contextPath}/regist1.action" method="post">
                  姓名:<input type="text" name="username"/></br>
                  密码:<input type="password" name="password"/></br>
                  年龄:<input type="text" name="age"/></br>
                  <input type="submit" value="注册"/>
              </form></br>

      action:

    package com.clj.demo2;
    
    import com.opensymphony.xwork2.ActionSupport;
    /**
     * 属性驱动
     * 方式一:将Action当做JavaBean类
     * @author Administrator
     *
     */
    public class regist1 extends ActionSupport{
        private String username;
        private String password;
        private Integer age;
        //传值,用set,不需要要用get
        public void setUsername(String username) {
            this.username = username;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public String execute() throws Exception{
            System.out.println(username+" "+password+" "+age);
            return NONE;
        }
    }

        2)属性驱动写法方式二:将提交的数据封装到一个类中

        jsp

    <h3>属性驱动的方式(把数据封装到javaBean中)</h3>
              <!-- 注意:页面的编写风格为OGNL表达写法 -->
                 <form action="${pageContext.request.contextPath}/regist2.action" method="post">
                     <!-- 这里的"user"是根据Aciton中封装属性的类的名称属性而定(private User user;) -->
                  姓名:<input type="text" name="user.username"/></br>
                  密码:<input type="password" name="user.password"/></br>
                  年龄:<input type="text" name="user.age"/></br>
                  <input type="submit" value="注册"/>
              </form></br>

          javabean

    package com.clj.demo2;
    
    public class User {
        private String username;
        private String password;
        private Integer age;
        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 Integer getAge() {
            return age;
        }
        public void setAge(Integer age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "User [username=" + username + ", password=" + password
                    + ", age=" + age + "]";
        }
        
    }

       action

    package com.clj.demo2;
    
    import com.opensymphony.xwork2.ActionSupport;
    /**
     * 属性驱动的方式,将数据封装到javaBean中
     * @author Administrator
     *
     */
    public class regist2 extends ActionSupport{
        //注意:属性驱动的方式,需要提供get和set方法
        private User user;
        
        public User getUser() {
            return user;
        }
    
        public void setUser(User user) {
            this.user = user;
        }
    
        public String execute(){
            System.out.println(user);
            return NONE;
        }
    }  

      * 注意:只提供一个set方法还不够,必须还需要提供user属性的get和set方法!!!

            > 先调用get方法,判断一下是否有user对象的实例对象,如果没有,调用set方法把拦截器创建的对象注入进来,接下直接调用get方法获取传过来的参数

      拓展:

      1.将数据封装到list中

        jsp

     

    <h3>向List集合封装数据(默认情况下,采用属性驱动的方式)</h3>
              <!-- 采用OGNL表达式 -->
              <form action="${pageContext.request.contextPath}/regist4.action" method="post">
                     <!-- 这里的"user"是根据Aciton中封装属性的类的名称属性而定(private User user;) -->
                  姓名:<input type="text" name="list[0].username"/></br>
                  密码:<input type="password" name="list[0].password"/></br>
                  年龄:<input type="text" name="list[0].age"/></br>
                  
                  姓名:<input type="text" name="list[1].username"/></br>
                  密码:<input type="password" name="list[1].password"/></br>
                  年龄:<input type="text" name="list[1].age"/></br>
                  <input type="submit" value="注册"/>
              </form></br>

     

        action

     

     

    package com.clj.demo2;
    
    import java.util.List;
    
    import com.opensymphony.xwork2.ActionSupport;
    /**
     * 属性驱动的方式,把数据封装List集合中
     * @author Administrator
     *
     */
    public class regist4 extends ActionSupport{
        private List<User> list;
    
        public List<User> getList() {
            return list;
        }
    
        public void setList(List<User> list) {
            this.list = list;
        }
        public String execute() throws Exception{
            for(User user:list){
                System.out.println(user);
            }
            return NONE;
        }
        
    }

     

      2.将数据封装到Map集合中

       jsp

    <h3>向Map集合封装数据(默认情况下,采用属性驱动的方式)</h3>
              <!-- 采用OGNL表达式 -->
              <form action="${pageContext.request.contextPath}/regist5.action" method="post">
                     <!-- 这里的"user"是根据Aciton中封装属性的类的名称属性而定(private User user;) -->
                  姓名:<input type="text" name="map['one'].username"/></br>
                  密码:<input type="password" name="map['one'].password"/></br>
                  年龄:<input type="text" name="map['one'].age"/></br>
                  
                  姓名:<input type="text" name="map['two'].username"/></br>
                  密码:<input type="password" name="map['two'].password"/></br>
                  年龄:<input type="text" name="map['two'].age"/></br>
                  <input type="submit" value="注册"/>
              </form></br>

       action

    package com.clj.demo2;
    
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    
    import com.opensymphony.xwork2.ActionSupport;
    /**
     * 属性驱动的方式,把数据封装Map集合中
     * @author Administrator
     *
     */
    public class regist5 extends ActionSupport{
        private Map<String,User> map=new HashMap<String,User>(); 
        
        public Map<String, User> getMap() {
            return map;
        }
    
        public void setMap(Map<String, User> map) {
            this.map = map;
        }
    
        public String execute() throws Exception{
            System.out.println(map);
            return NONE;
        }
        
    }

     

      2、方式二:模型驱动

        1)手动实例化javabean

     

    private User user=new User();

     

        2)实现ModelDriven<T>接口,实现getModel()的方法,在getModel()方法中返回javaBean

        jsp

    <h3>模型驱动</h3>
                 <form action="${pageContext.request.contextPath}/regist3.action" method="post">
                     <!-- 这里的"user"是根据Aciton中封装属性的类的名称属性而定(private User user;) -->
                  姓名:<input type="text" name="username"/></br>
                  密码:<input type="password" name="password"/></br>
                  年龄:<input type="text" name="age"/></br>
                  <input type="submit" value="注册"/>
              </form></br>

        action代码

    package com.clj.demo2;
    
    import com.opensymphony.xwork2.ActionSupport;
    import com.opensymphony.xwork2.ModelDriven;
    /**
     * 模型驱动的方式
     * 1.实现ModelDrivern接口
     * 2.必须手动实列化对象(需要自己new好)
     * @author Administrator
     */
    public class regist3 extends ActionSupport implements ModelDriven<User>{
        //必须手动实例化
        private User user=new User();
        //获取模型对象
        public User getModel() {
            // TODO Auto-generated method stub
            return user;
        }
        public String execute() throws Exception{
            System.out.println(user);
            return NONE;
        }
        
    }

    十、struts2之拦截器

      1、什么是拦截器?

      java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。

                                                                            ---------360百科

         拦截器的利用是struts2框架的一个特点,即面向切面编程

      2、编写一个拦截器

       1)定义一个拦截器类

    package com.itheima.interceptior;
    
    import com.google.common.collect.AbstractIterator;
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
    
    
    
    /**
     * 编写简单的拦截器
     * @author Administrator
     *
     */
    public class DemoInterceptor extends AbstractInterceptor{
        
        /**
         * intercept用来进行拦截的
         */
        public String intercept(ActionInvocation invocation) throws Exception {
            System.out.println("Action方法执行之前");
            //执行下一个拦截器
            String result=invocation.invoke();
            System.out.println("Action方法执行之后");
            return result;
        }
    }

      2) 定义一个action

    package com.clj.demo3;
    
    import com.opensymphony.xwork2.ActionSupport;
    
    public class UserAction extends ActionSupport{
        public String execute() throws Exception{
            System.out.println("我是Action,我正常执行了");
            return NONE;
        }
    }

      3) 配置文件配置

    <package name="demo3" extends="struts-default" namespace="/">
             <interceptors>
                 <!-- 定义了拦截器 -->
                 <interceptor name="DemoInterceptor" class="com.itheima.interceptior.DemoInterceptor"/>
             </interceptors>
            <action name="userAction" class="com.clj.demo3.UserAction">
                <!-- 只要是引用自己的拦截器,默认栈的拦截器就不执行了 ,必须手动引入默认栈-->
                <interceptor-ref name="DemoInterceptor"/>
                <interceptor-ref name="defaultStack"/>
            </action>
        </package>

      3、使用拦截器验证用户登录

         1) 定义一个拦截器

    package com.clj.interceptor;
    
    import org.apache.struts2.ServletActionContext;
    
    import com.heima.domain.User;
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.interceptor.MethodFilterInterceptor;
    
    /**
     * 自动以拦截器,判断当前系统是否已经登录,如果登录,继续执行
     * 如果没有登录,跳转到登录页面
     * AbstractInterceptor会拦截所有方法
     * MethodFilterInterceptor可以对指定的方法进行拦截
     * @author Administrator
     *
     */
    public class UserInterceptor extends MethodFilterInterceptor{
    
        /**
         * 进行拦截的方法
         */
        protected String doIntercept(ActionInvocation invocation) throws Exception {
            //获得session对象
            User user=(User) ServletActionContext.getRequest().getSession().getAttribute("existUser");
            if(user==null){
                //没有登录,返回字符串,后面就不会执行了
                return "login";
            }
            return invocation.invoke();
        }
        
    }

       2)action

    package com.itheima.action;
    
    import java.lang.reflect.InvocationTargetException;
    import java.util.Map;
    
    import javax.servlet.http.HttpServletRequest;
    
    import org.apache.commons.beanutils.BeanUtils;
    import org.apache.struts2.ServletActionContext;
    
    import com.heima.domain.User;
    import com.itheima.service.UserService;
    import com.opensymphony.xwork2.ActionSupport;
    
    /**
     * 用户登录模块控制器
     * @author Administrator
     *
     */
    public class UserAction extends ActionSupport{
        /**
         * 处理登录功能
         * @return
         */
        public String login(){
            //这边没有学习功能,封装数据,现在还需要request对象
            //怎么获取reqeust方式
            HttpServletRequest request=ServletActionContext.getRequest();
            //获取请求参数
            Map<String,String[]> map=request.getParameterMap();
            User user=new User();
            try {
                BeanUtils.populate(user,map);
                //调用业务层
                User existUser=new UserService().login(user);
                //判断
                if(existUser==null){
                    //说明,用户名或者密码错误了
                    return LOGIN;
                }else{
                    //存入session中
                    request.getSession().setAttribute("existUser", existUser);
                    return SUCCESS;
                }
            } catch (Exception e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } 
            return NONE;
        } 
    }

       配置文件

    <!-- 配置用户的模块 -->
            <action name="user_*" class="com.itheima.action.UserAction" method="{1}">
                <!--<result name="login">/login.jsp</result>-->
                <result name="success">/index.jsp</result>
                <interceptor-ref name="UserInterceptor">
                    <param name="excludeMethods">login</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack"/>
            </action>

    十一、OGNL

      1、什么是OGNL

       OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。

                                                                         ------------360百科

    Struts2框架使用OGNL作为默认的表达式语言

      2、演示OGNL表达式

    package com.clj.demo1;
    
    import ognl.Ognl;
    import ognl.OgnlContext;
    import ognl.OgnlException;
    
    import org.junit.Test;
    
    /**
     * 演示OGNL表达式
     * @author Administrator
     *
     */
    public class OgnlDemo {
        /**
         * OGNL访问对象的方法
         * @throws OgnlException 
         */
        @Test
        public void run1() throws OgnlException{
            //上下文对象
            OgnlContext context=new OgnlContext();
            //获取到根对象(ognl都是从根对象进行取值)
            Object root=context.getRoot();
            //存储数据
            context.put("name","美美");
            //获取值,表达式写法
            Object obj=Ognl.getValue("#name",context,root);
            System.out.println(obj);
        }
        /**
         * OGNL表达式调用方法
         * @throws OgnlException
         */
        @Test
        public void run2() throws OgnlException{
            //上下文对象
            OgnlContext context=new OgnlContext();
            //获取到根对象(ognl都是从根对象进行取值)
            Object root=context.getRoot();
            //获取值,表达式写法(这里是让字符串调用他的方法)
            Object obj=Ognl.getValue("'haha'.length()",context,root);
            System.out.println(obj);
        }
    }

      3、jsp中演示OGNL

        1) 先引入Strust2标签库

    <%@ taglib prefix="s" uri="/struts-tags" %>

       2) 调用

    <body>
           <h3>条件:假如值栈中已经存入值了,在JSP页面上从值栈中获取值</h3>
           <!-- 
               1.先引入Struts框架中提供的标签库,s标签
               2.可以使用提供的标签(很多,掌握重点的标签)
            -->
            <!-- 从值栈中获取值的value,中间编写就是OGNL表达式 -->
            <s:property value="username"/>
            <!-- 显示常量:加''号 -->
             <s:property value="'username'"/>
             <!-- 调用方法:加.加方法 -->
             <s:property value="'username'.length()"/>
      </body>

    十二、Struts2之值栈

      1、什么是值栈

      * 值栈就相当于Struts2框架的数据的中转站,向值栈存入一些数据。从值栈中获取到数据。

        * ValueStack 是 struts2 提供一个接口,实现类 OgnlValueStack ---- 值栈对象 (OGNL是从值栈中获取数据的 )

        * Action是多例的,有一起请求,创建Action实例,创建一个ActionContext对象,代表的是Action的上下文对象,还会创建一个ValueStack对象。

        * 每个Action实例都有一个ValueStack对象 (一个请求 对应 一个ValueStack对象

        * 在其中保存当前Action 对象和其他相关对象

        * Struts 框架把 ValueStack 对象保存在名为 “struts.valueStack” 的请求属性中,request中 (值栈对象 是 request一个属性)

            * ValueStack vs = (ValueStack)request.getAttribute("struts.valueStack");

      2、关于值栈的内部结构

      * 值栈由两部分组成

            > root      -- Struts把动作和相关对象压入 ObjectStack 中--List(底层ArrayList

            > context   -- Struts把各种各样的映射关系(一些 Map 类型的对象) 压入 ContextMap 中(底层Map,当讲ServletAPI时,完成接耦合方式ActionContext.getRequest()所返回的      Map集合就是此集合)

     

            * Struts会默认把下面这些映射压入ContextMap(context)中

            * 注意:request代表的是Map集合的key值(字符串名),value的值其实也是一个Map集合。

     

            > parameters: 该 Map 中包含当前请求的请求参数  ?name=xxx&password=123

            > request: 该 Map 中包含当前 request 对象中的所有属性

            > session: 该 Map 中包含当前 session 对象中的所有属性

            > application:该 Map 中包含当前 application  对象中的所有属性

            > attr: 该 Map 按如下顺序来检索某个属性: request, session, application

     

            * ValueStack中 存在root属性 (CompoundRoot) 、 context 属性 (OgnlContext )

            > CompoundRoot 就是ArrayList

            > OgnlContext 就是 Map

     

            * context 对应Map 引入 root对象

            > context中还存在 request、 session、application、 attr、 parameters 对象引用

            > OGNL表达式访问值栈中的数据

                * 访问root中数据时 不需要 #

                * 访问 request、 session、application、 attr、 parameters 对象数据 必须写 #

     

            > 操作值栈 默认指 操作 root 元素(至于context是框架自动将请求参数或者其他数据封装到conttext中)

       3、在jsp中查看值栈

     <!-- 在JSP页面上,查看值栈的内部结构 -->
         <s:debug/>

       4、关于值栈中压值

          1)压字符串之push方法

    /**
         * 演示值栈对象的目录结构
         * 想栈中压元素,先进先出
         * push:压入的对象
         * set:压入集合(先判断压入的对象是否是集合,不是则强转为集合,再创建键值对;是则在原有集合中压入元素)
         * @author Administrator
         *
         */
        public String execute() throws Exception{
            /*//使用获取值栈对象
            HttpServletRequest request=ServletActionContext.getRequest();
            ValueStack vs=(ValueStack) request.getAttribute("struts.valueStack");
            System.out.println(vs);*/
            //获取值栈对象,先获取到ActionContext对象
            ValueStack vs=ActionContext.getContext().getValueStack();
            System.out.println(vs);
            //栈顶压的是字符串
            vs.push("
    美美
    ");return NONE; }

       取值

    <h3>从值栈中获取值</h3>
         <!--值栈中获取的对象,当存入字符串时,栈顶第一个位置为对象,第二位置为Action,第三位置为封转栈的信息
             栈的默认索引是从0开始:[0]表示获取栈顶的封装对象的一些列信息,[0].top获取对象值
         //vs.push("美美");-->
         <s:property value="[0]"/>
         <s:property value="[0].top"/>

       2)压字符串之set方法

    ValueStack vs=ActionContext.getContext().getValueStack();
    //栈顶压的是集合
    vs.set("msg","金在中");

       取值

     <!-- 从栈顶获取字符串 ,方法为set,值栈中存的是Map集合>
         //vs.set("msg","金在中");-->
         <s:property value="[0].top.msg"/>

       3)栈顶放的是User对象,用push方法

    ValueStack vs=ActionContext.getContext().getValueStack();
    //创建User对象
    User user=new User();
    user.setUsername("美美");
    user.setPassword("123");
    //压栈
    vs.push(user);

       取值

     <!--栈顶放的是User对象,用push方法
             //[0].top关键字可以省略,值栈中提供getValue方法,从结果中找指定属性
            /* User user=new User();
            user.setUsername("美美");
            user.setPassword("123");
            //压栈
            vs.push(user);*/-->
         <s:property value="[0].top.username"/>
         <s:property value="[0].top.password"/>
         <s:property value="password"/>

       4)栈顶放的是User对象,用set方法

    ValueStack vs=ActionContext.getContext().getValueStack();
    //创建User对象
    User user=new User();
    user.setUsername("美美");
    user.setPassword("123");
    //压栈
    vs.set("user",user);

       取值

       <!--栈顶放的是User对象,用set方法
         // vs.set("user",user);-->
         <s:property value="[0].top.user.username"/>
         <s:property value="[0].top.user.password"/>
         <s:property value="user.password"/>
          

       5)在action中配置成员属性,并提供set/get方法,jsp同样可以来接收

    private User user=new User("小泽","456");
    //提供set/get方法

       取值

        <!-- 在ValueStack1Action提供了成员属性
           //private User user=new User("小泽","456");
           //提供set/get方法
          //vs.push(user);
                   从栈顶开始查找,找user的属性,显示名称,返回的小泽
          [1].top获取到ValueStack1Action,而该Action封装了user属性
          [0].top.user返回的是user对象-->
          <s:property value="user.username"/>

       6)获取值栈中(root)集合中的值push

    List<User> list=new ArrayList<User>();
            list.add(new User("熊大","123"));
            list.add(new User("熊二","456"));
            list.add(new User("熊三","789"));
            //把集合压栈
            vs.push(list);

       取值

         <!-- 获取list集合
                 //vs.push(list);-->
          <s:property value="[0].top[0].username"/>
          <s:property value="[0].top[1].username"/>

       7)获取值栈中(root)集合中的值set

    List<User> list=new ArrayList<User>();
            list.add(new User("熊大","123"));
            list.add(new User("熊二","456"));
            list.add(new User("熊三","789"));
            //把集合压栈
             vs.set("list",list);

       取值

        <!-- 获取list集合
                  //vs.set("list",list); -->
           <s:property value="list[0].username"/>

       8)利用迭代标签取值

        ValueStack vs=ActionContext.getContext().getValueStack();
            List<User> list=new ArrayList<User>();
            list.add(new User("熊大","123"));
            list.add(new User("熊二","456"));
            list.add(new User("熊三","789"));
            //把集合压栈
             vs.set("list",list);

        取值

    <!-- 迭代标签 
                 属性: * value 要迭代的集合,需要从值栈中获取
                    *  var   迭代过程中,遍历的对象
                          * var编写上,会把迭代产生的对象默认压入到context栈中
                          * var不编写上,默认吧迭代长生的对象压入到root栈中
                   
          -->
          <!-- 编写var:value="[0].top"等同于value="list" -->
          <s:iterator value="list" var="u">
                 <!--此时是压入context,取值要加#号-->
                 <s:property value="#u.username"/>
                 <s:property value="#u.password"/>
          </s:iterator>
     <!-- 没有编写var关键字-->
          <s:iterator value="list">
               <s:property value="[0].top.username"/>
               <s:property value="password"/>
          </s:iterator> 

       9) 从context栈中获取值

    ValueStack vs=ActionContext.getContext().getValueStack();
    //从context栈中获取值(注意:以上push与set默认都是操纵的root栈)
            //context底层已经封装request session对象,操作的都是map集合
        HttpServletRequest request=ServletActionContext.getRequest();
            request.setAttribute("msg","美美");
            
            request.getSession().setAttribute("msg", "小风");

       取值

    <!--  从context栈中获取值,加#号-->
          <s:property value="#request.msg"/>
          <s:property value="#session.msg"/>
                

       10)针对域名传过来的值,怎么接收

        加入域名为http://localhost:8080/xx/xx.action?id=5

     <!--  针对于域名传过来的参数(参数名为id),框架会自动封装 -->
          <s:property value="#parameters.id"/>

       11) 利用EL表达式接收数据

         引入jstl标签库

    <%@taglib prefix="c" uri="http://java.sun.com/jstl/core_rt" %>

        取值

     <!-- 在JSP页面上可以使用EL和JSTL标签库来取值
              使用装饰者模式,连接池全栈编码
              getAttribute()增强了 
          -->
          <c:forEach items="${list }" var="user">
                ${user.username}--${user.passwords}
          </c:forEach>

     

     

     

     

     

     

       

     

     

        

        


      

  • 相关阅读:
    Map之类的东西
    [待码][BZOJ1858]SCOI2010序列操作 jzyzoj1655
    Linux 系统时间和硬件时间
    自动化运维之puppet的学习(如何找到你需要的模块)
    linux 搭建hexo博客
    坚持不懈之linux haproxy的配置文件关键字查询手册
    坚持不懈之linux haproxy 配置文件 详情
    Linux Haproxy 安装和部署
    linux 破解版confluence安装
    zookeeper 简介
  • 原文地址:https://www.cnblogs.com/cailijia52o/p/8679629.html
Copyright © 2020-2023  润新知