Struts2的Action继承com.opensymphony.xwork2.ActionSupport类。
Struts2的配置文件中引入了package的概念,所有的action,result都必须配置到package中。package具有继承的特性,子package里的action可以使用父package里的资源。
Struts2的struts.xml配置文件
<?xmlversion="1.0" encoding="UTF-8"?>
<!DOCTYPE strutsPUBLIC "-//Apache Software Foundation//DTD Struts Configuration2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<!--name是包名,extends是继承父类的包名
abstract:设置package的属性为抽象的,抽象的package不能定义action,值true:false
namespace:定义package命名空间,该命名空间影响到url的地址,例如该命名空间为/test,那么访问的地址为http://localhost:8080/struts2/test/xx.action
-->
<struts>
<package name="main" extends="struts-default">
<interceptors>
<!--定义拦截器
name:拦截器名称
class:拦截器类路径
-->
<interceptor name="timer" class="com.kay.timer"></interceptor>
<interceptor name="logger" class="com.kay.logger"></interceptor>
<!--定义拦截器栈-->
<interceptor-stack name="mystack">
<interceptor-ref name="defaultStack">< interceptor-ref >
<interceptor-ref name=”timer”>< interceptor-ref >
<interceptor-ref name=”logger”>< interceptor-ref >
</interceptor-stack>
</interceptors>
<!--name:action名称
class:对应的类路径
method:调用Action的方法名
-->
<action name="login" class="com.login.action.LoginAction">
<result name="success">/welcome.jsp</result>
</action>
</package>
<!—struts2还有一个配置文件为struts.properties,内容为键值对的形式。
在struts.xml中可以用<constant>来配置struts2的属性,与struts.properties的作用是一样的
-->
<constant name="" value=""></constant>
</struts>
web.xml里的配置
<?xml version="1.0"encoding="UTF-8"?>
<web-appxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"version="2.5">
<!-- 配置Struts2框架的核心Filter-->
<filter>
<!-- 配置Struts2框架核心Filter的名字-->
<filter-name>struts2</filter-name>
<!-- 配置Struts2框架核心Filter的实现类-->
<!--在web.xml里面配置Struts,2.1.2之前的版本用下面这个 -->
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
<!--2.1.3 以后的版本用下面这个 -->
<!--<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>-->
</filter>
①核心过滤器StrutsPrepareAndExecuteFilter作为一个filter负责拦截所有的用户请求,该filter会过滤用户请求,然后将请求交给struts2框架处理
<filter-mapping>
<filter-name>struts2</filter-name>
<!-- 对全部请求url进行拦截(过滤)-->
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
②业务控制器就是用户自己实现的Action类,Action类中通常包含一个execute方法。该方法返回一个字符串,字符串与struts.xml中的result标签的name相对应,用于跳转到不同的页面。
1.访问Servlet API
Struts2提供了3种方式去访问Servlet API
01.ActionContext 上下文类,返回的都是map形式
例如:ActionContext context = ActionContext.getContext();
Map<String,Object> session = context.getSession();
02.实现***Aware接口 (implements requestAware applicationAware sessionAware)
private Map<String,Object> request;
private Map<String,Object> application;
private Map<String,Object> session;
public void setRequest(Map<String,Object> request){
this.request = request;
}
public void setRequest(Map<String,Object> application){
this.application = application;
}
public void setRequest(Map<String,Object> session){
this.sessison = session;
}
03.ServletActionContext
2.Action的搜索顺序
http://localhost:8080/struts2/path1/path2/path3/student.action
第一步:判断package是否存在,如path1/path2/path3
如果存在
第二步判断action是否存在,如果不存在则去默认的namespace的package里面寻找action
第三步:如果没有,则报错
如果不存在
第二步:检查上一级路径的package是否存在(直到默认的namespace),重复第一步
第三步:如果没有,则报错
3.动态方法调用
动态方法调用就是为了解决一个Action对应多个请求的处理,以免Action太多。
01.method方法,在<action>里添加method属性。
01.感叹号的方式
<action name=”helloWorld” class=””>
<result name = “add”>/add.jsp</result>
<result name= “update”>/update.jsp</result>
</action>
浏览器访问的时候:localhost:8080/Login/helloWord!add.action(helloWorld是action的名字,add是方法的名称,Login是项目名)
02.通配符的方式:
<action name=”helloWorld_*”method=”{1}” class=””>
<result name = “add”>/{1}.jsp</result>
<result name= “update”>/{1}.jsp</result>
</action>
4.指定多个配置文件
如果Action特别多,把他们全配置到一个struts.xml,文件会非常大。怎么解决那?
指定多个配置文件,根据模块,每个模块可以有自己的struts配置文件。通过一个总的struts.xml来进行添加和包含就可以了。
<includefile=”login.xml”></include>
<includefile=”system.xml”></include>
可以在每个配置文件加下面这句,保证编码不会乱
<constant name="struts.i18n.encoding" value="UTF-8" />
5.默认Action(访问错误路径的时候,走默认Action)
<package>
<default-action-refname=”index”></default-action-ref >
</package>
6.Struts2后缀(value的值就是更改了struts的后缀改变了)
<constantname=”struts.action.extension” value=”html”></constant>
7.接收参数
01.使用Action的属性接收参数(在Action中添加属性以及属性的getset方法,属性名要和表单中的name属性值一样)
02.使用Domain Model接收参数。如果属性很多,可以把属性放到一个类里(譬如对于登录,可以把用户名和密码放到user类里),然后在action中建立User user对象获取参数,不同的参数怎么对应,应该在表单的name属性中写user.username,user.password。
03.使用ModelDriven接收参数
Action必须实现ModelDriven<T>接口。泛型类,需要赋值转换的类ModelDriven<User>
重写方法getModel(),返回当前需要转换的对象,return user。get set 方法要去掉,然后user对象要实例化。privateUser user = new User();然后在form表单中也不需要指定user.username中的user了。只需要name=”username”。
获取list值时,前面form表单中name属性中可以写booklist[0]
8.处理结果类型
处理结果是字符串
<result name=”success”>/success.jsp</result>
Result元素中name就是result元素的逻辑视图名称
<result >/success.jsp</result>
如果省略了name属性,系统将采用默认的name属性值,默认的name值是success。
路径前面是有个/,带着斜杠是个绝对路径,开始是整个项目的上下文路径,如果不带/,相当于我们执行的Action的namespace指定的路径。
有5个内置的属性:
SUCCESS表示Action正确执行完成,返回相应的视图,success是name属性的默认值;
NONE 表示Action正确执行完成,但不返回任何视图
ERROR 表示Action执行失败,返回到错误处理视图
LOGIN Action因为用户没有登录的原因没有正确执行,将返回登录视图,要求用户进行登录验证。
INPUT Action的执行,需要从前端界面获取参数,INPUT就是代表这个参数输入的界面,一般在这个应用中,会对这些参数进行验证,如果验证没有通过(参数类型转换错误,或者addFieldError里有值)将自动返回到该视图。
if(user.getUsername()==null|| “”.equals(user.getUsername())){
this. adddFieldError(“username”,”用户名不能为空”);
returnINPUT;//如果添加这个肯定是会返回input界面,如果不想写这句,要把这些代码写到validate()方法中,会自动跳转
}
在jsp页面中,<%@ tagliburi="/struts-tags" prefix="s"%>
<s:fielderrorname=”username”></s:fielderror>
重写validate()方法
publicvoid validate(){
}
处理结果是通过在struts.xml使用<result>标签配置结果。根据位置的不同,分为两种结果:
局部结果:将<result>作为<action>元素的子元素配置
全局结果:将<result>作为<global-results>元素的子元素配置
<global-results>
<result name=”ERROR404”></result>
</global-results>
<result>还有子标签:<param>具有两个属性
01.<paramname=”location”>
<param name=”parse”>false</param>
location:该属性定义了该视图对应的实际视图资源
parse:该参数指定是否可以在实际视图名字中使用OGNL表达式。该属性默认为true
在< result type=””>还有个重要的属性就是type,type的默认值为dispatcher,这个类型支持JSP视图技术。
Struts2的拦截器
Struts2的运行过程
首先客户端通过HttpServletRequest向servlet容器,也就是tomcat提交一个请求,这个请求会经过一系列的过滤器(像ActionContextCleanUp),最终会被struts的核心控制器所过滤的就是FilterDispatcher(从struts2的2.1.3版本以后struts2的核心控制器发生了变化,变成了StrutsPrepareAndExecuteFilter),被核心控制器过滤后,核心控制器会访问ActionMapper来决定是否要调用某个action(也就是用户是否要请求某一个action,如果用户请求其它资源则不会访问我们的action),如果决定需要调用某个action,这个时候struts的核心控制器会把控制权委派给AcionProxy,这个时候代理会通过配置管理器ConfigurationManager来加载struts的核心配置文件struts.xml,如果在struts.xml文件中找到了我们需要调用的action后, AcionProxy会创建一个ActionInvocation的实例, ActionInvocation里包括了所创建的action的实例,同时还包括了许多拦截器,在调用action之前或之后它还需要调用非常多的拦截器。当拦截器反向执行完才会执行最终请求的响应,通过HttpServletResponse去响应客户端的请求。
Sturts2大多数核心功能是通过拦截器实现的,每个拦截器都完成每项功能.
拦截器方法在Action执行之前或之后执行
拦截器栈:相当于多个拦截器组合起来的.
拦截器执行过程,拦截器1---拦截器2--…--action—result—拦截器2—拦截器1
如何定义一个拦截器那?
1. 实现Interceptor接口
有3个抽象方法:
void init():初始化拦截器所需资源
void destroy():释放在init()中分配的资源
String intercept(ActionInvocation ai) throws Exception
实现拦截器功能
利用ActionInvocation参数获取Action状态
返回result字符串作为逻辑视图
2. 继承AbstractInterceptor类,它也实现了Interceptor接口
对init()方法和destroy()方法做了空实现
只需要实现intercept方法即可
一般采用这个方法定义拦截器
拦截器示例:计算Action的执行时间
01. 创建拦截器
publicclass TimeInterceptor extends AbstractInterceptor {
/*
* 计算执行action话费的时间
*/
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//1.在action执行之前
long start = System.currentTimeMillis();
//2.执行下一个拦截器,如果已经是最后一个拦截器,则执行目标Action
String result = invocation.invoke();
//3.执行action之后
long end = System.currentTimeMillis();
System.out.println("执行action话费的时间"+(end-start)+"ms");
return result;
}
}
02. 在配置文件中配置拦截器并引用它
<interceptors>
<interceptor name ="mytimer" class="com.interceptor.TimeInterceptor">
</interceptor>
</interceptors>
<interceptor-ref name="mytimer"></interceptor-ref>
Sturts2内建拦截器
params拦截器:负责将请求参数设置为Action属性
staticParams拦截器:通过在struts.xml中为action元素配置子元素param,从而来实现为action中的属性进行赋值
servletConfig拦截器:将源于Servlet API各种对象注入到Action,必须实现对应接口
fileUpload拦截器:对文件上传提供支持,将文件和元数据设置到对应的Action属性
exception拦截器:捕获异常,并且将异常映射到用户自定义的错误页面
validation拦截器:调用验证框架进行数据验证
还有很多内置的拦截器,可以在struts2-core.jar包里有个struts-default.xml中看到。struts在启动时会自动加载。
默认拦截器栈
在struts-default.xml中定义一个defaultStack拦截器栈,并将其指定为默认拦截器。
只要在定义包的过程中继承struts-default包,那么defaultStack将是默认的拦截器。
当为包中的某个action显示指定了某个拦截器,则默认的拦截器不会起作用, 必须显示指定默认拦截器。
如果我们没有为action显示指定拦截器,那么默认会使用defaultStack。
拦截器栈中的各个拦截器的顺序很重要。
publicclass TimeInterceptor extends AbstractInterceptor {
@Override
public String intercept(ActionInvocation invocation) throws Exception {
ActionContext context = ActionContext.getContext();
Map<String,Object> session =context.getSession();
if(session.get(“loginInfo”)!=null){
String result =invocation.invoke();
return result;
}else{
return “login”;
}
我们可以自定义拦截器栈将自定义的拦截器和默认的拦截器组合在一起
<interceptors>
<interceptorname = “auth” class=””></interceptor>
<interceptor-stack name =“”><!--自定义的拦截器栈-->
<interceptor-ref name =“defaultStack”></interceptor-ref>
<interceptor-ref name =“auth”></interceptor-ref>
</interceptor-stack>
</interceptors>