回顾
1、Struts2框架的概述,前端控制器的模式,核心的过滤器
2、入门 编写 struts.xml配置文件
3、配置文件
配置文件的加载
4、Action类的编写和访问
在Struts2框架中使用Servlet的API
1、在Action类中也可以获取到Servlet一些常用的API
提供JSP的表单页面的数据,在Action中使用Servlet的API接收到,然后保存到三个域对象中,最后显示到JSP的页面上
提供JSP注册的页面
<form action="${pageContext.request.contextPath }/demo1Action.action" method="post">
姓名:<input type="text" name="username"/><br/>
密码:<input type="password" name="password"/><br/>
<input type="submit" value="注册"/>
</form>
2、完全解耦合的方式
Struts2框架提供了一个类,ActionContext类,提供了一些方法,通过方法获取Servlet的API
常用的方法
static.ActionContext.getContext() 获取ActionContext对象实例
Map<String,Object>getParameters() 获取请求参数,相当于request.getParameterMap()
Map<String,Object>getSession() 获取的代表session域的Map集合,相当于操作session域
Map<String,Object>getApplication() 获取的代表application域的Map集合
void put(String key,Object value) 向request域存入值
3、使用原生Servlet的API的方式
Struts2框架提供了一个类,ServletActionContext 提供了一些静态的方法
getPageContext()
getRequest()
getResponse()
getServletContext()
页面的跳转
1、结果页面存在两种方式
全局结果页面
条件:如果<package>包中deec一些action都返回success,并且返回的页面都是同一个JSP页面,这样就可以配置全局的结果页面
全局结果页面针对的当前的包中的所有的Action,但是如果局部还有结果页面,会优先局部的,使用的标签
<global-results>
<result name="success">/demo1/suc.jsp</result>
</global-results>
局部结果页面
<result name="success">/demo1/suc.jsp</result>
2、结果页面的类型
结果页面使用<result>标签进行配置,包含两个属性
name 逻辑视图的名称
type 跳转的类型,一些常用的类型,常见的结果类型在struts-default.xml查找[重定向请求的参数没了 2个请求了]
dispatcher 转发,type的默认值.Action-->JSP
redirect 重定向Action-->JSP
chain 多个action之间跳转,从一个action转发到另一个Action。Action-->Action
redirectAction 多个action之间跳转,从一个action重定向到另一个Action。Action-->Action
stream 文件下载时使用
框架的数据封装
1、使用的原因
作为MVC框架,必须要负责解析HTTP请求参数,并将其封装到Model对象中
封装数据为开发提供了很多方便
Struts2框架提供了很强大的数据封装的功能,不再需要使用Servlet的API完成手动封装了
2、Struts2提供了两类数据封装的方式
第一种:属性驱动
提供对应属性的set方法进行数据封装
表单的哪些属性需要封装数据,那么在对应的Action类中提供该属性的set方法即可
表单中的数据提交,最终找到Action类的setXxx的方法,最后赋值给全局变量
Struts2框架采用的拦截器完成数据的封装
方式不是很好,因为属性很多,提供特别多的set方法,而且还需要手动将数据存入到对象中
这种情况下,Action类就相当于一个JavaBean,没有体现MVC的思想,Action类又封装数据,又接受请求处理,耦合性较高
在页面上使用OGNL表达式进行数据封装
页面中使用OGNL表达式进行数据的封装,就可以直接把属性封装到某一个JavaBean的对象中
在页面中定义一个JavaBean,并且提供set方法:例如 private User user;
页面中的编写发生了变化,需要使用OGNL的方式,表单中的写法<input type="text" name="user.username">
只提供一个set方法还不够,必须还需要提供user属性的get和set方法
先调用set方法,判断一下是否有user对象的实例对象,如果没有,调用set方法把拦截器创建的对象注入进来
第二种方式:模型驱动
使用模型驱动的方式,也可以把表单中的数据直接封装到一个JavaBean的对象中,并且表单的写法和之前的写法没有区别
编写的页面不需要任何变化,正常编写name属性的值
模型驱动的编写步骤
手动实例化JavaBean:private User user = new User();
实现ModelDriver<T>接口,实现getModel()方法,在getModel()方法中返回user
数据封装到集合中
1、封装复杂类型的参数(集合类型Collection、Map接口等)
2、页面中可能想批量添加一些数据,那么就可以使用集合。把数据封装到集合中
3、把数据封装到Collection中
因为Collection接口都会有下标值,所以页面的下标会有一些区别
<input type="text" name="products[0].name"/>
在Action中的写法 需要提供products的集合,并且提供get和set方法
4、把数据封装到Map中
Map集合是键值对的形式,页面的写法
<input type="text" name="map['1'].username"/>
Action中提供map集合,并且提供get和set方法
Struts2的拦截器
1、概述
拦截器就是AOP(Aspect-Oriented Programming)的一种实现,(AOP是指用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作)
过滤器:过滤从客户端发送到服务器请求的
拦截器:拦截对目标Action中的某些方法进行拦截
拦截器不能拦截JSP
拦截到Action中某些方法
2、拦截器和过滤器的区别
拦截器是基于JAVA反射机制的,过滤器是基于函数回调的
过滤器依赖于Servlet容器,而拦截器不依赖于Servlet容器
拦截器只能对Action请求起作用(Action中的方法)而过滤器可以对几乎所有的请求起作用(CSS JSP JS)
拦截器采用责任链模式
在责任链模式里,很多镀锡由每一个对象对其下家的引用而连接起来形成一条链
责任链每一个节点,都可以继续调用下一个节点,也可以阻止流程继续执行
在Struts2中可以定义多个拦截器,将多个拦截器按照特点顺序 组成拦截器栈(顺序调用 栈中的每一个拦截器)
3、在Struts2的核心是拦截器,运行流程
web.xml->org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter->#doFilter->execute.executeAction->dispatcher.serviceAction->创建代理对象->proxy.execute()->invocation.invoke() 迭代调用拦截器
自定义拦截器和配置
1、编写拦截器,需要实现Interceptor接口 实现接口中的三个方法
interceptor接口有很多的实现类,编写最简单的方式就是继承AbstractInterceptor实现类
public String intercept(ActionInvocation invocation){
User user = ServletActionContext.getRequest().getSession.getAttribute("existUser");
if(user == null){
} else{
//放行
return invocation.invoke();
}
}
2、需要在struts.xml中进行拦截器的配置,一共有两种方式
第一种
在<package>包中定义拦截器,出现在<package>包的上方
<interceptors>
//调用了拦截器
<interceptor name="DemoInterceptor" class="my.interceptor.DemoInterceptor"></interceptor>
</interceptors>
在某个action中加入拦截器
<interceptor-ref name="DemoInterceptor"/>
如果引入了自己定义的拦截器,那么Struts2框架默认的拦截器就不会再执行了,所以需要引入Struts2默认的拦截器
<interceptor-ref name="defaultStack"/>
第二种
在<package>包中定义拦截器的时候,自己直接定义一个拦截器栈
<interceptors>
<interceptor name="DemoInterceptor" class="my.interceptor.DemoInterceptor"></interceptor>
<!-- 定义拦截器栈 -->
<interceptor-stack name="myStack">
<interceptor-ref name="DemoInterceptor"></interceptor-ref>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
在Action包中引入自己定义的拦截器栈
<interceptor-ref name="myStack"></interceptor-ref>
使用拦截器判断用户是否已经登录