1.MVC模型
M:Model 模型 作用是封装数据。 目前就是实体类作为模型
V: View 视图 作用是展示数据。 JSP/HTLM
C: Controller 控制器 作用是控制程序流转的。 Servlet/Filter
2.概述
Struts2是一个基于MVC模式的轻量级web框架。
3.坏境变量的搭建
(1)导入jar包
G:\struts-2.3.24\apps\struts2-blank.war 这是一个案例。引用案例中WEB-INF \lib里的所有jar包。
(2)在根路径src下创建名为:struts.xml的文件。导入dtd约束。
dtd文件名 : struts-2.3.dtd
dtd文件的路径: G:\struts-2.3.24
(3)在web.xml内配置struts的核心过滤器
代码复制于:G:\struts-2.3.24\apps\web.xml
代码实现:Struts2项目 WEB-INF\web.xml
4.struts2的入门案例
动作类:它就是一个概念。它就是struts2框架用于处理请求的类。
我们以后处理请求都写动作类。
动作方法:动作类中用于处理请求的方法
编写规范:
1、 访问修饰符都是public
2、 方法的返回值一般都是String(可以是void)
3、 方法都没有参数
Struts2的核心控制器默认会处理以.action为后缀的url,或者是没有任何后缀的url。
代码实现:Struts2项目 index.jsp success.jsp struts.xml Test.HelloAction
5.struct2入门案例的执行过程
6.struct2的内部执行过程
7.Struts2的核心过滤器/控制器和作用
(1)Struts2框架的核心控制器是StrutsPrepareAndExecuteFilter。
(2)作用:
负责拦截由
核心过滤器默认只拦截请求,不拦截转发。
1、默认情况下,如果用户请求的路径不带后缀或者后缀以.action结尾,这时请求将被转入struts2框架处理。
2、否则struts2框架将略过该请求的处理。
8.查看org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter源
代码
1.过滤器在服务器启动时候创建,创建过滤器时候执行init方法
(1)在init方法中主要加载配置文件,包含自己创建的配置文件和struts2自带 的配置文件。
9.struts2的package标签详解
开启开发者模式:
作用:不需要重启Tomcat,struts的配置文件会自动更新。
在struts.xml中:
作用:给访问的action进行分包管理。把配置文件按照面向对象的思想来管理。
属性:
name:指定包的名称。必须写,并且必须唯一
extends:指定当前包的父包,子包自动具备父包所定义的配置。我们的包一般都
需要继承struts-default包。
abstract:把当前包声明为抽象包。抽象包就是用来被继承的。里面定义一般都是 公共的配置。只有没有action标签的包,才能定义为抽象包。
namespace:指定当前包的名称空间。它可以让我们的访问的URL模块化。当我们 指定了该属性,访问URL就变成了:名称空间+/hello
名称空间的写法:第一个字符必须是/,后面紧跟的字符必须是
一个字母。其余内容可以是字母,也可以是数 字。
名称空间的默认值是””
例如:我们访问用户
名称空间+/addUser.action
名称空间+/updateUser.action
10.struts2的action标签的介绍
作用:建立动作名称,动作类,动作方法的对应关系。
属性:
name:指定动作名称
class:指定动作类的全限定名称 包名+类名
method:指定动作方法的名称
11.动作类的三种创建方式
第一种方式:无侵入式的 实际开发用的不多
代码实现:Struts2项目 index.jsp success.jsp struts.xml Test.HelloAction
第二种方式:实现接口的方式 实际开发用的不多
我们的动作要实现一个接口:Action
默认的动作方法:execute
在配置action标签时,可以不写method。
包:com.opensymphony.xwork2.Action
代码实现:Struts2项目 index.jsp success.jsp struts.xml Test.Hello2Action
第三种方式:继承ActionSupport类的方式 实际开发中用的多
包:com.opensymphony.xwork2.ActionSupport
默认的动作类:ActionSupport
在配置action标签时时,可以不写class。
代码实现:Struts2项目 index.jsp success.jsp struts.xml Test.Hello3Action
12.action的三种访问方式
第一种方式:全匹配配置方式
在struts.xml配置:
在package标签内:
为动作类中的每个方法都对应配置一个Action。 (繁琐)
第二种方式:使用通配符方式 通配符:
(1)普通用法
在struts.xml配置action标签:
{数字} : 引用第几个的值
(2)高级用法
在user.jsp中修改:
(1)在struts.xml配置action标签:
<action name=””class=”” method=”{1}{2}”>
{数字} : 引用第几个的值
(2)在struts.xml配置action标签:
<action name=”*” class=”包名+.{2}Action” method=”{1}{2}”>
{数字} : 引用第几个的值
第三种方式:使用动态方法调用的方式(三步)
1、必须开启动态方法调用:
在struts.xml配置一个constant标签:
2、在user.jsp中修改:
3、在struts.xml配置action标签:
代码实现:Struts2项目 Test.UserAction user.jsp success.jsp
13.获取HttpServletRequest的方法
ServletActionContext.getRequet();
14.案例1:查询所有客户
要求:使用Hibernate和struts2框架。 数据库:mydb6。表:cst_customer
代码实现:Struts2Project1项目
15.result标签详解
作用:用于配置结果视图(结果视图可以是一个jsp/html,也可以是一个action)
属性:
name:指定逻辑结果视图。作用就是和动作方法的返回值进行比较。,当一致时,前
往配置的页面或者action。(去哪里)
(不写的话,默认是success)
type:指定前往结果视图的方式。以何种方式前往。(怎么去)
type的取值都是来源于struts-default.xml文件中package名称是struts -default包中定义的类型。
常用的结果类型:
dispatcher: 请求转发(默认值)
redirect: 重定向
redirectAction: 会自动给给action添加后缀
设置后缀:
只能重定向到另外一个动作
代码测试:Struts2项目 Test.Demo01 Demo01文件夹
请求转发和重定向的区别:
请求转发:一次请求 地址栏不变 请求域中数据不丢失 服务器行为
只能在当前应用中转发
重定向: 两次请求 地址栏改变 请求域中数据丢失 浏览器行为
可以重定向到当前应用的外部
响应浏览器的三种方式:
请求转发 重定向 使用流输出(如果只有一种方式,那就是此种方式)
全局结果视图和局部结果视图:
优先级:先局部后全局
全局结果视图:放在package内,action外。在global-results标签内部。
自定义包:
16.访问ServletAPI
第一种方式:
使用struts2框架提供的一个工具类,该类有相应的静态方法,可以直接获取
工具类:ServletActionContext
此种方式是我们实际开发中用的最多的方式
输出结果之后,找出其中一个和其它三个不一样:
Request(包装过的,对某个方法进行增强了)。它是struts2提供的。
第二种方式:
通过实现不同的接口,获取不同的对象。
要想使用Request,需要实现ServletRequestAware
要想使用Response,需要实现ServletResponseAware
要想使用ServletContext,需要实现ServletContextAware
在动作方法执行之前,拦截器会调用以上接口的方法,从而进行了ServletAPI 有关变量的赋值操作。
我们在action标签内部不写任何拦截器,默认是由defaultStack拦截器栈执行, 如果写了任何一个拦截器,默认的就失效了。
代码测试:Struts2项目 Test.Demo02 Demo02文件夹
如果说是一种方式获取ServletAPI对象,ActionContext中的get(key)
使用:ActionContext.getContext().get(String key);
如果说是三种方式获取ServletAPI对象,除了以上两种,还可以使用ActionContext
通过分析源码,我们得知,ActionContext看上去是一个类似Map的结构。
Map的key是String类型,value是Object类型。
17.请求参数的封装
代码测试:Struts2项目 Test.Demo03 Demo03文件夹
原理:
执行参数封装,是一个名称为params拦截器实现的。
封装的规则只有一个,它要去指定位置找属性,找到之后调用set方法赋值。
第一种方式:
属性驱动:没有实体类。(该数据不需要存入数据库时,可以不设置实体类)
要求:
1、用来接收表单数据的成员变量都定义在动作类中,所以称为动作类和模型数据写在一起。
2、表单元素的name属性的取值必须和动作类中成员get/set方法后面的部
份保存一致。
写法:
必须写上关于变量的get/set方法
细节:
1、 struts2框架会为我们解决post请求的中文乱码问题,get请求不解决
2、 struts2框架会自动为我们转换数据类型:
基本数据类型自动转换
字符串数组会按照逗号+空格的方式拼接成字符串
日期类型会按照本地格式转成日期对象
本地格式:yyyy-MM-dd
第二种方式:
属性驱动:有实体类。
要求:
1、用来接收表单数据的成员变量定义在对应的实体类中,把实体类定义在动作类中。
2、此时需要使用OGNL表达式来指定表单元素的name值
OGNL表达式:Objcet Graphic Navigation Lanagage
对象 图 导航 语言
写法:
1、动作类必须写上关于实体类的get/set方法
2、在表单元素的name属性写上: user.username user.password
user : 动作类中实体类的引用名称
username,age:实体类的成员名称。必须和set/get方法后面的保持一致。
第三种方式:(用的最多的方式)
模型驱动:有实体类。
无论是get请求或post请求,任意几个请求参数都会自动封装到实体类中。
要求:
1、动作类必须实现ModelDriven接口。ModelDriven<实体类>
2、动作类中必须定义实体类,并且必须实例化出来
3、提供接口抽象方法的实现,返回值必须是模型对象。(实体类对象)
写法:
1、implements ModelDriven<实体类>
2、在动作类中不需要写出关于实体类的get/set方法
原理:
模型驱动的实现,除了params拦截器之外,还需要一个叫modelDriven的拦截器配合。
复杂类型的封装:List集合的封装
复杂类型的封装都需要基于第二种方式实现。
写法:
1、动作类必须写上关于集合的get/set方法
2、在表单元的name属性写上: users[0].username users[0].password
users[0] : 为存储在List集合内的第一个变量赋值
username:实体类的成员名称。必须和set/get方法后面的保持一致。
复杂类型的封装:Map集合的封装
复杂类型的封装都需要基于第二种情况实现。
写法:
1、动作类必须写上关于集合的get/set方法
2、在表单元的name属性写上: users[‘key1’].username
users[‘key1’] : 为Map集合的key赋值为key1
username:实体类的成员名称。必须和set/get方法后面的保持一致。
给Map集合的value赋值为username。
18.案例2:添加客户
要求:使用Hibernate和struts2框架。 数据库:mydb6。表:cst_customer
代码实现:Struts2Project1项目
19.案例3:删除客户
要求:使用Hibernate和struts2框架。 数据库:mydb6。表:cst_customer
代码实现:Struts2Project1项目
20.请求参数封装失败后的处理方法
1、配置input结果视图,视图路径应该是从哪来回哪去
2、提示错误信息
使用struts2的标签。
(1)导入struts2的标签
<%@taglib uri=”/struts-tags”prefix=”s”%>
(2)使用struts2标签
A、表单:
内部的表单元素错误,自动带有错误信息提示功能。
B、提示错误信息的标签:
错误信息的字体变成红色:在html的内部添加:
关于中文提示的问题:
I18N :国际化
在实体类的包下创建File文件,名为:实体类名称.properties
错误提示信息:Invalid field value for field “password”
在File文件内:
键:invalid.fieldvalue.password
值:自定义值
3、把提交的数据回显回表单中显示出来(html标签和struts2标签都可以实现) 代码实现:Struts2项目 Test.Demo04 Demo04文件夹
21.OGNL表达式概述
OGNL:对象图导航语言
OGNL表达式不仅可以获取数据,还可以存数据。它可以调用java对象的方法。
user.name 看上去是字符串,当它执行user对象的getName方法时,表示用OGNL表达式解释。
使用OGNL表达式获取数据,是我们在开发中经常用到的。
使用OGNL表达式给对象赋值,是struts2框架做的。
22.OGNL表达式最基本的用法
要想使用OGNL表达式获取数据,必须借助struts2的标签库。
属性:
value : OGNL表达式
作用:
标签会把value属性取值所对应的内容输出到浏览器上
如果没有任何对应内容,则什么都不显示
原理:
通过OGNL表达式获取数据时,调用的是ValueStack的findValue
(String expression)方法
案例:使用
代码实现:Struts2项目 OGNL文件夹/Demo01.jsp
23.OGNL表达式和字符串的转换
(1)OGNL表达式转成字符串:
%{‘’} 或 %{“”}
可以把%{}去掉
(2)字符串转成OGNL表达式
%{}把字符串套起来 例如:%{AAA}
代码测试:Struts2项目 OGNL文件夹/Demo02.jsp
24.OGNL表达式访问对象的方法
案例:调用字符串的java方法
代码实现:Struts2项目 OGNL文件夹/Demo03.jsp
25.OGNL表达式访问类的静态成员和静态方法
(1)OGNL表达式访问类的静态成员(静态属性)
访问静态属性需要按照固定的书写规范来写。
规范:
@包名.包名…类名@静态属性名称
案例:调用Integer类的静态属性
代码实现:Struts2项目 OGNL文件夹/Demo04.jsp
(2)OGNL表达式访问类的静态方法
访问静态属性需要按照固定的书写规范来写。
规范:
@包名.包名…类名@静态方法名称
前提:
在struts2中必须配置允许使用静态方法
案例:调用Math类的random()方法
代码实现:Struts2项目 OGNL文件夹/Demo04.jsp
(3)OGNL表达式直接使用对象的方法
格式:对象名.方法名()
26.OGNL表达式操作集合对象(List,Map)
使用
属性:
list : 取值就是一个OGNL表达式
{} :表示创建一个List集合。
例如:{‘男’,’女’} == List list=new ArrayList(); list.add(“男”)
list.add(“女”)
#{} : 表示创建一个Map集合
例如:#{‘male’:’男’,’female’:’女’} == Map map=new HashMap();
map.put(“male”,”男”); map.put(“female”,”女”);
案例1:使用
代码实现:Struts2项目 OGNL文件夹/Demo05.jsp
案例2:使用
代码实现:Struts2项目 OGNL文件夹/Demo05.jsp
27.OGNL上下文—ContextMap
它是Struts2框架中封装数据的最大容器,封装了一次请求中可能会用到的所有数据。
它是一个Map结构。Map的key是String类型,Map的value是Object类型。
里面的内容包括但不限于如下内容:
(key是下列对象的名称(除了value stack),value是下列对象本身)
28.ActionContext以及它和ContextMap的关系
ActionContext就是一个工具类,里面提供了可以便捷操作ContextMap的方法。
ActionContext:创建它就必须赋值一个Map
创建时间点:每次请求都会创建新的。放在核心过滤器中doFilter方法。
由于java ee应用是多线程的,它通过把ActionContext绑定到ThreadLocal上实现线程同步。
我们通过代码得知:要想获取该对象,需要调用ActionContext的静态方法getContext()
从当前线程上获取。
29.通过ActionContext存入数据
方法:
首先获取ActionContext,然后在使用ActionContext的put方法存入你的数据。
往ActionContext里的contexMap中存入数据。
第一种方式:
通过ServletActionContext获取特定的contextMap,然后在使用setAttribute方法。
第二种方式:
通过ActionContext的getXXX方法获取特定的contextMap,然后再使用put 方法存入自己的数据。
使用
代码测试:Struts2项目 Test.Demo05 Demo05文件夹
30.使用OGNL表达式获取ActionContext中的数据
借助Struts2的
我们现在获取的数据,都是在Map中。
获取Map中的数据,OGNL表达式的写法是:#key
例如:获取Session中的数据 #Session.XXX
代码测试:Struts2项目 Test.Demo05 Demo05文件夹
31.ValueStack的概述
ValueStack又称为 : 值栈
具有栈的功能,先进后出。
获取ValueStack: ActionContext.getValueStack();
三大方法:
pop() : 删除栈顶元素 改变的栈的结构
push() : 插入栈顶元素 改变栈的结构
peek() : 获取栈顶元素 不改变栈的结构
ValueStack的结构:
对象名称(包名+类名) 对象的数据
对象的数据又包含:
Property Name Property Value
32.往ValueStack中存入数据。
(1)Action类的成员变量,要有get/set方法。
该变量会存在ValueStack内当前执行的Action对象中。
(2)
第一步:
获取ValueStack: ActionContext.getValueStack();
第二步:
使用push()方法,往ValueStack中插入元素。
Property Name是ValueStack中存储对象的属性,名称和getXXX方法后保持一致
首字母改成小写。
代码测试:Struts2项目 Test.Demo06 Demo06文件夹
33.获取ValueStack的属性值
目的:使用OGNL表达式,是能根据属性的名称获取属性的值。
方法:使用
如果要获取模型驱动的对象的属性,则model.属性名。
原理:从栈顶中往下查找,找到名称相同,停止查找。
如果没有,再去ContextMap中去寻找
注意:如果不写value属性,默认取的是栈顶的第一个对象
获取指定位置的属性:
[下标].属性名称 下标从0开始
s:property标签的原理:
通过OGNL表达式获取数据时,调用的是ValueStack的findValue(String expr)
代码测试:Struts2项目 Test.Demo06 Demo06文件夹
34.Struts2框架对EL表达式的改变
原理:在Struts2框架中,Request的getAttribute方法被增强了。
原本的EL表达式的搜索范围:
Page Request Session application
该表后的EL表达式的搜索范围:
Page Request ValueStack ActionContext(Map部分) session application
35.各种符号的总结
% :
1、把OGNL表达式转成字符串 %{“”} %{‘’}
2、把字符串转成OGNL表达式 %{}
# :
1、获取ContextMap中的数据 #key
2、在页面中可以创建Map集合 #{}
$ :
1、EL表达式的使用 ${}
2、可以在struts2的配置中使用OGNL表达式(配置可以是xml文件,也可以注解) ${}
36.案例:使用OGNL表达式获取客户列表展示
使用s:iterator标签获取 类似于c:foreach标签
value : 是一个OGNL表达式
var :
1、写了该属性,标签会把var的值作为key,把当前遍历的对象作为value,
存入contextMap中
2、 不写该属性,标签会把每个对象压入栈顶
代码实现:Struts2Project1项目 修改findAllCustomer方法
37.拦截器的概述和作用
概述:拦截器是动态拦截Action调用的对象
作用:
1、在不修改源代码的基础上,对已有的方法进行动态增强。
2、在struts2中,拦截器它就是对我们的动作方法进行增强。(其实就是把重复性
的代码提取出来,然后放到拦截器中,统一管理,统一调用。)
38.自定义拦截器的步骤
(1)写一个普通类,继承AbstractInterceptor(也可以实现Interceptor接口)
(2)配置拦截器(仿照struts-default文件)
1、声明拦截器:在package内,action外声明
2、引用拦截器:在action标签的内部
(引入了自己的拦截器后,默认的拦截器就失效了)
代码实现:Struts2项目 Test.MyInterceptor Test.Demo07 Demo07文件夹
39.自定义拦截器的放行(可选)
不放行的话,只会执行拦截器方法的内容。返回相应的值,也会执行相应的结果视图。
放行的方法:
invocation.invoke();
代码实现:Struts2项目 Test.MyInterceptor Test.Demo07 Demo07文件夹
40.自定义拦截器的返回值
1、拦截器放行的方法所得到的返回值也就是动作方法的返回值。
即: invocation.invoke()==Action类的return值
2、在放行的前提下,自定义拦截器类执行完retrun后,页面才会显示出result视图。
3、在不放行的前提下,自定义拦截器返回的什么值,页面就会响应什么结果视图。
4、在放行的前提下,如果自定义拦截的返回值与Action类的返回值不一样时,
优先执行Action类返回的结果视图。
原理:
放行后,将Action类的返回视图写入缓冲区中,无论自定义拦截器
返回什么,都不影响缓存冲,等结束后,将缓冲区的内容输出到页面
代码实现:Struts2项目 Test.MyInterceptor Test.Demo07 Demo07文件夹
41.多个拦截器的执行顺序问题
由引用顺序决定,与声明的顺序无关。
代码实现:Struts2项目 Test.MyInterceptor Test.MyInterceptor2 struts.xml
42.自定义拦截器的案例—-检查登录拦截的使用
1、在全局的package中也可以声明自定义拦截器。
出现的问题:配置拦截器时,会报错。
解决的办法:global-results标签必须在interceptors标签的后面。
2、默认拦截器栈失效
发现问题的前提:
(1)Action类继承ServletRequestAware并实现setServletRequest方法
(2)定义一个HttpServletRequest类型的属性。
(3)在setServletRequest方法对属性进行赋值
出现的原因:默认拦截器失效后,不会自动的调用setServletRequest方法
解决的办法:在action标签重新引用默认拦截器栈
即:
3、声明自定义拦截器栈和引用拦截器栈
在package标签内声明:
在action标签内引用:
4、将自定义拦截器栈声明为默认拦截器栈
在package标签内:
5、排除某一个action不要使用默认拦截器栈
1、自定义拦截器类继承MethodFilterInterceptor,并实现doInterceptor方法
2、同样在方法内部进行检查,拦截功能的代码实现
3、在struts-xml配置文件中,写入不需要拦截器进行拦截的action
两个参数:
excludeMethods 写入不需要拦截的动作类方法
includeMethods 写入需要拦截的动作类方法
在interceptor-ref标签内:
..
代码实现:Struts2Project2项目
43.使用注解配置Struts2
前提:
另外需要导入的jar包:struts2-convention-plugin-2.3.24.jar
注解的内容:
44.基于Struts2注解的配置
声明自定义包和拦截器,就需要使用xml文件。引用时,使用注解。
1、@ParentPackage : 用于指定父包。在类,接口,包,枚举上都可使用。
@ParentPackage(“父包名”)
2、@Namespaces : 用于指定名称空间。在类,接口,包,枚举上都可使用。
3、@Action : 用于指定动作方法。 在方法上使用。
value=”Action的名称”
results={@Result(name=”” type=”” location=””)}
4、@Results : 用于配置结果视图。在类上使用代表全局视图
@Result(name=”” type=”” location=””)
name:指定是哪一个Action的结果视图。引用动作方法的返回值
type:指定前往结果视图的方式。转发,重定向等。
location:结果视图的位置。例如:/index.jsp
5、关于其它参数配置,就写在web.xml中
写在filter标签内。
例如:开启开发者模式
例如:指定注解的位置
中文乱码问题