MVC框架及Struts2介绍
Struts2核心
Struts2拦截器
Struts2值栈和OGNL表达式
Struts2标签库
1 xml文件模块化管理
大部分应用中,随着应用规模的增加,系统中Action的数量也会大量增加,导致struts.xml配置文件变得很大。为了避免struts.xml文件过大,提高struts.xml文件的可读性,可以将一个struts.xml配置文件分解成多个配置文件,然后在struts.xml主文件中引入其他配置文件。配置文件的基本格式与struts.xml文件一样,写在resources文件(Source Folder文件)中。
struts.xml中<include>引入其他配置文件:
<struts>
<package name="default" namespace="/" extends="struts-default">
...
</package>
<!-- 引入struts-system.xml文件 -->
<include file="struts-system.xml"></include>
</struts>
2 <package>标签
在配置文件中,需要将<action>标签写在<package>中,<package>类似Java中的包,可以唯一确定一个包中的<action>,不同包中<action>可以同名,同包中不能同名。<package>的目的是为了进行模块化管理。
<package name="default" namespace="/" extends="struts-default" abstract="false">
...
</package>
name:包名,在整个应用中不能重复;
namespace:包命名空间,访问该包中action时额外加的路径;
extends:继承,继承其他包的配置文件,通常继承struts-default.xml中的;
abstract:当前包是抽象的包(用来被继承的,struts-default.xml中为”true”)。
访问action
http ://ip:port/<appContextPath>/<packageNamespace>/<actionName>[.action]
http ://ip:端口/<上下文路径>/<包的命名空间>/<action名称>[.后缀名]
如果上下文路径path=”“,namespace=”/”,则不需要加/<上下文路径>/<包的命名空间>。
3 Action的查找流程
简单查找流程
<package name="default" namespace="/system" extends="struts-default">
<action name="hello"></action>
</package >
访问的uri:http ://localhost/system/hello
uri分为两部分:
packageNamespace : /system
actionName:hello
查找Action时,首先通过packageNamespace在配置文件中查找对应的<package>标签,然后通过actionName在<package>标签中查找对应<action>。
复杂查找流程
<package name="default" namespace="/" extends="struts-default" >
...
</package >
<package name="path1" namespace="/path1" extends="struts-default" >
...
</package>
<package name="path2" namespace="/path1/path2" extends="struts-default" >
...
</package>
访问uri:http ://localhost/path1/path2/hello
先找<package>:
先会通过/path1/path2找对应的<package namespace=”/path1/path2”…>包,如果没有这个包,就退一级找/path1对应的<package namespace=”/path1”…>包,如果没有这个包,就找到<package namespace=”/”…>根包。
再找<action>:
如果找到包,就在当前包下面找Action,如果没有找到Action,不会退级找,而是到默认包中查找Action,如果还没有就报错。namespace=”/”代表根包,namespace=”“代表默认包。
4 Struts配置文件
4.1 配置文件
Struts2框架加载配置顺序
1.default.properties:该文件在struts2-core-2.3.20.jar/ org.apache.struts2中,配置中很多常量在其中;
2.struts-default.xml:该文件在struts2-core-2.3.20.jar中,可以查看配置方式;
3.struts-plugin.xml:该文件在struts2项目的lib包中,比如struts2-spring-plugin-2.3.20.jar,保存着一些插件;
4.struts.xml:web应用默认的struts配置文件;
5.struts.properties:struts的默认配置文件(一般配置不写在其中);
6.web.xml:web应用的配置文件(一般配置不写在其中)。
前三个文件是Struts2默认的配置文件,不能进行修改,如果多个文件配置了同一个常量,后一个配置文件会覆盖前一个配置文件的常量。
4.2 常量配置
常量配置在default.properties文件中,可以通过struts.xml配置常用常量(也可以在web.xml和struts.properties配置,但是不推荐)。
开发者模式
修改配置不需要重启服务器
<constant name="struts.devMode" value="true"/>
开发时使用,项目上线前需要关闭。
设置系统编码
<constant name="struts.i18n.encoding" value="utf-8"></constant>
设置后缀名
<constant name="struts.action.extension" value="action,do,,"></constant>
后缀名之间用逗号分隔,一般留下一个空串,访问时使用actionName.action、actionName.do或actionName。
4.3 默认配置
package继承了struts-default包,在struts-default.xml中配置了<action>和<result>标签的默认值。
<package name="default" namespace="/" extends="struts-default">
<action name="index">
<result>/index.jsp</result>
</action>
</package>
<action>
class属性可以不写,但一般写上,默认的属性值为:
<default-class-ref class=”com.opensymphony.xwork2.ActionSupport” />
method属性可以不写,默认值为:execute
<result>
name属性可以不写,默认为:success
type属性可以不写,默认为:dispatcher
5 Struts2获取ServletAPI
Struts2可以在不使用ServletAPI的情况下获取参数,也可以通过结果视图进行页面跳转。但是在一些特殊情况中依然需要获取request、response对象,比如获取浏览器的信息,获取当前项目所在的实际路径等。
5.1 ActionContext/ServletActionContext
public class ApiAction {
public String execute(){
// 通过ActionContext获取作用域对象
Map<String, Object> session = ActionContext.getContext().getSession();
Map<String, Object> application = ActionContext.getContext().getApplication();
// 通过ServletActionContext获取请求和响应对象
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
return "success";
}
}
通过ActionContext获取作用域对象Session时,获取的实际上是SessionMap,底层中封装了HttpSession对象,通过Map设置或获取值时实际上是往当前请求的Session中设置或获取值。这种方式更简单,类本身脱离了ServletAPI,通常使用这种方式。
5.2 ServletRequestAware/ServletResponseAware
public class ApiAction implements ServletRequestAware,ServletResponseAware {
private HttpServletRequest request;
private HttpServletResponse response;
public String execute(){
return "success";
}
// request
@Override
public void setServletRequest(HttpServletRequest request) {
this.request = request;
}
// response
@Override
public void setServletResponse(HttpServletResponse response) {
this.response = response;
}
}
通过Action类实现ServletRequestAware、ServletResponseAware接口获取请求与响应对象,只要Action实现了Aware(可感知)接口,Struts2就能感知到,框架就可以调用接口对应的方法。
6 Struts2返回类型
6.1 视图返回类型
在struts-default.xml配置文件中,Struts2定义了很多返回结果类型,并且为每个结果类型封装了一个类:
dispatcher:请求转发,默认类型
redirect:重定向
redirectAction:重定向到Action
velocity、freemarker:在模版中使用
结果视图的完整写法
<result name="success" type="dispatcher">
<param name="location"> index.jsp</param>
</result>
<result>标签中的属性:
name:指定配置逻辑视图名(和Action方法返回值对应),默认值为success;
type:指定结果类型,默认值为dispatcher。
标签中的内容为视图路径地址。
struts.xml中新增结果类型名称
<package name="default" namespace="/" extends="struts-default">
<result-types>
<result-type name="forward" class="org.apache.struts2.dispatcher.ServletDispatcherResult"/>
</result-types>
</package>
定义在<package>标签中,class为struts2为结果类型封装的类,替代dispatcher。
redirectAction
1.同包中跳转到Action
<package name="result" namespace="/result" extends="struts-default">
<action name="result01" class="cn.wenwen.action._01RedirectAction">
<result name="success" type="redirectAction">
result02
</result>
</action>
<action name="result02" class="cn.wenwen.action._02RedirectAction">
<result name="success">
/index.jsp
</result>
</action>
</package>
”result01”跳转到”result02”,跳转结果为Actionname,无需加”/”
2.异包中跳转到Action
<package name="result" namespace="/result" extends="struts-default">
<action name="result02" class="cn.wenwen.action._02RedirectAction">
<result name="success">
/index.jsp
</result>
</action>
</package>
<package name="res" namespace="/res" extends="struts-default">
<action name="result01" class="cn.wenwen.action._01RedirectAction">
<result name="success" type="redirectAction">
<param name="namespace">/result</param>
<param name="actionName">result02</param>
</result>
</action>
</package>
”result01”跳转到另一个包中的”result02”时,需要在<result>中设置参数,通过namespace找到另一个包,然后通过actionName找到包中的Action。
3.使用redirect也可以跳转到其它Action
<package name="default" namespace="/" extends="struts-default">
<action name="result01" class="cn.itsource._04_result.ResultAction01">
<result name="success" type="redirect">
/result/result02
</result>
</action>
</package>
<package name="result" namespace="/result" extends="struts-default">
<action name="result02" class="cn.itsource._04_result.ResultAction02">
<result name="success">
/success.jsp
</result>
</action>
</package>
结果视图内容为:/其它包namespace/其它action的name。
6.2 全局视图
局部视图只能在当前的<action>中使用,如果一个包中多个需要使用同一个结果视图,就需要定义全局视图。
<package name="default" namespace="/" extends="struts-default">
<global-results>
<result name="login">
/login.jsp
</result>
</global-results>
...
</package>
将全局视图<global-results>配置在<package>中,包中的所有<action>都可以使用。如果局部视图中有一个结果视图与全局中的结果视图名称相同,会使用局部视图。
如果写一个返回视图给几个包都使用,可以使用包之间的继承来实现。
7 Struts2实现Action的方式
7.1 普通Action类
使用POJO(JavaBean)类,并提供public修饰的无参方法。
public class MethodAction {
public String execute(){
return null;
}
}
struts.xml配置
<package name="method" namespace="/method" extends="struts-default">
<action name="methodAction" class="cn.wenwen.MethodAction " method="execute">
</action>
</package>
访问
http ://localhost/method/methodAction
7.2 实现Action接口
实现com.opensymphony.xwork2.Action接口,并覆写方法:
public class MethodAction implements Action {
@Override
public String execute() throws Exception {
return NONE;
}
}
在Action中,封装了SUCCESS、ERROR、INPUT、LOGIN、NONE字段以及execute()方法。
7.3 继承ActionSupport类
继承ActionSupport类,并覆写execute()方法。
public class MethodAction extends ActionSupport {
@Override
public String execute() throws Exception {
return NONE;
}
}
ActionSupport实现了Action类,同时定义了表单域校验、错误信息设置和获得国际化信息等方法。
最佳实践
写一个BaseAction继承ActionSupport,可以继承ActionSupport的功能,也可以扩展一些公共的常量和方法。让其它的Action来继承BaseAction,这样就可以使用自定义的常量和方法。
8 Action多方法配置
在一个Action中会有CRUD等多个方法,这时需要通过在struts.xml中配置,调用Action中不同的方法。
8.1 动态调用
采用”/Actionname!方法名”调用,需要开启动态调用的配置。
<package name="dynamic" namespace="/dynamic" extends="struts-default">
<!-- 开启动态调用 -->
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<action name="method" class="cn.wenwen.MethodAction " method="execute">
...
</action>
</package>
访问add()方法:http ://localhost/dynamic/method!add
动态调用的安全性不高,通常不使用。
8.2 使用通配符*
单通配符
<package name="default" namespace="/" extends="struts-default">
<action name="method_*" class="cn.wenwen.MethodAction" method="{1}">
...
</action>
</package>
”method_*”中星号表示一个通配符,根据传入的方法名在Action中匹配,{1}表示第一个通配符。访问add()方法:http ://localhost/method_add,如果访问的是execute()方法,可以不加_*直接用/method。
多通配符
<package name="default" namespace="/" extends="struts-default">
<action name="*_*" class="cn.wenwen.{1}Action" method="{2}">
...
</action>
</package>
{1}表示第一个通配符,替代部分类名,{2}表示第二个通配符,代表方法名。
访问add()方法:http: //localhost/Method_add
9 接收参数方式
9.1 普通参数
接收普通参数如name、password:
public class ParamAction extends ActionSupport {
private String name;
private String password;
public String execute() {
return NONE;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
}
写一个Action类继承ActionSupport覆写方法,定义需要接收的参数,只需提供set()方法,框架会匹配属性设置值。这种方式如果参数过多就会变得复杂。
struts.xml配置
<package name="default" namespace="/" extends="struts-default">
<action name="params" class="cn.wenwen.ParamAction"></action>
</package>
前台页面
<form action="/params" method="post">
用户名:<input type="text" name="name" /> <br />
密码:<input type="password" name="password" /> <br />
<input type="submit" value="...提交..." />
</form>
9.2 接收对象
如果参数过多,需要将数据封装为对象,比如User对象。
public class User {
private Long id;
private String name;
private String password;
// set、get方法
...
}
方式一:Action中将User实例化
public class ParamAction extends ActionSupport {
private User user = new User();
public String execute() {
return NONE;
}
// 框架获取User对象,然后调用User里面setter方法设置值
public User getUser() {
return user;
}
}
框架会通过getUser()获取User对象,然后调用User中的setter方法把值设置到对象属性中。
方式二:提供set方法。
public class ParamAction extends ActionSupport {
private User user;
public String execute() {
return NONE;
}
// 框架获取User对象,然后调用User里面setter方法设置值
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
如果没有实例化User,无法直接获取User对象,框架会通过反射创建一个User对象,调用setUser()方法将对象设置进去,然后获取User对象并设置属性值。
9.3 实现ModelDriven接口
实现ModelDriven(模型驱动)接口
public class ParamAction extends ActionSupport implements ModelDriven<User> {
private Long id;
private User user = new User();
public String execute() {
return NONE;
}
@Override
public User getModel() {
return user;
}
public void setId(Long id) {
this.id = id;
}
}
实现ModelDriven接口后,框架在设置参数时就会先调用getModel()方法来获取对象,然后调用对象中的setter方法设置属性值。这种方法可以和普通参数方法结合使用,利用普通参数方法设置id。如果一个Action中只封装了一个对象,就可以用这种方式。