我承认我的锅,昨天偷懒了emmm
今天学习Struts2~~
目录
一、Struts2简介
在介绍 Struts2之前,先来认识一下 Struts。 Struts1是最早的基于MVC模式的轻量级Web框架它能够合理的划分代码结构,并包含验证框架、国际化框架等多种实用工具框架。但是随着技术的进步, Struts的局限性也越来越多的暴露出来。为了符合更加灵活、高效的开发需求, Struts2框架应运而生。
Struts2框架Struts1的下一代产品,是在 Struts和 Webwork技术的基础上进行合并后的全新框架( Webwork是由 Opensymphony组织开发的,致力于组件化和代码重用的J2 EE Web框架,它也是个MVC框架)。虽然 Struts.2的名字与 Struts1相似,但其设计思想却有很大不同。实质上, Struts2是以 Webwork为核心的,它采用拦截器的机制来处理用户的请求。这样的设计也使得业务逻辑控制器能够与 Servletapi完全脱离开,所以 Struts2可以理解为 Webwork的更新产品。
那么Struts2框架相比原先的一些Web框架有哪些优势呢?
- 项目目开源,使用及拓展方便,天生优势
- 提供 Exception处理机制
- Result方式的页面导航,通过 Result标签很方便的实现重定向和页面跳转
- 通过简单、集中的配置来调度业务类,使得配置和修改都非常容易
- 提供简单、统一的表达式语言来访问所有可供访问的数据
- 提供标准、强大的验证框架和国际化框架
- 提供强大的、可以有效减少页面代码的标签
- 提供良好的Ajax支持
- 拥有简单的插件,只需放入相应的JAR包,任何人都可以扩展 Struts2框架,比如自定义拦截器自定义结果类型、自定义标签等,为 Struts2定制需要的功能,不需要什么特殊配置,并且可以发布给其他人使用
- 拥有智能的默认设置,不需要另外进行繁琐的设置。使用默认设置就可以完成大多数项日程序开发所需要的功能。
为了让大家对Struts2有个直接的认识,奉上宝图一份!
二、搭建Struts框架
我们先从官网上下载下来Struts2框架,解压后将相应的jar包导入我们的工程当中去,工程中主要使用的jar包有下面这些:
接下来我们来配置struts.xml文件:
<struts>
<package name="hello" namespace="/hello" extends="struts-default" >
<action name="HelloAction" class="aciton.HelloAction" method="hello" >
<result name="success">/hello.jsp</result>
</action>
</package>
</struts>
将struts2核心过滤器配置到web.xml文件当中:
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
给出一个示例的Demo吧:
public class HelloAction {
public String hello(){
System.out.println("hello world!");
return "success";
}
}
现在我们测试一番,运行!
测试成功,那接下来我们简单说说上面struts.xml文件当中的配置与我们的HelloAction的关系吧。
package:将Action配置封装.就是可以在Package中配置很多action.
name属性: 给包起个名字,起到标识作用.随便起.不能其他包名重复.
namespace属性:给action的访问路径中定义一个命名空间
extends属性: 继承一个 指定包
abstract属性:包是否为抽象的; 标识性属性.标识该包不能独立运行.专门被继承
action元素:配置action类
name属性: 决定了Action访问资源名.
class属性: action的完整类名
method属性: 指定调用Action中的哪个方法来处理请求
result元素:结果配置
name属性: 标识结果处理的名称.与action方法的返回值对应.
type属性: 指定调用哪一个result类来处理结果,默认使用转发.
标签体:填写页面的相对路径
三、配置详解
1、struts.xml配置
struts.xml基本配置在上一节的最后已经给出来了,那么只在这里补充一条,引入外部的struts.xml文件,这需要用到:
<include file="action/struts.xml" />
2、struts2常量配置
我们先来查看一下struts2-core.jar中有关struts2的常量的默认配置吧配置,在这个jar包的org.apache.struts2的default.properties
根据这个默认的配置文件,我们来配置我们的struts.xml文件:
<!-- i18n:国际化. 解决post提交乱码 -->
<constant name="struts.i18n.encoding" value="UTF-8" />
<!-- 指定反问action时的后缀名
http://localhost:8080/struts2_day01/hello/HelloAction.do
-->
<constant name="struts.action.extension" value="action" />
<!-- 指定struts2是否以开发模式运行
1.热加载主配置.(不需要重启即可生效)
2.提供更多错误信息输出,方便开发时的调试
-->
<constant name="struts.devMode" value="true" />
这里配置的常量是按照配置的顺序顺序执行的~
当然,配置struts2常量的方式不止这么一条,也可以在src/struts.properties或者是web.xml中配置,这里就不仔细说明了。
3、struts2配置进阶
我们在struts.xml文件当中配置如下内容。
<!-- 动态方法调用方式1:配置动态方法调用是否开启常量
默认是关闭的,需要开启
选用这个方式的话,那么在调用时有如下格式:/action/Demo!find.action
重点是这个叹号!,是格式要求
-->
<constant name="struts.enable.DynamicMethodInvocation" value="false"></constant>
<package name="dynamic" namespace="/dynamic" extends="struts-default" >
<!-- 动态方法调用方式2:通配符方式
使用{1} 取出第一个星号通配的内容
-->
<action name="Demo1Action_*" class="cn.itheima.b_dynamic.Demo1Action" method="{1}" >
<result name="success" >/hello.jsp</result>
</action>
</package>
我们主要使用的是动态方法调用方式2!!!
四、Action类详解
Action类的书写方式大致有三种:一种是直接创建一种POJO,不继承任何父类也不实现任何方法;另一种是实现一个Action接口,里面有execute方法,并且提供实现的规范;最后一种最常用,继承ActionSupport类:
//方式3: 继承一个类.ActionSupport
// 帮我们实现了 Validateable, ValidationAware, TextProvider, LocaleProvider .
//如果我们需要用到这些接口的实现时,不需要自己来实现了.
public class Demo5Action extends ActionSupport{
}
五、Struts进阶
1、结果跳转方式
1.转发
<!-- 转发 -->
<action name="Demo1Action" class="cn.itheima.a_result.Demo1Action" method="execute" >
<result name="success" type="dispatcher" >/hello.jsp</result>
</action>
2.重定向
<!-- 重定向 -->
<action name="Demo2Action" class="cn.itheima.a_result.Demo2Action" method="execute" >
<result name="success" type="redirect" >/hello.jsp</result>
</action>
3.转发到Action
<!-- 转发到Action -->
<action name="Demo3Action" class="cn.itheima.a_result.Demo3Action" method="execute" >
<result name="success" type="chain">
<!-- action的名字 -->
<param name="actionName">Demo1Action</param>
<!-- action所在的命名空间 -->
<param name="namespace">/</param>
</result>
</action>
4.重定向到Action
<!-- 重定向到Action -->
<action name="Demo4Action" class="cn.itheima.a_result.Demo4Action" method="execute" >
<result name="success" type="redirectAction">
<!-- action的名字 -->
<param name="actionName">Demo1Action</param>
<!-- action所在的命名空间 -->
<param name="namespace">/</param>
</result>
</action>
2、访问ServletAPI方式
在这里最重要的一个类就是——ActionContext,我们昵称它为数据中心,因为通过它,我们能够获得所有的Servlet使用的API!见下图:
怎么使用ActionContext呢?这里也给出一个Demo吧ლ(・´ェ`・ლ)
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
//如何在action中获得原生ServletAPI
public class Demo5Action extends ActionSupport {
public String execute() throws Exception {
//request域 => map (struts2并不推荐使用原生request域)
//不推荐
Map<String, Object> requestScope = (Map<String, Object>) ActionContext.getContext().get("request");
//推荐
ActionContext.getContext().put("name", "requestTom");
//session域 => map
Map<String, Object> sessionScope = ActionContext.getContext().getSession();
sessionScope.put("name", "sessionTom");
//application域 => map
Map<String, Object> applicationScope = ActionContext.getContext().getApplication();
applicationScope.put("name", "applicationTom");
return SUCCESS;
}
}
我们也能通过ServletActionContext或者通过实现如ServletRequestAware(在Struts2的jar包当中有很多以Aware结尾的类,都是我们可以继承过来的类),由于Struts2 并不推荐这两种方式,那我们就不再仔细讲述。
3、如何获得参数
与Servlet一点不同是,Action是线程安全的,可以使用成员变量来接受参数。
获得参数的方式有三种:
1.属性驱动
2.对象驱动
3.模型驱动
4、集合类型参数封装
在实际的开发当中,有时候我们需要批量插入用户或其他对象,在Action中需要接收到这多个Action中的封装对象,然后传递给业务层。那么这个时候就需要将表单的数据封装。
Struts2有两种集合类型的参数封装——list和map。
我们给出示例代码吧~
先编写页面:
<form action="${pageContext.request.contextPath}/Demo11Action" method="post" >
list:<input type="text" name="list" /><br>
list:<input type="text" name="list[3]" /><br>
map:<input type="text" name="map['haha']" /><br>
<input type="submit" value="提交" />
</form>
然后是工程代码:
import java.util.List;
import java.util.Map;
import com.opensymphony.xwork2.ActionSupport;
//struts2 封装集合类型参数
public class Demo11Action extends ActionSupport {
//list
private List<String> list;
//Map
private Map<String,String> map;
public String execute() throws Exception {
System.out.println("list:"+list);
System.out.println("map:"+map);
return SUCCESS;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public Map<String, String> getMap() {
return map;
}
public void setMap(Map<String, String> map) {
this.map = map;
}
}
对于list而言,我们可以在表单当中直接设置传递的参数,如上面写的list[3],表示直接将参数传递到list集合当中属于 3 的位置,也可以不指定位置,而让list根据传递的参数自动向后;对于map集合,我们则需要给出对应的键,如上面的map['haha'],这样才能从表单当中获取到相应的value值。
5、OGNL表达式
OGNL是Object-Graph Navigation Language的缩写,它是一种功能强大的表达式语言,通过它简单一致的表达式语法,可以存取对象的任意属性,调用对象的方法,遍历整个对象的结构图,实现字段类型转化等功能。它使用相同的表达式去存取对象的属性。
Struts2默认的表达式语言就是OGNL,它有下面这几个特点:
OGNL表达式有三个要素:表达式(表示做什么)、根对象(Root,表示对谁操作)、Context对象(规定在哪里进行操作,在表达式中访问对象的格式为#对象名称)。
Valuestack是 Struts的一个接口,字面意义为值栈, Ognl Valuestack是 Valuestack的实现类,客户端发起一个请求 struts2架构会创建一个 action实例同时创建一个 Ognl Valuestack值栈实例Ognl Valuestack(包括两个部分,值栈和map即ognl上下文)贯穿整个 Action的生命周期, struts2中使用OGNL将请求 Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。
我们如何操作值栈呢?
· #号
<s:property value="#request.name" /> 获取context的数据
<s:radio list="#{'1':'男', '2':'女'}" name="sex" /> 构建map集合等等
· %号
强制解析OGNL表达式
<s:textfield name="name" value="%{#request.name}" />
强制不解析OGNL表达式
<s:peoperty value="%{'#request.name'}" />
· $号
可以在配置文件当中使用OGNL表达式
6、拦截器
拦截器,在AOP( Aspect-oriented Programming)中用于在某个方法或字段被访问之前,进行拦截然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
在 Webwork的中文文档的解释为拦截器是动态拦截 Action调用的对象。它提供了一种机制可以使开发者可以定义在一个 action执行的前后执行的代码,也可以在一个 action执行前阻止其执行。同时也是提供了一种可以提取 action中可重用的部分的方式。
谈到拦截器,还有一个词大家应该知道一一拦截器链( Interceptor Chain,在 Struts2中称为拦截器栈 Interceptor Stack)。拦截器链就是将拦祓器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。
拦截器的实现原理是什么?
大部分时候,拦截器方法都是通过代理的方式来调用的。 Struts2的拦截器实现相对简单。当请求到达 Struts2的 Servletdispatcher时, Struts2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表,最后一个一个地调用列表中的拦截器。
Struts2拦截器是可插拔的,拦截器是AOP的一种实现。 Struts2拦截器栈就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,Suts2拦截器链中的拦截器就会按其之前定义的顺序被调用。
Struts2的执行流程大约如下图:
在程序开发过程中,为了满足我们不同的需要,我们有时需要创建自己的拦截器类,这就需要直接或间接的实现com.opensymphony.xwork2.interceptor.Interceptor接口。它定义的代码如下:
public interface Interceptor extends Serializable {
void init();
void destory();
String Intercept(ActionInvacation invocation) throws Exception;
}
在实际开发当中,为了更好的实现自定义拦截器,我们更常用继承抽象拦截器类AbstractInterceptor,它提供了init和destroy的空实现,使用实可以直接继承而不必要实现不需要的方法。
它的配置方法十分简单,给个例子~
<!-- name:指定拦截器名称
class:指定拦截器实现类
param:指定拦截器传入参数
-->
<interceptor name="interceptorName" class="interceptorClass">
<param name="paramName">paramValue</param>
</interceptor>
在实际开发中,我们经常使用多个拦截器,这时我们将拦截器组成拦截器栈组合使用。语法如下:
<!-- 指定拦截器 -->
<interceptors>
<!-- 指定拦截器栈 -->
<interceptor-stack name="inteceptorStackName">
<!-- 申明多个拦截器 -->
<interceptor-ref name="interceptorName" />
...
</interceptor-stack>
</interceptors>
Struts2的内容比我想象的要多emmm
现在才复习完一遍blbl
一会儿继续学习,我是小昶,我们明天再见~~
欢迎关注我们的公众号:落饼枫林,一起交流讨论学习那点事儿