讲了诸多原理性的东西,下面该来看看如何实践了:
首先,在MyEclipse中新建一个Web Project,命名为struts2(注意这里我用的版本是struts2.1.6),规范级别选择Java EE 5.0,当然了,我们仍然需要告诉Tomcat我们的项目在哪里,因此到Tomcat安装目录下的conf文件夹下的server.xml文件,为了节约时间,我们把test项目的上下文放到注释中,以免每次启动tomcat,都要加载该项目,相关配置部分如下:
<!-- <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/> <Context path="/test" docBase="D:\JavaWeb\test\WebRoot" reloadable="true"/> --> <Context path="/struts2" docBase="D:\JavaWeb\struts2\WebRoot" reloadable="true"/> </Host> </Engine> </Service> </Server>
重启tomcat服务器,访问http://localhost:8080/struts2,页面出现"This is my JSP page." 表示我们的项目已经纳入Tomcat的管理之下了。我们将structs2框架集成到我们新建的项目中,其实就是将structs2提供的JAR包添加到项目了,其中我们需要的JAR包有(在解压好的structs的解压文件中的lib目录下)commons-fileupload-1.2.1.jar、commons-logging-1.0.4.jar、freemarker-2.3.13.jar、ognl-2.6.11.jar、struts2-core-2.1.6.jar、xwork-core-2.1.2.jar共六个文件选中复制,回到MyEclipse,粘贴到WebRoot下面的WEB-INF下的lib目录下,这样这些第三方库就可以为我们所用了。
下面,我们用struts2写一个经典的hello world,标志学习struct2的起步:
在WebRoot下新建一个helloworld.jsp文件,将body中的内容更改为Hello World。当然我们可以直接访问http://localhost:8080/struts2/helloworld.jsp。但是这里我们通过struct2的控制实现间接访问:在src目录下新建一个包com.test.action,然后再改包下建立一个名为helloworld的类,定义一个execute方法:
package com.test.action; public class helloworld { public String execute() throws Exception { return "success"; } }
struts2的一个核心的东西是一个配置文件,该文件的默认名字为struts.xml,这个文件就描述了整个流程的转发以及执行过程。在src下新建一个名为struts的xml文件,解压缩struts2目录下的apps下的struts2-blank文件,展开下面的WEB-INF,打开src,打开java,找到struts.xml文件,打开将其头部的dtd(验证我们的struts.xml文件)信息粘贴到我们的新建的xml文件中(这里访问的时候并不是去网络中找dtd文件,这样的话dtd文件较大的话会拖慢运行速度,实际上它是先到本机中寻找,找不到再到网络中找,我们这里就是在本机的struts2-core-2.1.6.jar下面的struts-2.0.dtd中):
<?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">
利用MyEclipse的提示功能完整的xml文件内容如下(其中extends="struts-default"是为了引入本机struts2-core-2.1.6.jar下面的struts-default.xml,这样我们就拥有了struts2的基本功能):
<?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> <package name="struts2" extends="struts-default"> <action name="helloworld" class="com.test.action.HelloWorld"> <result name="success">/helloworld.jsp</result> </action> </package> </struts>
MyEclipse会自动的把这个文件copy一份复制到项目的WEB-INF目录下的classes目录下,我们之所以建立在src目录下,是为了在IDE中可以编辑它。
接下来,在web.xml中配置如下(配置之前需要的相关信息可以在D:\Program Files\struts-2.1.6\docs\struts2-core\apidocs里找到index.html中找到org.apache.struts2包下面的FilterDispatcher类,里面有一个信息:Deprecated. Since Struts 2.1.3, useStrutsPrepareAndExecuteFilter
instead orStrutsPrepareFilter
and StrutsExecuteFilter
if needing using the ActionContextCleanUp
filter in addition to this one,用来提示我们用新的类代替旧的类,可以看到StrutsPrepareAndExecuteFIlter的包名为:org.apache.struts2.dispatcher.ng.filter
):
<?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>
注意:过滤器也是在web应用启动的时候被加载的,相当于servlet配置了一个load-on-startup属性一样。
访问http://localhost:8080/struts2/helloworld.action,输出hello world即为成功。
最后,最重要的事情是,程序的运转流程:
首先我们在地址栏键入http://localhost:8080/struts2/helloworld.action,请求访问helloworld.action这个资源,请求到达了Tomcat服务器端,于是Tomcat到web.xml中找到了filter-mapping,因为其url-pattern被我们设定为/*,于是所有的客户想要访问的所有资源都需要经它过滤,经filter-name找到相应的filter(web应用启动时便被加载了),这里就是我们的struts2,根据这个filter-name找到响应的filter-class:org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter,流程转到struts.xml中,首先找到相应的包:struts2,然后找相应的action:name属性为helloworld,与该名字所对应的是class:com.test.action.HelloWorld进行处理,流程转到HelloWorld类,执行其execute方法,返回值为success,之后流程又返回到struts.xml中的action,找到result中name属性为success的,于是流程转到helloworld.jsp,于是我们的hello world输出来了。
此外一个,可能的疑惑是,一个客户请求对应一个request和response,作为doGet和doPost的两个参数,为什么我们整个过程中都没有看到过request和response对象呢,然而程序仍然能正常运转,但是,这只是表面上来看是这样的,底层它既然是基于HTTP协议的一个框架,肯定是有request和response,只不过struts2巧妙的把它们隐藏起来了,因此我们看不到他们。
上面的程序是处理一个静态的页面,下面我们来一个复杂点的,涉及到动态的页面。下面我们就用struts2来实现一个简单的登录系统:
首先新建一个login.jsp:
<body> <form action="login.action"> username: <input type="text" name="username" size="20"/><br> password: <input type="password" name="password" size="20"/><br/> <input type="submit" value="submit"> </form> </body>
然后,新建一个类,名为LoginAction(其中的username 和 password作为成员变量必须与表单中的一致,并且为其生成set和get注入方法):
package com.test.action; public class LoginAction { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String execute() throws Exception { return "success"; } }
接下来,配置struts.xml,在原来的基础上增加一个名为login的action:
<struts> <package name="struts2" extends="struts-default"> <action name="helloworld" class="com.test.action.HelloWorld"> <result name="success">/helloworld.jsp</result> </action> <action name="login" class="com.test.action.LoginAction"> <result name="success">/result.jsp</result> </action> </package> </struts>
最后,完成我们还缺少的一环,处理客户信息,新建一个result.jsp:
<body> username: ${requestScope.username }<br/> password: ${requestScope.password } </body>
重启Tomcat,访问:http://localhost:8080/struts2/login.jsp,输入zhangsan,12345,跳转到http://localhost:8080/struts2/login.action?username=zhangsan&password=12345,并且显示username和password信息,即为成功。这种Get提交方式不太安全,因此可以把表单的提交该为post方式。
学习内容:
Struts2是什么?
Struts2 = Struts + WebWork
为何Struts2使用XWork?
XWork是一个通用命令模式的框架,WebWork = WebWork Core + XWork,Struts2 = Struts 2 Core + XWork。Struts2把Web功能转换提供给XWork。
XWork提供了什么?
实现独立运行的命令模式框架:Action作为命令对象存在于XWork中
增加了高级功能
拦截器:包括设置表单参数,处理文件上传等
结果(Result):包括多个Action之间的链接,转向表示层
简单的IoC(或称DI,依赖注入)容器,可给Action对象注入值(Spring)
强大的对象查询语言-OGNL
自动类型转换
元数据驱动的验证框架
插件机制
Struts Core提供了什么?
系统架构:
Action:
Action是命令对象;Action应尽量简单;Action和任何Web对象无关;Action接口只有一个方法:
public interface Action { public String execute() throws Exception; }
需要注意的一点:Struts2下载包内不包含XWork源码,如有需要需从XWork网站下载。
Struts2基本开发配置(完成Struts2 Hello Workd):
执行流程为:action->FilterDispatcher->HelloWorldAction.execute()->"success"->struts.xml找到Result->显示HelloWorld.jsp
看不到的过程-拦截器:设置表单参数;设置请求属性
开发简单登录应用:
Struts2和1的异同点
不同点:FormBean被Action属性取代;ActionForWard被Result取代;Action类中不直接出现Servlet对象;引入了package的概念;引入了拦截器的概念;Struts2的开发大大简化
相同点:都是MVC架构;均提供了控制器和流程跳转功能;监听特定的URL地址来实现功能.action;均提供了切换view层的功能;提供了类似的标签库:表单和逻辑;都支持国际化功能
补充:package与action的关系,就好像Java中的包和类的关系一样,一个package可以包含多个action,Java中的包是有名字的,struts也是如此,这个名字是可以随意起的,此外,struts中的包还允许继承,如我们的struts.xml中,extends="struts-default",在MyEclipse中打开Struts2-core-2.1.6.jar,可以看到里面有一个struts-default.xml的文件, 可以看到他的包<package name="struts-default" abstract="true">,因此我们的struts.xml继承了这个名字为struts-default的包,具有了该包定义的所有功能,abstract为true表示该包为抽象包,不能直接用,我们自己写的struts就是一个具体的包。
下面我们用struts标签库来写一个login2.jsp:
<%@ page language="java" import="java.util.*" pageEncoding="ISO-8859-1"%> <%@ taglib uri="/struts-tags" prefix="s" %> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'login2.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <s:form action="login.action"> <s:textfield name="username" label="username"></s:textfield><br/> <s:password name="password" label="password"></s:password> <s:submit value="submit"></s:submit> </s:form> </body> </html>
注意<%@ taglib uri="/struts-tags" prefix="s" %>和body中的内容是我们自己添加的。此外我们可以按住Ctrl键,鼠标点击,跟进其源代码,在<s:textfield...这一行,跟进去发现一个8000多行的tld(struts-tags.tld)文件,其<uri>/struts-tags</uri>,此即我们的taglib的uri的来源。
此外,还用注意的一点,标准的HTML表单默认提交方法是Get,而Struts2的表单默认的提交方式是Post。还有,表单中的.action可以省略,它是struts2默认的后缀名。