Struts2 第二讲 -- Struts2的入门
搭建struts2环境时,我们一般需要做以下几个步骤的工作:
- 第一步:创建javaweb工程(这个很废话有木有)
- 第二步:找到开发Struts2应用需要使用到的jar文件.(这个很白痴有没有)
到http://struts.apache.org/download.cgi#struts2514.1下载struts-2.x.x-all.zip,最新的版本为2.5.14。下载完后解压文件,开发struts2应用需要依赖的jar文件在解压目录的lib文件夹下。不同的应用需要的JAR包是不同的。下面给出了开发Struts 2程序最少需要的JAR。
-
- struts2-core-2.3.3.jar:Struts 2框架的核心类库
- xwork-core-2.3.3.jar:Command模式框架,WebWork和Struts2都基于xwork, (以前使用Struts2时版本很低2.3.3,那是xwork-core-2.3.3.jar和struts2-core-2.3.3.jar还是独立的jar包,2.5.14中没有xwork-core包,和struts2-core合并了)
- ognl-3.0.5.jar: 对象图导航语言(Object Graph Navigation Language), struts2框架通过其读写对象的属性
- freemarker-2.3.19.jar:Struts 2的UI标签的模板使用FreeMarker编写
- commons-logging-1.1.x.jar:ASF出品的日志包,Struts 2框架使用这个日志包来支持Log4J和JDK 1.4+的日志记录。
- commons-fileupload-1.2.2.jar: 文件上传组件,2.1.6版本后需要加入此文件
- commons-io-2.0.1.jar:上传文件依赖的jar包
- commons-lang3-3.1.jar:对java.lang包的增强
- asm-3.3.jar:提供了字节码的读写的功能,包含了核心的功能,而其他 jar包都是基于这个核心的扩展.
- asm-commons-3.3.jar:提供了基于事件的表现形式。
- asm-tree-3.3.jar:提供了基于对象的表现形式。
- javassist-3.11.0.GA.jar:代码生成工具, struts2用它在运行时扩展 Java类
- log4j-api-2.9.1.jar包 依赖包
如图:
少了一个log4j-api-2.9.1.jar包
- 第三步:创建jsp文件.test.jsp
<body> 入门的路径:<br> 测试Struts2带有参数:<a href="${pageContext.request.contextPath}/primer/helloWorldAction.action?username='zhangsanfeng'">helloWorld</a><br> 测试命名空间:<a href="${pageContext.request.contextPath}/primer/primer/helloWorldAction.action">helloWorld</a><br> 测试action:<a href="${pageContext.request.contextPath}/primer/helloWorldAction.action">helloWorld</a><br> </body>
- 第四步:创建Action文件,用来控制页面和服务器之间的转发。
public class HelloWorldAction implements Action{ @Override public String execute() throws Exception { System.out.println("欢迎访问HelloWorldAction中的execute方法!"); return "success"; } //自定义add方法 public String add(){ System.out.println("欢迎访问HelloWorldAction中的add的方法!"); return "success"; } }
在这段代码中我们并没有继承ActionSupport,而是实现了接口Action(ActionSupport实现了Action接口),我们查看Action接口
public interface Action { public static final String SUCCESS = "success"; public static final String NONE = "none"; public static final String ERROR = "error"; public static final String INPUT = "input"; public static final String LOGIN = "login"; public String execute() throws Exception; }
这个接口中定义了几个常量和一个函数,这都是很有用的,常量是我们的返回结果,而函数是一个默认执行函数,后面我们做介绍.我们将代码扔改回继承ActionSupport类
HelloWorldAction extends ActionSupport
在ActionSupport类中,我们查看发现其中实现了execute(),
public String execute() throws Exception { return SUCCESS; }
注意:Struts2对Action类的操作,可以实现Action接口,也可以继承ActionSupport类(com.opensymphony.包下),但是也可以不继承因为struts-default.xml中
<default-class-ref class="com.opensymphony.xwork2.ActionSupport" />
这句话默认继承了ActionSupport类.
第五步:编写Struts2的配置文件,这个文件要求:
(1)必须放置到src下(即项目的classpath的根路径下)
(2)名称必须叫做struts.xml,不能叫做其他的名称
注意:我们这里先操作,操作完再讲,为啥子只能叫这个名,叫狗蛋.xml就不行,放在web-INF下就不行.
配置如下:
关于XML约束的解决办法:
XML是有约束的,约束我们可以从struts2-core-2.5.14.1.jar包下的struts-default.xml或者是struts-2.5.dtd下找到
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd">
问题2:解决不提示,我们在写struts.xml时,提示可以帮助我们书写并能避免错误,但有时候不提示,那么怎么解决呢?
解压struts2-core包,找到struts-2.5.dtd(我们可以将一些以后会用到的dtd统一放在一个文件夹下,便于查找.),在Eclipse中Window-preferences-XML-XML Catalog然后配置如下图:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN" "http://struts.apache.org/dtds/struts-2.5.dtd"> <struts> <!-- package包 * name:包的名称,在struts.xml中不允许出现重名,名称要求惟一,用作继承 * namespace:命名空间,表示访问URL的时候,是否通过命名空间访问,默认是/ * extends:表示继承,struts2要求所有的包必须继承struts-default,这样才能使用struts-default.xml文件中定义的返回类型和拦截器 --> <package name="primer" namespace="/primer" extends="struts-default"> <!-- 问题:如果请求的路径查找不到action的情况下,程序运行会抛出异常 ,可以通过配置当找不到action的情况下,会执行默认的action --> <!--指定默认的action引用,如果该包下没有对应action配置,则启用该配置--> <default-action-ref name="helloWorldAction"></default-action-ref> <!-- action: 指页面的URL连接的名称对应访问的Action类 * name:访问的Action的路径 * class:对应的类的全路径 配置:1: 如果不指定:class="cn.itcast.a_primer.HelloWorldAction" 如果没有为action指定class,默认是com.opensymphony.xwork2.ActionSupport 执行ActionSupport中的execute方法 配置2: 2>如果没有为action指定method,默认执行action中的execute() 方法。 ActionSupport的execute方法里面就一句话return "success"; 如果指定method,会执行method中定义的方法 配置3: 如果没有指定result的name属性,默认值为success。 --> <action name="helloWorldAction" class="cn.youric.you.one_primer.HelloWorldAction"> <!-- result:指访问Action类的方法返回值,对应跳转的页面 * name:Action类中方法的返回值 * <result>中的文本内容:表示需要跳转的页面 --> <result name="success">/primer/success.jsp</result> <result name="add">/primer/add.jsp</result> </action> </package> </struts>
Result中还可以有一个属性type,result 元素的 type 属性负责指定结果类型. type 属性的值必须是在包含当前包或者是当前包的父包里注册过的结果类型. type 属性的默认值为 dispatcher
这里注意:
- 1) <package name="primer">表示Struts2 把各种 Action 分门别类地组织成不同的包. 可以把包想象为一个模块. 一个典型的 struts.xml 文件可以有一个或多个包
- 2) <package namespace=”/primer”>表示,其中namespace 属性是可选的, 如果它没有给出, 则以 “/” 为默认值. 若 namespace 有一个非默认值, 则要想调用这个包里的Action, 就必须把这个属性所定义的命名空间添加到有关的 URI 字符串里
- 3) <package extends="struts-default">表示package 元素通常要对 struts-default.xml 文件里定义的 struts-default 包进行扩展. 这么做了以后, 包里的所有功能就可以使用,这些功能包括在 struts-default.xml 文件里的结果类型和拦截器
- 4) <action name="helloWorldAction">表示:每个 action 都必须有一个 name 属性, 该属性和用户请求的servletPath 之间存在着一一对应关系,此时对应:
<a href="${pageContext.request.contextPath}/helloWorldAction.action">helloWorld</a><br>
- 5) <action class="cn.itcast.a_primer.HelloWorldAction">表示:其中action 元素的 class 属性是可选的. 如果没有配置 class 属性, Struts 将把 com.opensymphony.xwork2.ActionSupport 作为其默认值. 如果配置了 class 属性, 还可以使用 method 属性配置该类的一个动作方法. method 属性的默认值为 execute 。
- 6) <result name="success">表示result 元素的 name 属性建立 <result> 和 Action 方法返回值之间的映射关系。name 属性的默认值为 “success
- 7) <result name="success">/primer/success.jsp</result>表示result 元素的 type 属性负责指定结果类型. type 属性的值必须是在包含当前包或者是当前包的父包里注册过的结果类型. type 属性的默认值为 dispatcher
- 8) result 元素:<action> 的一个子元素, 它告诉 struts 在完成动作后把控制权转交到哪里. result 元素(的name 属性)对应着 Action 方法的返回值. 因为动作方法在不同情况下可能返回不同的值, 所以同一个 action 元素可能会有多个 result 元素
在struts2框架中使用包来管理Action,包的作用和java中的类包是非常类似的,它主要用于管理一组业务功能相关的action。在实际应用中,我们应该把一组业务功能相关的Action放在同一个包下。配置包时必须指定name属性,如果其他包要继承该包,必须通过该属性进行引用,注意:name名称是唯一 。包的namespace属性用于定义该包的命名空间。该属性可以不配置,如果不指定该属性,默认的命名空间为“/”
通常每个包都应该继承struts-default包, struts-default包是由struts内置的,它定义了struts2内部的众多拦截器和Result类型。而Struts2很多核心的功能都是通过这些内置的拦截器实现。如:从请求中把请求参数封装到action、文件上传和数据验证等等都是通过拦截器实现的。当包继承了struts-default包才能使用struts2为我们提供的这些功能。 struts-default包是在struts2-core-2.x.x.jar文件中的struts-default.xml中定义。 struts-default.xml也是Struts2默认配置文件。 Struts2每次都会自动加载 struts-default.xml文件。加载的过程通过过滤器实现的
包还可以通过abstract=“true”定义为抽象包,抽象包中不能包含action。
第六步:在web.xml中加入Struts2 MVC框架启动配置,过滤器,没有它struts2就不能启动struts.xml,struts2的功能也就无法实现。[服务器启动是先要加载web.xml中的配置文件的,我们的web服务,不在web.xml中配置,一切都是空谈]
<!-- 添加struts2的核心过滤器,这是struts2运行的核心 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
完成上面的操作我们下面来实践一下:项目启动报错,这是因为我们少倒入一个jar包log4j-api-2.9.1.jar,我们倒入重启服务器OK
初次完成一个struts2的入门后我们来探讨前面提的问题,struts.xml的命名和位置,为什么要固定,我们在web.xml中知道了对struts.xml文件加载使用到了一个类org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter《Eclipse ---->Navigate---->open Type》
我们在这个类中发现了一个初始化方法init,我们在init上面打断点流程如下:
在StrutsPrepareAndExecuteFilter函数中,有初始化方法
public void init(FilterConfig filterConfig) throws ServletException { ......................... dispatcher = init.initDispatcher(config); ..................................... }
InitOperations public Dispatcher initDispatcher( HostConfig filterConfig ) { Dispatcher dispatcher = createDispatcher(filterConfig); dispatcher.init(); return dispatcher; }
Dispatcher public void init() { ............................. init_TraditionalXmlConfigurations(); // [2] ........................... }
private void init_TraditionalXmlConfigurations() { String configPaths = initParams.get("config"); if (configPaths == null) { configPaths = DEFAULT_CONFIGURATION_PATHS; } .................................... }
private static final String DEFAULT_CONFIGURATION_PATHS = "struts-default.xml,struts-plugin.xml,struts.xml";
在web.xml配置struts2的过滤器,在过滤器启动的时候,加载;按照顺序加载了三个文件,struts-default放置返回类型和过滤器,第二个是插件,第三个是我们的struts.xml.从上面我们看出名称是不能变的,而没给出路径,也就意味着只能从src下找,路径也是不变的.
加载完成后文件中的配置放置到内存中
<package name="primer" namespace="/" extends="struts-default"> <action name="helloWorldAction" class="cn.itcast.a_primer.HelloWorldAction"> <result name="success">/primer/success.jsp</result> </action> </package>
这里要知道
- 1) 在struts1.x中,struts框架是通过Servlet启动的,而在struts2中,struts框架是通过Filter启动的。
- 2) 在StrutsPrepareAndExecuteFilter的init()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。
- 3) struts2读取到struts.xml的内容后,是将内容封装进javabean对象然后存放在内存中,以后用户的每次请求处理将使用内存中的数据,而不是每次请求都读取struts.xml文件。
- 4) 过滤器启动后加载:使用init方法,初始化struts的各种xml文件和属性文件