步骤1.导入最基本的jar包
sturts2-core-2.x.x.jar: Struts2框架的核心类库
xwork-2.x.x.jar: Xwork类库,Struts2在其上构建
ognl-2.6.x.jar: 对象导航语言,Struts2框架通过其读写对象属性
freemarker-2.3.x.jar: Struts2的UI标签的模版使用Freemarker编写
commons-logging-1.1.x.jar: ASF出品的日志包,Struts框架使用这个日志包来支持Log4j和JDK1.4+的日志记录。
commons-filetemp-1.2.1.jar: 文件上传组件,2.1.6版本后必须加入次文件
commons-io-1..3.2.jar 文件上传下载需要
步骤2.将struts.xml放到src下
struts.xml配置
代码:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- <constant name="struts.enable.DynamicMethodInvocation" value="false" />
<constant name="struts.devMode" value="false" />//此struts.xml文件修改后是否立即生效
<include file="example.xml"/>
<package name="default" namespace="/" extends="struts-default">
<default-action-ref name="index" />
<action name="index">
<result type="redirectAction">
<param name="actionName">HelloWorld</param>
<param name="namespace">/example</param>
</result>
</action>
</package>
-->
<!-- Add packages here -->
<constant name="sturts.i18n.encoding" value="GBK"/>
<!—作用:官方宣称中文不乱码,但是还有乱码貌似->
<constant name="struts.devMode" value="true" />
<!—作用:修改后不用reload-->
<package name="b" namespace="/ab" extends="struts-default" >
<action name="*" class="www.baidu.com.Hello2" method="{1}">
<result name="fuckyou">
/Hello2.jsp
</result>
<result name="fuck">
/Hello.jsp
</result>
</action>
</package>
</struts>
(绿色是保留部分一边copy,不起作用,红色是修改重点)
步骤3.将web.xml放到webroot下的WEB-INF文件夹下
web.xml配置
代码:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<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>
</web-app>
注意:struts2.xml 被读取后,将以javabean的形式存放在内存中,以后struts2对每个用户的每次请求处理将使用内存中的数据,而不是每次都读取struts.xml文件了
文件所在
这些 struts.xml 和 web.xml可以在struts-2.1.8.1appsstruts2-blank-2.1.8.1WEB-INF下找到struts.xml和 web.xml和jar包
Action注意事项
1 更改jsp编码
Window -> Perference -> JSP(搜索) 设Encoding为 Chinese ,nation stander
2 复制struts2项目时注意
Copy后的项目 -> Property ->web(搜索) 修改context-root 为“/项目名”
Struts.xml增加文件中的提示
由于xml文件,是根据dtd文件来显示的,而dtd文件并不为MyEclipse所知道,所以要手动的指定dtd所在的位置。
属性中 搜索 catalog (登记)
将struts的uri复制到key中
Location是那个Struts-2.0.dtd文件的位置(这个文件可以在libstruts2-core-2.1.8.1.jar解压后找到)
Ok即可
Struts的运行机制
任何的运行机制都要从访问的网址开始:
例如:
http://localhost:8888/Struts2Test/hello
首先Tomcat会去寻找Struts2Test这个web站点,然后在这个站点中查看web.xml的配置
发现配置如下:
。。。。
<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>
。。。。
他用/*来匹配所有的访问,则filter调用doFilter,doFileter要参考struts.xml,因此找到struts.xml
查看struts中的namespace“/”,再在namespace为“/”之后查看有没有hello的action,有就直接输出result
NameSpace
namespace 是为了较少繁琐的定义路径而设置的
namespace如果不写,就是默认为空 :namespace=””;
如果为空,则namespace匹配所有的url中namespace。类似*号一样。
例如:http://localhost:8888/1/2/3/4/hello
/1/2/3/4就是可以被空的namespace所匹配。
package 与java中的package相似,这里的主要功能是 在 继承的时候要用的package的name属性,还有用来区分相同的名字。
如果一个 package被定义为abstract,则这个包只能被继承,不能定义任何的action
路径问题1(namespace路径问题)
如果访问的路径中的namespace,Struts.xml没有相对应的namespace,则就交给Tomcat去找web.xml是否有相应的设置,如果有就使用 例如:
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list> 就根据它来显示了(其实我试过很过都不行,只有部分可以)
路径问题2(相对和绝对路径问题)
这里要注意:要全部使用绝对的路径,否则会有问题:
问题例子:
如果你的namespace设置为:/rotoy要访问的action为hello,hello显示的页面为hello.jsp, index.jsp和hello.jsp是同一目录,都在WebrRoot下面。
而hello.jsp中有一个连接为:<a herf=”index.jsp”> 跳往index.jsp</a>
则URL为:http://localhost:8888/rotoy/hello访问正常,
但是如果点击hello.jsp中的连接,前往index.jsp的时候就出现错误了,找不到页面!
分析:hello.jsp和index.jsp在同一个目录下面,应该用那个相对路径可以访问的,那为什么出现错误呢?
原因是:由于程序只知道的是当前的路径,你访问的是hello.jsp 则当前的路径是:
http://localhost:888/rotoy,如果你直接点击那个相对路径,则就访问了http://localhost:8888/rotoy/index.jsp页面了,它是在当前的目录寻找,所以就出错了,所以那个连接最好是设置为绝对路径
Action 学习内容简要回顾
实现一个Action的3种方法:
1.直接定义一个普通类,有一个返回String类型的execute方法
2.实现Action接口(ActionSupport也是实现此接口)
3.继承ActionSupport接口(最常用,开发时候只用它,
原因:
它封装了许多方法,实现它可以用它的方法
)
struts2 调用每个action的类的时候是new一个出来,不是像struts1一样,用相同的一个,这样就避免了线程同步的问题。
查看ActionSupport的源码
如果一个ation没有写class属性,则默认执行的是AtionSupport这个类,这个类用到了另外的一个框架->xwork
如果要看ActionSupport的源码,必须要给xwor-2.1.X.jar文件附加源码
ActionSupport也是执行的是 execute方法,返回success
ActionSupport实现了Action接口
DMI 动态方法调用(Dynamic Method Invocation)
运用感叹号(!)于Action后面来调用Aciton的Class属性所指向的类中的方法
如:http://localhost:8888/T/abc/abc!text?name=abc&age=20
解:其中T为一个站点
第一个abc为namespace
第二个abc为action
则text为action类中的一个方法
name和age是向ation类中传递的2个参数
age会自动的在int和String中转换
注意:struts.xml中配置的文件中的<action>我们要把它和那个他对应的那个类想成同一个,因为那个类也是一个action,他们指的是同一个的不同映射结果!不要把它想成:配置文件中的action,然后这个action对应一个类! 不知这样的!他们是同一个!
通配符
例如:
<action name=”student*” class=”com.baidu.www.count” method=”{1}”>
<result>
/ShowResult.jsp
</result>
</action>
如果访问:http://localhost:8888/Student/studentadd
那么student就匹配了studentadd , *部分就匹配了add
{1}代码第一个*,{2}代表第二个*……
那么method=”add”了,就是*匹配了add
注意!匹配顺序:
先匹配最精确的action(就是最符合,最相像的)
带有*号的属于同一级别,谁前谁的优先级别大。
Action 接收参数的方法
例如:访问的地址为:http://localhost:8888/T/abc/count!add?name=abc&age=3
则:count action Mapping的class 中接收:
1用属性接收
1解:
在传递的属性很少时,用属性接收
具体:要在class中定义好name和age的getter和setter
Struts2会自动的调用并且赋值,我们直接调用name和age即可
例如:访问的地址为:http://localhost:8888/T/abc/count!add?man.name=abc&man.age=3
2用DomainModel接收
所谓的DomainModel就是一个DAO(应该是吧),用来传输数据中一个容器类
2解
可在传递的属性比较多时使用
定义一个DomainModel(另一个类,如man类)
里面定义好属性(name和age),和属性的getter和setter方法
在class中定义好这个DomainModel(即man不初始化),和man的getter setter方法
Struts2会自动的设置这个man的name 和age 属性,我们调用即可
用URL来给于参数,调用的URL:
http://localhost:8888/rotoy/add!man.age=22&&man.name=Rotoy
注意:action类中要有man的getter和setter方法
man中要有age和name的getter和setter方法
中文参数问题
如果Struts提交的参数是中文会有乱码
官方解决:
其中的
是官方的解决方案。
配置方法,参看default.properties
简单的参数验证
例如:class中的name属性接收时不满足条件
由于Struts中的class没有request等的对象,所以只能
在class中调用:this.addFieldError(“name”,”Error msg”);
JSP中接收
1先在顶端加:<%@taglib uri=”/struts-tags” prefix=”s” %>
2调用 <s: filed error fielName=”name” theme=simple” />
<s.property value=”errors.name[0]”/>
<s.debug></s:debug>//显示debug信息
<s:property></s:property>的作用是专门去取得:
和Stack Context (也叫Action Context)
中的值
Value Stack中放的是:错误信息和 Action 类中的属性。
其中
中的:
其中[]是指的数组,{}指的是:map类型的,{[]}明显是就map中的数组。
Action访问Web元素方法1
Action将要取得:
便于记忆
其中有 request(map类型),和 session(map类型),application(map类型)放在value context中(也叫Action context,其实是ThreadLocal对象,ThreadLocal就是一个Thead和其值)
而 Action 中的属性是放在 value Stack 中的。
这就类似于jsp:他的page相当于value satck中的属性,其他的request,session,application和Action 的一一相对应,这样便于记忆。
获取action的web元素:
单态模式:例如:ActionContext.getContext.get (“request”);
其中:ActionContext是静态引用, ActionContext.getContext是获得Action Context(Value Context)的实例。
ActionContext.getContext.get(“request”)是根据key获得request,还可以获得session,和Accpplication
方法分别为:
(由于取得的方法不同,所以只有request要强转)
获取后可以在Action中使用:
Jsp中可以取得:
关于:<s:property value=”#request.r1”/>的写法
由于有说明:
所以可以用#来取值。(value stack 中的直接取得,不用#)
注意细节:
在action中的request session application 都是map类型的,在jsp页面中可以取得,说明Struts在这个过程中,已经将 action中的map类型的web 元素,完全复制到了 jsp中的HttpRequsest, HttpSession HttpApplication中了
Action访问Web元素方法2
Ioc或者DI(最常用)
Invers of Control (控制反转)
Dependency Injection(依赖注入)依赖struts2
解释:都是将自己的属性交给别人来操作,所以依赖别人,叫DI,
有因为交给别人操作是把控制权交给别人,所以是IoC
Action实现了RequestAware ,SessionAware,ApplicationAware这些接口,然后重写里买呢的
setRequest(),setSession();setApplication()方法。就可以获得他们了
tip:其实真正开发reuqest几乎不用去获取,因为action的值会自动的放在value stack里面,
而value tack又是在request里面!
而application也不用,需要长久的话用数据库,或者放在一个类中。
之前都是map的request等,
如何获得真实HttpRequest呢?
如图:(因为几乎不用,所以只给图代码)
方法1;
方法2
总结访问web元素
1 访问Map类型
a)IoC(反转控制)(主要方法)
b)依赖Struts2
2访问原始类型(真实类型)
a)IoC(反转控制)
b)依赖Struts2
模块包含
如:
<struts>
<include file=”login.xml”/>//完全复制login.xml内容到这里
</struts>
这样是为了分工合作比较好。
默认Action
当输入的action不存在时,都转向这个action
Result的类型
注意:type=chain时候的result是指向action的,前面不要加/
默认是 dispatcher: forward)服务器跳转(只能跳转页面,不能是action)(就这2个常用)
redirect: 客户端跳转(只能跳转页面,不能是action)(就这2个常用)
chain:服务器跳转action (了解即可)
redircAction:客户端跳转action(了解即可)
freemarker:跳到freemarker页面(后面讲)
httpheader: 发送头信息(不用)
stream::下载(后面讲)
velocity: freemarker类似的模版框架(抛弃,freemark超过它)
xslt:与xml相关的xml语言(不用)
plaintext:将页面源码显示出来(不用)
tites:页面分成几块(不用)
result为chain或者redircAction时候跳转其他包的action
用<param name/>来指定
全局的result和package的exends
如果每个action都有一个相同的action,都写麻烦,用global-result
只要配置了这个global-result,这个package的每个action不用写,都有了
那其他的包要用extends来继承这个包的配置,这个继承是继承那个包的所有的配置,所以包括了那个全局结果集
动态result
在struts.xml文件中可以用${属性名}来获取value stack中的值。
不要和 el 表达式混淆,el是用在jsp中的
如果在action中将这个变量r根据情况设置,那么就是动态的结果了。
不同Action 的 value Stack
一次request就一个value stack,如果这时从一个action ,forward 到另一个action上,则他们共享一个value stack,因为forward不会发起新的request
那客户端跳转,这个action该如何将上次的值传给?
我们知道,如果是服务器跳转,直接在那个跳转的jsp页面的value stack中拿就可以了,
但是这里是客户端跳转,该怎么办呢?
答案是:将值取出,作为动态参数传给客户端跳转的那个界面
OGNL取值
Action中的domain Model 要自动的被struts 初始化的条件:
1:必须给action的domain Modle传值。
2:必须要有无参构造函数。
给acion的domain Model 传值:xxx/?user.age=99
它就就调用了无参构造,所以要有无参构造函数。
OGNL是为了方便取得value stack 而设置的,所以它都是写在<s:property></s:property>之中
访问本action的属性内容:
<s:property value=”cat.friend.name”></s:property>:action中有一个cat类,它有一个成员也是一个friend是dog类,访问dog的名字。
如果要访问静态的:
前提是要配置,默认是false
访问本action的静态属性:
都是在类和方法或属性前面加@
还有一种只能访问Math类的方法:
访问 构造方法:(也就是创建对象)
OGNL访问集合对象
其中数组也是根据下标来访问的。
Set不能用下标,因为set的无序的。
OGNL取值投影
所谓投影就是过滤:
投影就3中过滤方式:?#,^#,$#
?#:代表条件
^#:代表最前面的一个
$#:代表最后面的那一个
this代表的是,当前遍历的那个对象,注意OGNL中{}代表的是集合
所以可以表达成:
第一个:age==1的集合
第二个:age>1的集合中的第一个元素的age的集合,因为就一个元素,所以后面的那个age集合也就是一个
第3个:age>1的最后的那个集合的age属性的集合
第4个:age>1的最后的那个集合的age属性的集合是否存在
OGNL访问整个value stack
之前的访问都是在value stack中的action对象
注意:一个value stack中,不是只有一个action可以有其他的。
上图是一个value stack,有一个aciotn和一个defaultTextProvider2个对象,
用:
调用action
按照常理:
[0]应该是访问value stack里面的第一个值,从上往下,就是OGNLAction了
[1]:应该是访问 value stack 里面的第2个值,就是DefaultTextProvider了
但是:[0]却是代表这整个value stack 中的对象,这样是为了避免有多个action在value stack中,找不到对应的值
除了[0],之外特殊,其他都是正常的.[1]就代表从上往下第2个对象。
通用标签
<s:property></s:property>标签
1.在标签中,只要是默认的对象是object 的 那么就会将字符串解析成为ognl表达式,那么就去value stack里面取值:
2.<s:property value=”这里的默认是object的”></s:property>,所以会将里面的字符串作为取值的key,然后输出。
3.如果要直接写出你给的字符串,则要字符串,所以要包2层才可以。
4.Default是没有value的时候,输出default的值。
5.<s:property value=“XX”></s:property>,默认escape是true,就是直接不解析<html>代码,碰到直接输出,没有html的效果。
<s:set></s:set>
value type=string 是错误的,也是object,会将字符串解析成为ognl表达式。
id 和name 已经作废:var代替它们。
注意:有var就代表这个变量已经放入了action Context之中,用#来取得
set标签的作用:
将值 放到 各个 范围之中
。
默认放到action中,就是request 和 actionContext之中。
说明:
取值例子:
其中name的几个设置是旧的写法。不用理会。
<s:bean></s:bean>
name设置类详细信息
只有设置了var属性才能在在actionContext中找到,不然key是么有value的
它会自动帮你new。
<s:param >设置这个bean内属性的值
<include ></include>
由于有中文的时候会有问题,不用。
#$%
$用于struts.xml中,读取value stack 中的值
<s:fielderror></s:fielderror>
控制标签
if else
遍历集合
遍历map
注意:
定义map要在前面加#号,原因不详。
Key和value用冒号隔开
要取得一项做文章:
只要:
是collection map array 或者实现了enumeration iterator接口,都可以用这个标签遍历
默认配置信息获取
Struts声明式异常处理
首先,我们要将所有的action调用的类的异常,都是向上抛出
就算是调用这个的action也是抛出(这里扩大异常的范围了)
然后在struts中配置:这个配置是针对某一个package的,不是全部的,
只要这个package范围出现错误就跳往那个页面error.jsp。
针对全部的配置:
然后其他的从这里extend
(补全:extends = ‘bbs2009_dafault’)
注意:全局的只写
并不把result写在这里,result还是写在每个各自的action下面。(这个是为了让异常更加详细,更有针对性,配置在全局里面也可以,不过记住,全局result要写在全局mapping上面!!)
【各自配置result的】运行过程:
首先会先在各自的自己的action中找mapping,有就找自己对应的result,然后输出jsp,
如果没有,就从继承的里找mapping,找到后,再找自己action的relsut后输出jsp
【全局result】运行过程 :自己推理:先全局mapping,有!-->自己reslut没有!-->全局relsut。
default-action-ref 的问题
这个配置了以后,如果访问了这个namespace中的非正常路径,都会转到default-action-ref所对应的action里面,注意:但是它不会去执行那个action对应的class
只会单单的去显示那个action所对应的result。如果正常访问路径就会执行class
解决方案
在web.xml中配置action的名字:
就可以正常使用,即在访问路径错误的情况下,还能够执行class。注意:后来发现,打XX的地方default-acton-ref还是需要的
I18N
调用资源文件的代码:
ResourceBundle rb = ResourceBundle.getBundle("test",Locale.US);
System.out.println(rb.getString("System.info"));
注意:Locale.US那里是写国家名,不是语言名字:不是:Locale.CHINESE
test是资源文件的前面部分名字:
资源文件后面的名字是固定的!