struts2随手记

struts2  数据操作 值栈 拦截器

概述:应用在web层的框架,

      实在struts1和webwork基础之上发展全新的框架

      解决问题:创建很多的servlet,解决写servlet底层的帮助类的麻烦

      struts2 里面使用action(类似与过滤器,后进行不同处理)

版本:2.3.24


1导入jar包
    
2创建action类
    (1)访问servlet时候,执行service方法,底层用的是反射
     * (2)访问action,访问action的时候,默认执行名称execute方法
     package Action;

    public class HelloAction {
    /**
     * (1)访问servlet时候,执行service方法,底层用的是反射
     * (2)访问action,访问action的时候,默认执行名称execute方法
     *
     */
    public String execute(){
        
        return "ok";
    }
    }

3.创建servlet的时候要继承heepServlet,重写方法,在web.xml里面要进行配置
  action类似,配置action类的访问的路径

    创建struts2的核心配置文件,名称和位置是固定的,src下,struts.xml
    引入dtd的约束

    配置struts.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="hellodemo" extends="struts-default" namespace="/">
        <!--name中写上最终 访问的名称-->
        <action name="hello" class="Action.HelloAction">
            <!--配置方法的返回值到对应的页面中去-->
            <result name="ok">/hello.jsp</result>
        </action>

    </package>

</struts>
注意:配置过滤器:否则访问不到(struts2实现了过滤器,但是要配置)
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>


访问路径:
http://127.0.0.1/项目名/hello.action(.action可以不加,但是访问的浏览器版本不好的话最好加上)

基本执行过程:
        
    浏览器发送请求

    过滤器:里面做了
        过滤器在服务器启动的时候创建,servlet是第一次启动的时候创建

        1获取请求路径,得到路径中的hello的值

        2到src下面找到struts.xml 使用dom4j解析,得到xml文件中的内容,拿着hello到xml中去匹配对应的action的name值是否一样

        3匹配好name之后,找到name属性所在的标签里面的另一个属性class的值,得到action的全路径,通过反射实现全部的功能

             (反射:得到类的字节码文件执行操作)让action的方法执行
            Class jjj = Class.forName("action全路径");
            //得到名称是execute的方法
            Method m = jjj.getMethod("execute"); 
            //执行
            Object obj = m.invoke();

        4.得到action方法的返回值,到struts.xml文件中action标签里找到result标签,匹配result标签name属性值是否一样
          如果一样,跳转到配置页面中去


看源代码:很多功能使用过滤器做的,所以可以直接看过滤器即可

    StrutsPrepareAndExecuteFilter这是过滤器的名字
    结构 :init,dofilter,destory

    过滤器在服务器启动的时候创建,执行init方法
        
        init主要加载配置文件
            自己创建和struts自己的配置文件
            (默认的文件在struts里的、default/plugin/struts.xml、)
            **struts.xml和web.xml是自己写的


    
Struts2    配置

    核心配置文件:基本结构配置
        名称和位置固定
        在配置文件中主要三个标签:package、action、result。标签里面的属性
             package:类似于代码中的包,区别于不同的action,必须首先写package标签,在package里面才能配置action
            name:属性跟功能本身没有关系,在一个配置文件中可以写多个package标签,name属性值不能相同的

            extends:struts-default属性值是固定的,表示写了此属性了之后在package里面配置的类具有action功能
                
                        
            namespace:值要和action里面的name属性值构成访问路径,可以不写,默认就是/,建议写出来

        action:
            此标签用于配置action访问路径,

            name:值要和package里面的namespace属性值构成访问路径,可以不写,默认就是/,建议写出来,在一个package标签中可以写多个action标签,但是name不能相同

            class:action的全路径,底层是反射

            method:比如在action里面默认执行execute,但是在action里面写上其他的方法,可以通过action来执行,让多个方法进行执行

        result:标签用于根据action方法的返回值,配置到不同的路径里面去。不经是页面也可以是action
            
            name:和方法的返回值一样,配置方法的返回值:/hello.jsp
                <!--配置方法的返回值到对应的页面中去-->
                        <result name="ok">/hello.jsp</result>

            type:配置如何到路径中去:转发和重定向 默认是转发


        
            
struts的默认常量(封装的功能)配置修改:
    常用的方式:
    在struts.xml里面进行修改
     <constant name="struts.i18n.encoding" value="utf-8"></constant>
        
    还有两种方式
        src下面创建struts.properties

        在web.xml里面进行修改

    最常用的常量:
        struts.i18n.encoding=utf-8
        表单提交数据到action里面,子啊action可以获取表单提交数据
        表单提交数据会有中文乱码问题,解决
            以往:post 直接设置编码
                get做编码转换
        如果在action获取表单是post,不需处理中文乱码,但是如果是get还得自己处理。
        
        

分模块的开发(实际开发):
    
    单独写配置文件,把配置文件映入到核心配置文件中
    
        <!--引入hello.xml文件-->
        <include file="Action/hello.xml"></include>

Action的编写方式

    三种:

    第一种:创建普通类,此类不继承任何类,也不实现任何接口
package Action;

public class HelloAction {
    /**
     * (1)访问servlet时候,执行service方法,底层用的是反射
     * (2)访问action,访问action的时候,默认执行名称execute方法
     *
     */
    public String execute(){
        return "ok";
    }
}
    
    第二种:创建类,实现接口Action用的不多
        package Action;
/*
实现接口
 */

import com.opensymphony.xwork2.Action;

public class UserAction implements Action {
    @Override
    public String execute() throws Exception {
        //return "success";
        return SUCCESS;//可用接口中的常量作为返回值
    }
}

    
    第三种:创建类,继承ActionSupport(该类实现了包含action接口在内的很多结口)最常用
    

import com.opensymphony.xwork2.ActionSupport;

public class PersonAction extends ActionSupport {

    @Override
    public String execute() throws Exception {
        //return "success";
        return SUCCESS;//可用接口中的常量作为返回值
    }
}


action的多个方法的访问设置(重点)

三种方式:
    第一种:使用action标签的method属性,在这个属性里面写执行的action的方法
    大量方法配置会很麻烦
<!--配置action的方法的访问-->
    <package name="methoddemo" extends="struts-default" namespace="/">
        <!--method属性,写要执行的action里面的方法名称-->
        <action name="addAction" class="Method.BookAction" method="add"></action>
        <action name="updateAction" class="Method.BookAction" method="update"></action>


    第二种:常用的,通过通配符的方式,大量方法适用,在action标签name值写成*
        表示:用*匹配任意的内容
            比如访问hello, *可以匹配到
            比如访问add, *可以匹配到

    <!--配置action的方法的访问通配符的方式-->
    <package name="methoddemo" extends="struts-default" namespace="/">
        <!--
            name属性之里面写符号*
            执行action里面的add方法,访问book_add,使用book_*可以匹配到,*相当与add
            执行action里面的update方法,访问book_update,使用book_*可以匹配到,*相当与update
            以上两个路径使用book_*可以匹配到
            method属性写*值,{1}表示取到第一个*的值
        -->
        <action name="book_*" class="Method.BookAction" method="{1}"></action>
    </package>

    执行流程:
        访问路径---》book_*匹配到


    第三种:通过动态访问的方式实现(少用)

        写法很麻烦,还多
在前端的页面的链接用! 如:useraction!delete.action
        
    
        
        

如果action方法没有返回值,在配置文件中没有配置,出现404 no result defined,,,

    

action的方法里有返回值,如果有返回值的时候,类型必须是string

action的方法里没有返回值,如果没有返回值的时候,在result标签中不需要配置
    把方法的返回些微void
    但是建议写成返回"none"或NONE常量(注意action要继承ActionSupport类)的字符串,也可以不用配置result  
    public String execute(){
//        return "none";
        return NONE;
    }

        

servlet改struts2    
    与servlet很像,将service的调用放在了action类的方法里,使用与对象存储数据
    
    HttpServletReqeust request= ServletActionContext.getRequest();//获取请求,实际就HttpServletReqeust
request.setAttribute("list",list);


结果页面的配置:
    
    创建两个accton都返回success,跳转到公共页面

    全局结果页面:解决问题
                <action name="book" class="Action.BookAction">
            <result name="success">/hello.jsp</result>
        </action>
        <action name="orders" class="Action.OrdersAction">
            <result name="success">/hello.jsp</result>
        </action>

         解决方法
            <package name="demo1" extends="struts-default" namespace="/">
        <!--全局结果页面的配置-->
        <global-results>
            <result name="success">/hello.jsp</result>
        </global-results>
        <action name="book" class="Action.BookAction">
            <!--<result name="success">/hello.jsp</result>-->
        </action>
        <action name="orders" class="Action.OrdersAction">
            <!--<result name="success">/hello.jsp</result>-->
        </action>
    </package>
        

    局部结果页面:
    如:<action name="orders" class="Action.OrdersAction">
            <result name="success">/hello.jsp</result>
        </action>

    当局部和全局冲突时间,以局部为准

    <package name="demo1" extends="struts-default" namespace="/">
        <!--全局结果页面的配置-->
        <global-results>
            <result name="success">/hello.jsp</result>
        </global-results>
        <action name="book" class="Action.BookAction">
            <result name="success">/index.jsp</result>
        </action>
        <action name="orders" class="Action.OrdersAction">
            <!--<result name="success">/hello.jsp</result>-->
        </action>
    </package>


    result标签type属性:
        
        type用于指定如何到路径里去

        type属性值默认值转发:dispatcher
             <result name="success" type="dispathcer">/hello.jsp</result>
                  重定向:redirect
                
<action name="book" class="Action.BookAction">
            <result name="success">/index.jsp</result>
        </action>
        <action name="orders" class="Action.OrdersAction">
            <result name="success" type="redirect">/hello.jsp</result>
        </action>

                还有两个值:配置到action的:
                chain:转发到action用的少有缓存一般不用
            
                redirectAction:重定向到action
    <action name="book" class="Action.BookAction">
            <!--action访问名称-->
            <result name="success" type="redirectAction">orders</result>
        </action>
        <action name="orders" class="Action.OrdersAction">
            <result name="success" type="redirect">/hello.jsp</result>
        </action>


action表单提交数据

        web阶段提交表单提交到servlet里面使用request对象里面的方法获取,getParameter,getParameterMap
        
        提交表单到action,但是action没有request对象,不能直接使用request对象
        
        action获取action对象三种方式如下

    使用ActionContext类获取
        
        用Map<String Object> getParameters()方法
        因为方法不是静态方法,需要创建ActionContext对象
        该对象不是new出来的,用static ActionContext getContext()获取当前线程的actionContext对象
        
        具体:
    //通过ActionContext类获取
        //1获取ActionCOntext对象
        ActionContext actionContext = ActionContext.getContext();
        //2.调用方法获取表单数据
        //key是表单输入的name的属值,value是输入的值
        Map<String,Object> map = actionContext.getParameters();

        Set<String> keys= map.keySet();
        for (String key:keys) {
            //得到key的value
            Object[] object = (Object[])map.get(key);//考虑到复选框所以用数组
            System.out.println(Arrays.toString(object));
        }
        

    使用SerevletActionContext类获取
        调用类里面的静态方法,得到request对象
    //第二种方式使用ServletActionContext类获取
        //使用ServletActonContext获取request对象
        javax.servlet.http.HttpServletRequest request = ServletActionContext.getRequest();
        //调用request里面的方法得到信息
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String address = request.getParameter("address");
        System.out.println(username+" "+password+" "+address);
      

    使用接口注入方式获取

        让action实现一个接口,为了得到request
        
    public class Form3DemoAction extends ActionSupport implements ServletRequestAware {

    private HttpServletRequest request;

    @Override
    public void setServletRequest(HttpServletRequest httpServletRequest) {
        this.request=httpServletRequest;
    }

    @Override
    public String execute() throws Exception {
        //第三种方式使用接口
        request.getParameter("");
        return NONE;
    }


}

在action里面域对象:如javax.servlet.http.HttpServletRequest request = ServletActionContext.getRequest();
    
    1.request\session\servletContext域对象

    2.使用ServletActionContext类来操作


    //操作三个域对象
//        1.request传输到页面数据
        HttpServletRequest request = ServletActionContext.getRequest();
        request.setAttribute("req","reqValue");

        //2session域,保存登陆状态等
        HttpSession session = request.getSession();
        session.setAttribute("sess","sessionValue");

        //3servletContext,用的少
        ServletContext context = ServletActionContext.getServletContext();
        context.setAttribute("contname","contvalue");

struts2提供 获取 表单数据方式,简化数据获取方式

    原始的方式获取封装到实体类,最有效的方式

    //获取表单数据
        HttpServletRequest request = ServletActionContext.getRequest();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String address = request.getParameter("address");

        //封装到实体类的对象
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setAddress(address);
        System.out.println(user);

    属性封装
        可以直接把表单提交的数据封装到action属性里面

        实现:
            在action成员变量位置定义变量
            变量名称和表单输入项的name属性值一样
            
            生成的变量的set方法(set和get)

public class DataDemo1Action extends ActionSupport {

//    使用属性封装获取表单数据
    //定义变量
    //变量的名称和表单输入项name属性值一样
    private String username;
    private String password;
    private String address;

    //生成变量的set和get方法


    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 getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String execute() throws Exception {
        System.out.println(username+password+address);
        return NONE;
    }
}        
        该方式只是获取表单的数据到属性里面,不能把数据直接封装到实体类对象里面
        

    模型驱动封装(最常用,如添加数据的时候)
        优点:直接将表单的数据封装到实体类对象的方式,底层是原始的方式
    
        实现:
            action实现接口ModelDriven
            
            实现接口里面的方法,getModel方法
                把创建对象返回

            在action里面创建实体类对象

//使用模型驱动获取方式
public class DataDemo2Action extends ActionSupport implements ModelDriven<User> {
    //创建对象
    //要求表单实体类属性和实体类对象属性名相同
    private User user = new User();
    public User getModel() {
        //返回创建user对象
        return user;
    }
    @Override
    public String execute() throws Exception {
        System.out.println(user);
        return NONE;
    }
}
    使用模型驱动和属性封装的时候注意问题:
        1.在一个action中,获取表单数据可以属性封装或模型封装,但不能同时使用两者来获取同一个表单数据,如果都用只用模型的

        

    表达式封装(也可以归类为属性封装)
        实现过程:
            也可以将表单数据封装到实体类对象里面

            在action里面声明实体类    

            生成实体类变量的set和get方法
    
            在表单输入项的name属性值里面写表达式形式            
//使用表达式封装
public class DataDemo3Action extends ActionSupport{

    private User user;

    public User getUser() {
        return user;
    }

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

    @Override
    public String execute() throws Exception {
        System.out.println(user);
        return NONE;
    }
}

    <form action="{pageContext.request.contextPath}/data3.action" method="post">
        username:<input type="text" name="user.username">
    <%--user.username会调用user.setUsername方法--%>
        password:<input type="text" name="user.password">
        address:<input type="text" name="user.address">
        <br>
        <input type="submit" value="提交"/>

    </form>


比较表达式封装和模型驱动封装
        相同:都可以将数据封装到实体类对象里

        不同:
            模型驱动只能将数据封装到一个实体类里面
            在一个action里面不能使用模型驱动把数据封装到不同过的实体类对象里面
            使用表达式封装可以将数据封装到不同的实体类对象里面

//使用表达式封装
public class DataDemo3Action extends ActionSupport{

    private User user;
    private Book book;

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }

    public User getUser() {
        return user;
    }

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

    @Override
    public String execute() throws Exception {
        System.out.println(user);
        System.out.println(book.getBname());
        return NONE;
    }
}

        address:<input type="text" name="user.address">
        <br>
        bname:<input type="text" name="book.bname">

struts2 获取 数据封装到集合中
    
    封装到list集合
        在action里面声明list
        生成list变量的set和set方法
        在表单输入项里面写表达式

public class DataDemo3Action extends ActionSupport{

    private User user;
    private Book book;

    public Book getBook() {
        return book;
    }

    public void setBook(Book book) {
        this.book = book;
    }

    public User getUser() {
        return user;
    }

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

    @Override
    public String execute() throws Exception {
        System.out.println(user);
        System.out.println(book.getBname());
        return NONE;
    }
}


<form action="{pageContext.request.contextPath}/list.action" method="post">
        username:<input type="text" name="list[0].username">
    <%--user.username会调用user.setUsername方法--%>
        password:<input type="text" name="list[0].password">
        address:<input type="text" name="list[0].address">
        <br>

        username:<input type="text" name="list[1].username">
        <%--user.username会调用user.setUsername方法--%>
        password:<input type="text" name="list[1].password">
        address:<input type="text" name="list[1].address">
        <br>

        <input type="submit" value="提交"/>

    </form>

    封装到map集合
        1.声明一个map集合,
        2.生成get和set方法
        3.在表单输入项的name属性值里面写表达式

//封装数据到一个map集合
public class MapAction 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 {
        System.out.println(map);
        return NONE;
    }
}

<form action="{pageContext.request.contextPath}/map.action" method="post">
        <%--
            设置map的key
            设置value值
        --%>
        username:<input type="text" name="map['one'].username">
    <%--user.username会调用user.setUsername方法--%>
        password:<input type="text" name="map['one'].password">
        address:<input type="text" name="map['one'].address">
        <br>

        username:<input type="text" name="map['hhh'].username">
        <%--user.username会调用user.setUsername方法--%>
        password:<input type="text" name="map['hhh'].password">
        address:<input type="text" name="map['hhh'].address">
        <br>

        <input type="submit" value="提交"/>

    </form>


    


值栈:在struts中可以将数据放到值栈中,在页面中也可以取到

OGNL的概述

    在web阶段学过EL表达式只可用与jsp中,获取域对象里面的值,但是在html中就不行,
        
    ognl表达式,比el强大
        在struts2中用于操作值栈中的数据,
        一般把ognl和struts2中的标签结合使用,用于操作值栈

        
    ognl不是struts2的一部分,单独的项目,场合struts2一起使用
      使用ognl,首先要导入ognl的jar包,但是struts2已经提供了

    
ognl案例:
        
    ognl支持对象方法的调用,
    使用ognl和struts2实现计算字符串长度

    在java中使用字符串的length()方法

    步骤:
        引入struts2的标签库
        <%@ taglib prefix="s" uri="/struts-tags" %>

        使用标签实现操作
<%--
    使用ognl+struts2表达式
     value:ognl表达式
  --%>
  <s:property value="'haha'.length()"/>

什么是值栈
    
    在web阶段使用servlet以及域对象进行数据的存入,在页面中通过el表达式进行取出。域对象在一定的范围之内

    在struts2中提供了一种存储机制,类似于域对象,是值栈,可以存值和取值
        在action里面把数据存放到值栈里面,在页面中也能获取到值栈的数据
    
    servlet和action的区别:
        servlet默认在第一次访问的时候创建,创建一次,单实例对象

        action创面多次,访问一次创建一次,多实例对象
    

    值栈的存储位置

        每次访问action的时候都会创建一个action对象

        每个action对象里面都会有 *一个*!值栈对象(只有一个)

    获取值栈对象:
        
        获取有两种方式
          使用一个ActionContext类里里面你的方法得到值栈对象(常用)
    

        ActionContext context= ActionContext.getContext();
            //得到值栈信息
            ValueStack stack1 = context.getValueStack();
    
            ValueStack stack2 = context.getValueStack();
    
            System.out.println(stack1==stack2);
        每个action中只有一个值栈对象

    

    值栈内部结构

        栈:如同水杯,后进先出,放入内容的时候叫做压栈操作,最上面的是栈顶元素

        值栈的内部结构:
            分为两部分:
                root:机构是list集合
                    一般操作都是root里面数据,对应类是CompoundRoot,继承了ArrayList类

                context:结构map集合:主要存的是键值对,context储存的是对象的引用,key主要是request,session,application,parameters,attr,value对应是key代表对象的应用分别为:request对象的引用,HttpSession对象的引用,ServletContext对象的引用,传入的参数,向前面三个域对象的名称都相同,使用attr操作,获取上述域对象里面范围最小的值。
                    OgnlContext实现了Map接口

向值栈中放数据

    使用s:debug标签:使用该标签可以查看值栈结构和存储值
        访问action,执行action的方法,返回值配置返回daojsp中,jsp中使用该标签。
        在action中没有任何操作,栈顶元素就是Actiuon对象(引用)
        action对象里面有值栈对象
         值栈对象里面有action引用

    向值栈中放数据
        三种方式
        1.获取值栈对象,调用值栈对象里面的set方法
            ActionContext context = ActionContext.getContext();
                ValueStack stack = context.getValueStack();
                stack.set("username","itcast");

        2.获取值栈对象,调用值栈对象里面的push方法
    ActionContext context = ActionContext.getContext();
        ValueStack stack = context.getValueStack();
        //set
        stack.set("username","itcast");
        //push
        stack.push("abasdafsddfasdf");

    目前的栈内部:从上倒下
    栈顶
    java.lang.String    
    java.util.HashMap
    Action.ValueStackDemoAction
    栈底


        3.在action定义变量,生成变量的get方法(常用,减少空间浪费)
            这个方法直接数据放入Action.ValueStackDemoAction,而非如上面两种中自行开辟空间:java.lang.String和java.util.HashMap

public class ValueStackDemoAction extends ActionSupport {

    //定义成员变量
    private String name;
    //get方法生成
    public String getName() {
        return name;
    }

    public ValueStackDemoAction(){
        System.out.println("action实例化");
    }

    @Override
    public String execute() throws Exception {

        //在具体的执行方法里面设置值
        name = "fasdfasdfasdfasdf";

//        ActionContext context = ActionContext.getContext();
//        ValueStack stack = context.getValueStack();
//        //set
//        stack.set("username","itcast");
//        //push
//        stack.push("abasdafsddfasdf");

        return SUCCESS;
    }
}


    向值栈中发放对象
        
        1.定义成员变量

        2.生成成员变量的get方法

        3.在执行的方法里面向对象设置值
public class ObjectDemoAction extends ActionSupport {

    private User user = new User();

    public User getUser() {
        return user;
    }

    @Override
    public String execute() throws Exception {
        user.setUsername("asdfasd");
        user.setPassword("asdfasdf");
        user.setAddress("USA");
        return SUCCESS;
    }
}

    向值栈中放list对象
        定义一个list成员变量

        生成get

        在方法中放入值

public class ListDemoAction extends ActionSupport {

    private List<User> lsit = new ArrayList<User>();

    public List<User> getLsit() {
        return lsit;
    }

    @Override
    public String execute() throws Exception {
        User user = new User();
        lsit.add(user);
        lsit.add(user);
        return SUCCESS;
    }
}

    从值栈中取数据,使用struts2的标签和OGNL表达式取值栈数据
        <s:property value="ognl表达式">

        1。获取字符串
            向值栈中放入字符串
public class ValueStackActioin extends ActionSupport {

    private String username;

    public String getUsername() {
        return username;
    }

    @Override
    public String execute() throws Exception {
        username = "hello";
        return "success";
    }
}
            页面获取值栈中的字符串
 <%--获取字符串的值,根据名称就可以得到值--%>
 <s:property value="username"></s:property>
            
在jsp中使用struts2的标签和OGNL    
    
        
        2.获取对象
            
  private User user = new User();
    public User getUser() {
        return user;
    }

    @Override
    public String execute() throws Exception {
        username = "hello";
        user.setUsername("usernameshelklo");
        user.setPassword("asdfasdf");
        user.setAddress("asdfasdfasdfasdf");

        return "success";
    }

  <%--获取对象的值--%>
  <s:property value="user.username"></s:property>
  <s:property value="user.password"></s:property>
  <s:property value="user.address"></s:property>

        3.获取集合list
 private List<User> list = new ArrayList<User>();
    public List<User> getList() {
        return list;
    }

    @Override
    public String execute() throws Exception {
//        username = "hello";

//        user.setUsername("usernameshelklo");
//        user.setPassword("asdfasdf");
//        user.setAddress("asdfasdfasdfasdf");


        User user = new User();
        user.setUsername("张三");
        user.setPassword("1253563");
        user.setAddress("华山");

        User user1 = new User();
        user1.setUsername("李四");
        user1.setPassword("1253563");
        user1.setAddress("衡山");

        list.add(user);
        list.add(user1);


        return "success";
    }

 
<%--获取值栈中list集合中的数据--%>
  <%--第一种方法--%>
  <s:property value="list[0].username"></s:property>
  <s:property value="list[0].password"></s:property>
  <s:property value="list[0].address"></s:property>
  <br>
  <s:property value="list[1].username"></s:property>
  <s:property value="list[1].password"></s:property>
  <s:property value="list[1].address"></s:property>
  <br>
  <%--第二中方法,使用struts2标签,类似jstl的foreach
      <s:iterator>遍历值栈中的list集合

      <c:foreach item-="" var="user">
        ${user.username}
      </c:foreach>
      小心&和!注释方式
  --%>
  <s:iterator value="list">
    <%--遍历list得到list里面每个user对象--%>
    <s:property value="username"></s:property>
    <s:property value="password"></s:property>
    <s:property value="address"></s:property>
    <br>
  </s:iterator>

  <%--第三种方法--%>
  <s:iterator value="list" var="user">
    <%--娶不到
    <s:property value="address"></s:property>
    遍历list集合得到每个user对象机制,吧每次遍历出来的user对象放到context里面
    这样会加速,在contex里面分配临时空间,key是var的值user 值会放入user对象的引用
    获取context里面的数据特点,写ognl表达式
    使用特殊符号:#
    --%>
    <s:property value="#user.username"></s:property>
    <s:property value="#user.password"></s:property>
    <s:property value="#user.address"></s:property>
  </s:iterator>


其他操作:
    
    使用set方法向值栈放数据,获取
  <%--获取set方法放入的值--%>
  <%--根据名称获取值--%>
  <s:property value="itcast"></s:property>

    

    使用push方法向值栈放数据,获取
    使用push方法设置值,没有名称,只有设置的值
    想值栈放数据,把向值栈放数据存到数组里面,数组名称top,根据数组获取值    

  <%--获取push方法放入的值--%>
  <%--无名称取法,通过默认数组,用ognl的写法,取到数组中的第一个值,实际就是栈顶的值--%>
  <s:property value="[0].top"></s:property>


el表达式如何取到值栈中的值
    <%--使用foreach标签和el--%>
    <c:forEach items="${list}" var="user">
      <p>hello this is jstl</p>
      ${user.username}
      ${user.password}
      ${user.address}
    </c:forEach>

el表达式为什么获取到值栈数据的值

    1.本身用于取与域对象里面的值

    2.域对象里面放值使用setAttribute方法,获取值使用getAttribute();
     
    3.底层增强request对象里面的方法getAttribute方法
        首先从request域里面获取值,如果获取到,直接返回
        如果从request域对象娶不到值,到值栈中把值获取出来,把值放到域对象里面
    4.底层实在dofilter里面做了一个增强叫做wrapRequest(request),再往里面有一个StrutsRequestWrapper 继承了HttpServletRequestWrapper,增强的方法是getAttribute。
        
    5.建议:如果把数据放到了值栈中去,不建议用el取,因为会拖慢性能


OGNL的#、%使用

    #:可以获取值栈中context里面的数据。context是map类型的结构
        向request里面放入值,使用OGNL表达式获取值


public class ContextDemoActioin extends ActionSupport {

    @Override
    public String execute() throws Exception {

        HttpServletRequest request =  ServletActionContext.getRequest();
        request.setAttribute("req","reqValue");


        return "success";
    }
}

  <%--获取context里面的数据,写ognl的时候首先添加上符号
    #context的key名称,域对象的名称
  --%>
  <s:property value="#request.req"></s:property>
  </body>

    %:在struts2的标签中有一类表单标签
       %使用struts2标签里面使用ognl表达式,如果直接在struts2表单标签里面使用ognl表达式不知别,只有%之后才会识别

      <%--<s:property value="#request.req"/>--%>
  <%--<input type=" text" name="name" value="123"> 这是一个普通输入项--%>
  <s:textfield name="username" value="%{#request.req}"></s:textfield>

        

        
    


struts2 拦截器概述

    struts是框架,封装了很多功能,都是封装在拦截器里面。

    struts2里面封装了很多功能,有很多拦截器,不是每次这些拦截器都执行,每次执行默认的拦截器。

    struts2里面默认拦截器位置:corejar包里,有一个struts-default。xml配置文件,里面有一个<interceptor-stack name="defaultStack">就是默认拦截器的位置所在。内有很多拦截器的引用。

    拦截器在什么时候进行执行?
    在action对象创建之后,方法执行之前执行。拦截器类一般有一个intercept方法进行处理操作。


拦截器底层原理

    底层两个原理

    aop思想:
        aop指的是面向切面编程,有一个基本功能,扩展功能可以不通过修改元代码的形式

        比如登陆成功之后做一个用户权限判断(功能扩展),权限判断,不修改源代码(AOP)应对需求变动的时候特别好
        AOP更底层的是动态代理技术
        
    责任链模式:
        在java中有很多设计模式,责任链是其中一种
        责任链和过滤连模式相似
            过滤连:一个请求可以有多个过滤器进行过滤,每个过滤器只有通过放行才能到下一个过滤器。
        
            责任链:一次执行多个操作,
                先执行操作一,类似放行操作,进行修改操作,类似放行,进行操作三。。。。


    
    AOP和责任链是如何应用到拦截器里面的
        
        拦截器在action对象创建之后,action方法执行之前执行默认拦截器,执行的过程使用的就是aop的思想。(不该源代码就是先功能)action里面并没有显示调用拦截器,而是通过配置的方式实现。
        在执行拦截器的时候,执行很多拦截器,这个过程使用责任链模式。(类似放行的方式有序的是拦截器执行)

        在具体的执行的时候,从默认的拦截其中挑选使用到的,而拦截器之间的执行用的就是责任链的模式,通过放行逐个执行。

    源代码:(类似于放行操作的方法叫做invocation.invoke()的方法)
        执行action
            execute.executeAction(request,response,mapping)

        创建action对象,使用动态代理方式
            ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(
namespace,name,method,extraContext,true,false)
        执行action的方法
            proxy.execute();
        执行很多拦截器,遍历执行
            if(interceptors.hasNext()){}

重要概念:
        
    过滤器和拦截器的区别:
        过滤器:理论上可以过滤任意的内容,html,jsp,servlet,图片路径

        拦截器:可以拦截内容:action只有这个。

    
    Servlet和action的区别

        servlet:一默认的第一次访问的时候创建,创建一次,单实例对象
        action:每次访问的时候创建,创建多次,多实例对象


    

自定义拦截器:

    struts2里面有很多拦截器,是有struts2自己封装的功能,但是可能没有需要的功能,我们可以自己创建


    拦截器的基本结构:
        
        查看源代码:
            继承AbstractInterceptor类
            
            AbstractInterceptor类实现Interceptor接口

            Interceptor接口中有三个方法:

                void init()初始化,

                void destory()销毁

                String intercept(ActionInvoication invocation)    拦截逻辑

        
        一般选择继承类,用谁写谁


        
        (2)开发中一般使用另一种方式

            写类,继承MethodFilterInterceptor类
            让action里面的方法不进行拦截

        (3)让拦截器和action有关系,通过配置文件的方式建立关系,aop

        

案例需求:

    自定义登陆拦截器

    1需求:登陆状态判断,很多action的超链接,实现只有是登陆的状态,才可以点击action的超链接实现功能,如果不是登陆状态,点击action链接返回登陆页面

    2登陆状态:施一公session域对象实现
     登陆成功之后,把数据放到session里面
     判断session里面是否有值,可以知道是否有登陆状态

    3.实现登陆的基本功能。
        1.查询数据库判断用户名和密码。

        

    登陆的方法:


        

        public String login(){
            HttpServletRequest context = ServletAxtionContext.getRequest();
            String username = context.getParameter("username");
            String password= context.getParameter("password");            
            if("admin".equeals(username)&&"250".equals(password)){
                
                request.getSession().setAttribute("username",username);
                return "loginsuccess";

            }else{

            }

            return "login";
        }


添加登陆拦截器:
    判断是否登陆,从session中判断值
    
    实现过程:
        
        创建一个类继承MethodFilterInterceptor类


        重新MethodFilterInterceptor类里面的方法拦截器逻辑


//此方法写拦截器的逻辑即可
    @Override
    protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
        //判断session中用户信息
        HttpServletRequest context = ServletActionContext.getRequest();
        Object object =  context.getSession().getAttribute("username");
        if(object!=null){
            //登陆状态,做一个类似放行的工作
            return actionInvocation.invoke();
        }else{
            //不是
            //不执行放行
        //到result标签中找到名称是login的值,到配置的路径中去
            return "login";
        }
    }


            配置action和拦截器关系(注册拦截器)aop

            
             1.在要拦截的action标签所在的package标签里面声明拦截器
在package中
声明拦截器
<interceptors>
    <interceptor name="loginintercept" class="cn.it.interceptor.LoginInterceptor"></interceptor>
</interceptors>

              2.在具体的action标签使用声明的拦截器
使用:
在action里面
<interceptor-ref name="loginintercept"></interceptor-ref>
                

              3.struts2 里面执行很多的默认拦截器,但是如果在action里面配置自定义的拦截器,问题:默认的拦截器不会执行
                解决办法:把默认拦截器手动使用一次

在action里面:
方法一:把默认的<interceptor-ref>全复制进来,太多

方法二:映入:<interceptor-ref name="defaultStack">,将这些拦截器的外包标签引入即可


    配置的拦截器会对action里面的方法都拦截。登陆方法是不需要拦截的否则等不进去

    配置不拦截的方法:

        直接通过配置方式,是某些方法不拦截

    在使用拦截器里面配置:

<interceptor-ref name="loginintercept">

    <!--配置某些方法不拦截
        excludeMethods:忽略方法
    -->
    <param name="excludeMethods">方法名1.方法名2</param>

</interceptor-ref>

防止页面打开嵌套:在form标签中添加:target="_parent"

struts2常用标签:

    jsp页面中
    s:property:和ognl表达式在jsp页面中获取值栈数据
    s:iterator: 获取值栈中list集合数据,表示list集合
    s:debug:    查看值栈数据,结构
    s:if    
    

    struts2里面的表单标签:
    html中的表单:
        form:action method enctype

        输入项:大部分在input :type

                text,password,radio,checkbox,file,hidden,button,submit,image,reset
               不在input中:
                select,textarea

    对应的;struts2大部分都有
        form对应:s:form  常见属性形同

        输入项:text的  s:textfield 常见属性相同
            注意 有一个label属性:显示输入项的前面说名
            password的 s:password
            radio的:s:radio 多了一个list属性,
                value和显示值一样的时候:list="{'女','男'}"
                不一样额时候构建map集合:list="#{‘nv’:'女','nan':"男"}"
            checkbox的:s:checkboxlist 多了属性list
                list="{'asdf','asdfas','asdfasdf'}"

            下拉输入框:s:select 多了list同上

            文件上传:s:file 

            文本域:s:textarea 

            hidden的:s:hidden

            提交的:s:submit value=""
    
            重置的:s:reset    


按钮不在一行:可在form标签属性theme=“simple”    全在一行,不好之处

    


          

猜你喜欢

转载自blog.csdn.net/qq_42755868/article/details/81151099