Struts2笔记

发布于 2019-01-17  474 次阅读


Struts2框架:

Struts2 概述:

1.struts2 框架是应用在javaee三层结构中web层框架 hibernate 是dao层:

2.struts2 框架是在struts1 和 webwork 基础之上发展的"全新"的框架.

3.struts2 解决的问题.:

web阶段解决方案: 创建BaseServlet解决 (1).写到底层反射代码实现. 功能很多,创建更多servlet,存在维护特别不方便 struts2 是现阶段比较优的方案. 例: 用户管理系统(crud操作) ==> 过滤器(不同的操作,在类里面写不同的方法) ==> 分类执行类里面的方法 如: add方法/update方法 在struts2里面action(过滤器)

4.struts2版本: struts2-2.3.21-all.zip ; 这个版本是目前比较稳定的版本.

5.在web层常见框架: (1).struts2 (2).springMVC

Struts2 框架入门案例:

第一步: 导入jar包.

​ 解压struts2的jar包 ==> apps(案例)/docs(文档)/lib(struts2里面的所有jar包)/src(struts2的源代码) (1).在lib里面有所有的jar包, 不能把这些jar包全都导入项目中. (2).到apps里面 ,选择一个事例的程序,解压 ==> 选择里面WEB-INF的jar包.

第二步:创建action
/*
    (1).访问servlet时候, 都会执行service方法.
    (2).访问action, 每次访问action时候, 默认执行名称execute方法.
 */
public String execute(){
    System.out.println("执行了execute()方法");
    return "ok";
}
第三步: 配置action 类访问路径

(1).创建struts2核心配置文件. 核心配置文件名称和位置是固定的. 位置必须在src下面, 名称struts.xml

(2).映入dtd的约束.

<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">

(3).action 的相关配置.

<struts>
    <package name="hellodemo" extends="struts-default" namespace="/">
        <!-- name: 访问路径名称 -->
        <action name="hello" class="com.itcast.action.HelloAction">
            <!-- 配置方法的返回值, 使到达不同的页面 -->
            <result name="ok">/hello.jsp</result>
        </action>
    </package>
</struts>   

(4).配置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.在浏览器中访问上面路径

2.过滤器,在过滤器里面实现功能:

​ 第一步: 获取请求路径 ==> 得到路径里面的hello值.

​ 第二步: 到src下面找到struts.xml, 使用dom4解析, 得到xml文件中内容 ==> 那种hello值到xml文件中找标签action里面name属性值是否一样.

​ 第三步: 匹配name属性值一样, 都是hello ==> 找到name属性所在action里面另一个属性class值 ==> 得到action全路径 ==> 使用反射实现.

//反射的代码:
Class clazz = Class.forName("action全路径");
//得到名称是execute的方法.
Method m = clazz.getMethod("execute");
//方法执行
Object obj = m.incoke():

​ 第四步: 得到action方法的返回值 ==> 在struts.xml文件中, 找到action标签里面有result标签, 匹配result标签的name值是否一样 ==> 如果一样, 跳转到配置页面中.

查看struts2源代码:

​ class StrutsPrepareAndExecuteFilter implements StrutsStatics, Filter

  1. 过滤器在服务器启动时候创建, 创建过滤器时候执行init方法.
(1). init方法中主要加载配置文件

​ 包含自己创建的配置文件和struts2自带的配置文件.iniDispatcher() -- struts.xml -- web.xml

  1. Struts2核心配置文件:
1.名称和位置是固定的.

​ 名称为: struts.xml 位置: src下

2.在配置文件中只要有三个标签: packge, action, result, 标签里面的属性.

标签package :

​ 1.类似于代码包, 区别不同action, 必须首先写package标签, 在package里面才能配置action 2.package标签属性: (1).name属性 name属性的值跟功能本身没有关系, 在一个配置文件中可以写多个package标签, 但是里面的name属性不能相同. (2).extends属性(继承) extends属性值是固定的: struts-default 写了这个属性之后,在package里面配置的类具有action功能. (3).namespace属性.(名称空间) namespace属性值和action标签的name属性, 构成访问路径,默认是"/";

标签action :

​ 1.action标签配置action访问路径 2.action标签里面的属性: (1).name属性 name属性值和package的namespace的属性值构成访问路径. 在package标签里面写多个action标签, 但是action的name属性不能相同. (2).class属性(类的全路径) action的全路径 (3).method属性 比如在action里面默认执行的execute方法, 但是在action里面还能写其他的方法. 让action里面多个方法执行, 使用method进行配置.

标签result :

​ 1.根据action的方法返回值, 配置到不同的路径里面 2.result标签属性: (1).name属性 和方法的返回值一样 代码: <!-- 配置方法的返回值, 使到达不同的页面 --> <result name="ok">/hello.jsp</result> (2).type属性 配置如何到路径中(转发或者重定向) type属性默认值 做转发操作.

Struts2 常量配置:

  1. struts2框架, 帮我们实现了一部分功能, struts2里面有常量, 在常量里面封装一部分功能. 2.默认位置: Web App Libraries ==> struts2-core-2.3.24.jar ==> org.apache.struts2 ==> default.properies
  2. 修改struts2默认常量值:(1).常用方式: 在struts.xml中进行配置 代码: <!-- 配置常量 --> <constant name="struts.i18n.encoding" value="UTF-8"></constant>(2).还有两种方式(了解) 1.在src下创建 struts.preperies, 进行修改. 2.在web.xml进行配置.
  3. 介绍最常用的常量:struts.i18n.encoding=UTF-8 (1) 表单提交数据到action里面, 在action里面获取表单提交数据. (2) 表但提交数据有中文, 有乱码问题, 解决: -- post 提交直接设置编码 -- get 提交编码转换 (3) 如果在action 获取表单通过post方式提交中文, 中文乱码问题帮解决了, 不需要自己处理问题.

分模块开发:

  1. 单独写一个配置文件, 把配置文件引入到核心文件中去.
<!-- 引入hello.xml文件 -->
<include file="com/itcast/action/hello.xml"></include>

Action 编写方式:

1.action 编写有三种方式:

第一种: 创建普通类, 这个类不继承任何类, 不识闲任何接口.
public class HelloAction{}
第二种: 创建一个类, 实现接口 Action
/**
 * @author 实现接口
 *      注意: 引入mport com.opensymphony.xwork2.Action;
 */
public class UserAction implements Action{
    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }
}
第三种: 创建一个类, 继承类 ActionSupport (常用)
public class PersonAction extends ActionSupport{
    @Override
    public String execute() throws Exception {
        return SUCCESS;
    }
}

注意: 在源码中 实现了Action接口

​ public class ActionSupport implements Action

访问Action的方法(重点)

1.有三种方式实现:

​ 第一种方式: 使用action标签的method属性, 在这个属性里面写执行action的方式. 第二种方式: 使用通配符方式实现 第三种方式:动态方法访问(了解)

2.演示错误.

​ (1).如果action方法有返回值, 在配置文件中没有配置,出现错误. HTTP Status 404 - No result defined for action com.itcast.action.HelloAction and result ok

​ (2).在action里面的方法有返回值, 如果有返回值时候类型必须是String.

​ (3).action里面的方法可以没有返回值, 没有返回值的时候, 在result里面就不需要配置. -- 把方法写出void -- 让返回值, 返回"none".

public class HelloAction extends ActionSupport{
    public String execute(){
        System.out.println("执行了execute()方法");
        return NONE;
    }
}

使用Action标签method属性:

1.创建action ,创建多个方法:

public class BookAction extends ActionSupport{
    //添加
    public String add(){
        System.out.println("执行了add方法");
        return NONE;
    }
​
    //修改
    public String update(){
        System.out.println("执行了update方法");
        return NONE;
    }
}       
<!-- struts.xml里面的配置: -->
<!-- 配置action方法 -->
<package name="methoddemo" extends="struts-default" namespace="/">
    <!-- 有method属性, 写要执行的action里面要执行的方法的名称 -->
    <action name="addaction" class="com.itcast.method.BookAction" method="add"></action>
    <!-- 执行update方法 -->
    <action name="updateAction" class="com.itcast.method.BookAction" method="update"></action>
</package>

缺陷: action里面每个方法都需要配置, 如果有很多的方法, 则需要配置很多的action

2.使用通配符实现:(重点)

​ 1.在action标签里面name属性, name属性值里面写符号"*" 星号. (1) * 理解, 表示匹配任意内容 -- 比如访问hello , * 可以访问到 -- 比如add , * 可以访问到

​ 2.使用通配符实现

<!-- 通配符的方式实现 -->
<package name="methoddemo" extends="struts-default" namespace="/">
    <!-- 
      name属性值里面写符号 * 
       (1).执行action里面add方法, 访问book_add, 使用book_*可以匹配到, *相当于变成add
       (2).执行action里面update方法, 访问book_update, 使用book_*可以匹配到, *相当于变成update
      上面两个路径使用book_*可以匹配到.
      method属性写*值 : {1}
      -->
    <action name="book_*" class="com.itcast.method.BookAction" method="{1}"></action>
</package>      

注意: book_,里面,相当于update, 最终执行action的方法名称是update的method属性里面写update可以了.

struts2 结果页面配置:

(1).全局结果页面

​ 1.result标签配置的action方法的返回值到不同的路径里面.

​ 2.创建两个action, 执行默认的方法execute方法, 让两个action的方法都返回success, 返回success之后, 配置到同一个页面里面.

public class BookAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        return "success";
    }   
}
public class OrdersAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        return "success";
    }
}

struts.xml配置:

<struts>
    <package name="demp1" extends="struts-default" namespace="/">
        <action name="book" class="com.itcast.action.BookAction">
            <result name="success">/hello.jsp</result>
        </action>
        <action name="orders" class="com.itcast.action.OrdersAction">
            <result name="success">/hello.jsp</result>
        </action>
    </package>
</struts>

注意: 如果有多个action,方法里面返回值相同的,到页面也是相同的,这个时候可以使用全局结果页面配置.

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

注意:在package标签里面配置

(2).局部结果页面

<struts>
    <package name="demp1" extends="struts-default" namespace="/">
        <!-- 全局结果页面配置 -->
        <global-results>
            <result name="success">/hello.jsp</result>
        </global-results>
​
        <!-- 局部结果页面配置 -->
        <action name="book" class="com.itcast.action.BookAction">
            <result name="success">/hello.jsp</result>
        </action>
        <action name="orders" class="com.itcast.action.OrdersAction">
            <result name="success">/hello.jsp</result>
        </action>       
    </package>
</struts>   

注意: 配置全局页面, 也配置局部页面, 结果以局部为准.

(3).result标签 type属性.

​ 1.result标签里面除了name属性之外, 还有一个属性 type属性 (1). type属性: 如何到路径里面(转发还是重定向)

​ 2.type属性值: (1).默认值, 做转发操作, 值是dispatcher (2).做重定向操作, 值是redirect. 上面两个值dispatcher,redirect, 这两个值一般针对页面中配置. 下面的两个值是针对配置到action里面 (3).chain, 转发到action, 一般不用,有缓存问题. (4).redirectAction, 重定向到action

(1)(默认, 转发)
<action name="book" class="com.itcast.action.BookAction">
    <result name="success" type="dispatcher">/hello.jsp</result>
</action>
(2)(重定向)
<action name="book" class="com.itcast.action.BookAction">
    <result name="success" type="redirect">/hello.jsp</result>
</action>
(3)(转发, 一般不用)
<action name="orders" class="com.itcast.action.OrdersAction">
    <result name="success" type="chain">orders.action</result>
</action>
(4)(重定向)
<action name="orders" class="com.itcast.action.OrdersAction">
    <result name="success" type="redirectAction">orders.action</result>
</action>

在action获取表单提交数据.

1.之前在web阶段, 提交表单都是在servlet里面, 在servlet里面使用request对象里面的方法获取getParameter, getParameterMap

2.提交表单到action, 但是action没有request对象,不能直接使用request对象.

3.action中获取表单提交数据主要三种方式:

(1).使用ActionContext类获取

​ Map<String, Object> getParameters() 返回一个包含所有HttpServletRequest参数信 (1).英文方法不是静态的方法, 需要创建actionContent类的对象 (2).这个ActionContext对象不是New出来的 static ActionContext getContext() 获取当前线程的ActionContext对象 演示: (1).创建表单, 提交表单到action里面 (2).在action里面使用ActionContext获取数据.

表单 ==>

<form action="${pageContext.request.contextPath }/form1.action" method="post">
    username:<input type="text" name="username">
    <br/>
    password:<input type="text" name="password">
    <br/>
    address:<input type="text" name="address">
    <br/>
    <input type="submit" value="提交">
        </form>

struts.xml ==>

<!-- 获取表单提交的数据 -->
<package name="dome2" extends="struts-default" namespace="/">
    <action name="form1" class="com.itcast.from.Form1DomeAction"></action>
</package>

action ==>

public class Form1DomeAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        //第一种方式: 使用ActionContext类获取
        //1.获取ActionContext对象
        ActionContext context = ActionContext.getContext();
        //2.调用方法得到表单数据
        //key 是表单输入项name属性值, value是输入的值
        Map<String, Object> map = context.getParameters();
        Set<String> keys = map.keySet();
        for (String key : keys) {
            //根据key得到value, 得到的结果是数组形式的
            //数组形式, 应为输入项里面可能有复选框情况
            Object[] obj = (Object[])map.get(key);
            System.out.println(Arrays.toString(obj));
        }
        return NONE;
    }
}

(2).使用ServletActionContext类

​ 主要使用的方法: static HttpServletRequest getRequest(); 获取Web应用的HttpServletRequest对象. static HttpServletResponse getResponse(); 获取Web应用的HttpServletResponse对象. static ServletContext getServletContext(); 获取Web应用的ServletContext对象. static PageContext hetPageContext(); 获取Web应用的PageContext对象.

(1).调用类里面静态方法, 得到request对象.

表单 ==>

<form action="${pageContext.request.contextPath }/form2.action" method="post">
    username:<input type="text" name="username">
    <br/>
    password:<input type="text" name="password">
    <br/>
    address:<input type="text" name="address">
    <br/>
    <input type="submit" value="提交">
 </form>

struts.xml ==>

<!-- 获取表单提交的数据 -->
<package name="dome2" extends="struts-default" namespace="/">
    <action name="form1" class="com.itcast.from.Form1DomeAction"></action>
    <action name="form2" class="com.itcast.from.Form2DomeAction"></action>
</package>      

action ==>

public class Form2DomeAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        //第一种方式: 使用ServletActionContext类获取
        //1.使用ServletActionContext获取request对象.
        HttpServletRequest request = ServletActionContext.getRequest();
        //2.调用request里面的方法得到结果
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String address = request.getParameter("address");
        System.out.println("username = " + username + " ,password = " + password + " ,address = " + address);
        return NONE;
    }
}

(3).使用接口注入方式.

​ 1.让action实现接口, 为了得到request对象. ServletRequestAware 接口 ServletResponseAware 接口 ServletContextAware 接口 ServletPageContextAware 接口

public class Form3DomeAction extends ActionSupport implements ServletRequestAware{
    private HttpServletRequest request;
    @Override
    public void setServletRequest(HttpServletRequest request) {
        this.request = request;
    }
​
    @Override
    public String execute() throws Exception {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String address = request.getParameter("address");
        System.out.println(username +" ,"+password+" ,"+address);
        return NONE;
    }
}

注意: 其他操作如上

在action里面操作域对象:

​ 1.request session servletContext 域对象

​ 2.使用ServletActionContext类对象

//操作三个域对象
//1.request 域
HttpServletRequest request = ServletActionContext.getRequest();
request.setAttribute("req", "reqValue");
​
//2.session 域
HttpSession session = request.getSession();
session.setAttribute("sess", "sessValue");
​
//3.ServletContext 域
ServletContext context = ServletActionContext.getServletContext();
context.setAttribute("context", "contextValue");

struts2封装获取表单数据方式

使用原始方式获取表单封装到实体类对象

public class Form5DomeAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        //1.获取表单数据
        HttpServletRequest request = ServletActionContext.getRequest();
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        String address = request.getParameter("address");       
        //2.封装到实体类对象里面
        User user = new User();
        user.setUsername(username);
        user.setPassword(password);
        user.setAddress(address);
        System.out.println(user);
        return NONE;
    }
}

注意: 原始方式是最有效的代码;

(1).属性封装

​ 1.直接把表单提交属性封装到action的属性里面

​ 2.实现步骤: (1).在action成员变量位置定义变量 -- 变量名称和调单输入项的name属性值一样 (2).生成变量的set(set和get方法都写出来)

public class DataDome1Action extends ActionSupport {
    //1.定义变量
    //变量的名称和表单输入项name属性值一样
    private String username;
    private String password;
    private String address;
    //2.生成变量的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 getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    @Override
    public String execute() throws Exception {
        System.out.println("username:"+username+",password:"+password+",address:"+address);
        return NONE;
    }
}

注意: 使用属性封装获取表单数据到属性里面, 不能把数据直接封装到实体类对象里面

(2).模型驱动封装(重点)

​ 1.使用模型驱动方式, 可以直接把表单数据封装到实体类对象里面.

​ 2.实现步骤: (1).action实现接口, ModelDriven public class DataDome2Action extends ActionSupport implements ModelDriven<User>{} (2).实现接口里面的方法 getModel方法 public User getModel() {} (3).在action里面创建实体类对象.

public class DataDome2Action extends ActionSupport implements ModelDriven<User>{
    //创建对象
    //前提要求, 表单输入项name属性值和实体类属性名称一样.
    private User user = new User();
    @Override
    public User getModel() {
        //返回创建user对象
        return user;
    }
    @Override
    public String execute() throws Exception {
        System.out.println(user);
        return NONE;
    }
}

​ 3.使用模型驱动和属性封装注意的问题: (1).在一个action中, 获取表单数据可以属性封装, 使用模型驱动封装, 不能同时使用属性封装和模型驱动封装获取同一个表单的数据. -- 如果同时使用, 之后执行模型驱动.

(3).表达式封装(会用)

1.实现过程:

​ (1).使用表达式封装可以把表单数据封装到实体类对象里面 第一步: 在action里面声明实体类 //1.声明实体类 private User user; 第二步: 生成实体类变量的set和get方法 //2.生成实体类变量的set和get方法. 第三步: 在表单输入项的name属性值里面写表达式形式

<form action="${pageContext.request.contextPath }/data3.action" method="post">
    username:<input type="text" name="user.username">
    <br/>
    password:<input type="text" name="user.password">
    <br/>
    address:<input type="text" name="user.address">
    <br/>
    <input type="submit" value="提交">
</form>
2.把表达式封装归类到属性封装里面.

比较表达式封装和模型驱动封装.

​ 1.相同点: 使用表达式封装和模型驱动封装都可以把数据封装到实体类对象里面.

​ 2.不同点: (1).使用模型驱动只能把数据封装到一个实体类对象里面. -- 在一个action里面不能使用模型驱动数据封装到不同的实体类里面 (2).使用表达式封装可以把数据封装到不同的实体类对象里面.

struts2获取数据封装到集合中(会用)

(1).封装到list集合

​ 第一步: 在action声明List //1.声明List变量 private List<User> list; 第二步: 生成list变量的set和get方法 //2.getset方法 第三步: 在表单输入项里面写表达式.

<form action="${pageContext.request.contextPath }/list.action" method="post">
    <!-- list[0]: 表示list集合中的第一个user对象 -->
    username:<input type="text" name="list[0].username">
    <br/>
    password:<input type="text" name="list[0].password">
    <br/>
    address:<input type="text" name="list[0].address">
    <br/>
    <br/>
    username:<input type="text" name="list[1].username">
    <br/>
    password:<input type="text" name="list[1].password">
    <br/>
    address:<input type="text" name="list[1].address">
    <br/>
    <input type="submit" value="提交">
</form>

​ (2).封装到map集合

​ 第一步: 声明map集合 //1.声明一个map集合对象 private Map<String,User> map; 第二步: 生成get和set方法 //2.生成这个map集合对象的get和set方法. 第三步: 在表单输入项的name属性值里面写表达式.

public class MapAction extends ActionSupport{
    //1.声明一个map集合对象
    private Map<String,User> map;
    //2.生成这个map集合对象的get和set方法.
    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;
    }
}

jsp ==>

<form action="${pageContext.request.contextPath }/map.action" method="post">
    <!-- 设置key的值map["key值"] -->
    <!-- 设置value值 -->
    username:<input type="text" name="map['one'].username">
    <br/>
    password:<input type="text" name="map['one'].password">
    <br/>
    address:<input type="text" name="map['one'].address">
    <br/>
    <br/>
    username:<input type="text" name="map['abc'].username">
    <br/>
    password:<input type="text" name="map['abc'].password">
    <br/>
    address:<input type="text" name="map['abc'].address">
    <input type="submit" value="提交">
</form>

注意: Map引入的包为util下的.

OGNL概述:

​ 1.之前在Web阶段学习过EL表达式, EL表达式在jsp中获取域对象里面的值.

​ 2.OGNL是一种表达式, 这个表达式功能更加强大. (1).在struts2里面操作值栈数据 (2).一般把ognl在struts2操作, 和struts2标签一起使用操作值栈.

​ 3.OGNL不是struts2的一部分, 单独的项目, 经常和struts2一起使用. (1).使用ognl时候首先导入jar包, struts2提供jar包.

OGNL的作用:

​ struts2默认的表达式语言就是OGNL,它具有一下特点: -- 支持对象方法调用. 例如:objName methodName(). -- 支持类静态方法调用和值访问, 表达式的格式为@[类全名(包括包路径)]@{方法名|值名} 例如: @java.lang.String@format('foo %s','bar'). -- 支持赋值操作和表达式串联. 例如:price=100,discount=0.8,calcutePrice().在方法中进行乘法计算会返回80 -- 访问OBNL上下文(OGNL.context)和ActionContext. -- 操作集合对象

OGNL入门案例:

​ 1.使用OGNL+struts2标签实现计算字符串长度. (1).在java代码中, 调用字符串length().

​ 2.使用struts2标签 (1).使用jstl时候,导入jar包,在jsp页面中引入标签库. 使用struts2标签的时候,在jsp中引入标签库. <%@ taglib uri="/struts-tags" prefix="s"%> (2).使用struts2标签实现功能.

<!-- 
使用ognl+struts2标签实现计算字符串长度 
value属性值: ognl表达式
-->
<s:property value="'嘻嘻'.length()"/>

什么是值栈:

​ 1.之前在Web阶段, 在servlet里面进行操作, 把数据放到域对象里面,在页面中使用EL表达式获取到, 域对象在一定范文内, 存值和取值.

​ 2.在struts2里面提供了本身一种存储机制, 类似于域对象, 是值栈, 可以存值和取值. (1).在action里面把数据放到值栈里面,在页面中获取值栈数据.

​ 3.servlet和action区别: (1).Servlet: 默认在第一次访问的时候创建, 创建一次, 单实例对象. (2).action: 默认访问的时候创建, 每次访问action时候, 都会创建一个action对象.创建多次.每次访问都是一个新的对象. 多实例对象.

​ 4.值栈存储的位置: (1).每次访问action时候, 都会创建action对象. (2).在每个action对象里面都会有一个值栈对象.(只有一个)

获取值栈对象:

(1).常用的方式:

​ 使用ActionContext类里面的方法的到值栈对象.

public String execute() throws Exception {
    //1.获取ActionContext类的对象
    ActionContext context = ActionContext.getContext();
    //2.调用方法得到值栈对象
    ValueStack stack1 = context.getValueStack();
    ValueStack stack2 = context.getValueStack();
    // 控制台打印 true, 这证明了他本身就是一个值栈对象.
    System.out.println(stack1==stack2);
    return NONE;
}       

(2).每个action对象中只有一个值栈对象.

栈的特点:

​ 向栈里面放元素, 此时里面有个一个元素1, 在放一个元素2, 此时想从里面把元素拿出来, 最先拿出来的是元素2, 然后才是元素1. "先进后出, 后进先出"

值栈内部结构:

1.值栈内部的主要的结构分为两部分:

​ 第一部分: root, 结构是list集合 (常用) root的结构就是一个List集合

​ 第二部分: context, 结构是map集合 context的结构是Map集合.(key,value) context存储的对象的引用 context里面key的值是固定的值 request.session. application. parameters. attr context里面value的值是 request对象引用. HttpSession对象引用. ServletContext对应引用. 传递相关参数. 三个域对象里面放在, 名称都相同 setAttribute("name",value); 使用attr操作, 获取域对象里面的值, 获取域取值范围最小里面的值.

注意: 一般操作root里面的数据, 很少操作context里面的结构.

2.struts2里面标签 s:debug, 使用这个标签可以查看值栈结构和存储值.

(1).访问action, 执行action的方法有返回值, 配置返回值到jsp页面中, 在jsp页面中使用这个标签.

action ==>

public class ValueStackDemoAction extends ActionSupport {
    @Override
    public String execute() throws Exception {
        return "success";
    }
}   

struts.xml ==>

<struts>
    <package name="dome1" extends="struts-default" namespace="/">
        <action name="valueStackDemo1" class="com.itcast.action.ValueStackDemoAction">
            <result name="success">/valueStack.jsp</result>
        </action>
    </package>
</struts>

jsp ==>

<%@ taglib uri="/struts-tags" prefix="s" %>
<!-- 使用struts2标签查看值栈结构 -->
<s:debug></s:debug>

访问 valueStackDemo1.action, 点击页面中debug标签.查看结构

(2).在action没有做任何操作, 栈顶的元素是 com.itcast.action.ValueStackDemoAction

​ -- action对象里面有值栈对象. -- 值栈对象里面有action引用

向值栈放数据

1.向值栈放数据多种方式:

第一种方式: 获取值栈对象, 调用值栈对象里面的set方法.

public String execute() throws Exception {
    //第一种方式,使用值栈对象里面的set方法
    //1.获取值栈对象.
    ActionContext context = ActionContext.getContext();
    ValueStack stack = context.getValueStack();
    //2.调用set方法
    stack.set("username", "itcastitheima");
    return "success";
}

第二种方式: 获取值栈对象, 调用值栈对象里面的push方法

public String execute() throws Exception {
    //第一种方式,使用值栈对象里面的set方法
    //1.获取值栈对象.
    ActionContext context = ActionContext.getContext();
    ValueStack stack = context.getValueStack();
    //2.调用set方法
    stack.set("username", "itcastitheima");
    //3.调用push方法
    stack.push("abcd");
    return "success";
}

第三种方式: 在action定义变量, 生成变量的get方法.(常用)

public class ValueStackDemoAction extends ActionSupport {
    //1.定义变量:
    private String name;
    //2.生成get方法
    public String getName() {
        return name;
    }
    @Override
    public String execute() throws Exception {
​
        //3.在执行的方法里面向变量设置值
        name = "abcdefg";   
        return "success";
    }
}

向值栈放对象

1.实现步骤:

​ 第一步: 定义对象变量 第二步: 生成变量的get方法 第三步: 在执行的方法里面向对象中设置值.

entity ==>

public class User {
    private String username;
    private String password;
    private String address;
    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;
    }
}

action ==>

public class ObjectDemoAction extends ActionSupport {
    //第一步: 定义对象变量
    private User user = new User();
    //第二步: 生成get方法
    public User getUser() {
        return user;
    }
    @Override
    public String execute() throws Exception {
​
        //第三步: 向值栈的user里面放数据.
        user.setUsername("lucy");
        user.setPassword("123");
        user.setAddress("美国");
        return "success";
    }
}

向值栈放list集合

​ 第一步: 定义一个list集合变量 第二步: 生成变量的get方法 第三步: 在执行的方法里面向list集合设置值

public class ListDemoAction extends ActionSupport {
    //第一步: 定义list变量
    private List<User> list = new ArrayList<User>();
    //第二步: 生成get方法
    public List<User> getList() {
        return list;
    }
    @Override
    public String execute() throws Exception {
        //第三步: 向list中设置值
        User user1 = new User();
        user1.setUsername("花湖");
        user1.setPassword("6666");
        user1.setAddress("日本");
​
        User user2 = new User();
        user2.setUsername("小米");
        user2.setPassword("555");
        user2.setAddress("东京");
​
        list.add(user1);
        list.add(user2);    
        return "success";
    }
}

从值栈获取数据

获取字符串:

​ 1.使用struts2的标签+ognl表达式获取值栈数据. (1).<s:property value="ognl表达式">

​ 2.向值栈放字符串

public class ValueStackAction extends ActionSupport {
    private String username;
    public String getUsername() {
        return username;
    }
    @Override
    public String execute() throws Exception {
        username = "itcast";
        return "success";
    }
}

​ 3.在jsp使用struts2标签+ognl表达式获取

<!-- 1.获取字符串的值 -->
<s:property value="username"/>

获取对象

action ==>

public class ValueStackAction extends ActionSupport {
    private User user = new User();
    public User getUser() {
        return user;
    }
    @Override
    public String execute() throws Exception {
        user.setUsername("mary");
        user.setPassword("123");
        user.setAddress("日本");
        return "success";
    }
}

jsp ==>

<!-- 2.获取值栈对象里面的值 -->
<s:property value="user.username"/>
<s:property value="user.password"/>
<s:property value="user.address"/>

获取list集合

第一种方式:

action ==>

public class ValueStackAction extends ActionSupport {
    private List<User> list = new ArrayList<User>();
    public List<User> getList() {
        return list;
    }
    @Override
    public String execute() throws Exception {  
        User user1 = new User();
        user1.setUsername("小米");
        user1.setPassword("666");
        user1.setUsername("上海");
​
        User user2 = new User();
        user2.setUsername("小明");
        user2.setPassword("223");
        user2.setUsername("天津");
​
        list.add(user1);
        list.add(user2);
        return "success";
    }
}

jsp ==>

<!-- 第一种方式 -->
<s:property value="list[0].username"/>
<s:property value="list[0].password"/>
<s:property value="list[0].address"/>
<br/>
<s:property value="list[1].username"/>
<s:property value="list[1].password"/>
<s:property value="list[1].address"/>

第二种方式:

<!-- 第二种方式 -->
<!--
使用struts2标签, 类似与jsEL的forEach标签 
-->
<%-- <s:iterator> --%> <!-- 标签: 变量值栈的list集合 -->
<s:iterator value="list">
    <!-- 遍历list得到list里面每个user对象 -->
    <s:property value="username"/>
    <s:property value="password"/>
    <s:property value="address"/>
</s:iterator>

注意: 使用html注释s:property标签会有错误, 应使用<%-- -->注释

第三种方式:

<!-- 第三种方式 -->
<s:iterator value="list" var="user">
    <!--
遍历值栈list集合, 得到每个user对象
机制: 把每次遍历出来的user对象放到context里面
获取context里面数据特点, 写ognl表达式
使用特殊符号#
-->
    <s:property value="#user.username"/>
    <s:property value="#user.password"/>
    <s:property value="#user.address"/>
</s:iterator>

其他操作

1.使用set方法向值栈中放数据,获取

action ==>

public class ValueStackDemoAction extends ActionSupport {
    //1.定义变量:
    private String name;
    //2.生成get方法
    public String getName() {
        return name;
    }
    @Override
    public String execute() throws Exception {
​
        //3.在执行的方法里面向变量设置值
        name = "abcdefg";   
​
        //第一种方式,使用值栈对象里面的set方法
        //1.获取值栈对象.
        ActionContext context = ActionContext.getContext();
        ValueStack stack = context.getValueStack();
        //2.调用set方法
        stack.set("itcast", "itcastitheima");
​
        //3.调用push方法
        stack.push("abcd");
​
        return "success";
    }
}

jsp ==>

<!-- 获取set方法设置的值, 根据名称获取值 -->
<s:property value="itcast"/>

2.使用push方法向值栈中放数据,获取

​ //3.调用push方法 stack.push("abcd"); (1).使用push方法设置值, 没有名称, 只有设置的值. (2).向值栈中放数据, 把向值栈中放数据存到数组里面. 数组名称top, 根据数组获取值.

<!-- 获取push方法设置的值 -->
<s:property value="[0].top"/>   

3.forEach循环变量, 获取值栈数据

<!-- 使用foreach标签+EL表达式获取值栈list集合数据 -->
<c:forEach items="${list }" var="user">
    ${user.username }
    ${user.password }
    ${user.address }
</c:forEach>    

EL表达式获取值栈数据:

​ 1.EL表达式获取域对象值

​ 2.向域对象里面放值使用setAttribute方法, 获取值使用getAttribute方法.

​ 3.底层增强request对象里面的方法getAttribute方法. (1).首先从request域获取值, 如果获取到, 直接返回. (2).如果从request域获取不到值, 到值栈中把值获取出来, 把值放到与对象里面

​ 4.查看源代码:

class StrutsRequestWrapper extends HttpServletRequestWrapper{}
public Object getAttribute(String key){}

OGNL的#,%使用

#使用:

1.使用#获取context里面数据

<s:iterator value="list" var="user">
    <!--
遍历值栈list集合, 得到每个user对象
机制: 把每次遍历出来的user对象放到context里面
获取context里面数据特点, 写ognl表达式
使用特殊符号#
-->
    <s:property value="#user.username"/>
    <s:property value="#user.password"/>
    <s:property value="#user.address"/>
</s:iterator>

2.演示# 操作:

​ (1).向request域放值 (2).在页面中使用ognl获取.

<!--
获取context里面数据, 写ognl时候, 首先添加fu'hao 
#context的key名称
-->
<s:property value="#request.req"/>

%的使用:

​ 1.struts2的表单标签 (1).%使用struts2标签里面使用ognl表达式, 如果直接在struts2表单标签里面使用ognl表达式不识别, 只有%之后才会识别

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

拦截器概述:

​ 1.struts2是框架, 封装了很多的功能, struts2里面封装的功能都是在拦截器里面.

​ 2.struts2里面封装了很多的功能, 有很多的拦截器, 不是每次这个拦截器都执行, 每次执行默认的拦截器. 每次只执行一部分拦截器, 执行一部分功能

​ 3.struts2里面默认拦截器位置.

​ 4.拦截器在什么时候执行? (1).在action对象创建之后, action的方法执行之前. 执行

拦截器底层原理:

1.拦截器的底层使用两个原理:

第一个: aop思想

​ (0).后面spring里面把aop做更深乘次分析. (1).文字描述. Aop是面向切面(方面)编程, 有一个最基本功能, 拓展功能, 不通过修改源代码方法扩展功能. (2).画图分析: aop思想: 输入用户名和密码(表单) =提交表单=> action, 获取用户名和密码 =判断用户名和密码是否正确=> 正确(登录成功):到主页面[增加权限判断, 不用修改源代码, 添加权限判断] || 错误(登录失败):回到表单重写输入 扩展: 登录成功之后, 做用户权限判断, 比如 普通用户, 管理员和超级管理员.

第二个: 责任链模式

​ (1).在java中有很多的设计模式, 责任链模式就是其中的一种 (2).责任链模式和过滤链模式很相似 过滤链: 一个请求可以有多个过滤器进行过滤, 每个过滤器只有做放行才能到下一个过滤器. 责任链模式: 要一次性执行多个操作, 有添加, 修改, 删除三个操作. 首先执行添加操作, 添加操作之后做类似于放行操作, 执行修改操作, 修改操作执行之后做类似与放行操作, 执行删除操作.

2.aop思想和责任链模式如何应用到拦截器里面?

​ (1).文字描述 拦截器在action对象创建之后, action的方法执行之前, 执行 在actiobn执行之前默认拦截器, 执行过程使用aop思想. 在action没有直接调用拦截器的方法, 使用配置文件 进行操作. 在执行拦截器时候, 执行很多的拦截器, 这个过程使用责任链模式. -- 假如执行三个拦截器: 执行拦截器1, 执行拦截器1之后做放行操作, 执行拦截器2, 执行拦截器2之后做放行操作, 执行拦截器3. 执行拦截器3之后执行放行操作, 执行action里面的方法

​ (2).查看源代码: 1.执行action execute.executeAction(request,response,mapping); 2.创建action对象, 使用动态道理方式. ActionProxy proxy = getContext().getInstance(ActionProxyFactory.class).createActionProxy(namepace,name,method.extraContext,true,false); 3.执行action方法 proxy.execute(); 4.执行很多的拦截器, 遍历执行 if(interceptors.hasNext()){} 类似于放行的操作的方法: return invocation.invoke();

重要的概念:

​ 1.过滤器和拦截器的区别: (1).过滤器: 过滤器理论上可以过滤任意的内容, 比如:html,jsp,servlet,图片路径. (2).拦截器: 拦截器只可以拦截内容action

​ 2.Servlet和action的区别: (1).servlet默认是第一次访问的时候创建, 创建一次, 单实例对象. (2).action每次访问的时候创建, 创建多次, 多实例对象.

自定义拦截器:

​ 1.在struts2里面有很多的拦截器, 这些拦截器都是struts2封装的功能, 但是在实际开发中, struts2里面的拦截器可能没有要使用的功能吗这个时候需要自己写拦截器实现功能.

2.拦截器结构: (1).查看源代码,看拦截器结构 -- 继承类: public class ModelDrivenInterceptor extends AbstractInterceptor {} public abstract class AbstractInterceptor implements Interceptor {} 在接口里面有三个方法: void init(); -- 初始化方法 void destroy(); --销毁方法 String intercept(ActionInvocation invocation) throws Exception; -- 拦截逻辑操作 public interface Interceptor extends Serializable {}

​ (2).开发中, 建议使用另一个方法: -- 写类, 继承 MethodFilterIntereptor类实现 -- 让action里面否个方法不进行拦截.

​ (3).让拦截器和action有关系: -- 不是在action调用拦截器的方法,而是通过配置文件让建立关系.

自定义登录拦截器:

​ 1.需求: 在项目中, 有很多的action的超链接, 实现只有是登录的状态, 才可以点击action的超链接实现功能, 如果不是登录状态, 点击action超链接返回到登录页面.

​ 2.登录的状态: 使用session域对象实现. (1).登录成功之后,把数据放到session里面 (2).判断session是否有值, 可以知道是否是登录状态

​ 3.实现登录的基本功能: (1)查询数据库判断用户名和密码.

struts2的标签库:

​ 0.struts2标签使用jsp页面中 1.s:property: 和agnl表达式在jsp页面中获取值栈数据 3.s:iterator: 获取值栈list集合数据, 表示list集合 4.s:debug: 查看值栈结构和控制.

1.struts2的表单标签:

​ (1).form:action method (2).输入项: -- 大部分在input里面封装type=值 -- text: 普通输入项 -- password: 密码输入项 -- radio: 单选输入项 -- checkbox: 复选输入项 -- file: 文件上传项 -- hidden: 隐藏项 -- button: 普通按钮 -- submit: 提交按钮 -- image: 图片提交 -- resst: 重置 -- select: 下拉输入项 -- textrea: 文本域

2.在struts2里面对应html表单标签大部分都有:

<!-- from标签 -->
<!-- theme="simple" 所有的标签全部都在一行 -->
<s:form theme="simple">
    <!-- 1.普通输入项, label在输入项前面的文本 -->
    <s:textfield name="username" label="username"></s:textfield>
​
    <!-- 2.密码输入项 -->
    <s:password name="password" label="password"></s:password>
​
    <!-- 3.单选输入项 -->
    <!-- value属性值和显示值一样的 -->
    <s:radio list="{'女','男'}" name="sex" label="性别"></s:radio>
    <!-- value属性值和显示值不一样 -->
    <s:radio list="#{'nv':'女','nan':'男'}" name="sex1" label="性别"></s:radio>
​
    <!-- 4.复选输入项 -->
    <s:checkboxlist list="{'看书','游泳','打篮球','吃饭'}" name="love" label="爱好"></s:checkboxlist>
    <s:checkboxlist list="#{'shu':'看书','yong':'游泳','qiu':'打篮球','fan':'吃饭'}" name="love1" label="爱好"></s:checkboxlist>
​
    <!-- 5.下拉输入框 -->
    <s:select list="{'小学','中学','大学'}" name="college" label="学历"></s:select>
    <s:select list="#{'xiao':'小学','zhong':'中学','da':'大学'}" name="college1" label="学历"></s:select>
​
    <!-- 6.文件上传项 -->
    <s:file name="file" label="上传文件"></s:file>
​
    <!-- 7.隐藏项 -->
    <s:hidden name="hid" value="abcd"></s:hidden>
​
    <!-- 8.提交按钮 -->
    <s:submit value="提交"></s:submit>
​
    <!-- 9.重置按钮 -->
    <s:reset value="重置"></s:reset>
​
    <!-- 10.文本域 -->
    <s:textarea rows="3" cols="10" name="resume" label="简历"></s:textarea>
</s:form>       

公交车司机终于在众人的指责中将座位让给了老太太