zoukankan      html  css  js  c++  java
  • struts2笔记(2)

    1 <context-param>
    2     <param-name>pattern</param-name>
    3     <param-value>yyyy-MM-dd hh:mm:ss</param-value>
    4 </context-param>
    5 //获取当前 WEB 应用的初始化参数 pattern
    6 ServletContext servletContext = ServletActionContext.getServletContext();
    7 System.out.println(servletContext); 
    8 String pattern = servletContext.getInitParameter("pattern");
    获取web.xml中配置的参数

    Struts2 中, HTML 表单将被直接映射到一个 POJO,通过params拦截器,类中定义对应属性,及对应set方法即可。

    params拦截器会把请求参数的值赋给栈顶对象对应的各个属性,如果栈顶对象没有对应属性,则往下找下一个对象对应的属性。

    如果已经有了一个javabean,表单传过来了bean的属性,就不需要再action中再写一遍bean的每个属性来赋值了,可以直接写一个bean的变量,通过ModelDriven拦截器,如果 Action 类实现了 ModelDriven 接口,该拦截器将把 ModelDriven 接口的 getModel() 方法返回的对象置于栈顶,然后params拦截器就会将表单属性赋给栈顶的空的bean对象了。继承接口后这样写(可以没有setEmployee方法)

      
    1 private Employee employee;
    2 @Override
    3 public Employee getModel() {
    4     employee = new Employee();
    5     return employee;
    6 }
    View Code

     代码里不能直接return new Employee();因为和成员变量employee没关系,所以其他用到employee对象的时候,它是空。

    每次求情,只要有ModelDriven的getModel()方法,一般栈顶对象都会是该方法返回的对象!

    用class.hashcode()方法,可以看对象是不是同一个。

    关于回显:

      从值栈站顶开始查找匹配的属性,若找到,就添加到value属性中,就会自动给赋上。

    下图29。18

    通常情况下,用ModelDriven拦截器要和Preparable拦截器一起用。

    Struts 2.0 中的 modelDriven 拦截器负责把 Action 类以外的一个对象压入到值栈栈顶

    而 prepare 拦截器负责准备为 getModel() 方法准备 model

     1 5). 存在的问题: 
     2 
     3 getModel 方法
     4 
     5 public Employee getModel() {
     6     if(employeeId == null)
     7         employee = new Employee();
     8     else
     9         employee = dao.get(employeeId);
    10     
    11     return employee;
    12 }
    13 
    14 I.   在执行删除的时候, employeeId 不为 null, 但 getModel 方法却从数据库加载了一个对象. 不该加载!
    15 II.  指向查询全部信息时, 也 new Employee() 对象. 浪费!
    16 
    17 6). 解决方案: 使用 PrepareInterceptor 和 Preparable 接口. 
    18 
    19 7). 关于 PrepareInterceptor
    20 
    21 [分析后得到的结论]
    22  
    23 若 Action 实现了 Preparable 接口, 则 Struts 将尝试执行 prepare+ActionMethodName 方法,
    24 若 prepare+ActionMethodName 不存在, 则将尝试执行 prepareDo+ActionMethodName 方法.
    25 若都不存在, 就都不执行.
    26 
    27 若 PrepareInterceptor  的 alwaysInvokePrepare 属性为 false, 
    28 则 Struts2 将不会调用实现了 Preparable 接口的  Action 的 prepare() 方法
    29 
    30 [能解决 5) 的问题的方案]
    31 
    32 可以为每一个 ActionMethod 准备 prepare[ActionMethdName] 方法, 而抛弃掉原来的 prepare() 方法
    33 将 PrepareInterceptor  的 alwaysInvokePrepare 属性置为 false, 以避免 Struts2 框架再调用 prepare() 方法.
    34 
    35 如何在配置文件中为拦截器栈的属性赋值: 参看 /struts-2.3.15.3/docs/WW/docs/interceptors.html
    36 一共有三种方法,有的可以为一个action修改值,有的可以为所有action修改至,下面是为所有action修改属性
    37 <interceptors>
    38     <interceptor-stack name="parentStack">
    39         <interceptor-ref name="defaultStack">
    40             <param name="params.excludeParams">token</param>
    41         </interceptor-ref>
    42     </interceptor-stack>
    43 </interceptors>
    44  
    45 <default-interceptor-ref name="parentStack"/>
    View Code

    如图,私人订制,为需要的方法,添加上prepareMethod方法,来自自定义

    修改拦截器中部分属性的配置如下:

    paramsPrepareParmsStack拦截器栈,执行顺序:

    params -> prepare -> modelDriven -> params

    //***************************************类型转换*********

    Parameters拦截器:把请求参数映射到action属性,能自动完成字符串和基本数据类型的转换。

    如果类型转换失败:

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

    若 Action 类实现 ValidationAware 接口:Struts 在遇到类型转换错误时将不会继续调用其 Action 方法:  Struts 将检查相关 action 元素的声明是否包含着一个 name=input 的

    result(一般情况下,继承ActionSupport类就好了,然后,都是将表单输入页面当做该result,好比,后台age需要int,你输入个string,输入的不合法的值,我还给你返回这个界面).  如果有, Struts 将把控制权转交给那个 result  元素; 若没有 input 结果, Struts 将抛出一个异常

    此时返回到input的result页面后,输入框上面还有错误消息提示,输入不合法之类的(xhtml主题下)

    覆盖默认的出错消息

    在对应的 Action 类所在的包中新建  ActionClassName.properties 文件, ClassName 即为包含着输入字段的 Action 类的类名

    在属性文件中添加如下键值对: invalid.fieldvalue.fieldName=xxx

    这样就可以了,但是在simple主题下,没用。这个时候需要用标签来处理,值栈中有错误信息(${fieldErrors.arg[0]}、<s:fielderror fieldName="age"></s:fielderror>放在输入框后面即可)

     1 <body>
     2     
     3     <!--  
     4     问题1: 如何覆盖默认的错误消息?
     5     1). 在对应的 Action 类所在的包中新建  
     6         ActionClassName.properties 文件, ActionClassName 即为包含着输入字段的 Action 类的类名
     7     2). 在属性文件中添加如下键值对: invalid.fieldvalue.fieldName=xxx
     8     
     9     
    10     问题2: 如果是 simple 主题, 还会自动显示错误消息吗? 如果不会显示, 怎么办 ?
    11     1). 通过 debug 标签, 可知若转换出错, 则在值栈的 Action(实现了 ValidationAware 接口) 对象中有一个  fieldErrors 属性.
    12     该属性的类型为 Map<String, List<String>> 键: 字段(属性名), 值: 错误消息组成的 List. 所以可以使用 LE 或 OGNL 的方式
    13     来显示错误消息: ${fieldErrors.age[0]}
    14     
    15     2). 还可以使用 s:fielderror 标签来显示. 可以通过 fieldName 属性显示指定字段的错误.
    16     
    17     问题3. 若是 simple 主题, 且使用  <s:fielderror fieldName="age"></s:fielderror> 来显示错误消息, 则该消息在一个 
    18     ul, li, span 中. 如何去除 ul, li, span 呢 ?
    19     在 template.simple 下面的 fielderror.ftl 定义了 simple 主题下, s:fielderror 标签显示错误消息的样式. 所以修改该
    20     配置文件即可. 在 src 下新建  template.simple 包, 新建 fielderror.ftl 文件, 把原生的 fielderror.ftl 中的内容
    21     复制到新建的 fielderror.ftl 中, 然后剔除 ul, li, span 部分即可. 
    22     
    23     问题4. 如何自定义类型转换器 ?  
    24     1). 为什么需要自定义的类型转换器 ? 因为 Struts 不能自动完成 字符串 到 引用类型 的 转换.
    25     2). 如何定义类型转换器:
    26     I.  开发类型转换器的类: 扩展 StrutsTypeConverter 类.
    27     II. 配置类型转换器: 
    28     有两种方式
    29     ①. 基于字段的配置: 
    30         > 在字段所在的 Model(可能是 Action, 可能是一个 JavaBean) 的包下, 新建一个 ModelClassName-conversion.properties 文件
    31         > 在该文件中输入键值对: fieldName=类型转换器的全类名. 
    32         > 第一次使用该转换器时创建实例. 
    33         > 类型转换器是单实例的!    
    34     
    35     ②. 基于类型的配置:
    36         > 在 src 下新建 xwork-conversion.properties
    37         > 键入: 待转换的类型=类型转换器的全类名.
    38         > 在当前 Struts2 应用被加载时创建实例. 
    39         
    40     -->
    41     
    42     <s:debug></s:debug>
    43     
    44     <s:form action="testConversion" theme="simple">
    45         Age: <s:textfield name="age" label="Age"></s:textfield>
    46         ${fieldErrors.age[0] }
    47         ^<s:fielderror fieldName="age"></s:fielderror>
    48         <br><br>
    49         
    50         Birth: <s:textfield name="birth"></s:textfield>
    51         <s:fielderror fieldName="birth"></s:fielderror>
    52         <br><br>
    53         
    54         <s:submit></s:submit>
    55     </s:form>
    56     
    57 </body>
    类型转换的笔记

     以上是字符串到基本数据类型的类型转换,下面是字符串到引用类型的类型转换(如日期,这个时候需要自定义类型转换器)

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

    通常情况下,自定义类型转换器的类对StrutsTypeConverter进行扩展就好了

    1. Department 是模型, 实际录入的 Department. deptName 可以直接写到

    s:textfield 的 name 属性中. 那 mgr 属性如何处理呢 ?

    struts2 表单标签的 name 值可以被赋为 属性的属性: name=mgr.name, name=mgr.birth

    2. mgr 中有一个 Date 类型的 birth 属性, Struts2 可以完成自动的类型转换吗 ?

    全局的类型转换器可以正常工作!

     1 public class DateConverter extends StrutsTypeConverter {
     2 
     3     private DateFormat dateFormat;
     4     
     5     public DateConverter() {
     6         System.out.println("DateConverter's constructor...");
     7     }
     8     
     9     public DateFormat getDateFormat(){
    10         if(dateFormat == null){
    11             //获取当前 WEB 应用的初始化参数 pattern
    12             ServletContext servletContext = ServletActionContext.getServletContext();
    13             System.out.println(servletContext); 
    14             String pattern = servletContext.getInitParameter("pattern");
    15             dateFormat = new SimpleDateFormat(pattern);
    16         }
    17         
    18         return dateFormat;
    19     }
    20     
    21     @Override
    22     public Object convertFromString(Map context, String[] values, Class toClass) {
    23         
    24         System.out.println("convertFromString...");
    25         
    26         if(toClass == Date.class){
    27             if(values != null && values.length > 0){
    28                 String value = values[0];
    29                 try {
    30                     return getDateFormat().parseObject(value);
    31                 } catch (ParseException e) {
    32                     e.printStackTrace();
    33                 }
    34             }
    35         }
    36         
    37         //若没有转换成功, 则返回 values
    38         return values;
    39     }
    40 
    41     @Override
    42     public String convertToString(Map context, Object o) {
    43         
    44         System.out.println("convertToString...");
    45         
    46         if(o instanceof Date){
    47             Date date = (Date) o;
    48             return getDateFormat().format(date);
    49         }
    50         
    51         //若转换失败返回 null
    52         return null;
    53     }
    54 
    55 }
    Date类型自定义转换器示例

    //**************************************国际化**************************************

     1 1. 国际化的目标
     2 
     3 1). 如何配置国际化资源文件
     4 
     5 I.   Action 范围资源文件: 在Action类文件所在的路径建立名为 ActionName_language_country.properties 的文件
     6 II.  包范围资源文件: 在包的根路径下建立文件名为 package_language_country.properties 的属性文件,
     7 一旦建立,处于该包下的所有 Action 都可以访问该资源文件。注意:包范围资源文件的 baseName 就是package,不是Action所在的包名。
     8 III. 全局资源文件
     9     > 命名方式: basename_language_country.properties
    10     > struts.xml <constant name="struts.custom.i18n.resources" value="baseName"/>
    11 
    12 IV.  国际化资源文件加载的顺序如何呢 ? 离当前 Action 较近的将被优先加载. 
    13 
    14 假设我们在某个 ChildAction 中调用了getText("username"):
    15 
    16 (1) 加载和 ChildAction 的类文件在同一个包下的系列资源文件 ChildAction.properties
    17 (2) 加载  ChildAction 实现的接口 IChild,且和 IChildn 在同一个包下 IChild.properties 系列资源文件。
    18 (3) 加载 ChildAction 父类 Parent,且和 Parent 在同一个包下的 baseName 为 Parent.properties 系列资源文件。
    19 (4) 若 ChildAction 实现 ModelDriven 接口,则对于getModel()方法返回的model 对象,重新执行第(1)步操作。
    20 (5) 查找当前包下 package.properties 系列资源文件。
    21 (6) 沿着当前包上溯,直到最顶层包来查找 package.properties 的系列资源文件。
    22 (7) 查找 struts.custom.i18n.resources 常量指定 baseName 的系列资源文件。
    23 (8) 直接输出该key的字符串值。
    24 
    25 
    26 2). 如何在页面上 和 Action 类中访问国际化资源文件的  value 值
    27 
    28 I. 在 Action 类中. 若 Action 实现了 TextProvider 接口, 则可以调用其 getText() 方法获取 value 值
    29     > 通过继承 ActionSupport 的方式。 
    30     1.在action中访问国际化资源文件的value值
    31         String username = getText("username");
    32     2.带占位符的
    33         String time = getText("time",Arrays.asList(new Date()));
    34         syso,就可以打印出来
    35     
    36 II. 页面上可以使用 s:text 标签; 对于表单标签可以使用表单标签的 key 属性值
    37     > 若有占位符, 则可以使用 s:text 标签的 s:param 子标签来填充占位符
    38     > 可以利用标签和 OGNL 表达式直接访问值栈中的属性值(对象栈 和 Map 栈)
    39     
    40     time=Time:{0}(这个是在i18n.properties中写的)
    41     
    42     <s:text name="time">
    43         <s:param value="date"></s:param>
    44     </s:text>
    45 
    46     ------------------------------------
    47     
    48     time2=Time:${date}(类似一个ongl表达式的情况,在i18n.properties中直接获取值)
    49     
    50     <s:text name="time2"></s:text>
    51     
    52 
    53 3). 实现通过超链接切换语言. 
    54 
    55 I.  关键之处在于知道 Struts2 框架是如何确定 Local 对象的 !
    56 II. 可以通过阅读 I18N 拦截器知道. 
    57 III. 具体确定 Locale 对象的过程:
    58 
    59     > Struts2 使用 i18n 拦截器 处理国际化,并且将其注册在默认的拦截器栈中
    60     > i18n拦截器在执行Action方法前,自动查找请求中一个名为 request_locale 的参数。
    61           如果该参数存在,拦截器就将其作为参数,转换成Locale对象,并将其设为用户默认的Locale(代表国家/语言环境)。
    62           并把其设置为 session 的 WW_TRANS_I18N_LOCALE 属性
    63     > 若 request 没有名为request_locale 的参数,则 i18n 拦截器会从 Session 中获取 WW_TRANS_I18N_LOCALE 的属性值,
    64          若该值不为空,则将该属性值设置为浏览者的默认Locale 
    65     > 若 session 中的 WW_TRANS_I18N_LOCALE 的属性值为空,则从 ActionContext 中获取 Locale 对象。
    66     
    67 IV.  具体实现: 只需要在超连接的后面附着  request_locale 的请求参数, 值是 语言国家 代码.
    68     <a href="testI18n.action?request_locale=en_US">English</a>
    69     <a href="testI18n.action?request_locale=zh_CN">中文</a>
    70     
    71     > 注意: 超链接必须是一个 Struts2 的请求, 即使 i18n 拦截器工作!
    72     
    73 
    74  
    View Code

    在页面上使用国际化(xhtml主题):

    在页面上使用国际化(simple主题):

    国际化资源文件:

    **************************************国际化**************************************//

    //**************************************动态加载国际化**************************************

    i18n拦截器

    具体实现代码:

    **************************************动态加载国际化**************************************//

    这个博客主要是javaEE相关或者不相关的记录, hadoop与spark的相关文章我写在下面地址的博客啦~ http://www.cnblogs.com/sorco
  • 相关阅读:
    动态规划(最长公共序列,最长上升序列)
    滴滴笔试--算术转移(20190827)
    线段树和树状数组
    pair和list学习
    数据结构--树(建立、遍历)
    tmux常用命令与快捷键
    机器学习实战-逻辑回归
    字符流中第一个重复的字符
    机器学习实战-朴素贝叶斯
    Python第三方库
  • 原文地址:https://www.cnblogs.com/orco/p/6247367.html
Copyright © 2011-2022 走看看