MVC框架及Struts2介绍 Struts2核心 Struts2拦截器 Struts2值栈和OGNL表达式 Struts2标签库
大部分应用中,随着应用规模的增加,系统中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>在配置文件中,需要将<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=”/”,则不需要加/<上下文路径>/<包的命名空间>。
简单查找流程
<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=”“代表默认包。
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默认的配置文件,不能进行修改,如果多个文件配置了同一个常量,后一个配置文件会覆盖前一个配置文件的常量。
常量配置在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。
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
Struts2可以在不使用ServletAPI的情况下获取参数,也可以通过结果视图进行页面跳转。但是在一些特殊情况中依然需要获取request、response对象,比如获取浏览器的信息,获取当前项目所在的实际路径等。
通过ActionContext获取作用域对象Session时,获取的实际上是SessionMap,底层中封装了HttpSession对象,通过Map设置或获取值时实际上是往当前请求的Session中设置或获取值。这种方式更简单,类本身脱离了ServletAPI,通常使用这种方式。
通过Action类实现ServletRequestAware、ServletResponseAware接口获取请求与响应对象,只要Action实现了Aware(可感知)接口,Struts2就能感知到,框架就可以调用接口对应的方法。
在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。
局部视图只能在当前的<action>中使用,如果一个包中多个需要使用同一个结果视图,就需要定义全局视图。
<package name="default" namespace="/" extends="struts-default"> <global-results> <result name="login"> /login.jsp </result> </global-results> ... </package>将全局视图<global-results>配置在<package>中,包中的所有<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
实现com.opensymphony.xwork2.Action接口,并覆写方法:
public class MethodAction implements Action { @Override public String execute() throws Exception { return NONE; } }在Action中,封装了SUCCESS、ERROR、INPUT、LOGIN、NONE字段以及execute()方法。
继承ActionSupport类,并覆写execute()方法。
public class MethodAction extends ActionSupport { @Override public String execute() throws Exception { return NONE; } }ActionSupport实现了Action类,同时定义了表单域校验、错误信息设置和获得国际化信息等方法。
最佳实践 写一个BaseAction继承ActionSupport,可以继承ActionSupport的功能,也可以扩展一些公共的常量和方法。让其它的Action来继承BaseAction,这样就可以使用自定义的常量和方法。
在一个Action中会有CRUD等多个方法,这时需要通过在struts.xml中配置,调用Action中不同的方法。
采用”/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 动态调用的安全性不高,通常不使用。
单通配符
<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
接收普通参数如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>如果参数过多,需要将数据封装为对象,比如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对象并设置属性值。
实现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中只封装了一个对象,就可以用这种方式。