1. package元素
作用:
在struts2的配置文件中引入了面向对象的思想,使用了分包管理 。易于管理动作类。便于模块化开发动作类
属性:
name | 包的名称。必须写,且必须唯一 |
extends | 一般情况下需要继承struts-default包,但不是必须的 不过如果不继承的话,将无法使用struts2提供的核心功能 struts-default.xml中定义这struts-default这个包 而struts-default.xml是在我们的struts.xml加载之前加载 |
abstract | 把包声明为抽象包,如果为true则表示为抽象包 只要没有action标签元素的包,都可以被声明为抽象包,这一点和java类似 |
namespace | 名称空间。[访问路径=名称空间+动作名称] 默认取值为"" |
namespace注意事项
注意:默认值不是/,写自定义的namespace时前面要加上/
下面这一例子的访问路径是 项目虚拟路径/user/hello
注意:需要在访问action前添加红色命令空间
注意:如果访问 项目虚拟路径/user/a/b/hello是可以访问到的
如果访问 项目虚拟路径/a/b//user/hello是不可以访问到的
上面这种情况与namespace的查找规则有关
2. action元素
作用:
配置动作,处理请求路径
属性:
name:动作名称
class:动作类全名
method:动作类中的方法名称。默认是public String excute(){}
方法的要求:
1. public修饰
2. 返回值必须是String
3. 无参
动作类的第一种写法:
直接创建一个action类,不需要继承任何类,然后在struts.xml中配置
Action:
struts.xml
访问路径:http://localhost:8080/项目名/user/hello
动作类的第二种写法:
Action:
struts.xml:
访问路径为:http://localhost:8080/struts_1_war_exploded/user/hello1
Action接口中会有一些静态常量,如下图:
这些常量就是定义了一些固定的常用值,可以在implements了Action接口之后的action类里面使用
常量说明:
常量的变量名 | 对应的值 | 说明 |
SUCCESS | success | 动作方法执行一切ok |
ERROR | error | 动作方法执行时遇到了异常 |
INPUT | input | 回显(提交表单,返回页面之后,继续显示之前所打的数据) |
LOGIN | login | 一般转向登录页面 |
NONE | none | 不转向任何的视图 |
动作类的第三种写法:
写个 Action 类继承 ActionSuport 接口 [ 推荐使用这种方式 ]
ActionSupport 是实现 Action 接口的类,如果动作类方法体里面没有写excute方法,则会去父类Action中调用excute方法
import com.opensymphony.xwork2.ActionSupport;
public class HelloAction2 extends ActionSupport {
}
<!--这个action没有配置method,默认会访问Action的excute()方法
在HelloAction2里没有实现excute方法,找的是父类ActionSupport的excute()方法
-->
<action name="hello2" class="com.zr.web.action.HelloAction2">
<result name="success">/success.jsp</result>
</action>
默认的动作类
在struts-default.xml中定义了默认动作类和方法,当我们在action中没加class和method属性,那么会默认执行默认动作类
就是com.opensymphony.xwork2.ActionSupport这个类
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
我们自己也可以配置一个默认的动作类,在struts.xml中的package里面添加一个默认动作类,注意要将这个默认标签放在action标签前面,要不然会报错,也可以根据错误提示进行修改顺序
注意:一般很少修改
<default-class-ref class="com.opensymphony.xwork2.ActionSupport"></default-class-ref>
动作访问之通配符
* 通配符
Action的name属性如果写的是 * 表示自动填充输入的name名
Action的method属性如果写的是 {1} 表示前面的 * 所填充的name名
Action中的result标签中如果写的是 /{1}.jsp 表示前面的 * 所填充的name名
** 通配符
Action的name属性如果写的是 *_* 表示自动填充输入的name名
Action的method属性如果写的是 {1}{2} 表示前面的 *_* 所填充的name名
Action中的result标签中如果写的是 /{1}{2} .jsp 表示前面的 *_* 所填充的name名
比如创建一个UserAction,其中定义了一些方法,如deleteUser,addUser
当访问 delete_User,那么会自动填充上面的method中的1和2参数,自动去掉 _ ,为deleteUser,return一个值,查询result的name属性是否存在这个return的值,如果存在则,自动访问标签内部的路径,去掉_,自动填充1和2参数,则会自动访问deleteUser.jsp
动态方法的调用
写一个名为StudentAction的action类
import com.opensymphony.xwork2.ActionSupport;
public class StudentAction extends ActionSupport {
public String addStudent(){
return SUCCESS;
}
public String deleteStudent(){
return SUCCESS;
}
}
在struts.xml中配置动态调用方法的常量值为true,并且设置一个action,如下:
<struts>
<!--配置常量-->
<!--配置开发者模式-->
<constant name="struts.devMode" value="true"></constant>
<!--配置动态调用方法开启-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<package name="p1" extends="struts-default" namespace="/student">
<action name="student" class="com.zr.web.action.StudentAction">
<result name="success">/success.jsp</result>
</action>
</package>
</struts>
那么访问路径为:
http://localhost:8080/struts_1_war_exploded/student/student!addStudent
那么会调用StudentAction中的addStudent方法
3. result元素
作用:
为指定动作指定结果视图
属性:
name:逻辑视图的名称,对应着动作方法的返回值。默认值是success
type:结果类型,指的是用什么方式转到定义的页面。默认是dispatcher
result中type的取值
result中type的取值有四种类型
dispatcher | (默认值)使用请求转发,转向一个页面 |
redirect | 使用重定向,转向一个页面 |
chain | 转发到另一个相同名称空间的动作 转发到不同名称空间的动作 |
redirectAction | 重定向到另一个相同名称空间的动作 重定向到不同名称空间的动作 |
type的默认取值是dispatcher,转发
type的属性取值在struts-default.xml中定义着
示例:
写一个DemoAction,继承 ActionSupport
import com.opensymphony.xwork2.ActionSupport;
public class DemoAction extends ActionSupport {
}
在struts.xml中这样写:
<package name="p2" extends="struts-default" namespace="/test" >
<action name="demo1" class="com.zr.web.action.DemoAction">
<!--
1. 注意这里面是可以不用写name的,默认是success
2. type属性
dispatcher:默认值,转发到一个页面
redirect:重定向一个页面
chain:
redirectAction:
-->
<result name="success" type="dispatcher">/success.jsp</result>
</action>
</package>
那么启动项目后,访问下面路径会转发到succes.jsp页面(路径不变)
http://localhost:8080/struts_1_war_exploded/test/demo1
注意这里面不写方法是因为action类继承了ActionSupport,在其中有已经实现的excute()方法,如果在result标签后面没有加上method标签,则会默认调用这一excute()方法
上面这个是result的type为dispatcher(转发时的示例),其他的三个可以自己尝试
chain:转发到同一个包或者不同包的其他的action中去
redirectAction:重定向到同一个包或者不同包的另外一个action
当chain用来转发到另外一个不同的包中时
<result name="success" type="chain">
<param name="namespace">另外一个包的命名空间</param>
<param name="actionName">另外一个包中的action的名字</param>
</result>
result元素中param子元素
在转发或者重定向到不同包下的动作时,都用到了result元素的子元素param
param元素的作用:依赖注入(Dependence Injection)思想
我们通过struts-default.xml中的resultTypes元素中配置可以看出,每个结果类型视图其实都是靠一个类来实现的
而param元素就是将配置的参数,注入到该类中
调用的是对应类的setter方法进行注入的
自定义结果类型
其实结果类型就是一个类,这些类都实现com.opensymphony.xwork2.Result接口
或者继承自该接口的实现类org.apache.struts.dispatcher.StrutsResultSupport
这些类都有一个doExcute方法,用于执行结果视图(查看源码各种结果类型的类结构)
struts的内部实现就是Servlet
上面这种自定义结果类型其实就是一个类,这些类可以实现Result接口,也可以继承自StrutsResultSupport(Result接口实现类)
综上所述自己写一个结果视图
例子:输出CAPTCHA图像的结果类型
CAPTCHA 即 验证码
步骤:
第一步:继承StrutsResultSupport或者实现Result接口
第二步:重写doExecute方法
package result;
import cn.dsna.util.images.ValidateCode;
import com.opensymphony.xwork2.ActionInvocation;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.StrutsResultSupport;
import javax.servlet.http.HttpServletResponse;
/**
* 验证码的结果类型
*/
public class CAPTCHAResult extends StrutsResultSupport {
@Override
protected void doExecute(String s, ActionInvocation actionInvocation) throws Exception {
//生成验证码 这个方法需要导入一个名字叫做ValidateCode.jar的jar包
//参数分别为 验证码图片的宽度、高度、验证码字符的个数、验证码的干扰条个数
ValidateCode code=new ValidateCode(200,30,4,6);
//利用response将这个结果返回给客户端
HttpServletResponse response = ServletActionContext.getResponse();
//响应给客户端面
code.write(response.getOutputStream());
}
}
第三步:配置struts.xml文件
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--配置一个常量-->
<!--配置开发者模式-->
<constant name="struts.devMode" value="true"></constant>
<!--配置动态调用方法开启-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<package name="p1" extends="struts-default" namespace="/result" >
<!--声明一个结果类型-->
<result-types>
<!--验证码的结果类型-->
<result-type name="captcha" class="result.CAPTCHAResult"></result-type>
</result-types>
<!--配置action-->
<action name="checkcode">
<result type="captcha"></result>
</action>
</package>
</struts>
然后启动项目,访问如下路径,会在网页上返回一个验证码图片
http://localhost:8080/struts_1_war_exploded/result/checkcode
优化自定义结果类型
但是这样不能根据大小调整验证码宽度和高度,我们可以利用result中可以设置参数这一特点,在CAPTCHAResult类中添加两个变量 width和height,为其添加setter和getter
package result;
import cn.dsna.util.images.ValidateCode;
import com.opensymphony.xwork2.ActionInvocation;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.StrutsResultSupport;
import javax.servlet.http.HttpServletResponse;
/**
* 验证码的结果类型
*/
public class CAPTCHAResult extends StrutsResultSupport {
private int width; //验证码宽度
private int height; //验证码高度
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
@Override
protected void doExecute(String s, ActionInvocation actionInvocation) throws Exception {
//生成验证码 这个方法需要导入一个名字叫做ValidateCode.jar的jar包
//参数分别为 验证码图片的宽度、高度、验证码字符的个数、验证码的干扰条个数
ValidateCode code=new ValidateCode(width,height,4,6);
//利用response将这个结果返回给客户端
HttpServletResponse response = ServletActionContext.getResponse();
//响应给客户端面
code.write(response.getOutputStream());
}
}
在struts.xml中result设置参数
<action name="checkcode">
<result type="captcha">
<param name="width">120</param>
<param name="height">30</param>
</result>
</action>
那么在这些param中name写为变量名,那么当执行此result时,就会把这些参数自动填充给相应的变量
全局视图和局部视图
前面所用到的result就可以称为结果视图,上面所用的所有这种视图是局部视图,只能作用于一个package中
那么如果想要一个result作用于所有package,即全局视图,就需要声明一个抽象包,可以被继承
如下面所示的struts.xml文件中,先配置了一个抽象包,然后下面两个包都继承自这个抽象包
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!--配置一个常量-->
<!--配置开发者模式-->
<constant name="struts.devMode" value="true"></constant>
<!--配置动态调用方法开启-->
<constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
<package name="myDefault" extends="struts-default" abstract="true">
<!--全局的结果视图配置:
声明一个验证码的结果类型
-->
<result-types>
<result-type name="captcha" class="result.CAPTCHAResult"></result-type>
</result-types>
</package>
<package name="p1" extends="myDefault" namespace="/result1" >
<!--配置action-->
<action name="checkcode">
<result type="captcha">
<param name="width">120</param>
<param name="height">30</param>
</result>
</action>
</package>
<package name="p2" extends="myDefault" namespace="/result2" >
<!--配置action-->
<action name="checkcode">
<result type="captcha">
<param name="width">120</param>
<param name="height">30</param>
</result>
</action>
</package>
</struts>
这里面注意:抽象包内没有action元素,只能用于继承
动作类中的Servlet api访问讲解
获取servlet api的方式
第一种方式:通过ServletActionContext获取
TestAction类
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class TestAction extends ActionSupport {
public String test(){
//获取servlet api的方式
//第一种方式:通过ServletActionContext获取
//1. response
HttpServletResponse response = ServletActionContext.getResponse();
//2. request
HttpServletRequest request = ServletActionContext.getRequest();
//3. session
HttpSession session = request.getSession();
//4. application 即 ServletContext对象
ServletContext application = ServletActionContext.getServletContext();
/*
org.apache.struts2.dispatcher.StrutsRequestWrapper@3aa7a9ee 属于struts的
org.apache.catalina.connector.ResponseFacade@1a5a082d 属于tomcat
org.apache.catalina.session.StandardSessionFacade@644e9268 属于tomcat
org.apache.catalina.core.ApplicationContextFacade@3ddb7736 属于tomcat
*/
System.out.println(request);
System.out.println(response);
System.out.println(session);
System.out.println(application);
return NONE;
}
}
struts.xml
<package name="test" extends="struts-default">
<action name="testAction" class="com.zr.web.action.TestAction" method="test"></action>
</package>
第二种方式:通过实现接口让struts自动注入
Test1Action类
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.interceptor.ServletRequestAware;
import org.apache.struts2.interceptor.ServletResponseAware;
import org.apache.struts2.util.ServletContextAware;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Test1Action extends ActionSupport implements ServletRequestAware, ServletResponseAware, ServletContextAware {
HttpServletResponse response;
HttpServletRequest request;
ServletContext application;
public String test(){
//获取servlet api的方式
//第二种方式:通过实现接口让struts自动注入
/**
* Aware 注入,调用方法,注入参数
* 实现两个接口 ServletRequestAware, ServletResponseAware
* 那么访问该action的时候会自动调用下面的两个setServletRequest,setServletResponse方法
* 会自动将 HttpServletRequest request 和 HttpServletResponse response 注入进来
*/
return NONE;
}
@Override
public void setServletRequest(HttpServletRequest request) {
this.request=request;
}
@Override
public void setServletResponse(HttpServletResponse response) {
this.response=response;
}
@Override
public void setServletContext(ServletContext application) {
this.application=application;
}
}
struts.xml
<package name="test" extends="struts-default">
<action name="test1Action" class="com.zr.web.action.Test1Action" method="test"></action>
</package>
第二种注入方式的原理是因为struts有个拦截器servletConfig
<interceptor name="servletConfig" class="org.apache.struts2.interceptor.ServletConfigInterceptor"/>
再看看struts的架构图
在执行action之前会经过一些拦截器,在这些拦截器中就有一个servletConfig拦截器
在拦截器的源码中判断action中是否实现了ServletResponseAware,ServletRequestAware等接口,如果实现了,则setServletResponse()