struts2框架引入到web项目中:
1,把struts2相关的jar包引入到项目中。
2把struts的配置文件直接放到src下面,名字叫做strut.xml(运行是配置文件被框架自动读取)
注意:如果struts.xml文件中不能自动提示标签,把相应的dtd文件配置上去。
3在web.xml文件中配置struts框架过滤器
第一种filter的配置:(这是struts2框架2.0使用的配置方式)
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
第二种filter配置:(这是struts2框架2.0以上使用的配置方式 同时2.0以上的版本也可以使用上面的配置方式)
这个过滤器类是2.0版本以上新增加的类。
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
这个过滤器的作用:拦截struts框架中的action。
注意:如果不配置这个filter,struts框架就不能够正常工作。
2.struts2框架中的Action
struts2框架底层还是封装了Servlet的相关内容来实现出来的。只不过struts2框架除了servlet的功能
以外还扩展出来很多其他的功能,同时还大大简化了以前在servlet中繁琐的操作。
在struts框架中,有一种类就是以前我们在web项目中所使用的servlet,那么这中类,在struts2框架中被称为
Action
所以Action其实也是一种java类,比servlet功能更加强大的java类。同时还比servlet中的操作简单。
3.为什么Action会有比servlet强大的功能以及简洁的操作?
因为我们在web.xml文件中配置了struts2框架中专门的过滤器。用做拦截访问action的请求,拦截住以后。就
可以给Action添加很多丰富的功能。
4,如何去写一个struts框架中的Action:
三种方式:
1.直接写一个类,不需要继承类和实现某个接口,但这个类里面一定要有一个固定的方法(也是不一定的可以用
method="test"这个属性指定。):
public String execute(){
return "";
}
注意:execute方法一定要返回String类型的对象。每一个字符串都可以对应一种跳转的页面。
(字符串是自己定义的,跳转页面也是自己在struts.xml中定义的。)
2.实现一个指定的接口:Action
只有一个抽象方式 execute();
同时还要五个String类型的静态属性:ERROR,SUCCESS,INPUT,NONE,LOGIN
3.继承一个父类ActionSupport
5.写完Action类后需要在struts.xml文件中进行配置。
在struts.xml配置Action的目的和作用:
通知struts2框架我们写的这个类是一个Action,将来struts框架中要给这个类创建对象,调用方法以及加入
更多丰富的功能。
例如:
<package name="test" extends="struts-default" namespace="/test">
<action name="MyTest">
<result>/index.jsp</result>
</action>
<action name="test1" class="com.briup.web.action.ActionTest1">
<result name="myFirstAction">/success.jsp</result>
<result name="myError">/error.jsp</result>
</action>
</package>
name="test1"表示当前配置这个action的名字为test1,这个名字是随便起的,可以和action类的名字相同或者不同.
同时将来浏览器中的地址栏里面就是要出现这个名字来访问当前这个action类
class=".."表示当前配置的action对应的是哪一个java类,我们可以配置一个action,但是这个action可以没有对应
任何java类。就像上面配置的MyTest的例子.
<result>标签表示将来这个action访问完了之后有哪些跳转.
<result name="myError">/error.jsp</result> 表示当前这个action如果返回的字符串是myError,就那么页面就
跳转到/error.jsp中
注意:每一个action被访问完之后都会有一个字符串类型的返回值,即使访问一个没有任何java类对应action的时候,
这个action也会默认返回字符串:success
<result name="success"> <==> <result>
<result>标签中的name属性默认值就是success
<package name="test" extends="struts-default" namespace="/test">
<package>:一个struts.xml文件中可以配置多个<package>标签,一个<package>标签里面可以配置多个<action>标签,
一个<action>标签里面可以配置多个<result>
name="test"标签给当前package起一个名字为test,作用:1.唯一标识当前这个package。
2.方便package与package之间通过这个名字来实现继承的关系。
extends="struts-default" 标签当前这个package继承了另外一个名字叫做struts-default的package,
这个package在struts2的核心jar包中的struts-default.xml文件中定义的,里面定义了很默认的配置.
注意:我们在struts2中定义的所有package,都会是直接或者间接的继承了struts-default这个package.
namespace="/test" 表示当前package的命名空间为/test,将来这个package里面的所有的action在被访问的时候,
路径里面都要加上这个命名空间.
特殊的action配置,:使用通配符来配置,
使用前提:原来需要配置的多个action名字或者类的名字是有一定的规律的。
例如:原来需要配置这样三个action:
<action name="test1" class="com.briup.web.action.ActionTest1">
<result>/success.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="test2" class="com.briup.web.action.ActionTest2">
<result>/success.jsp</result>
<result name="error">/error.jsp</result>
</action>
<action name="test3" class="com.briup.web.action.ActionTest3">
<result>/success.jsp</result>
<result name="error">/error.jsp</result>
</action
这时候,我们就可以使用通配符配置一个action来代替这三个action
<action name="test*" class="com.briup.web.action.ActionTest{1}">
<result>/success.jsp</result>
<result name="error">/error.jsp</result>
</action>
{1}代表的前面name属性中所出现的第一个*号,如果有第二个*,可以用{2}来表示
text*就是将来在浏览器中输入的这个action名字,如果输入的是test1,那么这个*好就代表1,如果输入的是
testlogin ,那么这个*好就代表login。
注意:如果原本需要配置的多个action,没有非常明显的规律,就不要使用这种方法配置。
6.在struts.xml文件中配置struts2框架的属性.
<constant name="struts.devMode" value="true"></constant>
作用:修改完struts.xml配置文件后不需要重新启动服务器。但要注意在开发完之后,要重新设置为false。
<constant name="struts.custom.i18n.resources" value="message"></constant>
作用:这册国际化的资源文件(value属性指的是文件名的前缀)
7.action 的特点及其访问:
http://localhost:8002/jd1307_struts2/namespace/actionName.action
servlet是线程不安全的,因为servlet是单例,struts2框架中的action是线程安全的,因为每次
访问都会创建一个新的Action对象,所以在action里面可以随便的定义成员变量(只有成员变量才有
线程安全的问题
);
访问:
(strut2框架的版本不同默认情况有所不同)
默认情况下,访问action的时候,使用namespace/actionName.action或者namespace/actionName就可以访问的到.
但是由于不加任何后缀名也可以访问到这个action,这样容易和其他资源的访问产生冲突,比如servlet的访问.
所以我们需要配置一下,把action访问规定成,只能使用后缀名.action或者是.do 或者是其他形式来访问.
//可以使用.action或者.do来访问
<constant name="struts.action.extension" value="action,do"></constant>
//只能使用.action
<constant name="struts.action.extension" value="action"></constant>
8.访问action的时候,action中的方法的调用:
1,默认情况下,访问action会调用action中的exexute方法,这个方法执行完的时候,会返回一个字符串。
然后根据字符串进行跳转。
2,可以在<action>标签里面加上一个method属性,来指明将来访问这个action的时候会调用哪个方法。
例如:
<action name="test" class=" " method="login">
注意:我们可以定义多个名字不同的action对应相同的java类,这个我们也可以用method来指定方面,这是我们
也是可以访问到一个类中的不同的方法。
<action name="test" class=" " method="login">
<action name="test1" class=" " method="register">
这样可以使用test,test1两个不同名字的action就是访问到同一个类中的两个不同的方法,:login,
register但是login方法和register方法必须是和execute方法类似 ,有String类型的返回值。
3.地址栏中动态指定要调用的方法
例如:
<action name="test" class="类A">
类A里面有俩个方法:register login
默认情况下地址栏中通过test.action来访问这个action会访问到它的execute方法,同时我们还可以在地址栏
中动态的指定要访问的方法:
test!login.action 这样就能访问到名字为test的action对应类A中的login方法了.
9。配置全局的跳转:
<global-results>
<result name="success">/Msg.jsp</result>
<result name="myError">/error.jsp</result>
</global-results>
作用:将来在任何的其他action中,如果有需要返回success字符串跳转到Msg.jsp或者myError字符串跳转到
error.jsp的时候,就不需要在单独的哦定义,因为已经把这两个跳转定义成了全局的跳转,对当前package里面的所有
action都起作用,同时还可以在某一个action再重新定义一些这两个跳转,这个时候全局跳转就不会对这个action起
作用了,(覆盖了全局跳转)
10.配置package中默认的action
<!-- 配置默认的action -->
<default-action-ref name="MyTest"></default-action-ref>
作用:如果地址栏中访问量当前package下面一个不存在的action的时候,正常情况下会直接报错的,
错误信息显示这个
action找不到,但我们一旦配置了这个默认的action之后,那么再去访问一个不存在的actin就不会保持了
而是直接就去访问这个默认的action
这个默认的action需要在当前package里面定义出来,并且在
<default-action-ref name="MyTest"></default-action-ref>里面引用一下。
注意:访问某个package下面action的时候有几种错误情况:
1,action找不到
2,action找到了但是action对应的类找不到。
3.action找到了,对应的类找到了,但是在类中要执行的方法没有找到
4,action找到了,对应的类找到了,但是在类中要执行的方法找到了,但是方法返回的字符串在<result>
中没有定义。
5.action找到了,对应的类找到了,但是在类中要执行的方法找到了,但是方法返回的字符串在<result>
中也定义了,但是跳转页面没有找到。
配置默认的action实现类:
<!-- 配置默认的实现类 -->
<default-class-ref class="com.briup.web.action.ActionText"></default-class-ref>
11.action中跳转的方式:
<result name="" type="">..</result>
name属性指的是跳转的名字,也是action返回的字符串,
type属性指的是跳转的类型,常用到的有以下四种:
dispatcher:从一个action里面跳转到一个页面中(服务器内部跳转)这个属性是type的默认值。
chain:从一个action里面跳转到另外一个action(服务器内部跳转)
1.同一个package下面的action跳转:
/test下面的action跳转到/test下面的action
<result type="chain">methodTest1</result>
或者:
<result type="chain">
<param name="actionName">methodTest1</param>
<param name="namespace">/test</param>
</result>
2.不同的俩个package下面的action跳转
/test下面的action跳转到/user下面的action
<result type="chain">
<param name="actionName">mytest</param>
<param name="namespace">/user</param>
</result>
redirect:从一个action里面客户端重定向到一个页面中。
<result name="success" type="redirect">/Msg</result>
redirectAction:从一个action里面客户端重定向到一个action中。
1.同一个package下面的action跳转:
/test下面的action跳转到/test下面的action
<result type="redirectAction">methodTest1</result>
或者
<result type="redirectAction">
<param name="actionName">methodTest1</param>
<param name="namespace">/test</param>
</result>
2.不同的俩个package下面的action跳转
/test下面的action跳转到/user下面的action
<result type="redirectAction">
<param name="actionName">mytest</param>
<param name="namespace">/user</param>
</result>
12.strut2框架中的拦截器(interceptor)
1.什么是拦截器(interceptor)
拦截器是struts2框架中提供的一种java类,
作用:是用来拦截那些访问action的请求,拦截到这些请求后,可以丰富action的功能或者
额外的处理一下访问action的类。
2.拦截器(interceptor)是如果工作的
a,要有一个拦截器的类(可能是struts2框架自带的或者我们自己定义的一个类)
b,在配置文件中把这个拦截器配置出来。
c,指明这个拦截器要拦截哪一个或者哪一些action
d,客户端发送一个请求访问一个被拦截器拦截的action
e,这个请求会先被struts2的filter所拦截,filter会先检查这个请求是不是请求的action,如果是action
的话,那么会再检查这个action有没有被定义的拦截器所拦截,如果有就把这个请求较高拦截器去处理。
3.如何自定义一个拦截器
strut2框架已经写好了很多拦截器(在struts2的核心jar包),同时也把这样拦截器配置在配置文件里面(
在struts-default.xml中)
除此以外,我们还能写自己的拦截器。
要写一个拦截器,首先要实现一个接口:com.opensymphony.xwork2.interceptor.Interceptor
例如:
public class MyInterceptor implements Interceptor{
public void destroy() {
System.out.println("in destory() of MyInterceptor");
}
public void init() {
System.out.println("in init() of MyInterceptor");
}
public String intercept(ActionInvocation ai) throws Exception {
System.out.println("before...");
//ai.invoke()其实就是帮我们去调用action中将要执行的方法,比如execute方法
//ai.invoke()的放回值其实就是action中方法执行完返回的字符串
String s = ai.invoke();
System.out.println("after...");
return s;
}
}
4.拦截器栈
当前一个action需要被多个拦截器拦截的时候,正常情况下,我们需要在这个action中去引用要使用到的多个
拦截器,但是我们可以使用一个拦截器栈去包含那几个拦截器,然后在action中直接引用这个拦截器栈就可以了.
1,一个拦截器栈可以包含多个拦截器
2,一个拦截器栈也可以包含多个拦截器栈
3.定义拦截器或者拦截器栈都要在<interceptors>标签中
例如:
<interceptors>
<interceptor name="myInterceptor" class="com.briup.web.interceptor.MyInterceptor"></interceptor>
<interceptor-stack name="myStack">
<interceptor-ref name="myInterceptor"></interceptor-ref>
<!-- 这是struts-default.xml文件中定义的一个拦截器 -->
<interceptor-ref name="params"></interceptor-ref>
<!-- 这是struts-default.xml文件中定义的一个拦截器栈 -->
<interceptor-ref name="basicStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<interceptors>
<interceptor name="myInterceptor" class="com.briup.web.interceptor.MyInterceptor"></interceptor>
<interceptor-stack name="myStack">
<interceptor-ref name="myInterceptor"></interceptor-ref>
<!-- 这是struts-default.xml文件中定义的一个拦截器栈 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
5.默认拦截器/拦截器栈
在一个package中,我们可以把一个拦截器或者拦截器栈声明为一个默认的拦截器/拦截器栈
作用:将来这个package中所有的action都会被这个默认的拦截器/拦截器栈所拦截。
例如:
//myStack可以是一个拦截器/拦截器栈
<default-interceptor-ref name="myStack"></default-interceptor-ref>
,一般情况下,我们所写的任何action都会被一个叫做defaultStack的拦截器所拦截,这个拦截器栈里面
中包含了十几个拦截器,这些拦截器给我们的action提供了很多丰富的功能。
因为我们写所有的package都是直接或间接的继承了struts-default.xml文件中的一个名字叫struts-default的
package,struts-default包中又把名字叫defaultStack的拦截器栈配置成了一个默认的拦截器栈,
那么我们的package就把这个配置继承了过来,所有我们的action正常情况下都会被defaultStack所拦截.
但是如果我们一旦指明了某一个action被我们所写的一个拦截器/拦截器栈所拦截,那么这个action就不会
被defaultStack拦截了.所以我们可以在action中主动的再声明这个action被defaultStack所拦截,或者把
defaultStack加入到我们自定义的拦截器栈里面(拦截器栈可以包含拦截器栈。)
6.package之间的继承
我们可以专门再定义一个package,在这个package里面我们只做拦截器/拦截器栈的定义:
<!-- 在这个package中,我们只定义拦截器/拦截器栈 -->
<package name="MyInter" extends="struts-default" namespace="/">
<interceptors>
<interceptor name="myInterceptor" class="com.briup.web.interceptor.MyInterceptor"></interceptor>
<interceptor-stack name="myStack">
<interceptor-ref name="myInterceptor"></interceptor-ref>
<!-- 这是struts-default.xml文件中定义的一个拦截器栈 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 声明默认拦截器/拦截器栈 -->
<!-- 当前包中所有的action都会被这个myStack所拦截器 -->
<!-- 继承了当前包的其他包里面的所有action也会被这个myStack所拦截器 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
</package>
然后我们可以让其他的package去继承我们这个MyInter包,这样以来,
其他包中的action都会被我们这个MyInter包中的默认拦截器栈myStack所拦截了。
注意:一定要保证action至少是被defaultStack这个拦截器栈所拦截的.
13.拦截器(interceptor)和过滤器(filter)的区别:
相同点:
1,拦截器和过滤器都是一种Java类。
2,都能拦截客户端发过来的请求。
3,拦截的请求之后都可以做一些相应的处理,最终还可以把这个请求放行。
4.都需要实现各自相应的接口以及在相应的配置文件中配置.
不同点:
1.拦截器(interceptor)是struts2框架中的定义的,过滤器(filter)是web里面的对象,是J2EE标准里面定义的.
2.拦截器(interceptor)只会拦截器访问action的请求,过滤器(filter)能够拦截所有请求.
3.拦截器(interceptor)定义在struts.xml文件中,过滤器(filter)定义在web.xml文件中.
4.拦截器(interceptor)对象的创建、调用、销毁是struts2框架负责的,过滤器(filter)对象的创建、
调用、销毁服务器负责的.
我们自己定义的filter拦截器struts2中的action的问题
1.可以拦截
2.需要在web.xml文件中把我们自己的filter配置在struts2的filter的上面才可以.
因为web.xml文件中filter配置的先后顺序控制filter起作用的顺序,同时如果struts的filter先拦截到
访问action的请求后,不会把这个请求交给下面的filter,而是交给了他它内部的拦截器(interceptor)了,
但是如果我们自己filter拦截到请求之后,还是依然会交给下一个filter,也就是交给struts2的filter.
14.前台页面向后台action中传参
第一种情况:
例如:
通过页面要把id=1 name=tom age=20这三个参数传给action
1.action里面定义三个成员变量id name age,这个三个变量的名字一定要和所传变量的名字一致.
2.提供get/set方法
3.将来页面把这三个参数传过来的时候,struts2框架会自动的帮我们把这个三个参数值放action中的
三个属性里面.(同时还做了类型的转换)
注意:这个工作其实是由defaultStack这个拦截器栈里面的拦截器来完成了.
传值完成之后,我们只要在execute方法中去直接使用就可以了,不需要做其他事情.
第二种情况:
在接受到页面传值的时候,还可以让struts2框架直接帮我们把这些接受到的值封装到一个javabean对象里面。
1,action中定义一个User类型的变量
user,User类中有三个属性值,id,name,age,同时User类中还有get/set方法
2,action中给这个user属性提供get/set方法
3,页面向action传值的时候,参数的名字要写出user.id=1 user.name=?user.age=?
我们将来接受到这个参数值以后,struts2的框架会帮我们去创建一个User对象,并且把所传参数三个值封装到
对象的三个属性中。最后把这个封装好的对象放到action的user属性中。
15.从action向页面传值
在action中依然可以像以前在servlet里面一样,使用request,session,application向页面传值之外,action
里面还有两个独有的传值方式:ValueStack,ActionContext
1.ValueStack是一个接口:com.opensymphony.xwork2.util.ValueStack
ActionContext是一个类:com.opensymphony.xwork2.ActionContext
我们可以使用这个俩个类型的对象,从action里面把值带到页面.
2.我们在页面中,可以通过一个struts2的标签来看到action传到页面中的值:<s:debug/>
页面引入标签库:<%@taglib uri="/struts-tags" prefix="s" %>
3.当前action进行跳转的时候,struts2框架会自动的把当这个action对象本身分别放到ValueStack和
ActionContext这个俩个对象,然后struts2框架再把这个俩个对象传给页面,所以我们在页面中只要通过这个
俩个对象,就可以拿到之前放进去的值.(在页面的debug标签中,可以看到struts框架放到这俩个对象里面的action)
4.除了struts框架自动的向ValueStack和ActionContext里面放值以外,我们还可以手动的向这俩个对象里面放值.
5.如何拿到ValueStack和ActionContext对象
获得ActionContext对象:
ActionContext ac = ActionContext.getContext();
获得ValueStack对象:
ValueStack vs = ac.getValueStack();
6.自己向ac和vs中主动放值
向ActionContext对象中放值:
ac.put(String,Object);
ac.put("hello","world");
向ValueStack对象中放值:
User user = new User();
vs.push(user);
注意:ValueStack是压的对象,显示是对象的属性值,
7.ValueStack的特点(值栈)
1.把对象放到vs里面之后,我们从这个vs中是拿不到这个对象的,但是我们直接拿到这个对象的属性
以及属性值。
注意(vs分三列,Object,PropertyName,PropertyValue:Object中存的是对象,PropertyName里面放的是
对象的属性名字,PropertyValue是放的属性的值)
2.从vs中拿值的时候,是从vs中的PropertyName这一列拿值的,拿的是PropertyValue这一列的值(在
dubug中的vs视图可以看到这些列)
所以如果我们通过vs把一个值传到页面,我们不能直接把这个值放到vs里,因为这样拿不到,
我们应该把这个值放到一个对象的属性里面,然后再把这个对象放vs中,
这个时候就可以通过vs拿到这个对象的属性了,也就是我们要传的值.
3.每次浏览器发送一个新的请求,都会生成一个新的ValueStack对象,上一次的ValueStack对象就没了,
找不到了.(类似之前学习的request对象的特点)
4.每次创建一个新的ValueStack对象后,会把这个对象放到ActionContext里面.
8.ActionContext的特点
1.向ac里面放值的时候是通过key-value的形式存放的,key是String类型,value是Object类型,
取值的是同样通过key拿到value.
2.struts框架默认向这个对象里面存放的对象(数据)很多,包括request、session、
application、ValueStack、parameters等
3.每次请求都会创建一个新的ActionContext对象(每次请求打印出ac的地址值可以看出来)
9.注意:使用vs和ac传值的时候,要使用服务器内部跳转的方式.
16.在action中访问web元素(request session application)
1.在struts2框架中,这三个对象分别都有俩个类型:原类型 Map类型
2.原类型:
HttpServletRequest request
HttpSession session
ServletContext application
Map类型:
Map<String,Object> request
Map<String,Object> session
Map<String,Object> application
3.在使用的时候,我们可以选择使用原类型的request或者选择使用Map类型的request.
(session和application也是这样的情况)
4.不管是原类型的还是Map类型的对象,都是被struts2框架默认存放到了ActionContext对象里面.
(使用debug标签可以看到)
5.原类型的和Map类型的关系.
a.使用Map类型的对象,可以降低代码中对 servlet的API的依赖(降耦)
b.我们使用原类型大多时候也是存值和取值,而且原类型里面本身也是封装了Map对象。
所以我们使用Map类型的对象也可以完成存值和取值.
c.Map类型的request对象里面的值(k-v),其实就是复制的原类型的request对象里面的值(k-v),
当然原类型的request对象里面除了k-v类型的键值对以外,还有其他的属性和方法,
因为它毕竟是HttpServletRequest类型的对象.
d.所以原类型的request和Map类型的request对象,我们可以理解为他们里面的值(k-v)是相通的,
相通的意思就是:这个对象里面有什么值,那个对象里就也会什么值.所以我们在action里面向Map类型
的对象中存放一个值(k-v),将来在页面中同样是可以使用原类型的request对象那这个值(k-v)取出来的.
注:session和application的情况也是一样的道理.
6.在action中如果拿到Map类型和原类型的对象
1.获取Map类型对象
第一种方式:自己在方法中主动获得
ActionContext ac = ActionContext.getContext();
//获得Map类型request
Map<String,Object> request =
(Map<String, Object>) ac.get("request");
//获得Map类型session
Map<String, Object> session = ac.getSession();
//获得Map类型application
Map<String, Object> application = ac.getApplication();
第二种方式:让struts2框架把Map类型的对象自动的放到action里(依赖注入)
1.第一种方式是自己主动拿到这个对象.
2,第二种方式是自己被动接受这个对象.
实现三个接口,分别可以让struts2框架把Map类型的request、session、application对象通过调用实现的接口中方法传给我们的action,在action里面我们只要接收这三个对象就可以了,那到后可以直接使用.
三个接口依次为:
RequestAware,SessionAware,ApplicationAware
例如
public class WebActionTest extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
private Map<String, Object> request;
private Map<String, Object> session;
private Map<String, Object> application;
@Override
public String execute() throws Exception {
//页面中用原类型的对象去正常值就可以了
request.put("MyName", "tom");
session.put("YourName", "zhansan");
application.put("HerName", "lily");
return SUCCESS;
}
public void setRequest(Map<String, Object> request) {
this.request = request;
}
public void setSession(Map<String, Object> session) {
this.session = session;
}
public void setApplication(Map<String, Object> session) {
this.application = application;
}
}
2.获取原类型对象
第一种方式:自己主动获得
获得原类型request对象
HttpServletRequest req = ServletActionContext.getRequest();
获得原类型response对象
HttpServletResponse res = ServletActionContext.getResponse();
获得原类型session对象
HttpSession sess = req.getSession();
获得原类型application对象
ServletContext app1 = sess.getServletContext();
或者
ServletContext app2 = ServletActionContext.getServletContext();
第二种方式:自己被动接收
struts2框架中提供了一个接口,可以用来获得原类型的request对象,因为通过原类型的request对象
就可以获得原类型的session对象和原类型的application对象
实现接口:ServletRequestAware,然后struts2框架会通过action所实现的抽象方法,把原类型
的request对象自动放到action里面.
类似的还有一接口:ServletResponseAware,和上面的效果、用法是一样的。
17.页面中获得action传过来的值
在struts2框架所提供的页面取值方式中,需要使用到俩个东西:struts2框架的标签、OGNL表达式
注意:同时我们也可以使用jsp内置对象取值已经使用jstl标签+EL表达式取值.
struts2中可以使用的取值方式:
1.jsp内置对象取值
2.jstl标签+EL表达式取值
3.struts2标签+OGNL表达式
注意:OGNL表达式只能写在struts2的标签属性中,在这里面我们先使用一下struts2的这样
一个标签:<s:property value=""/>,这个标签的作用就是向页面输出值.
例如:
<s:property value=" OGNL表达式写在这 "/>
一)从ValueStack和ActionContext中取值
1.从ValueStack中取值.
//注意这个value属性中的值name,其实就是ongl表达式
//这个表示从valueStack中取一个名字叫做name的property值
<s:property value="name"/>
<s:property value="user"/>
<s:property value="user.id"/>
<s:property value="user.name"/>
注意:从ValueStack中取值的时候,如果Valuestack里面有俩个名字相同的值,
我们只能取到最上面的值(从debug标签中看vs中最上面的值)
(经过一些处理,也可以取到下面的)
2.从ActionContext中取值.
要使用ognl表达式通过AC中的key来拿相对于的value值。取值的时候需要加上一个符号:#
<s:property value="#action.name"/><br>
<s:property value="#msg"/><br>
<s:property value="#user"/><br>
<s:property value="#user.id"/><br>
<s:property value="#user.name"/><br>
<s:property value="#user.age"/><br>
3.ActionContext中的parameters、attr、request、session、application等key值.(这些都是AC中的key)
parameters对应的值中存放的是客户端所传过来的参数.
//接收客户端传来的名字为name的参数值
<s:property value="#parameters.name"/><br>
//获得request中的值
<s:property value="#request.MyName"/><br>
//获得session中的值
<s:property value="#session.MyName"/><br>
//获得application中的值
<s:property value="#application.MyName"/><br>
//默认依次从request、session、appliction中取值,取到了就直接输出,取不到就算了.
<s:property value="#attr.MyName"/><br>
二)还可以使用以前的方式从request、session、application中取值.
注意:如果我们用request通过key去取值的时候,会先在request里面找,request里面找不到
会到ValueStack里面找。因为ValueStack默认也被放在request里面.
但是session和application没有像request的这样的特点.
使用jsp脚本代码取值
<%=request.getAttribute("name") %><br>
<%=session.getAttribute("name") %><br>
<%=application.getAttribute("name") %><br>
使用EL表达式取值:
${requestScope.MyName }<br>
${requestScope.name } <br>
${sessionScope.MyName } <br>
${applicationScope.MyName } <br>
${MyName } <br>
${name } <br>
118.OGNL表达式
Object Graph Navigation Language
像之前学习的EL表达式一样,这个也是一种表达式语言,但是比EL表达式的功能要强.
EL基本上可以写在页面中的任何一个位置
OGNL只能写在struts2标签的属性值中.
OGNL表达式的使用:
<h1>输出文本字符串</h1>
${"hello"}//el表达式
${"1+1"}//el表达式
<s:property value="'hello'"/>
<s:property value="'1+1'"/>
<h1>输出数学运算式子的结果</h1>
${1+1}//el表达式
<s:property value="1+1"/>
<s:property value="(1+8)+45*12"/>
<h1>输出boolean表达式</h1>
${1<2 }//el表达式
<s:property value="1<2"/>
<s:property value="1<2||2>0"/>
<s:property value="1<2&&1<6"/>
<s:property value="1<2?'hello':'hh'"/>
××××××××××××××××××××××××××××××
1.输出文本字符串
<s:property value="'hello'"/><br>
<s:property value="'hello world'"/><br>
<s:property value="'1+1'"/><br>
2.输出数学运算式子的结果
<s:property value="1+1"/><br>
<s:property value="((1+1)*4-3)*4-5"/><br>
3.输出boolean表达式的结果
<s:property value="1<2"/><br>
<s:property value="1 == 2"/><br>
<s:property value="1 >= 2"/><br>
<s:property value="1>2||1<0"/><br>
<s:property value="1>2&&1>0"/><br>
<s:property value="1>2?'hello':'world'"/><br>
4.从ValueStack中取值
<s:property value="name"/><br>
<s:property value="locale"/><br>
<s:property value="user"/><br>
<s:property value="user.id"/><br>
<s:property value="user.name"/><br>
<s:property value="user.age"/><br>
5.从ValueStack中取值的时候,有俩个名字相同的值
<!-- [1]表示去拿到ValueStack(值栈)中第二对象的name属性值 -->
<!-- ValueStack(值栈)中对象从上到下的下标依次为0、1、2、3.... -->
<s:property value="[1].name"/><br>
6.取到ValueStack中属性值,如果属性值是一个对象,还能调用这个对象的方法
<!-- 注意:只要是能拿到一个对象,就能调用方法,不管这个对象从哪个地方拿到的 -->
<s:property value="user.getName()"/><br>
<s:property value="user.say()"/><br>
7.取到ActionContext中value值,如果值是一个对象,还能调用这个对象的方法
<s:property value="#user.getName()"/><br>
8.调用类中的构造器创建对象,并且调用对象的方法
<s:property value="new com.briup.bean.User().getId()"/><br>
9.直接调用字符串对象的方法
<s:property value="'abc'.equals('bcd')"/><br>
<s:property value="'nihao'.equals('nihao')"/><br>
10.调用ValueStack中action对象/其他对象的静态方法
<!-- 格式:@vs1@静态方法的名字() -->
<!-- vs1代表ValueStack中的第一个对象(从上到下) -->
<!-- vs2代表ValueStack中的第二个对象(从上到下) -->
<s:property value="@vs1@test()"/><br>
11.调用JDK中类/自定义类的静态方法/静态属性
<!-- 格式:@...@... -->
<!--
第一个@后面要加上类的全名
如果没有写,默认值是: java.lang.*
虽然有默认值,但是还是要求任何时候都写明确这个值.
第二个@后面要加上静态属性/静态方法的名字
-->
<s:property value="@@PI"/><br>
<s:property value="@java.lang.Math@PI"/><br>
<s:property value="@java.lang.Math@random()"/><br>
<s:property value="@com.briup.bean.User@test()"/><br>
12.从ActionContext中取值
<s:property value="#action.name"/><br>
<s:property value="#msg"/><br>
<s:property value="#user"/><br>
<s:property value="#user.id"/><br>
<s:property value="#user.name"/><br>
<s:property value="#user.age"/><br>
<s:property value="#parameters.name"/><br>
<s:property value="#request.MyName"/><br>
<s:property value="#session.MyName"/><br>
<s:property value="#application.MyName"/><br>
<s:property value="#attr.MyName"/><br>
<s:property value="#request"/><br>
<s:property value="#request.name"/><br>
//这个是OGNL测试的时候所用到的action类和User类
public class GetValueActionTest extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
private String name;
private User user;
private Map<String,Object> request;
private Map<String,Object> session;
private Map<String,Object> application;
@Override
public String execute() throws Exception {
//System.out.println(this);
user = new User();
user.setId(100);
user.setName("zhangsan");
user.setAge(20);
User u = new User();
u.setId(500);
u.setName("lisi");
u.setAge(30);
ActionContext ac = ActionContext.getContext();
ValueStack vs = ac.getValueStack();
vs.push(u);
ac.put("user",u);
ac.put("msg","hello world");
name = "tom";
request.put("MyName", "tom1");
session.put("MyName", "tom2");
application.put("MyName","tom3");
return SUCCESS;
}
public String myOGNL() throws Exception {
//System.out.println(this);
user = new User();
user.setId(100);
user.setName("zhangsan");
user.setAge(20);
User u = new User();
u.setId(500);
u.setName("lisi");
u.setAge(30);
ActionContext ac = ActionContext.getContext();
ValueStack vs = ac.getValueStack();
vs.push(u);
ac.put("user",u);
ac.put("msg","hello world");
name = "tom";
request.put("MyName", "tom1");
session.put("MyName", "tom2");
application.put("MyName","tom3");
return SUCCESS;
}
public static String test(){
return "static method";
}
public static String getVOMethod(){
return "GetValueActionTest";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public void setRequest(Map<String, Object> request) {
// TODO Auto-generated method stub
this.request = request;
}
public void setSession(Map<String, Object> session) {
// TODO Auto-generated method stub
this.session = session;
}
public void setApplication(Map<String, Object> application) {
// TODO Auto-generated method stub
this.application = application;
}
}
package com.briup.bean;
public class User {
private long id;
private String name;
private int age;
public String say(){
return "user say hello";
}
public static String test(){
return "static method in User";
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
19.struts2框架中的标签
<s:debug></s:debug>标签:
用来显示action传到页面中的值(调试代码时候常用到的)
<s:property value=""/>标签:
取值并在页面中输出内容
<s:if> 标签:
<s:elseif> 标签:
<s:else > 标签:
例子:
注意:接收到的参数是字符串类型,需要先转换成int类型再和数字比较
<s:if test="@java.lang.Integer@parseInt(#parameters.score) >= 90">
优秀
</s:if>
<s:elseif test="@java.lang.Integer@parseInt(#parameters.score) >= 80">
良
</s:elseif>
<s:elseif test="@java.lang.Integer@parseInt(#parameters.score) >= 70">
中
</s:elseif>
<s:elseif test="@java.lang.Integer@parseInt(#parameters.score) >= 60">
及格
</s:elseif>
<s:else>
差
</s:else>
<s:fielderror>标签:
浏览器发送请求到action,在运行期间,如果内部出现了什么错误,将来跳转之后能用这个标签
来显示出错误的信息.
<s:iterator>标签:
遍历List集合:
注意:每次遍历接收到的集合 中的对象,都会默认放到ValueStack和ActionContext里面。所以每次遍历拿到
一个对象后,我们可以从这两个地方取值。
从ValueStack取值:
value属性值是要遍历的集合(可以从ValueStack和ActionContext里面取到List集合),
id属性值,是表示每次遍历到的对象用什么名字接受。
<s:iterator value="list" id="u">
<s:property value="id"/>
<s:property value="name"/>
<s:property value="age"/>
</s:iterator>
从ActionContext取值。
<hr/>
<s:iterator value="list" id="u">或者:<s:iterator value="#action.list" id="u">
<s:property value="#u.id"/>
<s:property value="#u.name"/>
<s:property value="#u.age"/>
</s:iterator>
遍历Map类型的集合:
注意:每次遍历Map类型的集合拿到的时候一个键值对,这样的键值对有俩个固定的属性:key value,
分别拿到对应的key和value值.
<s:iterator value="map" id="entry">
//从ValueStack中取遍历到的对象属性值。
<s:property value="key"/> -->
<s:property value="value.id"/>
<s:property value="value.name"/>
<s:property value="value.age"/>
<br>
</s:iterator>
<br>
<s:iterator value="map" id="entry">
//从ActionContext中取遍历到的对象属性值。
<s:property value="#entry.key"/> -->
<s:property value="#entry.value.id"/>
<s:property value="#entry.value.name"/>
<s:property value="#entry.value.age"/>
<br>
</s:iterator>
<s:set>标签:
作用:把一个键值对(key-value)放到一个指定的范围里面,如果不指定,
默认是放在ActionContext里面(debug中可以看到)
//name属性表示值的名字(key)
//value属性表示值的内容(value)
//value可以是一个固定的字符串,也可以用从其他范围中取出的变量来表示
//scope属性表示要存放值的范围.可以是request、session、application等,默认是ActionContext
存值:
例如
<s:set name="MyName" value="'tom'"></s:set>
<s:set name="MyName" value="user.name"></s:set>
<s:set name="MyName" value="#entry.value.name"></s:set>
<s:set name="MyName" value="'tom1'" scope="request"></s:set>
取值:
例如
<s:property value="#MyName"/><br>
<s:property value="#request.MyName"/><br>
特殊的情况:
1.存一个key的名字特殊的值
存值:
<s:set name="my.msg" value="'hello world'"></s:set>
取值:
//这样是取不到的
<s:property value="#my.msg"/>
//这样就可以取到了
<s:property value="#attr['my.msg']"/>
2.直接存放一个List/Map集合
存值: List/数组
<s:set name="myList" value="{'tom1','tom2','tom3'}"></s:set>
取值:
//获得集合的长度
<s:property value="#myList.size"/><br>
//取到集合中某一个下标的值
<s:property value="#myList[0]"/><br>
存值: Map类型集合
//#除了可以表示从ActionContext中取值以为,还能用来声明Map类型集合
<s:set name="myMap" value="#{'1':'tom1','2':'tom2','3':'tom3'}"></s:set>
取值:
//取得Map集合的长度
<s:property value="#myMap.size"/><br>
//取到所有Map集合中的key值
<s:property value="#myMap.keys"/><br>
//取到所有Map集合中的value值
<s:property value="#myMap.values"/><br>
//通过key值取到Map集合中的相对于的value值
<s:property value="#myMap['2']"/><br>
<<s:include>标签
作用:把另一个页面直接包含在当前这个标签所在位置.
例如:
<s:include value="index.jsp"></s:include>
同时还可以传参数
<s:include value="index.jsp">
<s:param name="name" value="zhangsan"></s:param>
</s:include>
可以使用request.getParameter("name")来取得这个参数.
也可以使用ognl表达式取,但是比较麻烦.
<s:form>标签已经表单中的输入框元素等:
例如:
<s:form action="user/TagFormActionTest.action" method="post">
<s:textfield name="username" label="用户名"></s:textfield>
<s:password name="password" label="密码"></s:password>
<!--
把"男" 或者 "女"这个字符串传到action中
<s:radio list="{'男','女'}" name="gender" label="性别"></s:radio>
下面是把"0"或者"1"传给action
-->
<s:radio list="#{'0':'男','1':'女'}" name="gender" label="性别"></s:radio>
<!--
struts2标签中的checkbox分俩种
1.单个的checkbox
2.一组checkbox(多个checkbox是一起的),多个的叫做checkboxlist
-->
<s:checkbox name="autoLogin" fieldValue="yes" label="一周内自动登录"></s:checkbox>
<!--
value="{'2'}" 设置默认选择的是篮球
也可以这样: 这个和上面单选框所表示的情况是一样的
list="{'足球','篮球','排球'}"
-->
<s:checkboxlist list="#{'1':'足球','2':'篮球','3':'排球'}" name="like" label="爱好"
value="{'2'}"></s:checkboxlist>
<!--
headerKey="-1"
headerValue="请选择"
这个俩个表示下拉列表最开始会多一个选项
'-1':'请选择'
-->
<s:select list="#{'1':'北京','2':'上海','3':'南京'}" name="city" label="城市" headerKey="-1" headerValue="请选择"></s:select>
<s:textarea cols="10" rows="5" name="dis" label="个人介绍"></s:textarea>
<s:submit value="提交" method="execute"></s:submit>
<s:submit value="注册" method="register"></s:submit>
<s:submit type="image" src="123.png"></s:submit>
<s:submit type="image" src="3.png"></s:submit>
</s:form>
<s:a>标签
生成一个超链接
<s:url>标签
声明一个变量,这个变量的值是一个url,然后把这个变量默认的放到ActionContext里面
例如:
<s:a href="http://www.baidu.com">百度1</s:a>
<s:url value="http://www.baidu.com" var="myURL1"></s:url>
<!-- myURL1是一个变量,在这里面要用%{myURL1}来拿这个变量值
格式:%{ongl表达式}
<s:url/>是会把这个变量放到ActionContext里面的,
同时我们不仅可以从ActionContext到这个变量值,
还可以从ValueStack拿到。
类似于<s:set/>标签的效果
-->
<s:a href="%{myURL1}">百度2</s:a>
<s:url value="/index.jsp" var="myURL2"></s:url>
<s:a href="%{myURL2}">index.jsp</s:a>
<s:url action="mytest" namespace="/user" var="myURL3"></s:url>
<s:a href="%{myURL3}">mytest.action</s:a>
<s:set name="myURL4" value="'http://www.baidu.com'"></s:set>
<s:a href="%{#myURL4}">百度3</s:a>
<s:text name="name">
作用:使用国际化资源文件中的配置,name属性的值,为自己配置的资源文件的key值。就可以拿到资源文件中配置的
值了。
20.struts2框架中的自定义转换器(convertor)
1.转换器的作用
帮我们把客户端传过来的数据,进行类型转换的.
2,转化器如何工作:
struts框架中已经写好了很多转换器,在我们传值的时候,框架如果发现某一个值需要进行类型转换
,而框架内部已经存在这样一个相应的类型转换器,那么就会调用这个类型转换器帮我们进行类型转换。
例如:用户写好了年龄24然后传给action,本来这是一个字符串,但是传到action中就会变成一个int类型的值。
这个及时类型转换器完成的工作。
同时我们还可以自定义转换器,按照我们自己的要求,把一个值转换成另外一种类型的值。
3,如何去写一个自定义转换器
前提:页面有一个输入框,输入框中输入类似于这样的数据:1:tom:20,提交数据之后
这个值会变成User对象
,然后放到了action里面
1,写一个转换器类
继承一个父类(抽象类):StrutsTypeConverter
例如:
package com.briup.web.converter;
import java.util.Map;
import org.apache.struts2.util.StrutsTypeConverter;
import com.briup.bean.User;
public class MyConverter extends StrutsTypeConverter {
@Override
public Object convertFromString(Map map, String[] str, Class c) {
System.out.println("in MyConverter"+str.length);
String s = str[0];
String[] strings = s.split(":");
long id = Long.parseLong(strings[0]);
String name = strings[1];
int age = Integer.parseInt(strings[2]);
User user = new User(id, name, age);
return user;
}
@Override
public String convertToString(Map map, Object o) {
return o.toString();
}
}
2,配置转换器
a,配置成局部的转换器
特点:只对某一个action起作用
写一个.properties资源文件
1,文件的位置:
和要使用的action放在同一个包下面
2,文件的名字:
xxx-conversion.properties
xxx值得是action的类名
注意:文件名字中的-conversion.properties是固定的,xxx是可变的
3,文件的内容:
例如:
user=com.briup.web.converter.MyConverter
表示的意思:当前数据提交到这个名字为xxx的action里面的时候,如果action中有一个名字叫
user的属性,那么这个属性的值就要通过com.briup.web.converter.MyConverter 这个
转换器转换后在获得。
b,配置成全局的转换器
1,文件的位置:
直接放到src下面
2,文件的名字:
xwork-conversion.properties
3,文件的内容:
例如:
com.briup.bean.User=com.briup.web.converter.MyConverter
表示的意思:当前数据提交到任何的action里面的时候,如果action里面有一个
类型为com.briup.bean.User的属性,
那么这个属性的值就要通过com.briup.web.converter.MyConverter 这个
转换器转换后在获得。
21.struts框架中的数据验证(validation)
作用:客户端提交的数据在到达action之前,struts框架可以帮我们去验证一下这个数据是否符合我们的格式要求,
如果符合要求,就让action去接受这个数据,如果不符合,就会提示出错误,然后默认返回input字符串。
1,我们需要使用xwork-2.1.2.jar这个jar包的类来进行数据的验证
2,需要写一个xml文件
作用:描述清楚action中的哪一个属性需要被xwork-2.1.2.jar中的哪一个类进行验证,并且定义出验证不通过
后返回的信息。
a,文件的名字
xxx-validation.xml
xxx指的是数据提交到的action的类名,xxx后面是固定的写法。
b,文件的位置
和这个名字为xxx的action相同的包下面。
c,文件的内容
这个xml文件内容是由一个dtd文件控制的。所以我们在文件中引入这个dtd,然后就可以自动提示生成要写的
标签了。
在这个xml文件中引入头部声明(引用dtd):
在xwork-2.1.2.jar中,有很多dtd文件,我们可以打开一个叫xwork-validator-1.0.2.dtd文件,
这个文件的注释里面就有我们需要的头部声明,就是这个标签:<!DOCTYPE ...>
把这个复杂到我们的xml文件中,做为头部声明来引用需要的dtd文件,然后就可以自动提示了,
如果不能提交,就像以前一样,在MyEclipse中进行配置就可以了.
一个配置的例子:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE validators PUBLIC
"-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"http://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<!-- 给当前action的哪一个属性做验证 -->
<field name="username">
<!-- 使用哪一个验证器来验证这个属性值 -->
<!-- 验证器的名字可以从xwork-2.1.2.jar包的default.xml中找到 -->
<!-- default.xml在com.opensymphony.xwork2.validator.validators包下面 -->
<field-validator type="requiredstring">
<!-- 如果这个验证没通过,返回的字符串信息 -->
<message>用户名不为空</message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<message>密码不能为空</message>
</field-validator>
<!-- 同一个属性可以使用多个验证器验证 -->
<field-validator type="stringlength">
<!-- 可以给验证器传参数 -->
<!-- 参数名字可以在验证器类(API)中看到 -->
<!-- 在default.xml文件中可以找这个验证器是哪个类 -->
<param name="minLength">4</param>
<param name="maxLength">7</param>
<message>密码长度必须是4-7个字符之间</message>
</field-validator>
</field>
</validators>
22.struts2框架的国际化配置(i18n)
作用:不同国家或者地区的人访问我们这个同一个web项目,在页面中显示的文字等内容是不同的,
是和当前国家或者地区保持一致的。
internationalization
1.配置两个资源文件
xxx_zh.properties
xxx_en.properties
例如:xxx随便起的名字,比如:可以为message
2.这两个文件直接放在src下面。
比如:message_en.properties这个文件当中存放的是要显示英文信息
message_zh.properties这个文件当中存放的是要显示中文信息
例如:message_en.properties文件内容:
name=UserName
pwd=PassWord
注:name是key,UserName是是value值,name是在页面中使用的,value是要最终显示在页面的内容,也
就是说,我们在页面中通过key来拿到相对应的value来进行显示。
name=用户名
pwd=密码
注:properties文件中是不能直接写中文的。
要写出这样,JdK的命令native2ascii可以完成这个工作
name \u7528\u6237\u540D
pwd=\u5BC6\u7801
4,在struts.xml文件中配置国际化的资源文件。
message为资源文件的前缀:
<constant name="struts.custom.i18n.resources" value="message"></constant>
5,在页面中使用struts2的标签通过key拿到资源文件中的value值进行显示。
页面中的代码
<s:text name="name"></s:text><input type="text" name="username"/><br>
<s:text name="pwd"></s:text><input type="password" name="password">
住: <s:text name="name">可以通过key拿到资源文件的value
6.将来浏览器中到底是显示中文还是英文,要看浏览器中默认优先使用的是哪一种语言来显示当前页面的,(我们
自己可以设置这个语言)