文章目录
一.概述
- Struts2框架=Struts+XWork
- Strust2 核心功能:
- 允许POJO(Plain Old Java Objects)对象作为Action.
- Action的execute 方法不再与Servlet API耦合,更易测试
- 支持更多视图技术(JSP、FreeMarker、Velocity)
- 基于Spring AOP思想的拦截器(感觉在Struts2中,使用数据的封装和国际化等等功能非常容易,)机制,更易扩展
- 更强大,更易用输入校验功能
- 整合Ajax支持
二.第一个Struts2程序
- 拷贝/apps/struts2-blank/WEB-INF/lib中的jar到项目的lib中.
找到根下apps目录,找到struts2-blank(Struts2提供的空白项目),里面整合了Struts2的依`赖环境和配置.
Struts运行必要jar包如下:
struts2-core-2.3.1.1.jar: Struts 2框架的核心类库
xwork-core-2.3.1.1.jar: Command模式框架,WebWork和Struts2都基于xwork
ognl-3.0.3.jar: 对象图导航语言(Object Graph Navigation Language), struts2框架通过其读写对象的属性
freemarker-2.3.18.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-lang-2.5.jar: 对java.lang包的增强
- web.xml中配置Struts2的前端控制器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
id="WebApp_ID" version="3.0">
<display-name>struts2crud</display-name>
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
- 拷贝struts.xml文件到项目的Source folder文件夹中
- 定义一个POJO类,HelloAction,提供公共无参数execute方法
//POJO类
public class HelloAction {
public String execute() {
System.out.println("Hello World");
//返回的逻辑试图名称
return "dusk";
}
}
- 在struts.xml文件中,配置HelloAction
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
<!-- namespace决定访问路径 -->
<package name="hellopkg" extends="struts-default" namespace="/hello">
<action name="world" class="com.dusk.hello.HelloAction" method="execute"/>
<result name="dusk" type="dispatcher">/views/hello.jsp</result>
</action>
</package>
</struts>
- 部署Web项目,访问Action
访问格式: http://ip:port/contextPath/namespace/actionName[.action]
访问格式:http://localhost:80/hello/world[.action]
三.Struts2简单流程
四.Struts2基本配置
Struts2框架按照如下顺序加载struts2配置:
- default.properties
该文件保存在 struts2-core-2.3.7.jar 中 org.apache.struts2包里面:包含了Struts2的默认常量配置 - struts-default.xml
该文件保存在 struts2-core-2.3.7.jar:包含了框架依赖的对象配置和结果类型,拦截器等配置. - struts-plugin.xml
该文件保存在Struts2框架的插件中:struts-Xxx-plugin-2.3.7.jar.由插件提供
上述三个文件是框架自带的,我们不能修改,只能使用. - struts.xml
该文件是web应用默认的struts配置文件.重点.配置自定义的Action和其他信息. - struts.properties
该文件是Struts的默认配置文件–>可以修改default.properties 的常量配置. - web.xml 该文件是Web应用的配置文件
上述三个文件是我们可以修改操作的.
注意:
1.在大部分应用里,随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得非常臃肿。为了避免struts.xml文件过于庞大、臃肿,提高struts.xml文件的可读性,我们可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml文件中包含其他配置文件。下面的struts.xml通过元素指定多个配置文件:
struts.xml:
<struts>
<include file="分支文件的路径"/>
...
</struts>
- 如果多个文件配置了同一个struts2常量,则后一个文件中配置的常量值会覆盖前面文件配置的常量值.
一般的,我们只在struts.xml中做常量配置
Struts2中常见常量:
- :指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法和freemarker、velocity的输出
<constant name="struts.i18n.encoding" value="UTF-8"/>
- :该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。
如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号( , )隔开
<constant name="struts.action.extension" value="action,,"/>
- :设置浏览器是否缓存静态内容,默认值为true(生产环境下使用),开发阶段最好关闭
<constant name="struts.serve.static.browserCache" value="false"/>
- :当struts的配置文件修改后,系统是否自动重新加载该文件,默认值为false(生产环境下使用),开发阶段最好打开
<constant name="struts.configuration.xml.reload" value="true"/>
- :开发模式下使用,这样可以打印出更详细的错误信息
<constant name="struts.devMode" value="true" />
:修改struts.xml之后,不要重启Tomcat.
6) :默认的视图主题
<constant name="struts.ui.theme" value="simple" />
- :是否支持动态方法调用
<constant name="struts.enable.DynamicMethodInvocation" value="false"/>
五.package元素
- 元素: 是根元素的子元素.
用来对多个元素分类管理,和Java中的package没有关系.
常见的属性:
<package name="" extends="" namespace="" abstract=""></package>
- name:
表示的名字,但是要保证不同的元素的name不同. 可以通过该名字被其他的包所指代. - extends:
表示当前继承哪一个,一般都是:struts-default.
而struts-default其实就是struts-default.xml中元素的名字.
继承struts-default之后,就拥有了该定义的所有资源.(结果返回类型,拦截器…) - namespace:
表示命名空间,一般的以"/"打头,命名一般以模块名.如: /crm, /oa. 和的name决定了一个Action类的访问路径. - abstract:
抽象的,缺省值是false. 若一个的abstract=“true”,那么该中就不能再定义元素,只能用来继承.
六.action元素
元素:是元素的子元素.
- 专门用来配置Action对象的.
<action name="" class="" method=""/>
- 常见的属性:
- name:
action的名称,在同一个中,action的名字必须唯一.
和的namespace共同决定了一个Action类的访问路径.
Struts2中的资源名称: package的namespace/action的name
注意:action的name值不能以"/"打头. - class:
一个Action类的全限定名. 缺省值:ActionSupport类. - method:
当前Action动作访问的方法, 缺省值:execute.
- name:
七.result元素
<result name="" type=""></result>
局部结果视图: <result>定义在<action>中.
全局结果视图: <result>定义在<global-results>中,而<global-results>在<package>中
-
逻辑视图寻找顺序:先从当前的Action中去选择局部结果视图,找到就跳转,找不到,再找当前action所在package中找全局的结果视图,找到,跳转,找不到,报错.No result defined.
-
常见的属性:
name:Action方法返回的逻辑视图名称. 缺省值:success
type:结果的跳转类型.该类型的值在struts-default.xml中已经预定义好了. 缺省值:dispatcher
- 常见的type值(结果类型):
dispatcher: 表示从Action请求转发到页面(JSP).缺省值
redirect: 表示从Action重定向到页面(JSP).
chain: 表示从Action请求转发到另一个Action.
redirectAction: 表示从Action重定向到另一个Action.
stream: 表示返回流. 用于文件下载时使用.
八.Action类的编写
- 方式一,使用公共的POJO类作为Action. 提供公共的无参数的Action方法.(不推荐)
pubilc class Action1{
public String execute(){
return "success";
}
}
- 缺点:
- 没有一种方式约束Action方法必须是公共的无参数的.
- Action方法的返回逻辑视图名可以自定指定. 有时起名不规范. 比如:“ooxx”.
- 方式二,实现于com.opensymphony.xwork2.Action接口.并覆写execute方法即可.(不推荐)
Action接口中,不仅提供了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 class Action2 implements Action{
public String execute(){
return SUCCESS;
}
}
- 缺点:
- 不支持国际化,数据校验,消息机制.
- 方式三,定义一个类,继承于com.opensymphony.xwork2.ActionSupport类.(推荐)
public class ActionSupport implements Action, Validateable, ValidationAware, TextProvider,LocaleProvider, Serializable {
}
public class Action3 extends ActionSupport{
public String execute(){
return SUCCESS;
}
}
九.Action中方法调用
- 方式一(不推荐)
<action name="employeeSave" class="com.dusk.EmployeeAction" method="save"/>
- 方式二(不推荐)
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
<package name="methodPak" extends="struts-default">
<action name="employeeSave" class="com.dusk.EmployeeAction"/>
</package>
调用 methodPak!方法名
- 方式三(推荐)
使用通配符的方式类配置: 通配符:* (推荐)
<action name="empoyee_*" class="com.manymethod.EmployeeAction" method="{1}">
Action的名字: empoyee_Action方法: 比如:emp_list,那么{1}的值就是list
empoyee_edit,那么{1}的值就是edit
两个通配符:
<action name="*_*" class="com.manymethod.{1}Action" method="{2}">
Action名字:Action类名_Action方法. 比如:Employee_list,表示调用的EmployeeAction中的list方法
比如:Department_edit,表示调用DepartmentAction中的edit方法.
十.Action获取请求参数
- 方式一
Action本身作为Model对象,通过OGNL表达式调用Action中的setter方法封装(属性注入).
Action类
public class LoginAction extends ActionSupport {
@Setter
private String username;
@Setter
private String password;
private IEmployeeService service = new EmployeeServiceImpl();
public String execute() {
try {
service.login(username, password);
} catch (Exception e) {
addActionError(e.getMessage());//在Action中设置错误信息
return LOGIN;//返回登录界面
}
return SUCCESS;
}
}
Jsp界面
<a style="color:red"><s:property value="actionErrors"/></a>
<s:form action="login">
账号:<s:textfield name="username"/><br>
密码:<s:password name="password"/><br>
<s:submit value="朕要登录"/><br>
</s:form>
- 方式二
创建独立Model对象,通过OGNL表达式把数据封装到Action对象的子属性中.
Model对象
@Getter@Setter@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Employee {
private Long id;
private String username;
private String password;
}
Action类
public class EmployeeAction extends ActionSupport {
@Getter
private Employee e = new Employee();
}
Jap页面
<s:a action="employee_input">编辑
<s:param name="e.id" value="id"/>
</s:a> |
<s:a action="employee_delete" >删除
<s:param name="e.id" value="id"/>
</s:a>
十一.ValueStack和OGNL介绍
- 通过ActionContext对象获取
ValueStack vs = ActionContext.getContext().getValueStack();
- ValueStack内部结构
root:类型: CompoundRoot extends ArrayList : 表示栈的数据结构(后进先出)
context: 类型: Map: : 上下文
- 把数据放入ValueStack.
-
把数据放入root中:(栈,ArrayList.每次都是压在栈顶)
框架默认把当前被Action对象存入栈顶,这个设置建议大家不要去改动,
在Action对象中提供读取属性的方法(getter方法)一般的,把单个对象可放入root中,就在栈顶.
-
把数据放入context中:
ActionContext对象.put(String key,Object value);
-
从root中获取数据: 直接使用属性名获取. ---> <s:property value="属性名"/>
从context中获取数据: 属性名称前加 # 号 ---> <s:property value="#属性名"/>