Struts2学习笔记

来源:互联网 发布:漫画制作软件 编辑:程序博客网 时间:2024/06/03 19:18

一、开发Struts2应用依赖的jar文件(http://download.csdn.net/detail/huangzebiao007/6358105

struts2-core-2.x.x.jar :Struts 2框架的核心类库

xwork-core-2.x.x.jar :XWork类库,Struts 2在其上构建

ognl-2.6.x.jar :对象图导航语言(Object Graph Navigation Language),struts2框架通过其读写对象的属性

freemarker-2.3.x.jar :Struts 2UI标签的模板使用FreeMarker编写

commons-logging-1.x.x.jar :ASF出品的日志包,Struts 2框架使用这个日志包来支持Log4JJDK 1.4+的日志记录。

commons-fileupload-1.2.1.jar 文件上传组件,2.1.6版本后必须加入此文件

二、struts2开发流程

1web.xml

<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> <!-- 自从Struts 2.1.3以后,下面的FilterDispatcher已经标注为过时    <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> --> 



StrutsPrepareAndExecuteFilterinit()方法中将会读取类路径下默认的配置文件struts.xml完成初始化操作。struts2读取到struts.xml的内容后,以javabean形式存放在内存中,以后struts2对用户的每次请求处理将使用内存中的数据,而不是每次都读取struts.xml文件

如果struts.xml文件放置到别的文件夹下,例如com.hzb.xml下,则在xml配置文件中要做如下设置:

<filter><filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class><init-param><param-name>config</param-name><param-value>struts-default.xml,              struts-plugin.xml,              /com/hzb/xml/struts.xml              </param-value></init-param></filter>
2配置文件struts.xml
<?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="hzb" namespace="/test" extends="struts-default">        <action name="helloworld" class="com.hzb.action.HelloWorldAction" method="execute" >            <result name="success">/hello.jsp</result>        </action>    </package> </struts>

配置包时必须指定name属性,该name属性值可以任意取名,但必须唯一,他不对应java的类包,如果其他包要继承该包,必须通过该属性进行引用。包的namespace属性用于定义该包的命名空间,命名空间作为访问该包下Action的路径的一部分,如访问上面例子的Action,访问路径为:http://localhost:8080/struts2/test/helloworld.action。 namespace属性可以不配置,对本例而言,如果不指定该属性,默认的命名空间为“”(空字符串)。http://localhost:8080/struts2/helloworld.action(后缀“.action”可不加

通常每个包都继承struts-default包, 因为Struts2很多核心的功能都是拦截器来实现。如:从请求中把请求参数封装到action、文件上传和数据验证等等都是通过拦截器实现的。 struts-default定义了这些拦截器和Result类型。可以这么说:当包继承了struts-default才能使用struts2提供的核心功能。 struts-default包是在struts2-core-2.x.x.jar文件中的struts-default.xml中定义。 struts-default.xml也是Struts2默认配置文件。 Struts2每次都会自动加载 struts-default.xml文件。包还可以通过abstract=true”定义为抽象包,抽象包中不能包含action

3、创建Action类,通常继承了ActionSupport 类

package com.hzb.action;import com.opensymphony.xwork2.ActionSupport;public class HelloWorldAction extends ActionSupport{private String message;public String getMessage() {return message;}public void setMessage(String message) {this.message = message;}public String execute() {this.message = "我的第一个struts2应用";return "success";}}

4、返回视图页面hello.jsp

<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%><%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 'hello.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>     ${message }  <br>  </body></html>

三、struts2常量

1常量可以在struts.xmlstruts.properties中配置,两种配置方式如下:

struts.xml文件中配置常量

<struts>

    <constant name="struts.action.extension" value="do"/>

</struts>

struts.properties中配置常量

struts.action.extension=do

 2、常用常量

<!-- 指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的输出 --><constant name="struts.i18n.encoding" value="UTF-8"/><!-- 该属性指定需要Struts 2处理的请求后缀,该属性的默认值是action,即所有匹配*.action的请求都由Struts2处理。如果用户需要指定多个请求后缀,则多个后缀之间以英文逗号(,)隔开。 --><constant name="struts.action.extension" value="do"/><!-- 设置浏览器是否缓存静态内容,默认值为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" /><!-- 默认的视图主题 --><constant name="struts.ui.theme" value="simple" /><!– 与spring集成时,指定由spring负责action对象的创建 --><constant name="struts.objectFactory" value="spring" /> <!–该属性设置Struts 2是否支持动态方法调用,该属性的默认值是true。如果需要关闭动态方法调用,则可设置该属性为false。 --><constant name="struts.enable.DynamicMethodInvocation" value="false"/><!--上传文件的大小限制(字节为单位)--><constant name="struts.multipart.maxSize" value=“10701096"/>

四、struts.xml通过<include>元素包含配置文件

<?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><include file="/com/hzb/xml/struts-user.xml"/><include file="struts-order.xml"/></struts>
五、配置文件说明

1、Action配置中的各项默认值

如果没有为action指定class,默认是ActionSupport

如果没有为action指定method,默认执行action中的execute() 方法。

如果没有指定resultname属性,默认值为success

 2、Actionresult的各种转发类型

<action name="helloworld" class="com.hzb.action.HelloWorldAction">

        <result type= "dispatcher" name="success">/hello.jsp</result>

</action>

rstruts2中提供了多种结果类型,常用的类型有: dispatcher(默认值--forward)、 redirect 、 redirectAction 、 plainText

 在result中还可以使用${属性名}表达式访问action中的属性,表达式里的属性名对应action中的属性。如下:

<result type="redirect">/view.jsp?id=${id}</result>

 下面是redirectAction 结果类型的例子,如果重定向的action中同一个包下: 

<result type="redirectAction">helloworld</result>

如果重定向的action在别的命名空间下:

<result type="redirectAction">

<param name="actionName">helloworld</param>

<param name="namespace">/test</param>

</result>

plaintext:显示原始文件内容,例如:当我们需要原样显示jsp文件源代码 的时候,我们可以使用此类型。

<result name="source" type="plainText ">

<param name="location">/xxx.jsp</param>

<param name="charSet">UTF-8</param><!-- 指定读取文件的编码 -->

</result>

 3、多个Action共享一个视图--全局result配置

<package ....>

<global-results>

<result name="message">/message.jsp</result>

</global-results>

</package>

 4、为Action的属性注入值

Struts2Action中的属性提供了依赖注入功能,在struts2的配置文件中,我们可以很方便地为Action中的属性注入值。注意:属性必须提供setter方法。

public class HelloWorldAction{

private String savePath;

public String getSavePath() {

return savePath;

}

public void setSavePath(String savePath) {

this.savePath = savePath;

}

}

<package name="hzb" namespace="/test" extends="struts-default">

<action name="helloworld" class="com.hzb.action.HelloWorldAction" >

<param name="savePath">/images</param>

<result name="success">/hello.jsp</result>

</action>

</package>

上面通过<param>节点为actionsavePath属性注入“/images

六、动态方法调用

如果Action中存在多个方法时,我们可以使用!+方法名调用指定方法。

public class HelloWorldAction{private String message;....public String execute() throws Exception{this.message = "我的第一个struts2应用";return "success";}public String other() throws Exception{this.message = "第二个方法";return "success";}}
http://localhost:8080/struts2/test/helloworld!other.action
七、使用通配符定义action

<package name="hzb" namespace="/test" extends="struts-default"><action name="helloworld_*" class="com.hzb.action.HelloWorldAction" method="{1}"><result name="success">/hello.jsp</result></action></package>public class HelloWorldAction{private String message;....public String execute() throws Exception{this.message = "我的第一个struts2应用";return "success";}public String other() throws Exception{this.message = "第二个方法";return "success";}}

要访问other()方法,可以通过这样的URL访问:/test/helloworld_other.action

八、自定义类型转换器

1、自定义类型转换器,即定义一个类继承DefaultTypeConverter 

为了实现双向转换,判断toType的类型即可判断转换的方向。toType类型是需要转换的目标类型,当toType类型是User类型时,表明需要将字符串转换成对象实例;当toType类型是String类型时,表明需要把对象实例转换为字符串类型。

public class UserConverter extends DefaultTypeConverter{public Object convertValue(Map context, Object value,Class toType) {//当需要将字符串向User类型转换时,即浏览器请求->Actionif(toType == UserBean.class){//系统的请求参数是一个字符串数组String[] params = (String[]) value;//创建一个User实例UserBean user = new UserBean();//只处理请求参数数组第一个数组元素,并将该字符串以英文逗号分割成两个字符串(因为客户端是user,password格式提交上来给user属性的)String[] userValue = params[0].split(",");//为user实例赋值user.setName(userValue[0]);user.setPassword(userValue[1]);return user;}if(toType == String.class){//将需要转换的值强制类型转换成User类型,即Action->浏览器UserBean user = (UserBean) value;return "<" +user.getName()+","+user.getPassword()+">";}return null;}}

 2、注册类型转换器

若注册为局部类型转换器,则:

Action类所在的包下放置ActionClassName-conversion.properties文件,ActionClassNameAction的类名(不含包名),后面的-conversion.properties是固定写法,在properties文件中的内容为:

属性名称=类型转换器的全类名

如例:UserLoginAction-conversion.properties文件中的内容为:

user= com.hzb.conversion.UserConverter 

 

若将上面的类型转换器注册为全局类型转换器,则:

WEB-INF/classes下放置xwork-conversion.properties文件 。在properties文件中的内容为:

待转换的类型=类型转换器的全类名

对于本例而言, xwork-conversion.properties文件中的内容为:

com.hzb.po.UserBean= com.hzb.conversion.UserConverter

九、HttpServletRequest / HttpSession / ServletContext / HttpServletResponse对象

获取方法:

<body>

 ${requestScope.req}<br>

${sessionScope.ses}<br>

${applicationScope.app} <br>

</body>

设值方法:

//方法一,通过ServletActionContext.类直接获取:public String rsa() throws Exception{HttpServletRequest request = ServletActionContext.getRequest();HttpSession session = request.getSession() ;ServletContext servletContext = ServletActionContext.getServletContext();HttpServletResponse response = ServletActionContext.getResponse();request.setAttribute("req","请求范围属性" );session .setAttribute("ses", "会话范围属性");servletContext.setAttribute("app", "应用范围属性");return "scope";}//方法二,实现指定接口,由struts框架运行时注入(一般不用):public class HelloWorldAction implements ServletRequestAware, ServletResponseAware, ServletContextAware{private HttpServletRequest request;private ServletContext servletContext;private HttpServletResponse response;public void setServletRequest(HttpServletRequest req) {this.request=req;}public void setServletResponse(HttpServletResponse res) {this.response=res;}public void setServletContext(ServletContext ser) {this.servletContext=ser;}}//方法三:通过ActionContext 类public String scope() throws Exception{//这种方式比较好   ActionContext ctx = ActionContext.getContext();   ctx.getApplication().put("app", "应用范围");//往ServletContext里放入app   ctx.getSession().put("ses", "session范围");//往session里放入ses   ctx.put("req", "request范围");//往request里放入req   return "scope";}

十、文件上传

<form enctype="multipart/form-data"   action="${pageContext.request.contextPath}/fileUpload.action" method="post">  <input type="file" name="uploadImage">    <input type = "submit" value="提交"/></form>public class FileUploadAction extends ActionSupport {private File uploadImage;// 得到上传的文件private String uploadImageContentType;// 得到文件的类型private String uploadImageFileName;// 得到文件的名称public String execute() throws Exception {String realpath = ServletActionContext.getServletContext().getRealPath("/images");System.out.println(uploadImageContentType);System.out.println(realpath);System.out.println(uploadImageFileName);File file = new File(realpath);if (!file.exists())file.mkdirs();FileUtils.copyFile(uploadImage, new File(file, uploadImageFileName));return "success";}public File getUploadImage() {return uploadImage;}public void setUploadImage(File uploadImage) {this.uploadImage = uploadImage;}public String getUploadImageContentType() {return uploadImageContentType;}public void setUploadImageContentType(String uploadImageContentType) {this.uploadImageContentType = uploadImageContentType;}public String getUploadImageFileName() {return uploadImageFileName;}public void setUploadImageFileName(String uploadImageFileName) {this.uploadImageFileName = uploadImageFileName;}}

十一、多文件上传

<form enctype="multipart/form-data" action="${pageContext.request.contextPath}/fileUpload.action" method="post">   <input  type="file" name="uploadImages">   <input  type="file" name="uploadImages">   <input type = "submit" value="提交"/></form>

private File[] uploadImages;// 得到上传的文件private String[] uploadImagesContentType;//得到文件的类型private String[] uploadImagesFileName;//得到文件的名称public String execute() throws Exception {String realpath = ServletActionContext.getServletContext().getRealPath("/images");File file = new File(realpath);if(!file.exists()) file.mkdirs();for(int i=0 ;i<uploadImages.length; i++){ File uploadImage = uploadImages[i];FileUtils.copyFile(uploadImage, new File(file, uploadImagesFileName[i]));}return "success";}
十二、自定义拦截器

1、<http://localhost:8080/struts2/user.jsp表示用户已登陆,存放session对象
2<http://localhost:8080/struts2/quit.jsp表示用户已退出,移除session对象
3<http://localhost:8080/struts2/login/addUIHelloWorld.action>  如果session存在则往下执行,否则提示你没有权限执行该操作
4<http://localhost:8080/struts2/login/executeHelloWorld.action>  如果session存在则往下执行,否则提示你没有权限执行该操作
代码
user.jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    request.getSession().setAttribute("user", "hzb");
%>
 用户已经登录
quit.jsp页面
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
    request.getSession().removeAttribute("user");
%>

 用户已经退出登录Action类package com.hzb.action;public class HelloWorldAction {    private String message;    public String addUI() {        this.message = "addUI";        return "success";    }    public String execute() throws Exception {        this.message = "execute";        return "success";    }    public String getMessage() {        return message;    }    public void setMessage(String message) {        this.message = message;    }}权限类package com.hzb.interceptor;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionInvocation;import com.opensymphony.xwork2.interceptor.Interceptor;/** * 限制没有登录的用户进入访问页面 */public class PermissionInterceptor implements Interceptor {    public void destroy() {    }    public void init() {    }    public String intercept(ActionInvocation invocation) throws Exception {        Object user = ActionContext.getContext().getSession().get("user");        // 如果user不为null,代表用户已经登录,允许执行action中的方法        if (user != null){            return invocation.invoke();        }        ActionContext.getContext().put("msg", "你没有权限执行该操作");        return "success";    }}
struts.xml配置文件

<?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="login" namespace="/login" extends="struts-default">        <interceptors>            <!-- 自定义拦截器 -->            <interceptor name="permission" class="com.hzb.interceptor.PermissionInterceptor"/>            <!-- 配制默许的拦截器到拦截器栈 -->             <interceptor-stack name="permissionStack">                                   <interceptor-ref name="defaultStack" />                   <interceptor-ref name="permission" />             </interceptor-stack>         </interceptors>        <!-- 配置默认的拦截器 -->        <default-interceptor-ref name="permissionStack" />        <!-- 全局变量 -->        <global-results>            <result name="success">/WEB-INF/page/message.jsp</result>        </global-results>        <action name="helloWorld_*" class="com.hzb.action.HelloWorldAction"            method="{1}">            <!-- <interceptor-ref name="permissionStack" />  -->        </action>    </package></struts> 

因为struts2中如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack中的拦截器实现的,所以我们定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能。

如果希望包下的所有action都使用自定义的拦截器,可以通过<default-interceptor-ref name=permissionStack/>把拦截器定义为默认拦截器。注意:每个包只能指定一个默认拦截器。另外,一旦我们为该包中的某个action显式指定了某个拦截器,则默认拦截器不会起作用。

十三、输入校验

输入校验的流程:

1。类型转换器对请求参数执行类型转换,并把转换后的值赋给action中的属性。

2。如果在执行类型转换的过程中出现异常,系统会将异常信息保存到ActionContextconversionError拦截器将异常信息添加到fieldErrors里。不管类型转换是否出现异常,都会进入第3步。

3。系统通过反射技术先调用action中的validateXxx()方法,Xxx为方法名。

4。再调用action中的validate()方法。

5。经过上面4步,如果系统中的fieldErrors存在错误信息(即存放错误信息的集合的size大于0),系统自动将请求转发至名称为input的视图。如果系统中的fieldErrors没有任何错误信息,系统将执行action中的处理方法。

1. 采用手工编写代码实现。

通过重写validate() 方法实现, validate()方法会校验actionexecute方法。当某个数据校验失败时,我们应该调用addFieldError()方法往系统的fieldErrors添加校验失败信息(为了使用addFieldError()方法,action可以继承ActionSupport ),如果系统的fieldErrors包含失败信息,struts2会将请求转发到名为inputresult。在input视图中可以通过<s:fielderror/>显示失败信息。


public void validate() {       if(this.mobile==null || "".equals(this.mobile.trim())){           this.addFieldError("username", "手机号不能为空");       }else{         if(!Pattern.compile("^1[358]\\d{9}").matcher(this.mobile.trim()).matches()){       this.addFieldError(“mobile", "手机号的格式不正确");        }       }}//验证失败后,请求转发至input视图:<result name="input">/addUser.jsp</result>在addUser.jsp页面中使用<s:fielderror/>显示失败信息。validateXxx()方法:validateXxx()只会校验action中方法名为Xxx的方法。其中Xxx的第一个字母要大写。validateXxx()方法使用例子:public String add() throws Exception{  return "success";}public void validateAdd(){        if(username==null && "".equals(username.trim()))           this.addFieldError("username", "用户名不能为空");}

假设现在有多个业务逻辑方法,应该针对每个业务逻辑进行校验。但现在只有一个validate方法,不可能把所有业务逻辑的验证都放在validate方法里。所以需要针对每个业务逻辑方法增加一个validateXxx()方法。这里要特别注意的是,如果action中重写了validate方法,那么validate方法一定会被调用(参看上面的执行流程)。

newReport为例,action方法的调用顺序如下:validateNewReport()->validate()->newReport

因此在这种情况下,不要重写validate方法。但是这有牵涉到一个问题,如果不写validate方法,那execute方法如何校验呢?按照上面的规则,只要编写一个validateExecute方法进行校验就可以了。

2、基于XML配置方式实现

使用基于XML配置方式实现输入校验时,Action也需要继承ActionSupport,并且提供校验文件,校验文件和action类放在同一个包下,文件的取名格式为:ActionClassName-validation.xml,其中ActionClassNameaction的简单类名,-validation为固定写法。如果Action类为com.hzb.UserAction,那么该文件的取名应为:UserAction-validation.xml。下面是校验文件的模版:

<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.3//EN" "http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd"> <validators>    <field name="username">        <field-validator type="requiredstring">            <param name="trim">true</param>            <message>用户名不能为空!</message>        </field-validator>    </field></validators>

<field>指定action中要校验的属性,<field-validator>指定校验器

系统提供的校验器如下:

required (必填校验器,要求field的值不能为null)

requiredstring (必填字符串校验器,要求field的值不能为null,并且长度大于0,默认情况下会对字符串去前后空格)

stringlength(字符串长度校验器,要求field的值必须在指定的范围内,否则校验失败,minLength参数指定最小长度,maxLength参数指定最大长度,trim参数指定校验field之前是否去除字符串前后的空格)

regex(正则表达式校验器,检查被校验的field是否匹配一个正则表达式.expression参数指定正则表达式,caseSensitive参数指定进行正则表达式匹配时,是否区分大小写,默认值为true)

int(整数校验器,要求field的整数值必须在指定范围内,min指定最小值,max指定最大值)

double(双精度浮点数校验器,要求field的双精度浮点数必须在指定范围内,min指定最小值,max指定最大值)

fieldexpression(字段OGNL表达式校验器,要求field满足一个ognl表达式,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过)

email(邮件地址校验器,要求如果field的值非空,则必须是合法的邮件地址)

url(网址校验器,要求如果field的值非空,则必须是合法的url地址)

date(日期校验器,要求field的日期值必须在指定范围内,min指定最小值,max指定最大值)

conversion(转换校验器,指定在类型转换失败时,提示的错误信息)

visitor(用于校验action中的复合属性,它指定一个校验文件用于校验复合属性中的属性)

expression(OGNL表达式校验器,expression参数指定ognl表达式,该逻辑表达式基于ValueStack进行求值,返回true时校验通过,否则不通过,该校验器不可用在字段校验器风格的配置中)

required  必填校验器<field-validator type="required">       <message>性别不能为空!</message></field-validator>requiredstring  必填字符串校验器<field-validator type="requiredstring">       <param name="trim">true</param>       <message>用户名不能为空!</message></field-validator>stringlength:字符串长度校验器<field-validator type="stringlength"><param name="maxLength">10</param><param name="minLength">2</param><param name="trim">true</param><message><![CDATA[产品名称应在2-10个字符之间]]></message></field-validator>email:邮件地址校验器<field-validator type="email"><message>电子邮件地址无效</message></field-validator>regex:正则表达式校验器<field-validator type="regex">     <param name="expression"><![CDATA[^1[358]\d{9}$]]></param>     <message>手机号格式不正确!</message></field-validator>int:整数校验器<field-validator type="int"><param name="min">1</param><param name="max">150</param><message>年龄必须在1-150之间</message></field-validator>字段OGNL表达式校验器<field name="imagefile"><field-validator type="fieldexpression"><param name="expression"><![CDATA[imagefile.length() <= 0]]></param><message>文件不能为空</message></field-validator></field>

当校验文件的取名为ActionClassName-validation.xml时,会对 action中的所有处理方法实施输入验证。如果你只需要对action中的某个action方法实施校验,那么,校验文件的取名应为:ActionClassName-ActionName-validation.xml,其中ActionNamestruts.xmlaction的名称。例如:在实际应用中,常有以下配置:

<action name="user_*" class="com.hzb.action.UserAction" method="{1}“ >

<result name="success">/WEB-INF/page/message.jsp</result>

<result name="input">/WEB-INF/page/addUser.jsp</result>

</action>

UserAction中有以下两个处理方法:

public String add() throws Exception{

}

public String update() throws Exception{

}

要对add()方法实施验证,校验文件的取名为: UserAction-user_add-validation.xml

要对update()方法实施验证,校验文件的取名为: UserAction-user_update-validation.xml

当为某个action提供了ActionClassName-validation.xmlActionClassName-ActionName-validation.xml两种规则的校验文件时,系统按下面顺序寻找校验文件:

1AconClassName-validation.xml

2ActionClassName-ActionName-validation.xml

系统寻找到第一个校验文件时还会继续搜索后面的校验文件,当搜索到所有校验文件时,会把校验文件里的所有校验规则汇总,然后全部应用于action方法的校验。如果两个校验文件中指定的校验规则冲突,则只使用后面文件中的校验规则。

action继承了另一个action,父类action的校验文件会先被搜索到。

十四、OGNL与struts2标签

1、ognl的结构

ActionContext(ValueStack、parameters、request、session、application、attr)

当struts2接受一个请求时,会迅速创建ActionContextValueStack、action的实例,然后把action实例存入ValueStack中,所以action的实例变量可以被ognl直接访问。

ValueStack中的对象不用加#可以直接访问;如果访问其他Context中的对象,由于他们不是根对象,所以在访问时,需要添加#前缀。

application对象:用于访问ServletContext,例如#application.userName或者#application['userName'],相当于调用ServletContextgetAttribute("username")

session对象:用来访问HttpSession,例如#session.userName或者#session['userName'],相当于调用session.getAttribute("userName")

request对象:用来访问HttpServletRequest,例如#request.userName或者#request['userName'],相当于调用request.getAttribute("userName")

parameters对象:用于访问HTTP的请求参数,例如#parameters.userName或者#parameters['userName'],相当于调用request.getParameter("username")

attr对象:用于按page->request->session->application顺序访问其属性。

2采用OGNL表达式创建List/Map集合对象:

Set标签用于将某个值放入指定范围。

scope:指定变量被放置的范围,该属性可以接受applicationsessionrequest、 pageaction。如果没有设置该属性,则默认放置在OGNL Context(不是值栈)中。

value:赋给变量的值.如果没有设置该属性,则将ValueStack栈顶的值赋给变量。

使用如下代码直接生成一个List对象:

 <s:set name="list" value="{'zhangming','xiaoi','liming'}" scope="request"/>

//遍历的对象会被放入值栈的栈顶

<s:iterator value="#list">

  <s:property/><br>

</s:iterator>

生成一个Map对象:

<s:set name="foobar" value="#{'foo1':'bar1', 'foo2':'bar2'}"  scope="request"/>

<s:iterator value="#foobar" >

  <s:property value="key"/>=<s:property value="value"/><br>

</s:iterator>

3、OGNL表达式的投影功能

?:获得所有符合逻辑的元素。

^:获得符合逻辑的第一个元素。

$:获得符合逻辑的最后一个元素。

例如代码:

<s:iterator value="books.{?#this.price > 35}">//遍历的对象会被放入值栈的栈顶

      <s:property value="title" /> - $<s:property value="price" /><br>

</s:iterator>

在上面代码中,直接在集合后紧跟.{}运算符表明用于取出该集合的子集,{}内的表达式用于获取符合条件的元素,this指的是为了从大集合books筛选数据到小集合,需要对大集合books进行迭代,this代表当前迭代的元素。本例的表达式用于获取集合中价格大于35的书集合。

public class BookAction extends ActionSupport {     private List<Book> books;     public String execute() {         books = new LinkedList<Book>();         books.add(new Book("A735619678", "spring", 67));         books.add(new Book("B435555322", "ejb3.0",15));     }}

4、ognl“%”“#”“$”三个符号的使用

1)“#”符号有三种用途:  

 (1)、访问非根对象(struts中值栈为根对象)

 (2)用于过滤和投影集合books.{?#this.price>35} ,  #books.{?#this.price>35}(如果books不在值栈范围要加#

 (3)构造Map, #{'foo1':'bar1', 'foo2':'bar2'}  

2)“%”符号的用途是在标签的属性值被理解为字符串类型时,告诉执行环境%{}里的是OGNL表达式。    

<s:set name="myMap" value="#{'key1':'value1','key2':'value2'}"/>     

<s:property value="#myMap['key1']"/>     

<s:url value="#myMap['key1']" />   

<s:set name="myMap" value="#{'key1':'value1','key2':'value2'}"/>  

<s:property value="#myMap['key1']"/>  

<s:url value="#myMap['key1']"/>  

上面的代码第2行会在页面上输出“value1”,而第3行则会输出"#myMap['key1']"这么一个字符串。 如果将第3行改写成这样:   

<s:url value="%{#myMap['key1']}"/>    

则输出为“value1”。  

这说明struts2里不同的标签对ognl的表达式的理解是不一样的。如果当有的标签看不懂类似“#myMap['key1']”的语句时,就要用%{}来把这括进去,翻译一下了。 

一般像property,if test,iterator这种类型的可以看懂,而hidden,input,url这种表单类型的不能看懂。

3)、“$”有两种用途   

(1)、在国际化资源文件中,引用OGNL表达式。  

(2)、在Struts 2配置文件中,引用OGNL表达式:   

<action name="saveUser" class="userAction" method="save">  

<result type="redirect">listUser.action?msg=${msg}</result>  

</action> 

5、常用的语句

1)加入struts2标签:<%@ taglib uri="/struts-tags" prefix="s"%>

2)iterator标签:用于对集合进行迭代,这里的集合包含ListSet和数组。

<s:set name="list" value="{'zhangming','xiaoi','liming'}" />

<s:iterator value="#list" status="st">

      <font color=<s:if test="#st.odd">red</s:if><s:else>blue</s:else>>

              <s:property />

      </font>

     <br>

</s:iterator>

value:可选属性,指定被迭代的集合,如果没有设置该属性,则使用ValueStack栈顶的集合。

id:可选属性,指定集合里元素的id

status:可选属性,该属性指定迭代时的IteratorStatus实例。

该实例包含如下几个方法:

int getCount(),返回当前迭代了几个元素。

int getIndex(), 返回当前迭代元素的索引。

boolean isEven(),返回当前被迭代元素的索引是否是偶数

boolean isOdd(),返回当前被迭代元素的索引是否是奇数

boolean isFirst(),返回当前被迭代元素是否是第一个元素。

boolean isLast(),返回当前被迭代元素是否是最后一个元素。

3)date日期标签:<s:datename="#request.time"format="yyyy-MM-dd日"/>

4)action实例化一个action标签:<s:action name="listNewsByIsPass"></s:action>
原创粉丝点击