struts2学习(二)

主要内容

struts2值栈
struts2拦截器


struts2值栈

ognl概述

  1. EL表达式在jsp中获取域对象里面的值
  2. OGNL也是一种表达式,这个表达式功能更加强大
    (1)在struts2里面操作值栈数据
    (2)一般把ognl在struts2操作:和struts2标签一起使用操作值栈
  3. OGNL不是struts2的一部分,单独的项目,经常和struts2一起使用
    (1)使用ognl时候首先导入jar包,struts2提供jar包

OGNL入门案例

  1. 使用ognl+struts2标签实现计算字符串长度
    支持对象方法调用,比如objName.methodName()
    在Java代码中,调用字符串length()

  2. 使用struts2标签

(1)使用jstl时候,导入jar包之外,在jsp页面中引入标签库使用struts2标签时候,在jsp中引入标签库

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

(2)使用struts2标签实现操作

1
<!-- 使用ognl加struts2标签实现计算字符串长度 --> <s:property value="'asdasd'.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. 获取值栈对象有多种方式
    (1)常用方式:使用ActionContext类里面的方法得到值栈对象
    1
    2
    3
    4
    5
    6
    7
    public String execute() throws Exception {
    //获取ActionContext类对象
    ActionContext context =ActionContext.getContext();
    //调用方法得到值栈
    ValueStack stack1 = context.getValueStack();
    return NONE;
    }

值栈内部结构

  1. 值栈分为两部分:

    第一部分 root,结构是list集合

    • 一般操作都是root里面数据

      第二部分 context,结构map集合

具体看下图


  1. struts2里面标签 s:debug,使用这个标签可以查看值栈结构和存储值
    (1)访问action,执行action的方法有返回值,配置返回值到jsp页面中,在jsp页面中使用这个标签
1
2
<!--struts2标签查看值栈结构-->
<s:debug></s:debug>

就会多一个debug按钮来查看信息

action对象里面有值栈对象
值栈对象里面有action引用


向值栈放数据

向值栈放数据多种方式

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

1
2
3
4
5
6
7
8
public String execute() throws Exception {
//第一种方法 获取值栈对象里面的set方法
//获取值栈对象
ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
//调用方法set方法
stack.set("username","shelhon");
return "ok";

debug页面就会多一个入栈 java.util.HashMap

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

1
2
//调用方法push方法
stack.push("abdc");

又多一个入栈 :java.lang.String

第三种 在action定义变量,生成变量的get方法

1
2
3
4
5
6
7
8
9
private String name;
public String getName() {
return name;
}
@Override public String execute() throws Exception {
//在执行方法里面向变量来赋值
name ="asdasd";
return "ok";
}

这种方法直接在原来的值栈上面写入数据,不需要生成新的值栈来存储,可以节省空间


向值栈放对象

  1. 实现步骤

第一步 定义对象变量

1
2
//1定义变量
private User user = new User();

第二步 生成变量的get方法

1
2
3
public User getUser() {
return user;
}

第三步 在执行的方法里面向对象中设置值

1
2
3
4
5
6
7
public String execute() throws Exception {
//3 向值栈的user里面放数据
user.setUsername("luck");
user.setPassword("123");
user.setAddress("gz");
return "ok";
}

向值栈放list集合

第一步 定义list集合变量

1
private List<User> list = new ArrayList<User>();

第二步 生成变量的get方法

1
2
3
public List<User> getList() {
return list;
}

第三步 在执行的方法里面向list集合设置值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public String execute() throws Exception {
User user1= new User();
user1.setUsername("ben");
user1.setAddress("gz");
user1.setPassword("111");

User user2 =new User();
user2.setUsername("jack");
user2.setPassword("009");
user2.setAddress("cd");

list.add(user1);
list.add(user2);
return "ok";
}


从值栈获取数据

使用struts2的标签+ognl表达式获取值栈数据

获取字符串

  1. 向值栈放字符串
1
2
3
4
5
6
7
8
9
10
11
12
13
public class ValueStackAction extends ActionSupport {
//定义变量
private String username;
public String getUsername(){
return username;
}
@Override
public String execute() throws Exception {
//给变量赋值
username="shelhon";
return "ok";
}
}
  1. 在jsp使用struts2标签+ognl表达式获取
1
<s:property value="username"/>

获取对象

  1. 向值栈放对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public void setUser(User user) {
this.user = user;
}

private User user =new User();
public User getUser() {
return user;
}

public String execute() throws Exception {
user.setUsername("asd");
user.setPassword("222");
user.setAddress("gz");

return "ok";
  1. 在页面中获取值
    1
    2
    3
    <s:property value="user.username"/>
    <s:property value="user.password"/>
    <s:property value="user.address"/>

获取list集合

三种方法
一开始先把list放到值栈去

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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("qsx");
user1.setAddress("gz");
user1.setPassword("111");
User user2 =new User();
user2.setUsername("jack");
user2.setPassword("009");
user2.setAddress("cd");
list.add(user1);
list.add(user2);

return "ok";

第一种

1
2
3
4
5
6
7
<!-- 第一种方式 --> 
<s:property value="list[0].username"/>
<s:property value="list[0].possword"/>
<s:property value="list[0].address"/>
<s:property value="list[1].username"/>
<s:property value="list[1].possword"/>
<s:property value="list[1].address"/>

第二种

1
2
3
4
5
6
7
<!-- 使用struts2标签,类似jst1的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>

第三种

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

其他操作

先获取set方法设置的值

  1. 使用set方法向值栈放数据,获取
    1
    2
    ValueStack stack = context.getValueStack();
    stack.set("shelhon","shelhon.cn");
1
<s:property value="shelhon"/>
  1. 使用push方法向值栈放数据,获取
1
stack.push("asdb");

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

1
<s:property value="[0].top"/>

  1. EL表达式获取值栈数据
    首先要先导入两个jar包,分别是jstl.jar和standard.jar
    切记用idea的maven时,需要把这个jar包导入到tomcat里面去,具体看另一篇笔记,配置依赖的问题。

在jsp上面补个标签

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

1
2
3
4
<c:forEach items="${list }" var="user">
${user.username }
${user.password }
${user.address } </c:forEach>
  • EL表达式获取域对象值
  • 向域对象里面放值使用setAttribute方法,获取值使用getAttribute方法
  • 底层增强request对象里面的方法getAttribute方法
    (1) 首先从request域获取值,如果获取到,直接返回
    (2)如果从request域获取不到值,到值栈中把值获取出来,把值放到域对象里面

  • 源码:
    public class StrutsRequestWrapper extends HttpServletRequestWrapper
    public Object getAttribute(String key)

不建议这么做,性能很低

OGNL的#、%使用

关于 # 号的使用

使用#获取context里面数据

1
2
3
<s:property value="#user.username"/>
<s:property value="#user.username"/>
<s:property value="#user.username"/>

关于 % 的使用

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

错误示范,识别不了

1
<s:textfield name="username" value="#request.req"></s:textfield>

正确的应该是

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

就是一个 %{} 里面写入ognl表达式


Struts2拦截器概述

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

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

  3. struts2里面默认拦截器位置
    在struts2-core-2.3.24.jar里面有个叫struts-default.xml的文件
    最下面的内容是默认的拦截器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <interceptor-stack name="defaultStack">
    <interceptor-ref name="exception"/>
    <interceptor-ref name="alias"/>
    <interceptor-ref name="servletConfig"/>
    <interceptor-ref name="i18n"/>
    <interceptor-ref name="prepare"/>
    <interceptor-ref name="chain"/>
    <interceptor-ref name="scopedModelDriven"/>
    <interceptor-ref name="modelDriven"/>
    <interceptor-ref name="fileUpload"/>
    <interceptor-ref name="checkbox"/>
    <interceptor-ref name="datetime"/>
    <interceptor-ref name="multiselect"/>
    <interceptor-ref name="staticParams"/>
    <interceptor-ref name="actionMappingParams"/>
    <interceptor-ref name="params"/>
    <interceptor-ref name="conversionError"/>
    <interceptor-ref name="validation">
    <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="workflow">
    <param name="excludeMethods">input,back,cancel,browse</param>
    </interceptor-ref>
    <interceptor-ref name="debugging"/>
    <interceptor-ref name="deprecation"/>
    </interceptor-stack>
  4. 拦截器在什么时候执行?
    在action对象创建之后,action的方法执行之前


拦截器底层原理

  1. 拦截器底层使用两个原理
    第一个: aop思想
    文字描述:
    Aop是面向切面(方面)编程,有基本功能,扩展功能,不通过修改源代码方式扩展功能

看图理解

第二个 :责任链模式
(1)在java中有很多的设计模式,责任链模式是其中的一种
(2)责任链模式和过滤链很相似的
责任链模式:
要执行多个操作,有添加、修改、删除三个操作。
首先执行添加操作,添加操作执行之后 做类似于放行操作,执行修改操作,修改操作执行之后做类似于放行操作,执行删除操作

过滤链:一个请求可有多个过滤器进行过滤,每个过滤器只有做放行才能到下一个过滤器

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

1)文字描述:

  • 拦截器在action对象创建之后,action的方法执行之前执行

  • 在action方法执行之前执行默认拦截器,执行过程使用aop思想,在action没有直接调用拦截器的方法,使用配置文件方式进行操作

  • 在执行拦截器时候,执行很多的拦截器,这个过程使用责任链模式

  • 假如执行三个拦截器,执行拦截器1,执行拦截器1之后做放行操作,执行拦截器2,执行拦截器2之后做放行,执行拦截器3,执行拦截器3之后放行,执行action的方法

看图分析

重要的概念

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

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

自定义拦截器

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

  2. 拦截器结构

(1)从源码查看拦截器结构

  • 继承类
    1
    class ModelDrivenInterceptor extends AbstractIntercetor
1
class AbstractInterceptor implements Interceptor

在接口里有三个方法
初始化:

1
void init();

销毁:

1
void destroy();

拦截逻辑操作:

1
String intercept(ActionInvocation invocation)

(2)开发中,建议使用另外一种方式

  • 写类,继承 MethodFilterInterceptor类实现

  • 让action里面某个的方法不进行拦截

(3)让拦截器和action有关系

  • 不是在action调用拦截器的方法,而是通过配置文件方式让建立关系

自定义登录拦截器

  1. 需求:在项目中,有很多的action的超链接,实现只有是登录的状态,才可以点击action的超链接实现功能,如果不是登录状态,点击action超链接返回到登录页面
  1. 登录的状态:使用session域对象实现
    (1)登录成功之后,把数据放到session里面
    (2)判断session是否有值,可以知道是否是登录状态

  2. 实现登录的基本功能
    查询数据库判断用户名和密码(另外实现)

  1. 添加登录拦截器功能

(1)判断是否登录:判断session里面是否有名称是username的值

(2)拦截器实现过程

第一步 创建类,继承MethodFilterInterceptor类

第二步 重写MethodFilterInterceptor类里面的方法写拦截器逻辑

第三步 配置action和拦截器关系(注册拦截器)

(1)在要拦截的action标签所在的package标签里面声明拦截器

(2)在具体的action标签里面使用声明的拦截器

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

  1. 配置拦截器,对action里面所有的方法都进行拦截
    (1)在action里面有login的登录的方法,这个方法不需要拦截,如果这个方法都拦截,问题是,永远登录不进去了
    (2)解决:让login方法不进行拦截
  • 直接通过配置方式让action里面某些方法不进行拦截

Struts2的标签库

struts2标签只能使用jsp页面中

  1. s:property: 和ognl表达式在jsp页面中获取值栈数据

  2. s:iterator: 获取值栈list集合数据,表示list集合

  3. s:debug: 查看值栈结构和数据

Struts2表单标签(会用)

1 html表单标签

(1)form : action、method、enctype

(2)输入项

  • 大部分在input里面封装 type=”值”

  • text:普通输入项

  • password:密码输入项

  • radio:单选输入项

  • checkbox:复选输入项

  • file:文件上传项

  • hidden:隐藏项

  • button:普通按钮

  • submit:提交按钮

  • image:图片提交

  • reset:重置

  • select:下拉输入项

  • textarea:文本域

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<s:form>
<s:textfield name="username" label="username"> </s:textfield>
<s:password name="password" label="mima"> </s:password>
// 值和名称一样
<s:radio list="{'nv','nan'}" name="sex" label="xingbie"></s:radio>
//值和名称不一样
<s:radio list="#{'nv':'女','nan':'男'}" name="sex" label="xingbie"></s:radio>
<s:checkboxlist list="{'1','2','3','4'}" name="fav" label="随便挑"></s:checkboxlist>
<s:select list="{'a','b','c','d'}" name="abcd" label="abcd"></s:select>

<s:textarea rows="3" cols="10" value="jianli" label="jianli"> </s:textarea>
<s:file name="file" label="dakai"> </s:file>
<s:hidden name="hid" value="asdb"> </s:hidden>
<s:submit name="sub" value="tijiao"> </s:submit>
<s:reset value="chongzhi"> </s:reset>
</s:form>
Just for fun!
------------- 文章已经到尾 -------------