一、Struts2入门
struts2概述
- javaee三层中的web层
- 在struts1和webwork基础上的全新的框架
- 解决一些问题
①当功能很多,会创建很多的servlet,那么维护起来不方便,在javaweb阶段我们是通过BaseServlet的的底层反射来实现的
- struts2版本
目前比较稳定的版本 - web层框架
①struts2
②springMVC
struts2入门案例
- 从lib目录中导入jar包,但是里面可能上百个jar包,你可以从app目录(里面是一些案例,最好从blank案例中拿)中找到里面的web-inf->lib下的jar包进行copy
关于jar包详情可参考:https://blog.csdn.net/For_ZZHacker/article/details/85675995 - 创建action(这里的action就相当于javaweb学的servlet)
① 每次访问servlet的时候都会默认执行service方法(写一个servlet:写一个类的时候需要继承httpservlet类,然后重写里面的方法(例如doget,dopost),然后再web.xml中配置访问servlet的路径)
② 每次访问action的时候都会默认执行execute方法(同样需要配置action的访问路径,见下一步)
- 配置action类的访问路径
① 创建struts2的核心配置文件,该配置文件的名称和位置是固定的,跟hibernate的配置文件一样。位置在src下面,文件名称叫struts.xml
② 引入dtd的约束
访问路径为:http://127.0.0.1:8080/项目名/hello.action
(action可加可不加,常用浏览器例如火狐,谷歌,IE没问题,杂牌浏览器还是加上后面的action有可能会出错)
注意:此时访问会出现404问题,一个可能是服务器启动报异常了,另一个就是没有配置过滤器!!! - 配置struts2的过滤器(在web.xml中配置)
(struts2已经帮我们封装好了过滤器,我们只需要配置一下即可)
此时再去访问就会访问成功!!! - 小总结:通过一个案例我们知道了使用框架我们可以少些很多的代码,他给我们封装了许多代码,但是我们需要去配置运用这些封装好了的类。
另外:struts.xml里面有许多的action,web.xml就定义了一个过滤器
struts2底层执行过程
-
几个概念
过滤器是在启动服务器的时候创建的,servlet默认是在第一次访问的时候创建的
框架的学习反射是重点!!!!
-
查看过滤器源代码
里面有init方法,doFilter方法,destroy方法
①过滤器在服务器启动的时候就会执行,创建过滤器时候执行init方法
- init方法中加载struts2自带的配置文件和自己创建的配置文件(struts.xml,web.xml)
- 现在再来看一下第二个加载的配置文件是什么
小总结:我们开发的时候只需要关心struts.xml,web.xml这两个需要自己配的配置文件即可
struts2相关配置
struts2的核心配置文件struts.xml
最大的标签是<struts>
里面有3个常用标签从大到小<package><action><results>
,以及里面的属性.
① package标签
- 类似一个代码包,区别不同的action,要配置action,必须首先写package标签,在package标签中才能配置action
- package标签属性
- name属性:用来区分不同的package,随便起名
- extends属性:就是个继承的意思
- namespace属性:不写默认也是“/”,最好写上。
② action标签
- action标签主要配置action的访问路径
- action的标签属性
- name属性:区分不同的action;package标签中的namespace属性和这里的name属性构成了访问路径
- class属性:全路径=包名+类名,通过反射的原理去执行该类的
- method属性:
③ result标签
- 根据你的action中的方法返回值,将页面定位到指定的页面或action上
- result标签的属性
- name属性:和你方法的返回值要一样
里面的“/”代表的是当前项目的根目录
- type属性:
有4个值:dispatcher(默认),redirect,chain,redirectAction
dispatcher(默认)和redirect:result标签中“/”代表的是项目根路径,不写就代表当前路径下
chain和redirectAction:result标签中“/”没有任何意义,不需要写,写了就是多余,也就是只能从当前路径去指定页面!!!
chain:只能转发到同一命名空间下的Action
redirect:可以重定向到action中去,也可以重定向到显示页面中去
转发后页面变了,但是地址栏并没变,本质来讲转发就是同一个请求,重定向是又一次新的请求(相当于2次请求)
struts2常量配置
- struts2框架,帮我们实现一部分功能,struts2里面有常量,在常量里面封装一部分功能。
- struts2默认的常量位置(记住)
- 修改struts2默认常量值
① 常用方法
该标签写<struts>
下面,和<package>
标签同级
② 还有2种方式(了解)
- 常用常量
分模块开发
- 每个人自己的模块配置文件单独开发,最后合并引入到核心配置文件中就行,这样就不会将我们的核心配置文件给弄乱了。
struts2的action创建
action的编写方式
- action编写的3种方式
- 创建类,实现Action接口方式(将一些常用的返回值定义为常量例如SUCCESS=“success”),不常用
- 创建类,继承类ActionSupport,常用
当然也可以用那些常量,因为也实现了interface Action
struts2的action方法访问(重点)
- 一共三种方式实现
第一种:使用action标签的method属性,在这个属性里面写执行的action的方法,不写默认执行execute()方法
第二种:使用通配符的方式实现
第三种:动态访问实现(不用)
- 一个错误演示
- 一个action访问不同方法的例子
- 普通方式
- 使用通配符的方式
- 又是一个struts2应用的案例
二、Struts2数据操作
结果页面的配置
- 全局结果页面
使用global-results
标签将result
标签写这里面,global-results
标签位于package
标签里面,此时action
标签默认就有global-results
标签中包含的result
标签
- 局部结果页面
- result标签type属性
在action获取表单提交的数据
- 使用ActionContext类获取
- 一个例子来演示
- 创建表单,提交表单到action里面
- 使用ServletActionContext类获取
- 使用接口注入方式获取(实现不同的接口,例如ServletRequestAware接口里面有个方法可以设置出request对象)
让action实现接口,为了得到request对象,需要新建一个成员变量来进行赋值的,然后在execute方法中才能使用
ware:器皿,物品—》容器
request用的多,session经典案例是用在登录的时候,context用的少
struts2提供获取表单数据方式(减少了代码,替代了上面的方式例如:ServletActionContext)
原始的写法获取表单数据并封装到实体类中(麻烦费劲,但是有效稳定)
- 属性封装(会用即可)
- 模型驱动封装(重点)
- 表达式封装(也可以认为是属性封装的特例,因为写法原理一样)
struts2获取数据封装到集合中
- 封装到list集合
- 封装到map集合
扩展-表达式封装和模型驱动比较
相同点:都封装到实体类中
不同点:模型驱动只能封装到同一个实体类对象中,表达式封装可以封装到不同实体类中
案例-添加客户功能
三、Struts2值栈
OGNL概述
- web阶段用EL表达式在jsp页面中来获取域对象里面的值
- ognl表达式比EL表达式功能更强大
(1)在struts2里面操作值栈数据
(2)一般把ognl在struts2操作:和struts2标签一起使用操作值栈
EL表达式,OGNL表达式(从表单获取数据三种方式中的表达式方式(隶属于属性封装方式))
html标签,jstl标签,struts2标签
- OGNL不是struts2的一部分,单独的项目,经常和struts2一起使用
(1)使用ognl时候首先导入jar包,struts2提供了ognl的jar包
OGNL入门案例
什么是值栈
获取值栈对象
值栈内部结构
下图中root部分是个栈,栈里面有2个元素,因为没有操作值栈,所以栈顶元素是当前值栈所在action的一个引用(为了方便操作的),当你往栈里面放东西就会放到栈顶的位置上。
向值栈放数据
1 向值栈放数据多种方式
第一种 获取值栈对象,调用值栈对象里面的 set 方法
第二种 获取值栈对象,调用值栈对象里面的 push方法
第三种 在action定义变量,生成变量的get方法(好处是减少空间的分配了)
向值栈放对象
向值栈放list集合
从值栈获取数据
1 使用struts2的标签+ognl表达式获取值栈数据
(1)<s:property value=”ognl表达式”/>
获取字符串
1 向值栈放字符串
2 在jsp使用struts2标签+ognl表达式获取
获取对象
获取list集合
第三种方式使用struts2的iterator标签类似于jstl的foreach标签
想使用context里面的数据需要加个“#”,将数据放到context这样的操作目的是为了方便取值,不占用root部分,提高效率
这里注意一下application,其实就是ServletContext对象,记得这个applicatIon域中是共享的
foreach+EL表达式的方式(需要jstl.jar包和standard.jar,并且在开头引入c标签taglib uri是jstl/core)
其他操作
ognl的数组获取值的写法先写下标,再写数组名,中间有点号,值栈的栈顶就是0号位置,依次向下排,所有的都会放到这个top数组,不是只有push这种没有key的。
注意:很多种写法都用<s:property value="ognl表达式">
来获取,实质上这个标签是从栈顶先来寻找符合的值,找到就直接显示,不管后面符合该表达式的值了。
EL表达式获取值栈数据(为什么能取到)
如果数据在值栈中虽然能取到,但是性能很低,因为有多余操作,例如先去域对象中找等等。
先看例子:能够取到值栈中的数据
先解释一个词wrap:包起来,穿外衣,缠绕—》本质就是增强的意思
源码里面会有这个词,以及wrapper可以理解为包装器和增强器
EL表达式中就是对request进行了增强,本质就是对getAttubute进行了增强
看源码首先从struts2的过滤器中开始看-----》找到里面有个doFilter方法—》再看到这个doFilter方法中的request被增强了使用wrapRequest(oldRequest)方法
最后这个选中的ActionContext.put,又将标志值(看好了不是attribute,只是一个标志而已)放到了值栈的第二部分context中去了,其实这个context中包含request对象的引用,Httpsession对象的引用,servletContext对象的引用等等(也因此可以用ognl表达式获取到域对象中的数据),此时put进去就和这些域对象平起平坐了。
ActionContext.getContext.put(String,Object)是把对象放到了StackContext中,这个对象跟request,session等一样,它们平起平坐,但这些都不是root对象(这些是context对象),所以要通过#访问。
request.setAttribute(String,Object)就是把值放到request范围,而StackConext里含有request对象,所以可以通过#request.*来访问。
OGNL的#、%使用
#使用
%使用
注意是表单标签
上面这个图就相当于html中的input标签,所以一般不用ognl的表单标签,因为性能低,不如直接用html的表单标签
案例-显示所有信息列表(用值栈来存数据,以前用的域对象)
首先想到3种方式set,put,直接定义成员变量方式,第三种最常用
四、Struts2拦截器(interceptor)
拦截器的概述
- 拦截器是struts2里面的概念
- struts2框架封装的功能都是在拦截器里面
- 在没有自定义拦截器的情况下,每次执行action,默认只会执行默认的拦截器
下图是常量的位置:
下图是struts2里面默认拦截器的位置:
这个文件结构跟自己定义的struts.xml结构差不多
其中的package标签名字就是struts-default,还定义了result-type,默认是dispatcher
这里还指定了默认的拦截器栈
在这个文件中<interceptors>
里面定义了大量的<interceptor>
这些就是定义的拦截器,还有一些拦截器栈
下图这些只是引用<interceptor-ref>
,真正的定义拦截器是在上面定义的
4. 拦截器的执行时间:
在action创建之后,执行action中的方法之前 ,执行的拦截器,可以通过在默认的随便一个拦截器上打个断点来验证,会发现先到拦截器中的断点,再到action中的具体方法中的断点上
追踪一个拦截器看一下(就拿这个模型驱动的拦截器来演示一下):
这里是xml文件,用ctrl+鼠标左键不能连接到,先选中用ctrl+shift+t来找到该类
百度解释拦截器:
一、概述:
java里的拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个action执行的前后执行的代码,也可以在一个action执行前阻止其执行,同时也提供了一种可以提取action中可重用部分的方式。在AOP(Aspect-Oriented Programming)中拦截器用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。
二、原理:
大部分时候,拦截器方法都是通过代理的方式来调用的。Struts 2的拦截器实现相对简单。当请求到达Struts 2的ServletDispatcher时,Struts 2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),最后一个一个地调用列表中的拦截器。Struts2拦截器是可插拔的,拦截器是AOP的一种实现。Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Struts2拦截器链中的拦截器就会按其之前定义的顺序被调用。
三、定义一个拦截器
自定义一个拦截器需要三步:
1 .自定义一个实现Interceptor接口(或者继承自AbstractInterceptor)的类。
2 .在struts.xml中注册上一步中定义的拦截器。
3 .在需要使用的Action中引用上述定义的拦截器,为了方便也可将拦截器定义为默认的拦截器,这样在不加特殊声明的情况下所有的Action都被这个拦截器拦截。
四、与过滤器的区别:
过滤器可以简单理解为“取你所想取”,忽视掉那些你不想要的东西;拦截器可以简单理解为“拒你所想拒”,关心你想要拒绝掉哪些东西,比如一个BBS论坛上拦截掉敏感词汇。
1.拦截器是基于java反射机制的,而过滤器是基于函数回调的。
2.拦截器不依赖于servlet容器,而过滤器依赖于servlet容器。
3.拦截器只对action起作用,而过滤器几乎可以对所有请求起作用。
4.拦截器可以访问action上下文、值栈里的对象,而过滤器不能。
5.在action的生命周期里,拦截器可以多起调用,而过滤器只能在容器初始化时调用一次。
拦截器底层原理
1 拦截器底层使用两个原理
第一个 aop思想(aop的底层是动态代理)
(0)后面在spring里面把aop做更深层次分析
(1)文字描述:
Aop是面向切面(方面)编程:有个基本功能,需要扩展功能,不通过修改源代码方式扩展功能。
(2)画图分析:
第二个 责任链模式
(1)在java中有很多的设计模式,责任链模式是其中的一种
(2)责任链模式和过滤链很相似的
责任链模式:
要执行多个操作,有添加、修改、删除三个操作。
首先执行添加操作,添加操作执行之后 做类似于放行操作,执行修改操作,修改操作执行之后做类似于放行操作,执行删除操作
过滤链:一个请求可有多个过滤器进行过滤,每个过滤器只有做放行才能到下一个过滤器
2 aop思想和责任链模式如何应用到拦截器里面?
(1)文字描述:
-
拦截器在action对象创建之后,action的方法执行之前执行
-
在action方法执行之前执行默认拦截器,执行过程使用aop思想,在action没有直接调用拦截器的方法,使用配置文件方式进行操作
-
在执行拦截器时候,执行很多的拦截器,这个过程使用责任链模式
– 假如执行三个拦截器,执行拦截器1,执行拦截器1之后做放行操作,执行拦截器2,执行拦截器2之后做放行,执行拦截器3,执行拦截器3之后放行,执行action的方法
(2)画图分析
3 查看源代码
源码主要步骤:
重要概念
1 过滤器和拦截器区别
(1)过滤器:服务器启动时创建,过滤器理论上可以任意内容,比如html、jsp、servlet、图片路径
(2)拦截器:拦截器只可以拦截action
2 Servlet和action区别
(1)servlet默认第一次访问时候创建,创建一次,单实例对象
(2)action每次访问时候创建,创建多次,多实例对象
自定义拦截器
自定义登录拦截器
1 需求:在项目中,有很多的action的超链接,实现只有是登录的状态,才可以点击action的超链接实现功能,如果不是登录状态,点击action超链接返回到登录页面
2 登录的状态:使用session域对象实现
(1)登录成功之后,把数据放到session里面
(2)判断session是否有值,可以知道是否是登录状态
3 实现登录的基本功能
(1)查询数据库判断用户名和密码
此时可以在jsp页面用EL表达式来获取到session域中的信息
4 添加登录拦截器功能
(1)判断是否登录:判断session里面是否有名称是username的值
(2)拦截器实现过程
第一步 创建类,继承MethodFilterInterceptor类
第二步 重写MethodFilterInterceptor类里面的方法写拦截器逻辑
第三步 配置action和拦截器关系(注册拦截器)
(1)在要拦截的action标签所在的package标签里面声明拦截器
(2)在具体的action标签里面使用声明的拦截器
(3)struts2里面执行很多的默认拦截器,但是如果在action里面配置自定义拦截器,
问题:默认的拦截器不会执行了,如果没有到默认拦截器中的功能也可以不引用。
解决:把默认拦截器手动使用一次
5 配置的拦截器,会对action里面所有的方法都进行拦截
(1)在action里面有login的登录的方法,这个方法不需要拦截,如果这个方法都拦截,问题是,永远登录不进去了
(2)解决:让login方法不进行拦截
这里就是为什么要继承MethodFilterIntercepor类的原因了,如果继承的是AbstractInterceptor类需要用反射的方法才让实现让一些方法不拦截,而继承这个类直接就可以使用配置的方式来实现,如下:
- 直接通过配置方式让action里面某些方法不进行拦截,多个方法用逗号分隔
6 如果登录状态,直接到功能页面,如果不是登录显示登陆页面
登录之后出现小问题:
原因:
解决:设置打开的位置是在父窗口中打开,这个target在以前a标签中见过
struts2的标签库
0 struts2标签使用jsp页面中
1 s:property: 和ognl表达式在jsp页面中获取值栈数据
2 s:iterator: 获取值栈list集合数据,表示list集合
3 s:debug: 查看值栈结构和数据
Struts表单标签(会用)
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表单标签大部分都有
而且可以通过查看源代码的方式来看这些标签装换成html标签的样子
不能在标签的前面写该标签的名字,否则不在一行上,因为它会装换成
html标签的时候是用的table->tr->td,要用label标签写名字
用map的格式可以解决显示的值和value对应的值不一样的情况!!!
缺少两个知识点
1 struts2文件上传
2 错误处理机制
五、一些实用小细节
- 当你用eclipse复制一个项目的时候,不但需要修改项目的名,还需要修改项目的上下文路径,也就是你访问的时候需要输入的访问项目的名称。
右键-》properties
- 关于页面刷新
我用的是chrome浏览器:
F5:刷新网页,重新显示当前页面内容
Ctrl+F5(Ctrl+Shift+R):重新加载当前网页而不使用缓存内容,缓存虽然加快了显示的速度,但是修改后可能不会正常显示。效果是忽略缓存,强行刷新网页(包括重载js),重新请求
Shift+F5:用过重新载入新的js脚本,跟ctrl+F5 一样
Ctrl+Shift+Del 清除Google浏览器缓存的快捷键
F5和Ctrl+F5原理,可参看:https://www.cnblogs.com/cxd4321/archive/2009/03/11/1408425.html
关于客户端的刷新功能,可参看:
http://www.cnblogs.com/volnet/archive/2012/11/02/2752019.html
- eclipse一些使用问题
直接启动tomcat也会自动运行publish(发布),但是有时项目很大会有问题,但是最保险的方式是先publish,再start.关闭的时候最好先stop,再start,虽然restart这个功能可以用。 - 关于注释
图中是jsp的注释,可以在jsp标签中随便注释,为所欲为。
<!-- -->
是html的标签,不能注释掉里面的jstl标签和ognl标签,否则会报错!!!!