Struts 2学习笔记:OGNL OGNLOGNL全称Object-Graph Navigation Language(对象 图 导航 语言)工作在视图层用来取代页面中的Java脚本简化数据的访问操作与JSP2.0中内置的EL相比它们同属于表达式语言:用于进行数据访问但是OGNL的功能更为强大.提供了很多日所不具备的功能如强大的类型转换功能 访问方法 操作集合对象等…OGNL是一 种强大的技术被集成在Struts2框架中用来帮助实现数据的传输和类型转换OGNL是基于字符串的HTTP输入/输出和基于Java 对象的内部处理之间的“黏合剂它的功能非常强大。学习了OGNL这个强大的工具开发效率会成倍地提升。(但目前SSH架构不常用, 一般用于老项目的维护) OGNL目前只能在Struts2中使用...所以..有点难受OGNL在框架中主要做两件事情:1. 表达式语言在视图层将 数据——页面—传入——框架且从框架获取输出数据生成页面的过程中OGNL提供了简单的语法将表单 或 Struts2标签 与Java各种类型的数据绑定起来。如我们前面学习的页面中 input type textname “user userName” /的输入操作对应Action 类中User对象的name属性。在OGNL的帮助下输入提交时数据从请求参数转移到了Action 的JavaBean属性上:输出时数据又从这些属性转移到页面上展示s:property value“user.userName”/2. 类型转换器除了表达式语言我们还会用到OGNL类型转换器。每次数据流入和流出框架页面中字符串类型的数据和Java数据类型之间都会发生转换。OGNL流程详解图解1.0数据流入如上图解数据最开始来自页面InputForm.html表单已 neme OGNL形式提交数据,请求以HTTPServletRequest进入框架(Struts2):请求参数 name-value 以字符串类型进行传递的..Struts2 和 OGNL对请求参数进行处理类型转换并将数据匹配赋值最后保存至值栈。数据流出数据流出 和 流入类似, 只不过顺序是反过来的.当Action 完成业务处理后, 最终会返回一个结果…并生成一个页面。在处理请求过程中,所以业务对象都保留在值栈中ValueStack值栈值栈类似于一个容器存储区域,用来保存Mdel(模型)对象用于在页面控制器之间数据传递交互展示值栈具有栈的特征:可以存储,多个对象, 以先入后出原则存储从上到下的顺序读取;框架在处理每个请求时都会 创建该请求对应的运行环境。并将请求对应的Action对象放入其中。如上图Action 对象被放在一个叫作值栈(ValueStack) 的对象中。先入后出存放params拦截器(后面章节将会学习)会负责将来自HtSerleRequest对象的数据传到值栈上。在生成页面的过程中页面标签可以访问值栈并通过OGNL表达式获取对象的属性值。图解1.0 ResultPage.jsp页面:property 标签利用表达式user age,在值栈中取到了user 对象age 属性的值。同样地。这时也需要进行类型转换将整型转换为字符串。年龄:20”在查找OGNL表达式对应的属性时会从栈顶开始依次往下, 查找一直到栈底…从上往下原则查找..OGNL表达式其实并没有什么, 特别之前其实就用过点击访问bean属性:s:property value“Action中属性名” /对象类型s:property value“Action中对象名.对象属性” / 即可~访问集合对象:s:iterator value” ” /!--表达式对于集合/数组类型遍历方式: 之前已经学习过了... --!-- 迭代 集合/数组--s:iteratorvalue集合/数组s:property//s:iterator!-- 迭代对象集合 --s:iteratorvalue对象集合s:propertyvalue对象属性名1/s:propertyvalue对象属性名2/s:propertyvalue对象属性名..//s:iterator使用 Struts 2的iterator标签送代一个集合或者数组、其中value属性用于指定要迭代的集合属性。iteator标签在迭代过程中,会把选代的每一个对象暂时压入值栈的栈顶。这样在该标签内部可以直接访问元素对象的属性和方法。即可以像示例中那样使用不带value属性的propery标签输出数据。对于集合对象的访问,在开发过程中往往还有以下几种情况。访问列表或者数组的某一个元素,可以用属性名[index]的方式。访问Map的某一个元素,可以用 属性名[‘Key’] 的方式,通过size 或者length来访问集合的长度访问ActionContext中的数据OGNL 表达式是面向值栈中的对象来解析的OGNL表达式可以针对运行环境中的任意一个对象进行解析,值栈只是运行环境中存放的对象;ActionContext也称为运行上下文。AitionContext 中包含了框架处理一个请求时会用到的所有的数据。session aplication…通常与业务相关的数据是放在值栈内的。ActionContext 中的数据存放如 requset作用域中数据下面对ActionContex中的对象进行说明。aplication,用于访问aplication属性。例如,#application.username ,相当于调用aplication.getAtribute(“username”);session,用于访问session属性。例如,#session.username ,相当于调用session.getAtribute(“username”);request,用于访问request属性。例如,#request.username ,相当于调用request.getAtribute(“username”);parameters,用于访问parameters属性。例如,#parameters.username ,相当于调用parameters.getAtribute(“username”);attr 按照 pageContext-request-session-aplication 顺序访问其属性。 #attr.username作用域存储的对象并不是在值栈中, 取值时候, 通过 #作用域.对象名 访问;对于已经声明的值栈对象如果字符展示如果页面中想要输出 username但是值栈中存储了对于的值, 而想到的只是 username字符;可以使用s: property value“%{username}” %{…可以使值栈/栈文本中关键字字符输出.}查看ActionContext中的数据Struts2特意提供了s:debug/标签。会在页面中生成一个超链接, 单击会出现如下图的 ValueStack(值栈) 和 StackContext(栈文本/作用域) 资源。方便用户开发者查看参数…数据方便找错。类型转换在基于HTTP协议的We应用中,客户端请求的所有内容(如在表单中输入的姓名、年龄、生日等)均以文本编码的方式传输到服务器端,但服务器端的编程语言(如 Java)有着丰富的数据类型int boolean Date…在Servlet 中,类型转换工作是由开发者自己完成的。例如可以通过下面的语句完成字将串类型 和 整型,字符串类型和日期类型之间的类型转换。//Servlet 原生写法, 获取表单数据…学过JDBC Servlet 都知道的贼难受~String age request.getParameter(“age”);int age Integer.parseInt(age); //还要做强制类型转换.可以看出,类型转换的工作是必不可少的、重复性的。加果有一个优秀的类型转换机制, 必将大大节省开发时间,提高开发效率。Struts2 提供了非常强大的类型转换器, 功能提供了多种内置类型转换器完全透明的对请求数据进行转换Struts2 扩展性: 如果内置的转换器不能满足应用需要, 开发者可以简单开发出自己的类型转换器内置转换器:对于大部分的常用类型,开发人员在开发过程中不需要自己编码实现类型转换。这是因为在Struts2框架中可以完成大多数常用的类转换。实现字符串类型和常用类型之间的转换。具体的转换器种类包括String: 将int, long. double, boolean, String类型的数组或者java, util. Date类型转换为字串。boolean/Boolean:在字符串和布尔值之间进行转换。char/Character:在字符串和字符之间进行转换。int/Integer. float/Float. long/Long. double/Double:在字符串和数值型数据之间进行转换。Date:在字符串和日期类型之间进行转换。具体输入/输出格式与当前的Local( 中当地的 格式的 )相关。数组和集合:在字符串数组和数组对象、集合对象之间进行转换。…实例代码接着以往项目扩展学习1.原始类型和包装类这种情况比较简单,我们一直使用的也是这种方式。HelloWord.jsp!-- 省略JSP其它部分... --bodyp${msg }/p!-- 单纯直接使用EL是获取不到滴...EL是获取作用域中的数据,这里都没有存哦~ --h1s:propertyvaluemsgdefaultmsg为null展示默认数据/!-- 使用Struts2标签库:在值栈中从上往下找到,对应属性并输出其值... --!-- 如果没有default 且msg为null 则空字符展示--/h1!-- 表单 namename 可以用于传递参数.. --formactionhellomethodpost名字:inputtypetextnamenameinputtypesubmitvalue提交/form/bodyHelloWordAction.javaimportcom.opensymphony.xwork2.Action;publicclassHelloWordActionimplementsAction{//获取页面表单名字;privateStringname;//等会向页面输出的变量...privateStringmsg;//实现方法OverridepublicStringexecute()throwsException{System.out.println(name);msghello:name;//拼接向页面输出的信息;returnhello;//返回 逻辑视图名,struts.xml根据result name返回的逻辑视图名 找到最后的响应页面/result}//省略get/set...}2.多值类型请求参数的处理…如果在请求中出理现多个值对应同一个请求参数的情况。补充一下SpringMVC中参数传递也可通过类似方式…Struts 2会将这样的数据转换为面向集合的数据类型数组、集合…数组添加工程params.jsp% page languagejava importjava.util.* pageEncodingUTF-8% % taglib prefixs uri/struts-tags %!-- 别忘了引入Struts2标签库 --% String path request.getContextPath(); String basePath request.getScheme()://request.getServerName():request.getServerPort()path/; %!DOCTYPEHTMLPUBLIC-//W3C//DTD HTML 4.01 Transitional//ENhtmlheadbasehref%basePath%titleMy JSP params.jsp starting page/titlemetahttp-equivpragmacontentno-cachemetahttp-equivcache-controlcontentno-cachemetahttp-equivexpirescontent0metahttp-equivkeywordscontentkeyword1,keyword2,keyword3metahttp-equivdescriptioncontentThis is my page/headbody!-- 多值类型请求参数的处理.. --s:formactionparamsmethodpost!-- 一个表单中,多个同名name 的表单--!-- 数组:SZ1 --s:textfieldnamesz1valueA/s:textfields:textfieldnamesz1valueB/s:textfields:textfieldnamesz1valueC/s:textfield!-- 数组:SZ2 还可以在,在声明时候指定数组长度及下标! --s:textfieldnamesz2[0]value0/s:textfields:textfieldnamesz2[4]value4/s:textfields:textfieldnamesz2[1]value1/s:textfield!-- 对象类型貌似不支持对象数组... --s:textfieldnameusers.userNamevalueABC/s:textfields:textfieldnameusers.userNamevalueACB/s:textfields:textfieldnameusers.userNamevalueBCA/s:textfields:submitvalue提交/s:submit/s:form/body/htmlParamsAction.javaimportcom.opensymphony.xwork2.Action;publicclassParamsActionimplementsAction{//全局变量..privateString[]sz1;privateint[]sz2newint[4];//对于指定数组长度的数组,页面可以指定给数组下标赋值,需要手动实例化//相当于Action中定义好了一个数组及长度,页面将请求数据匹配的根据下标一个个往里放;//对于页面参数 数组元素越界的是放不进的, 页面中的 sz2[4]放不进去... 除非改变数组长度为5;OverridepublicStringexecute()throwsException{//请求进入execute();//循环遍历数组..//SZ1for(inti0;isz1.length;i){System.out.println(sz1[i]);}//SZ2for(inti0;isz2.length;i){System.out.println(sz2[i]);}returnparams;}//省略get/set...}集合按照与数组类似的方式,Struts 2支持将一系列请求参数自动转换到各种集合类型的属性。以List为例来讲解使用List 与使用数组几乎相同仅有的不同是集合类型可以借助泛型实现;修改ParamsAction.javaimportjava.util.List;importcom.opensymphony.xwork2.Action;importcom.wsm.entity.User;publicclassParamsActionimplementsAction{//全局变量..privateListsz1;privateListIntegersz2;privateListUserusers;//对于集合类型,不需要进行初始化.//如果没有泛型说明,集合保存的类型都是String//如果泛型指定了类型为JavaBean类型,Struts2会自动创建指定类型的对象为List元素存储..OverridepublicStringexecute()throwsException{//SZ1for(Objectsz:sz1){System.out.println(sz);}//SZ2for(Integersz:sz2){System.out.println(sz);}for(Useru:users){System.out.println(u.getUserName());}returnparams;}//省略get/set...}自定义转换器:随着互联网的不断普及,用户体验已经成为网站吸引用户的主要手段。如在日期输入框中输入“1993/12/24”或者“ 193 年12月24日”都可以而无须指定某种特定的时间格式。对于Java 的基本数据类型及一些系统类(如Date 类、集合类), Sruts 2提供了内置类型转换功能。但也有一定的限制 :很显然,对于内置的日期类型转换对输入/输出格式是有要求的。如果希望 Struts 2可以更智能;1. 创建自定义类型转换器Struts 2提供了一个开发人员编写自定义类型转换器使用的基类:继承org.apache.struts2.util.StrutsTypeConverter抽象类定义了两个抽象方法,用于不同的转换方向分别如下将一个或多个字符串值转换为指定的类型public Object convertFromString(Map context, String[] values, Class toType)将指定对象转化为字符串public String convertToString(Map context, Object object)参数context 是表示OGNL上下文的Map对象参数values是要转换的字符串值参数toType是要转换的目标类型参数object是要转换的对象。如果继承StrutsTypeConverter抽象类编写自定义类型转换器,需要重写以上两个抽象方法2. 配置自定义类型转换器自定义类型转换器后还必须进行配置,将类型转换器和某个类或属性通过.properties文件建立关联;Struts 2提供了两种方式来配置自定义类型转换器应用于全局范围的类型转换器(整个项目的指定类型都会进行类型转换…)要指定应用于全局范围的类型转换器,需要在classpath的根目录下(通常是WEB目录,对应开发时的 src目录)下创建一个名为xwork-conversion.properties属性文件,其内容为要转换类全名类型转换其类全名应用于特定类的类型转换器(仅在该Action下的类型作类型转换)要指定应用于特定类的类型转换器、需要在特定类(一般都是Action)的相同目录下创建一个名为:ClassName--conversion.properties属性文件, (ClassName代码实际类名)其内容为特定转换类的对应属性名类型转换其类全名实现本章以自定义的来进行演示…日期格式多种格式没有标注的, 不用管是上面的其它案例…页面Date.jsp!-- 省略JSP --bodyformactiongodatemethodpostp请输入日期inputnamebirthday/pinputtypesubmitvalue提交/form!-- 别忘了Struts2类库 --s:propertyvaluebirthday//bodyDateAction.javapublicclassDateActionimplementsAction{privateDatebirthday;OverridepublicStringexecute()throwsException{System.out.println(birthday);returnsuccess;//别忘了配置struts.xml}//省略get/set..}创建一个 com.zb.converter 包专门存放类型转换器转换器DateConverter.javaimportjava.text.DateFormat;importjava.text.SimpleDateFormat;importjava.util.Date;importjava.util.Map;importorg.apache.struts2.util.StrutsTypeConverter;importcom.opensymphony.xwork2.conversion.TypeConversionException;publicclassDateConverterextendsStrutsTypeConverter{//支持多种日期格式,常量数组[]privatefinalDateFormat[]dfs{newSimpleDateFormat(yyyy年MM月dd日),newSimpleDateFormat(yyyy/MM/dd),newSimpleDateFormat(yyyy-MM-dd),//省略其它...};Override//将指定格式字符串转换为日期类型publicObjectconvertFromString(Mapcontext,String[]value,Classtotype){StringdateStrvalue[0];//获取日期字符串for(inti0;idfs.length;i){//遍历日期支持格式,进行转换..try{returndfs[i].parse(dateStr);//SimpleDateFormat中的parse方法,把String型的字符串转换成特定格式的date类型}catch(Exceptione){continue;//转换失败,结束本次循环..}}//如果遍历完毕后仍没有转换成功表示出现转换异常thrownewTypeConversionException();}Override//将日期转换为指定的字符串格式publicStringconvertToString(Mapcontext,Objectobject){Datedate(Date)object;//输出格式是yyyy-MM-ddreturnnewSimpleDateFormat(yyyy-MM-dd).format(date);}}配置.propertiesDateAction-conversion.propertiesbirthdaycom.zb.converter.DateConverter#birthday 特定类中的要转换类型的属性名;#com.zb.converter.DateConverter 指定转换器类的全路径…