Struts2概述
1.struts2 框架应用在javaee三层结构中web层框架
2.struts2框架在struts和webwork基础之上发展全新的框架
其他框架:
springMVC
struts2框架入门
1.导入jar包
asm asm-commons asm-tree
commons-fileupload commons-io commons-lang3
freemarker javassist
log4j-api log4j-core
ognl
strtuts2-core
2.创建Action类,创建execute方法,返回string
每次访问servlet时候,都会执行service方法
写类继承 HttpServlet,重写类里面的方法
在web.xml中配置servlet访问路径,或者注解
访问action,默认执行execute方法
配置action类访问路径
配置action类访问路径
创建struts2核心配置文件
核心配置文件名称和位置是固定的
位置必须在src下面,名称struts.xml
struts.xml:
<struts>
<package name="hellodemo" extends="struts-default" namespace="/">
<!-- name:访问名称 -->
<action name="hello" class="cn.itcast.action.HelloAction">
<!-- 配置方法的返回值到页面 -->
<result name="ok">/hello.jsp</result>
</action>
</package>
</struts>
http://127.0.0.1/项目名/hello(.action)
此时还不能访问,因为还没有配置过滤器
过滤器在服务启动时就执行
servlet在第一次访问时执行
OpenSessionInViewFilter要在struts前面
<!-- 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>
查看源代码
class StrutsPrepareAndExecuteFilter implements StrutsStatics,filter
1.过滤器在服务器启动时候创建,创建过滤器时候执行init方法
在init方法中主要加载配置文件
包含自己创建的配置文件和strtus2自带配置文件
struts.xml
web.xml
struts2配置
struts2的核心配置文件
src下strts.xml
名称和位置固定
在配置文件中主要三个标签:package,action,result,标签里面的属性
package
1.类似于代码包,区别不同的action,要配置action,必须首先写package标签。在package里面才能配置action.
2.package标签属性
name:属性值跟功能本身没有关系,也就是说可以随意命名
在一个配置文件可以写多个package标签,name属性不能相同
extends:
extends="struts-default"
属性值固定,struts-default
写了这个属性之后,在package里面配置的类具有action功能
namespace属性:
namespace属性值和action标签里面的name属性值构成访问路径
一般可不写,默认“/”
action:
1.action标签配置action访问路径
2.action标签属性
name:
namespace属性值和action标签里面的name属性值构成访问路径
在package标签里面有多个action标签,但是action的name属性不能相同
class:
action全路径
method:
比如在action里面默认执行的方法execute方法,但是在action里面写其他的方法,让其他方法方法可以执行,使用method进行配置
result:
根据action的方法返回值,配置到不同的路径里面
result标签属性
name:
和方法的返回值一样
<!--配置方法的返回值到页面-->
<result name="ok">/hello.jsp</result>
type:
配置如何到路径中(转发或者重定向)
属性默认做转发操作
3.修改struts默认常量值
常用的方式
在struts.xml中进行配置
其他两种方式:
在src下面创建struts.properties进行修改
在web.xml
常用常量介绍:
struts.i18n.encoding=UTF-8
表单提交数据到action里面,在action可以获取表单提交数据
表单提交数据有中文,有乱码问题
post提交直接设置编码
get提交做编码转换
如果在action获取表单通过post方式提交中文,中文乱码问题帮解决了,不需要自己处理问题
模块开发:
在核心配置文件中引入配置文件
<!--引入hello.xml文件-->
<include file="cn/itcast/action/hello.xlm"></include>
Action编写方式
1.action编写有三种方式
第一种 创建普通类,这个类不继承任何类,不实现任何接口
第二种 创建类,实现接口Action
实现接口中方法,里面还有String常量
第三种 创建类,继承类ActionSupport
ActionSupport本身就实现了Action接口
访问action的方法
1.有三种方式实现
第一种 使用action标签的method属性,在这个属性里面写执行的action的方法
method="add"
<package name="methoddemo" extends="struts-default" namespace="/">
<action name="addAction" class="cn.itcast.method.BookAction" method="add"></action>
<action name="updateAction" class="cn.itcast.method.BookAction" method="update"></action>
</package>
action里面每个方法都需要配置,如果有很多方法,需要多次配置
第二种 使用通配符方式实现
1 在action标签里面name属性,name属性值里面写符号 * 星号
"*"理解:表示匹配任意内容
{1}表示匹配第一个*的内容。Book_add,{1}代表add
<package name="methoddemo" extends="struts-default" namespace="/">
<action name="Book_*" class="cn.itcast.method.BookAction" method="{1}"></action>
</package>
第三种 动态访问实现(不用)
2.演示错误
1.如果action方法有返回值,在配置文件中没有配置,出现错误
2.acrion方法返回String
3.action里面的方法可以没有返回值,没有返回值的时候,在result标签不需要配置
-把方法写成void
-让返回值,返回"none"
1.结果页面配置
全局结果页面
如果在一个package里面有多个action,方法里面的返回值相同,到页面也是相同,这个时候就可以使用全局结果页面配置
<package name="demo" extends="strtus-default" namespace="/">
<global-result>
<result name="success">/hello.jsp</result>
</global-result>
<action name="addAction" class="cn.itcast.method.BookAction" method="add"></action>
<action name="updateAction" class="cn.itcast.method.BookAction" method="update"></action>
</package>
局部结果页面
平时在action里面写result的方式就是局部结果页面
既有全局结果页面又有局部结果页面以局部结果页面为准
result标签type属性
type:
针对到页面中配置:
默认值,做转发操作,dispatcher
做重定向操作,redirect,地址栏变化
针对到其他action里面:
chain,转发到acton,一般不用,有缓存问题
redirectActon ,重定向到action
<package name="demo" extends="strtus-default" namespace="/">
<action name="addAction" class="cn.itcast.method.BookAction" method="add">updateAction</action>
<action name="updateAction" class="cn.itcast.method.BookAction" method="update">/<helo class="jsp"></helo></action>
</package>
2.在action获取表单提交数据,action没有request对象,所以不能直接使用request对象
使用ActionContext类获取
使用静态的getContext()获取当前线程的ActionContext对象,然后调用getParameters(),此方法返回包含所有HttpServletRequest参数信息
里面得到的是以数组形式返回的object
使用ServletActionContext类获取
调用静态方法,得到对象
getRequest(),HttpServletRequest对象
getResponse(),HttpServletResponse对象
getServletContext(),ServletContext对象
getPageContext(),PageContext对象
使用接口注入方式获取
implements ServletRequestAware
3.struts2提供获取表单数据方式
属性封装
直接把表单提交属性封装到action的属性里面
实现步骤:
在action成员变量位置定义变量,变量名称和表单输入项的name属性值一样
生成变量的set方法
struts2自动封装到变量里面,没有封装到对象中
模型驱动封装
可以把表单数据封装到对象里面
实现步骤:
action实现接口ModelDriven
实现里面的方法,getModel方法把创建对象返回,创建对象不是声明
在action里面创建实体类对象
要求:表单输入项name属性值和实体类属性名称一样
在一个action中,不能同时使用属性封装和模型驱动封装,同时使用时,只会执行模型驱动封装。
表达式封装
把表单数据封装到实体类对象里面
第一步 在action里面声明实体类
private User user;
第二步 生成实体类变量的set和get方法
public void setUser(User user){
this.user = user;
}
public User getUser(){
return user;
}
第三步 在表单输入项的name属性值里面写表达式形式
jsp中修改:
username:<input type="text" name="user.username">
比较表达式封装和模型驱动封装
1.使用表达式封装和模型驱动封装都可以把数据封装到实体类对象里面
2.不同点:
使用模板驱动只能把数据封装到一个实体类对象里面,在一个action里面不能使用模型驱动把数据封装到不同的实体类对象里面
使用表达式封装可以把数据封装到不同的实体类对象里面 list[index]
4.struts2获取数据封装到集合中
封装到list集合
在action声明List
生成list变量的set和get方法
在表单输入项里面写表达式 map['key值']
封装到map集合
声明map集合
生成get和set方法
在表单输入项的name属性值里面写表达式
实例:
示例中,添加结束后,返回列表。不能直接返回jsp里面,因为没数据。可以redirectAction到action
<result name="list">list.jsp</result>
<!-- action方法里面有list方法-->
<result name="addCustomer" type="redirectActon">customer_list</result>
ognl概述
EL表达式在jsp中获取域对象里面的值
OGNL是一种表达式,这个表达式功能更加强大
在struts2里面操作值栈数据
一般把ognl在struts2操作,和struts2标签一起使用操作值栈
OGNL是一个单独的项目
导入jar包 ognl
ognl入门案例
使用ognl+struts2标签实现计算字符串长度
objName.methodName()
在java代码中,调用字符串.length();
使用struts2标签,在jsp中引入标签库
<%@ taglib uri="/struts-tags" prefix="s"%>
使用struts2标签实现操作
<!--使用ognl+struts2标签实现计算字符串长度
value属性值:ognl表达式
-->
<s:property value="'haha'.length()"/>
什么是值栈
1.之前在web阶段,在servlet里面进行操作,把数据放到域对象里面,在页面中使用el表达式获取到,域对象在一定范围内,存值和取值
2.在struts2里面提供本身一种存储机制,类似于域对象,是值栈,可以存储和取值
在action里面把数据放到值栈里面,在页面中获取到值栈数据
1.servlet和action区别
servlet:默认在第一次访问时候创建,创建一次,单实例对象
action:访问时候创建,每次访问action时候,都会创建action对象,创建多次,多实例对象
2.值栈存储位置
每次访问action时候,都会创建action对象
在每个action对象里面都会有一个值栈对象
如何获取值栈对象
常用方式:使用ActionContext类里面的方法得到值栈对象
//获取ActionContext类对象
ActionContext context = ActionContext.getContext();
//调用方法得到值栈对象
ValueStack stack = context.getValueStack();
每一个ActionContext里面只有一个值栈
值栈内部结构
第一部分root,结构是list集合,ArrayList
一般操作的是root里面的数据
第二部分context,结构map集合,Map
context存储的对象引用
向值栈放数据
s:debug标签
调试,查看值栈结构和存储值
没做任何操作,栈顶元素是cn.itcast.action.ValueStackDemoAction,action引用
action对象里面有值栈对象
值栈对象里面有action引用
第一种 获取值栈对象,调用值栈对象里面的set方法
ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
stack.set(); HashMap
第二种 获取值栈对象,调用值栈对象里面的push方法
stack.push(); String
第三种 在action定义变量,生成变量的get方法
一般使用第三种方式,因为第三种方式不申请新的空间,节省空间
向值栈放字符串
向值栈放对象
定义对象变量
生成变量的get方法
在执行的方法里面向对象中设置值
向值栈放list集合
定义list集合变量
生成变量的get方法
在执行方法里面向list集合设置值
从值栈获取数据
使用struts2标签+ognl表达式获取值栈数据
<s:property value="ognl表达式"/>
从值栈获取字符串
<s:property value="存储字符串名称"/>
从值栈获取对象
<s:property value="存储对象.属性"/>
从值栈获取list集合
第一种方式:
<s:property value="list[0].usernaem"/>
第二种方式:
s:iterator标签使用
<!--
<s:iterator>:遍历值栈的list集合
<c:foreach items="" var="user">
${user.username}
</c:foreach>
-->
<s:iterator value="list">
<s:property value="list所存储对象属性"></s:property>
</s:iterator>
第三种方式
<!--
遍历值栈list集合,得到每个user对象
机制:把每次遍历出来的对象放到context里面
获取context里面数据特点:写ognl表达式,使用特殊符号:#
-->
<s:iterator value="lsit" var="user">
<s:property value="#user.username"></s:property>
</s:iterator>
使用set,push方法如何取值?
<!-- 获取set方法设置的值,根据名称获取值 stack.set("itcast","abck") -->
<s:property value="itcast"></s:property>
<!-- 使用push方法获取值,没有名称,只用设置的值 -->
<!-- 向值栈存放数据,把向值栈放数据存放到数组里面,数组名称top,根据数组获取值 -->
<!-- stack.push("abcd") -->
<!-- [0].top是ognl写法 -->
<s:property value="[0].top"></s:property>
EL表达式获取值栈数据
<!-- 使用foreach标签+el表达式获取值栈list集合数据 -->
<!-- 导入jstl+standard jar包 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:forEach items="${list}" var="user">
${user.usernaem}
${user.password}
${user.address}
</c:forEach>
为什么EL表达式可以获取值栈数据?
EL表达式获取域对象值
向域对象里面放值使用setAttribute方法,获取值使用getAttribute方法
底层增强request对象里面的方法getAttribute方法
首先从request域获取值,如果获取到,直接返回
如果从request域获取不到值,到值栈中把值获取出来,把值放到域对象里面
ognl表达式#,%使用
# 获取context里面数据
获取context里面数据,写ognl时候,首先添加符号
#ocntext的key名称.域对象名称
% 在struts2标签中表单标签
在struts2标签里面使用ognl表达式,如果直接在struts表单标签里面使用ognl表达式不识别,只有%之后才会识别
Struts2拦截器概述
struts2是框架封装了很多功能,struts2里面封装的功能都是在拦截器里面
struts2里面每次执行默认的拦截器
struts2里面默认拦截器位置
struts2-core struts-default.xml
1 拦截器底层使用两个原理
aop思想
面向切面编程,不通过修改源代码方式拓展功能
责任链模式
过滤链:一个请求可有多个过滤器进行过滤,每个过滤器只有做放行才能到下一个过滤器
aop思想和责任链模式如何应用到拦截器里面?
拦截器在action对象创建之后,action的方法执行之前执行
在action方法执行之前执行默认拦截器,执行过程使用aop思想,在action没有直接调用拦截器的方法,使用配置文件方式进行操作
在执行拦截器时候,执行很多的拦截器,这个过程使用责任链模式
加入执行三个拦截器,执行拦截器1,执行拦截器1之后做放行操作,执行拦截器2,执行拦截器2之后做放行,执行拦截器3,执行拦截器3之后放行,执行action方法
执行action
execute.executeAction(request,response,mapping)
创建action对象,使用动态代理方式
ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace,name,method,extraCotext,true,false)
执行action方法
proxy.execute()
执行很多的拦截器,便利执行
if(interceptors.hasNext())
类似于放行的操作的方法
return invocation.invoke()
过滤器和拦截器区别:
过滤器:过滤器理论上可以任意内容,比如html,jsp,servlet,图片路径
拦截器:拦截器只可以拦截action
servlet和action区别:
servlet默认第一次访问时创建,创建一次,单实例对象
action每次访问时候创建,创建多次,多实例对象
在struts2里面有很多的拦截器,这些拦截器是struts2封装的功能,可以自己写
拦截器结构
继承类
class ModelDrivenIntercepter extends AbstractInterceptor
calss AbstractInterceptor implements Interceptor
接口里面有三个方法
init 初始化
destroy 销毁
intercept(ActionInvocation invocation) 拦截逻辑操作
开发中使用
写类,继承MethodFileterINterceptor类实现
让action中某个方法不被拦截
让拦截器和action有关系
不是在action调用拦截器的方法,而是通过配置文件方式让建立关系
自定义登录拦截器
1 需求:在项目中,有很多的action的超链接,实现只有登录状态才可以点击action的超链接实现功能,如果不是登录状态,点击action超链接返回到登录页面
2 登录的状态:使用session域对象实现
登陆成功之后,把数据放到session里面
判断session是否有值,可以知道是否是登录状态
示例:
判断是否登录,判断session里面是否有名称username的值
拦截器实现过程:
创建类,继承MethodFilterInterceptor类
重写MethodFilterceptor类里面的方法写拦截器逻辑
配置action和拦截器关系(注册拦截器)
1.在要拦截的action标签所在的package标签里面声明拦截器
<interceptors>
<interceptor name="拦截器名字" calss=""></interceptor>
</interceptors>
2.在具体的action标签里面使用声明的拦截器
<interceptor-ref name="loginintercept"></interceptor-ref>
3.struts2里面执行很多的默认拦截器,但是如果在action里面配置自定义拦截器,默认的拦截器不会执行
解决:把默认的拦截器手动使用一次
<interceptor-ref name="defaultStack"></interceptor-ref>
配置拦截器,对action里面所有的方法都进行拦截
配置不拦截:
<interceptors>
<interceptor name="拦截器名字" calss="">
配置action里面不进行拦截的方法
name:excludeMethods
值:action不拦截的方法名称
<param name="excludeMethods">方法名称login,add</param>
</interceptor>
</interceptors>
出现框架嵌套网页问题:
jsp 标签form target="_parent"
Struts2标签库
struts2标签使用jsp页面中
s:property 和ogml表达式在jsp页面中获取值栈数据
s:property 获取值栈list集合数据,表示变量list集合
s:debug:查看debug属性