7.类型转换、消息处理与国际化

7.类型转换、消息处理与国际化

@(10_Struts2)[JavaEE, Struts2]

  • 前边我们说过了 Http协议 有两个缺陷一个是无状态一个是纯文本
  • 纯文本也就是说Http请求中的内容都是以字符串的形式发送的。
  • 但是Java又是一个强类型语言,所以将一个字符串转换成Java中的数据类型这一重任就落在了Struts2的肩膀上。
  • 类型转换最常见的可能就是将将10/29/2015转换为一个date类型等。
  • 关于类型转换我们要做的主要有两件事:
    • 类型转换失败后的处理
    • 特殊类型的自定义类型转换器

类型转换失败消息处理

  • 类型转换失败
    • 若 Action 类没有实现 ValidationAware 接口: Struts 在遇到类型转换错误时仍会继续调用其 Action 方法, 就好像什么都没发生一样.

    • 若 Action 类实现 ValidationAware 接口:Struts 在遇到类型转换错误时将不会继续调用其 Action 方法:

      • Struts 将检查相关 action 元素的声明是否包含着一个 name=input 的 result.
      • 如果有, Struts 将把控制权转交给那个 result 元素;
      • 若没有 input 结果, Struts 将抛出一个异常
    • 实现 ValidationAware 接口,在之前的文章中我们提到,我们可以继承 com.opensymphony.xwork2.ActionSupport 类的形式来实现 ValidationAware 接口, 在ActionSupport 中已经帮我们实现好了


  • 类型转换出错时如何处理

    • 如果我们输入错误的数字,想转换为年龄;当我们的 result name="input" 的时候,会返回到这个结果页面。
    • 错误的年龄
    • 但是对于这种错误的提示,我们需要处理
  • 类型转换错误消息的定制

    • 作为默认的 default 拦截器的一员, ConversionError 拦截器负责添加与类型转换有关的出错消息(前提: Action 类必须实现了 ValidationAware 接口)和保存各请求参数的原始值.
    • 若字段标签使用的不是 simple 主题, 则非法输入字段将导致一条有着如上图格式的出错消息。
  • 覆盖默认的出错消息

    • 在对应的 Action 类所在的包中新建 ActionClassName.properties 文件, ClassName 即为包含着输入字段的 Action 类的类名
    • 在属性文件中添加如下键值对: invalid.fieldvalue.fieldName=Customer Message
# EmployeeAction.properties
invalid.fieldvalue.age=年龄格式不正确,请重新输入!
  • 自定义的消息
  • 定制出错消息的样式:

    • 每一条出错消息都被打包在一个 HTML span 元素里, 可以通过覆盖其行标为 errorMessage 的那个 css 样式来改变出错消息的格式.
    • 显示错误消息: 如果是 simple 主题, 可以通过 <s:fielderror fieldName=“filedname”></s:fielderror> 标签显示错误消息
    • 通过s:fielderror 标签
<s:form action="emp_update" theme="simple">
    <s:hidden name="id"></s:hidden>
    姓名:<s:textfield name="name"></s:textfield> <br>
    年龄:<s:textfield name="age" ></s:textfield>
    <!-- 通过标签获取错误消息 -->
    <span style="color:red"><s:fielderror fieldName="age"></s:fielderror></span><br>
    部门: <s:textfield name="dept"></s:textfield><br>
    职务:<s:textfield name="role"></s:textfield><br>
    <s:submit value="修改"></s:submit>
</s:form>
  • 但是对于这种错误消息的格式我们是可以修改的,修改其默认的 freemark 模板
  • struts2-core-2.3.15.3.jar 的 /template/simple/fielderror.ftl,这是 struts2 默认自带的错误消息模板,我们在 src 路径下建立相同的包和模板,并且修改里面的 html 标签。删除文件中错误消息的 的 ul、li、span便签

![删除的模板

  • 效果

自定义类型转换器

  • 定制类型转换器

  • 自定义类型转换器必须实现 ongl.TypeConverter 接口或对这个接口的某种具体实现做扩展

  • 扩展 StrutsTypeConverter 类

    • 在大多数类型转换器里, 需要提供从 String 类型到非 String 类型和与此相反的转换功能
    • 在 StrutsTypeConverter 中有两个抽象方法:
  • 配置自定义的类型转换器

    • 在应用程序里使用一个自定义的类型转换器之前, 必须先对它进行配置. 这种配置既可以基于字段, 也可以基于类型
    • 基于字段类型转换配置-局部转换器
      • 可以为某个 Model(该 Model 类也可能是 Action) 的各个属性分别配置一个自定义的转换器.
      • 创建一个属性文件: ModelClassName-conversion.properties, 该文件需和相对应的 Model(Model有可能是一个Action) 类放在同一个目录下
      • fieldName=Converter全类名,例如: birth=org.pan.struts2.conver.DateConverter
    • 基于类型-全局转换器
      • 在资源目录下,src 或者 其他的 resources 创建 xwork-conversion.properties文件
      • xwork-conversion.properties 文件里把每一个需要进行类型转换的类与一个类型转换器关联起来
      • java.util.Date=org.pan.struts2.conver.DateConverter
      • 若类型转换失败,给出自定义的信息。

复杂属性,集合协同工作

  • 复杂属性
    • 类型转换与复杂属性配合使用
    • form 标签的 name 属性可以被映射到一个属性的属性.
    • 复杂属性
<s:form action="user_add">
    <s:textfield name="user.name" label="姓名"></s:textfield>
    <s:textfield name="user.gender" label="性别"></s:textfield>
    <s:textfield name="user.address" label="地址"></s:textfield>
    <s:textfield name="user.mgr.name" label="经理名称"></s:textfield>
    <s:textfield name="user.mgr.birth" label="经理生日"></s:textfield>
    <s:submit value="添加"></s:submit>
</s:form>
  • 集合协同
    • 类型转换与 Collection 配合使用

国际化

  • 概述

    • 在程序设计领域, 把在无需改写源代码即可让开发出来的应用程序能够支持多种语言和数据格式的技术称为国际化.
    • 与国际化对应的是本地化, 指让一个具备国际化支持的应用程序支持某个特定的地区
    • Struts2 国际化是建立在 Java 国际化基础上的:
    • 为不同国家/语言提供对应的消息资源文件
      • Struts2 框架会根据请求中包含的
        • Locale 加载对应的资源文件
      • 通过程序代码取得该资源文件中
      • 指定 key 对应的消息
  • 默认拦截器栈中有一个i18n拦截器,这个拦截器用来设置当前Locale信息

    • 当i18n拦截器被调用时,他会先去查找request_locale这个请求参数,它会根据干参数来创建一个Locale对象。并将Locale对象放入进session域中。之后在加载国际化资源文件时就根据刚刚创建的Locale对象
  • 当i18n拦截的请求中没有request_locale这个参数,

  • 它会先去session中获取Locale对象,如果session中,则直接使用该对象

  • 如果session中没有,则会根据用户浏览器信息或本地服务器的信息去创建一个Locale对象并使用

  • 配置国际化资源文件

    • Action 范围资源文件:
      • 在Action类文件所在的路径建立名为ActionName_language_country.properties 的文件
    • 包范围资源文件:
      • 在包的根路径下建立文件名为package_language_country.properties 的属性文件,一旦建立,处于该包下的所有 Action 都可以访问该资源文件。
      • 注意:包范围资源文件的 baseName 就是package,不是Action所在的包名
    • 全局资源文件
      • 命名方式: basename_language_country.properties
      • struts.xml <constant name="struts.custom.i18n.resources" value="baseName"/>
<!-- 配置国际化资源 -->
<constant name="struts.custom.i18n.resources" value="i18n"/>
  • 临时指定资源文件:<s:i18n.../> 标签的 name 属性指定临时的国际化资源文件
  • 总结:
    • 国际化资源文件加载的顺序如何呢 ?
      • 离当前 Action 较近的将被优先加载.
    • 假设我们在某个 ChildAction 中调用了getText("username")
      • (1)加载和 ChildAction 的类文件在同一个包下的系列资源文件 ChildAction.properties
      • (2)加载 ChildAction 实现的接口 IChild,且和 IChildn 在同一个包下 IChild.properties 系列资源文件。
      • (3)加载 ChildAction 父类 Parent,且和 Parent 在同一个包下的 baseName 为 Parent.properties 系列资源文件。
      • (4) 若 ChildAction 实现 ModelDriven 接口,则对于getModel()方法返回的model 对象,重新执行第(1)步操作。
      • (5) 查找当前包下 package.properties 系列资源文件。
      • (6) 沿着当前包上溯,直到最顶层包来查找 package.properties 的系列资源文件。
      • (7) 查找 struts.custom.i18n.resources 常量指定 baseName 的系列资源文件。
      • (8) 直接输出该key的字符串值。
  • Action 范围国际化
  • package 范围国际化
  • 全局的国际化
    • 首先需要去 struts.xml 中指定baseName
<!-- 指定国际化 baseName, 以便于建立全局的国际化资源文件 -->
<constant name="struts.custom.i18n.resources" value="myI18n"></constant>
  • 全局的配置
  • 在这还需要讲到一种方式:在页面国际化资源

    • 如果我们在资源路径下建立好了 国际化资源,但是没有在 struts.xml 中配置 baseName
    • 我们可以使用 <s:i18n name="baseName"> 标签来获取
    <!-- 如果是配置了页面国际化资源文件,
    那么国际的内容只能在i18n标签中使用,一旦离开i18n标签则不能使用 -->
    <s:i18n name="myI18n">
        <s:text name="username"></s:text>
        <s:form>
            <s:textfield name="username" key="username"></s:textfield>
            <s:password name="password" key="password"></s:password>
            <s:submit key="submit"></s:submit>
        </s:form>
    </s:i18n>

  • 访问国际化消息
    • JSP 页面访问国际化消息

      • 不带占位符:
        • <s:text name="key"/>
        • 表单元素的 label 属性:可替换为 key 或使用 getText() 方法,并对其进行强制 OGNL 解析,使用%{}
      • 带占位符:
        • 在 <s:text.../> 标签中使用多个 <s:param.../> 标签来填充消息中的占位符。
        • Struts2 直接在国际化消息资源文件中通过 “${}” 使用表达式,该表达式将从值栈中获取对应的属性值(对象栈 和 Map 栈)
    • Action 访问国际化消息:

      • 若 Action 类继承了 ActionSupport ,则可调用 TextProvider 接口的 getText 方法

  • 利用超链接实现动态加载国际化资源文件
    • Struts2 使用 i18n 拦截器 处理国际化,并且将其注册在默认的拦截器中
    • i18n拦截器在执行Action方法前,自动查找请求中一个名为request_locale 的参数
    • 如果该参数存在,拦截器就将其作为参数,转换成Locale对象,并将其设为用户默认的Locale(代表国家/语言环境)。并把其设置为 session 的 WW_TRANS_I18N_LOCALE 属性
    • request 没有名为request_locale 的参数,则 i18n 拦截器会从 Session 中获取 WW_TRANS_I18N_LOCALE 的属性值,若该值不为空,则将该属性值设置为浏览者的默认Locale
    • 若 session 中的 WW_TRANS_I18N_LOCALE 的属性值为空,则从 ActionContext 中获取 Locale 对象。
<!-- 必須是 struts 請求,使得 i18 拦截器工作 -->
<a href="userLogin.action?request_locale=en_US">English</a>
<a href="userLogin.action?request_locale=zh_CN">中文</a>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,383评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,522评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,852评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,621评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,741评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,929评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,076评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,803评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,265评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,582评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,716评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,395评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,039评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,027评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,488评论 2 361
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,612评论 2 350

推荐阅读更多精彩内容