Struts2框架入门

Struts2框架入门

前言: 因最近工作项目的需要,所以去学习了struts2框架,本文记录struts2框架学习的过程以及出现的问题,希望可以大家提供帮助.

1 Struts2入门知识

1 Struts2概述

struts2框架是应用JAVAEE的MVC三层架构.

WEB层常用框架:

  • Struts2
  • SpringMVC

2 Struts2框架入门

1 导入jar包
在这里插入图片描述
2 创建action
在这里插入图片描述
3 配置action类访问路径

  • 创建struts2核心配置文件 (名称和位置固定必须在src下面名称struts.xml)
  • 引入dtd约束
    在这里插入图片描述
    在这里插入图片描述
    访问路径: http:127.0.0.1:8080/struts2_day01/hello.action
    (struts2_day01为自己设置项目访问路径)

页面报错: 404
原因: 没有配置过滤器. 配置过滤器可以成功访问.
在这里插入图片描述

3 Struts2访问流程

  • 1 地址栏访问 http://127.0.0.1:8080/struts2_test1/hello.action
  • 2 过滤器进行过滤,获取请求路径,得到路径里面hello值.
  • 3 到src下面找到struts.xml,使用dom4j解析得到xml文件中内容,拿着hello值到xml文件找action标签,匹配name属性值是一样.
  • 4 匹配name属性值一样,都是hello,找到name属性所在的action标签里面,另外一个属性class值,得到action全路径,使用反射实现功能.

Class clazz = Class.forName(“action全路径”);
Method m = clazz.getMethod("execute);
得到名称是execute的方法
方法执行,有返回值.
Object obj = m.invoke();

  • 5 得到action方法的返回值,在struts.xml文件中,找到action标签里面,有result标签,匹配标签的name属性,判断是否一样,一样,跳转到配置页面中.

4 Struts2过滤器源代码查看

1 StrutsPrepareAndExecuteFilter 实现Filter
init方法中主要加载配置文件,包括自己创建的配置文件和struts2自带配置文件(struts-default.xml 等) struts.xml和web.xml .
在这里插入图片描述

5 Struts2核心配置文件Struts.xml分析

1 名称和位置固定的

位置: src目录下
名称: struts.xml

2 标签

1 package

作用: 类似代码包,区别不同的action.

标签属性:

  • name: 属性值和功能没有关系,属性值不能相同.
  • extends: 固定为struts-default,写了之后,在package里面配置的类具有action功能.
  • namespace: 属性值和action标签里面的name构成访问路径 一般为/ ,不写默认为/.
2 action

作用: 配置action访问路径.

标签属性:

  • name: package标签的namespace属性值和name构成访问路径,package中可以写多个action,但是action的name不能相同.
  • class: action全路径.
  • method: action中默认执行execute方法,使用method,可以执行指定的方法,如add,update等.
3 result

作用: 根据action方法的返回值,配置到不同的路径里面.
标签属性:

  • name: 等于action的方法的返回值(字符串)
  • type: 如何到路径中去(转发或者重定向) 默认做转发操作
4 常量配置
  • 1: 在struts.xml中定义<constant name="Xxx" value="Xxx"></constant> (如, 设置struts.il8n.encoding为UTF-8)
  • 2: 在src下创建struts.properties,此文件是框架的默认配置文件
  • 3: 在web.xml中进行配置

3 Action的三种编写方式

1 创建普通类,不继承任何类,不实现任何接口.
2 创建类,实现接口Action 重写execute方法,还提供了常量可以使用.
3 创建类,继承ActionSupport ,这个类也实现了Action接口.

4 访问action的常用方法

1 使用action标签的method属性

Action类中每一个方法对应,struts.xml中一个action.

2 使用通配符方式实现(重点)

<action name="book_*" class="..." method="{1}">
ps:

book_add 可以访问 method=add 所以method用{1} 等于 *号

book_update 可以访问 method=update 所以method用{1} 等于 *号

3 动态访问实现 (少用)

1: struts2默认是关闭的,需要开启一个常量
<constant name="struts.enable.DynamicMethod Invocation" value="true"></constant>
2: 动态方法访问的配置:
<action name="userAction" class = "类全名"></action>
3: 页面路径访问:
<a href="${pageContext.request.contextPath}/userAction!save.action"> 添加用户</a>

5 其他问题

1 在action获取表单通过post方式提交.中文乱码问题框架帮忙解决了,不需要自己处理.
2 分模块开发

1 单独写每一个配置文件,
2 把每一个配置文件引入核心配置文件struts.xml中<include file="文件全路径"/>

注意: 导入多个文件报错时, 首先去检查package的name是否有相同的,因为最终引入struts2中,所以不能有相同的.

3 常见错误演示
  • 1: 404 No Result defined for action …
    原因: 在action中没设置返回值.
  • 2: 在action里面的方法有返回值,如果有返回值时候类型必须是String类型.
  • 3: action里面的方法可以没有返回值,没有返回值时候,在result标签不需要配置
    • 把方法上写void
    • 让返回值,返回"none"

2 Struts2数据操作

1 结果页面配置

全局结果页面: 在package里面,如果返回结果一样,可以统一处理.
<global-results><result name="success" >/index.jsp</result></global-results>

局部结果页面: 如果全局和局部都存在,以局部为准
<result name="success" >/index2.jsp</result>

result标签type属性:

  • 1: 默认值,做转发操作,值是dispatcher
  • 2: 做重定向操作,值是redirect
    • 配置到其他的action里面: 直接访问action名称
  • 3: chain:转发到action,一般不用,缓存问题
  • 4: redirectAction: 重定向到action

2 action获取表单提交数据

1 之前web阶段,表单提交到servlet里面,使用getParameter, getParameterMap.

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

3 action获取表单提交数据的三种方式.

1 使用ActionContext类

说明: 因为方法不是静态方法,需要创建 ,不是new出来的,使用静态方法 ActionContext.getContext获取当前线程的ActionContext(使用getParameters()得到map 根据key得到value,value为数组(因为存在复选框的情况))

2 使用ServletActionContext类

调用类里面静态方法,得到request对象ServletActionContext.getRequest()得到request,request.getParameter(“Xxx”)得到值.

3 使用接口注入方式(很少)

说明:让action实现接口 ServletRequestAware,重写方法得到request,首先定义request,在方法中赋值request.

3 Struts2提供获取表单数据方式

1 属性封装

说明: 直接把表单提交的属性封装到action的属性(成员变量)里面,不能封装到实体类中.

1 action成员变量和表单字段一样
2 生成变量的set和get方法

2 模型驱动封装

说明: 可以直接把表达封装到实体类对象里面(实体类以User为例).

1 action实现接口ModelDrivern<实体类>
2 实现接口里面的方法,getModel方法,把创建对象返回 return user
3 在action里面创建实体类对象 User user = new user()

要求:实体类属性和表单属性名相同

模型驱动和属性封装注意问题: 不能同时使用两者获得同一个表单.同时使用,只会执行模型驱动.

3 表达式封装(会用)

  • 1 在action中声明实体类 private User user
  • 2 生成实体类变量的set和get方法 setUser()/getUser()
  • 3 在表单输入项的name属性值里面写表达式形式 user.username/user.password

比较表达式封装和模型封装:
相同点: 都可以把数据封装到实体类.
不同点: 模型封装只能封装一个实体类,表达式封装可以封装多个实体类.

4 Struts2获取数据封装到集合中

1 封装到list集合

1: 在action声明List变量 List<User> list
2: 生成set和get方法
3: 表达式传入参数 list[0].name list[0].password

2 封装到map集合

1: 声明map集合 Map<String,User> map
2: 生成get和set方法.
3: 表达式传入参数 map['one'].username map['one'].password

3 Struts2值栈

1 引入OGNL

1 OGNL概述

ognl: 表达式,功能更加强大.

  • 在struts2里面操作值栈数据
  • 一般把ognl在struts2操作,和struts2标签一起使用操作值栈

说明: OGNL不是struts2的一部分,单独的项目,经常和struts2一起使用.(使用ognl首先需要导入jar包,struts2提供jar包)

2 OGNL入门案列

支持对象方法调用:

Q:

  • 使用ognl+struts2标签计算字符串长度

A:

  • 1 使用struts2标签,引入标签库<%@ tablib uri="/struts-tags" prefix="s" %>
  • 2 <s:property value="'haha'.length()" /> 得到字符串长度

2 值栈

1 什么是值栈

1. 引入: 在web阶段,在servlet里面进行操作,把数据放到域对象里面,在页面中使用el表达式获取到,域对象在一定范围内,存值和取值.

2. 值栈: Struts2 里面提供本身一种存取机制,类似于域对象.

3. Servlet和Action区别:

  • Servlet:默认在第一次访问时候创建,只创建一次.
  • Action:访问时候创建,每次访问action时候,都会创建action对象,创建多次,多实例对象.

4. 值栈存储位置:

  • 每次访问action时候,都会创建action对象
  • 在每个action对象里面都会有一个值栈对象

5. 获取值栈对象:
使用类ActionContext类里面的方法得到值栈对象ValueStack value = ActionContext.getContext().getValueStack() (每个action中只有一个值栈)

6. 栈数据结构:
特点: 先进后出 (最上面元素称为栈顶元素)

组成: root 和 context

  • root: 结构是List集合,其中CompoundRoot 继承ArrayList.
  • context: 结构Map集合,其中OgnlContext 实现Map接口.

context内容:

key (固定)value
requestrequest对象引用
sessionHttpSession对象引用
applicationServletContext对象引用
parameters传递相关的参数
attr三个域对象值

注意: attr中属性名称相同,使用attr操作,获取域对象里面的值,是获取域对象最小的值(如上面域同时存在相同值,使用attr操作,从request域中获取)

s:dubug: 可以查看栈值结构和存储值,只能由于调试(在页面直接写该标签)

  • 在action没有做任何操作,栈顶元素就是action对象
  • 值栈对象里面有action引用

2 向值栈存入数据

方法一:

  • 1 先获取值栈对象
  • 2 调用值栈对象里面的set方法 stack.set("key","value")

方法二:

  • 1 先获取值栈对象
  • 2 调用值栈对象里面的push方法stack.push("value")

方法三: (使用较多)

  • 1 先定义变量,生成变量get方法
  • 2 在执行方法里面向变量设置值
  • 3 优点: 在action对象里面创建,减少内存浪费.

向值栈放对象: 存在action对象里面,不会浪费空间

  • 1 定义对象变量
  • 2 生成变量get方法
  • 3 在执行方法里面设置值

向值栈放list对象:

  • 1 定义list集合变量
  • 2 生成变量的get方法
  • 3 在执行的方法里面设置值

3 向值栈获取数据

获取数据: 使用struts2标签+ognl表达式获取值栈
<s:property value="Xxx" />

1 获取字符串: 如 <s:property value="username" />

2 获取获取对象属性: 如 <s:property value="user.username" /> (先使用action的get方法得到对象,再用对象中get方法得到值)

3 获取list集合:

  • 方法1: 写固定了,不方便修改

<s:property value=“list[0]” /> 得到对象
<s:property value=“list[0].username” /> 得到属性

  • 方法2: struts2标签<s:iterator> 类似jstl中foreach标签
	<s:iterator value ="list">
	<!--遍历得到每一个user对象-->
	<s:property value="user" /> 
	</s:iterator>
  • 方法3: <s:iterator value ="list" var="user">
    1 遍历得到每一个user对象, 优化机制,每次遍历出来的user对象会放到context里面(提高取值效率).
    2 临时存放,map -> var值 user对象 (context数据特点Map)
<s:iterator value ="list" var="user">
<-- 写ognl表达式 使用特殊符号#  -->
<s:property value="#user.username" /> 
</s:iterator>

4 其他操作:

  • 1 使用set方法设置的 ,获取值<s:property value="username" />
  • 2 使用push方法,获取值,(向值栈中存的数据,会放到数组中,数组名为top), <s:property value="[0].top" /> ,取到数组中第一个值,即为栈顶值.

4 常见问题

1: html注释和jstl注释不一样,html注释不能注释jsp中标签.

  • html注释<--! Xxx -->
  • jsp注释<%-- Xxx --%>

2: EL表达式获取值栈数据(为什么?): (性能低)

  • 1 EL表达式获取域对象值
  • 2 向与对象里面放值使用setAttribute方法,获取值使用getAttribute方法
  • 3 底层增强request对象里面的方法getAttribute方法
    • 1 首先从request域获取值,如果获取值,直接返回
    • 2 如果从request域获取不到值,到值栈中把值获取出来,把值放到域对象里面
  • 4 查看源代码 WrapRequest 增强 (增强: 继承或动态代理)

3: OGNL中# 和% 的使用:

  • 1 使用#获取context里面参数 request.setAttribute("req","");
<!-- context的key名称.域对象 -->
<s:property value="#.request.req" /> 
  • 2 %使用在struts2标签中表单标签
<!-- 在struts2标签里面直接使用ognl表达式,不能识别,需要使用% -->
<s:textfield name="username"  value="%{#.request.req}" ></s"textfield>	

4: 标签中使用的c:或s:

  • 在页面开头设定的 <%@ tablib uri="/struts-tags" prefix=“s” %> 中prefix有关.

4 Struts2拦截器

1 拦截器概述

1: struts2是框架,封装了很多的功能,struts2里面封装的功能都是在拦截器里面.
2: struts2 有很多拦截器,不是每次都执行这些拦截器,每次执行默认的拦截器.
3: struts2 中默认拦截器位置:struts2-core包中 struts-default.xml中

<!-- 拦截器-->
<interceptor name="Aaa",class="Xxx" >
<!--  引用拦截器-->
<interceptor-ref name="Aaa" > 

4: 拦截器执行时机: 在action对象创建之后,action方法执行之前

2 拦截器底层原理

1 AOP思想

AOP: 面向切面编程 有基本功能,扩展功能,不通过修改源代码方式扩展功能.

2 责任链模式

在java中有很多的设计模式,责任链是其中一种,责任链模式和过滤链很相似的.

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

责任链: 要执行多个操作,有添加,修改,删除操作,每个操作完成之后,放行.

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

  • 1 在action创建之后,action的方法执行之前.
  • 2 所在action方法执行之前执行默认的拦截器,执行过程使用aop思想, 在action没有直接调用拦截器的方法,使用配置文件方式进行操作.
  • 3 在执行拦截器时候,执行很多拦截器,这个过程使用责任链模式.

3 源代码分析

1: doFilter方法中 执行action execute.Action(request,response,mapping)
2: action创建对象 使用动态代理 ActionProxy proxy
3: 执行方法 proxy.execute();
4: 遍历拦截器 if(interceptors.hasNext()){} , 类似放行操作的方法: return invocation.invoke();

重点区分:
1 过滤器和拦截器区别:

  • 过滤器: 理论上可以过滤任意内容,比如html,jsp,图片路径等
  • 拦截器: 只可以拦截action

2 Servlet和action区别:

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

4 自定义拦截器

1 引入

Q: Why DIY ?
A: 在struts2里面有很多拦截器,但在实际开发中,有些功能没有,需要自己实现.

拦截器结构:

  • 1 继承了AbstractInterceptor
  • 2 实现Interceptor接口, 有三个方法 init()初始化 , destroy()销毁, interceptor()拦截操作.
2 自定义拦截器的方法

方法1: 可以自定义一个类,继承继承了AbstractInterceptor 也可以直接去实现Interceptor接口,建议继承 ,需要就重写,不需要可以不处理.

(推荐)方法2: 创建类, 继承MethodFilterInterceptor类实现,可以实现让action里面某个方法不进行拦截.

拦截器和action建立关系: 通过配置文件建立关系.

  • 1 在要拦截的action里面所在package标签里面申明拦截器
<interceptors>
<interceptor name="adc"  class= "Xxx"></interceptor>
</interceptors>
  • 2 struts2里面执行很多默认拦截器,但是如果使用自定义的拦截器,就不会使用默认拦截器,需要手动加上默认拦截器.
<!-- action引用拦截器-->		
<interceptor-ref name= "adc" ></interceptor-ref>
<!--加上默认拦截器 -->		
<interceptor-ref name= "defaultStack" ></interceptor-ref>
  • 3 配置的拦截器,对action中所有方法都进行拦截
    • 1 像登录的方法,不应该拦截,否则,永远登录不上.
    • 2 解决:让login不进行拦截 .
<!--	直接通过配置不拦截某些方法 -->	
<param name="excludeMethods">login <param>
<!-- 多个方法用逗号隔开  如login,logout-->				
<interceptor-ref name= "adc" >
<param name="excludeMethods">login,logout<param>
</interceptor-ref>

5 Struts2的标签库

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

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值