一、Struts2概述
I.在很长一段时间Struts1在MVC框架中占有绝对的地位,虽然Struts1可以很好地实现将控制与业务逻辑相分离,但是其自身仍然存在这一定的缺陷1.表现层支持单一
Struts1只支持jsp作为表现层,而在实际开发中不一定只是使用jsp作为表现层,如FreeMarker、Velocity等。
2.对ServletAPI依赖
jsp+Servlet+JavaBean方式属于Model II的开发模式,而Struts1也是基于ModelII的开发模式,因此会在其中应用大量的ServletAPI,而ServletAPI需要Web容器进行初始化,从而进一步对web容器产生依赖
3.不利于代码复用
在Struts开发的代码中除了自己定义的类外,还必须使用Struts1中的某些类(如actionForm),这样一来,与Struts1的类耦合在一起很难进行代码重用 Struts2在设计之初,更多的是以 WebWork的设计思想为核心,从应用角度也更接近于 WebWork的使用习惯。Struts1与WebWork的优势互补是的Struts2拥有更加广阔的前景II.开发Struts2应用一般由两大部分组成
1.确认环境
(1)将Struts2框架支持jar包引入项目中
(2)修改工程的web.xml文件,配置过滤器。
2.代码编写
(1)编写开发处理请求的Action类,实现具体的请求方法(方法返回字符串类型)
(2)编写struts.xml文件,对Action进行配置
(3)编写与Action相关的JSP页面
二、Struts2的应用
1.创建好web项目Struts2Demo,在项目中引用Struts2的jar包,下面来做一个登录的Demo文件名 | 说明 |
---|---|
struts2-core-xxx.jar | Struts2框架的核心类库 |
xwork-core-xxx.jar | XWork类库,Struts2的构建基础 |
ognl-xxx.jar | Struts2使用的一种表达式语言类型 |
freemarker-xxx.jar | Struts2的标签模板使用类库 |
javassist-xxx.GA.jar | 对字节码进行处理 |
commons-fileupload.jar | 文件上传时需要使用 |
commons-io-xxx.jar | Java IO扩展 |
Commons-lang-xxx.jar | 包含了一些数据类型的工具类 |
2.配置web.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0"
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_3_0.xsd">
<display-name></display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!--
1.使用filter元素定义过滤器,
filter-name指定过滤器名字(自定义),
filter-class指定对应的java类的完整类名,这里固定指定为org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter类
2.使用filter-mapping元素表示将所有的请求拦截并交给上面的filter-class进行处理。
-->
<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>
3.创建com.wzj.action.HelloWorldAction类,并实现com.opensymphony.xwork2.Action接口
(在以后的应用中更多的是继承com.opensymphony.xwork2.ActionSupport类,后续讲解),其中只有一个execute方法
package com.wzj.action;
import com.opensymphony.xwork2.Action;
public class HelloWorldAction implements Action{
/**
* 定义字段name、password,并提供其get、set方法
* 当请求过来的时候Struts2框架会自动将表单中的数据映射到字段中
* 注意字段名称和表单中的控件名称对应,且字段需提供get、set方法
*/
private String name;
private Strig password;
/**
* 当Struts2处理请求时,在默认配置下调用的方法
*/
@Override
public String execute() throws Exception {
if (this.name.equals("张三")&&this.password.equals("123")) {
return "success";
}else {
return "input";
}
}
//省略get、set方法..
}
4.在src下创建名为struts.xml文件,并做如下配置
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.1.7//EN"
"http://struts.apache.org/dtds/struts-2.1.7.dtd">
<struts>
<!--
1.package:用于定义Struts2处理请求的逻辑单元,
name属性:必须且唯一,用来指定包的名称(被其他包引用)
extends属性:类型java的extends关键字,指定继承自哪个包
2.action:用于配置Struts2的工作单元Action类,将请求中的URI(action名字)对应到一个Action类,让其进行处理请求
name属性:必须的,用来表示action的名称,class属性可选,用来指定哪个类来进行处理,
不指定的话则默认是com.opensymphony.xwork2.ActionSupport类
3.result:设定Action类处理之后系统将怎么做,或者跳转到哪个页面
name属性:指定字符串名称,必须和Action中的execute方法返回的字符串想进行匹配
result元素的值表示与逻辑视图名称对应的物力资源之间的映射,用来指定这个结果对应的实际资源的位置
-->
<package name="UserPackage" namespace="/" extends="struts-default">
<action name="helloWorld" class="com.wzj.action.HelloWorldAction">
<result name="success">/success.jsp</result>
<result name="input">/index.jsp</result>
</action>
</package>
</struts>
5.编写index.jsp页面
<body>
<form action="helloWorld" method="post">
<p>用户名:<input type="text" name="name"/></p>
<p>密 码:<input type="text" name="password"/></p>
<input type="submit" value="提交"/>
</form>
</body>
6.启动项目,并访问首页http://localhost:8080//Struts2Demo/index.jsp
点击提交后页面跳转到success.jsp。
7.简单流程总结
(1)浏览器通过页面form表单发送请求名为helloWorld的action至服务器通过上面实现的一个简单的Demo,相信大家一定会有很多的疑问,没关系,我们一一道来。
(2)服务器接收到请求以后,根据web.xml的配置,将所有的请求都发送给Struts2内置的StrutsPrepareAndExecuteFilter过滤器
(3)然后过滤器会默认去查找名字为struts.xml的配置内容,根据配置,将请求发送给HelloWorldAction类进行处理,并调用默认的execute方法
(4)根据execute方法的返回值去匹配result元素的name属性值,若匹配,则跳转到对应的视图
(5)页面显示数据
三、Struts2配置详解
1.web.xml任何一个Web应用程序都是基于请求/响应模式构建的,所以无论哪种MVC框架都离不开web.xml文件的配置;Struts2需要在web.xml中配置其核心控制器——StrutsPrepareAndExecuteFilter,用于初始化并处理请求。StrutsPrepareAndExecuteFilter可以包含一些要初始化的参数,如config——要加载的XML文档,如果没有设置此参数,Struts2将默认加载struts-default.xml、struts-plugin.xml、struts.xml文件。
2.struts.xml
①使用constant元素配置常量,改变Struts2的一些行为,如下可以处理中文乱码问题:
<struts>
<!--省略-->
<constant name="struts.i18n.encoding" value="UTF-8"></constant>
<package name="UserPackage" namespace="/" extends="struts-default">
<!--省略-->
</package>
</struts>
②package中的属性和其他子元素已在注释中详细解释,这里看一下namespace属性:
namespace是可选属性,该属性定义该包中action的命名空间,如果没设置,则此action将被放入默认命名空间。Struts2框架用action的名称和它所在的命名空间来标示一个action。默认命名空间用""表示,也可以使用"/"定义一个根命名空间,两者是有区别的。当Struts2接收到一个请求时,框架会将url分为namespace和action两部分,框架首先会在namespace中查找action,如果找不到则进入默认命名空间查找。
3.action
(1)action的作用
在MVC框架中,控制器是由两部分组成,分别如下:
①核心控制器(Filter):用于拦截用户请求并进行处理编写Action可以通过新建Java类,然后实现com.opensymphony.xwork2.Action接口的方式,也可以通过继承com.opensymphony.xwork2.ActionSupport类的方式。ActionSupport是Action接口的一个实现类。
②业务控制器(Action):调用相应的Model类实现业务需求,返回结果
action对于开发者而言才是核心,action有如下作用:
①封装工作单元
可以把action看做控制器的一部分,其主要就是控制业务逻辑
②数据转移的场所
在action中可以定义需要用到的字段甚至对象,如示例中演示所示,但注意要为成员字段提供get、set方法同样也可以将多个字段封装成对象,但是表单中的名称需要改变,如下:将name和password封装成User对象,Action 中:
package com.wzj.action;
import com.opensymphony.xwork2.Action;
public class HelloWorldAction implements Action{
/**
* 直接定义User,省略get、set方法
*/
private User user;
/**
* 当Struts2处理请求时,在默认配置下调用的方法
*/
@Override
public String execute() throws Exception {
if (user.getName().equals("张三")&&user.getPassword().equals("123")) {
return "success";
}else {
return "input";
}
}
}
表单中:
<form action="helloWorld" method="post">
<p>用户名:<input type="text" name="use.name"/></p>
<p>密 码:<input type="text" name="user.password"/></p>
<input type="submit" value="提交"/>
</form>
③返回结果字符串(2)action中的方法
在com.opensymphony.xwork2.Action接口中定义了五个常量,用来表示返回结果字符串,所以为了防止书写错误可以直接使用其中定义好的常量—— ERROR、INPUT、LOGIN、NONE、SUCCESS;
如果没有进行配置,则默认情况下框架会调用 execute方法,当然也可以在同一个action中定义多个方法(格式和execute方法一样,返回字符串),这时候就要在
struts.xml文件的action中进行配置:
<!--为action元素添加method 方法,名字对应自定义的方法名称-->
<action name="helloWorld" class="com.wzj.action.HelloWorldAction" method="login">
...
</action>
(3)action中动态方法调用
为了减少Action的数量,可以使用动态方法进行处理。
动态方法调用是指表单元素的Action并不是直接等于某一个Action的名称,而是通过在Action名称中使用感叹号(!)来标示要调用的方法名称,格式为:actionName!methodName
例如:
<action name="user" class="com.wzj.action.HelloWorldAction">
<!-- 省略...... -->
</action>
当请求user!login时则调用HelloWorldAction类中的login方法;
当请求user!register时则调用HelloWorldAction类中的register方法
基于这种方式会带来安全隐患考虑,在实际应用中很少用这种方式,建议少使用。如果使用method方式指定方法名的话,那么问题又来了,一个请求对应着一个Action,开发过程中必然struts.xml中的action元素的数量会庞大,所以Struts2框架就为我们提供了通配符方式来解决这种问题。
(4)action中使用通配符
在action元素中的name属性支持通配符操作,例如:
<!--
1.使用*来表示实际请求的名称字符串
2.使用{1}的方式来获取到实际的*代表的值
-->
<action name="user-*" class="com.wzj.action.HelloWorldAction">
<result name="success">/{1}_success.jsp</result>
<result name="input">/{1}.jsp</result>
</action>
加入请求"user-login",则"*"的值就为login,表达式{1}的值就是name属性中第一个*的值
(5)配置默认的action
如果请求一个不存在的action,则页面肯定会抛出错误,为了解决这个问题,框架允许指定一个默认的action
<package name="UserPackage" namespace="/" extends="struts-default">
<!-- 指定默认action使用default-action-ref元素 -->
<default-action-ref name="helloWorld"></default-action-ref>
<action name="helloWorld" class="com.wzj.action.HelloWorldAction" method="login">
<result name="success">/success.jsp</result>
<result name="input">/index.jsp</result>
</action>
</package>
4.result
当Action处理用户请求结束后,会返回一个字符串——逻辑视图的名称,然后再与result元素的name属性值进行匹配,并跳转到result元素的值——物理视图名称。
<result name="success">/success.jsp</result>
(1)result中有一个type属性,表示怎样转到结果视图(转发、重定向...)
①dispatch类型——默认的结果类型,表示转发到物理视图
②redirect类型——将请求重定向到物理视图,之前request中的数据将丢失
③redirectAction类型——将请求重定向到action名称
④chain类型——将请求转发到action名称
⑤Struts2定义的类型不止这些,可以在struts2-core-2.1.8.jar/struts-default.xml文件中找到名为"struts-default"的包,其中定义了很多类型:
(2)全局结果
之前配置的result都是定义在action元素内部,不能供其他action使用,多个action可能需要访问同一个result,这时全局结果就派上了用场。全局结果也在包中定义:
<package name="UserPackage" namespace="/" extends="struts-default">
<global-results>
<result name="error">error.jsp</result>
</global-results>
<!--省略-->
</package>
当action中的请求处理完之后会首先在本Action中进行匹配result,如果匹配不成功则去全局结果中匹配。