struts2(3)

来源:互联网 发布:杨过 知乎 编辑:程序博客网 时间:2024/05/11 00:58

一、Struts2的国际化(需要知道)

         配置国际化资源消息包            

1.准备资源文件,资源文件的命名格式如下:


        baseName_language_country.properties
         baseName_language.properties
         baseName.properties
        其中baseName是资源文件的基本名,我们可以自定义,但language和country必须是java支持的语言和国家。如:
       中国大陆: baseName_zh_CN.properties
        美国: baseName_en_US.properties

现在为应用添加两个资源文件:
第一个存放中文:baseName_zh_CN.properties
内容为:welcome=欢迎学习国际化

第二个存放英语(美国): baseName_en_US.properties
内容为: welcome=Welcome  study to internationalization

  2.在struts.xml配置全局国际化消息资源包  value为资源文件的基本名

                    <constant name="struts.custom.i18n.resources" value="beseName"></constant>


  3.在页面或者action中访问国际化信息

                        

 在动作中

         

自由配置

 国际化—输出带占位符的国际化信息    需要配置全局

 

配置局部消息资源包 

一定要经过Action才行:

书写规范:在动作类所在包中,建立名字”动作类名-zh-CN.properties”的配置文件。动作类中访问,发现局部的比全局的优先级高。

总结:

 

 

二、Struts2中的拦截器

         在执行动作方法前或执行结果后,做拦截处理。AOP编程思想。

      1、自定义拦截器

                a、定义一个类继承AbstractInterceptor或者实现Interceptor

              

            b、struts.xml中定义

           

         c、动作中使用

        

  

   2:练习    

            因为struts2中如文件上传,数据验证,封装请求参数到action等功能都是由系统默认的defaultStack中的拦截器实现的,所以我们定义的拦截器需要引用系统默认的defaultStack,这样应用才可以使用struts2框架提供的众多功能。
       如果希望包下的所有action都使用自定义的拦截器,可以通过<default-interceptor-ref name=“permissionStack”/>把拦截器定义为默认拦截器。注意:每个包只能指定一个默认拦截器。另外,一旦我们为该包中的某个action显式指定了某个拦截器,则默认拦截器不会起作用。

    

把自己定义的拦截器放到拦截器栈        在package里配置后    其他类继承这个package就可以不再配置拦截器了 

 <!-- 定义拦截器栈 -->     <interceptor-stack name="<span style="color:#ff0000;">mydefalutstack</span>">     <!-- 把自己的定义的拦截器也加入进来  -->     <span style="color:#ff0000;"><interceptor-ref name="sessionCheckInterceptor"/></span>    <interceptor-ref name="exception"/>            <interceptor-ref name="alias"/>            <interceptor-ref name="servletConfig"/>            <interceptor-ref name="i18n"/>            <interceptor-ref name="prepare"/>            <interceptor-ref name="chain"/>            <interceptor-ref name="scopedModelDriven"/>            <interceptor-ref name="modelDriven"/>            <interceptor-ref name="fileUpload"/>            <interceptor-ref name="checkbox"/>            <interceptor-ref name="multiselect"/>            <interceptor-ref name="staticParams"/>            <interceptor-ref name="actionMappingParams"/>            <interceptor-ref name="params">                <param name="excludeParams">dojo\..*,^struts\..*,^session\..*,^request\..*,^application\..*,^servlet(Request|Response)\..*,parameters\...*</param>            </interceptor-ref>            <interceptor-ref name="conversionError"/>            <interceptor-ref name="validation">                <param name="excludeMethods">input,back,cancel,browse</param>            </interceptor-ref>            <interceptor-ref name="workflow">                <param name="excludeMethods">input,back,cancel,browse</param>            </interceptor-ref>            <interceptor-ref name="debugging"/>            <interceptor-ref name="demo1Interceptor"></interceptor-ref>            </interceptor-stack>               </interceptors>     <!-- 配置默认拦截器栈 -->     <default-interceptor-ref name="<span style="color:#ff0000;">mydefalutstack</span>"></default-interceptor-ref>

   3、methodFilterInterceptor 

          拦截器是拦截所有动作方法的

        Struts2还提供了一个MethodFilterIntercepter类,该类是AbstractInterceptor类的子类,如果你需要实现的拦截器支持方法过滤性   可以指定不拦截那些方法和拦截那些

            例子:判断是否有登录  没有登录就返回到登录视图     如果是登录就不拦截

                

                   

     

 

三、文件的上传和下载(重要  记住拦截器和结果类型stream)

             文件的上传是由一个FileUpload拦截器实现的

                       上传的前提:表单的method是post   enctype是multipart/form-data      提供 type=file 的上传输入域

                                      在 Action 中新添加 3 个和文件上传相关的属性. 这 3 个属性的名字必须是以下格式

                              

                                      uploadImage 是 jsp 页面上的 file 标签的名字.
                                                           上传文件:<input type="file" name="uploadImage">

           1.单文件的上传
                    
<span style="font-size:12px;">//单文件上传public class Upload1Action extends ActionSupport {private String name;private File photo;// 和上传的输入域名称一致,必须File类型private String photoFileName;// 文件名:上传的输入域名FileNameprivate String photoContentType;// 上传的文件的MIME类型public String getName() {return name;}public void setName(String name) {this.name = name;}public File getPhoto() {return photo;}public void setPhoto(File photo) {this.photo = photo;}public String getPhotoFileName() {return photoFileName;}public void setPhotoFileName(String photoFileName) {this.photoFileName = photoFileName;}public String getPhotoContentType() {return photoContentType;}public void setPhotoContentType(String photoContentType) {this.photoContentType = photoContentType;} public String upload() throws IOException{ System.out.println(name+":"+photoFileName+":"+photoContentType); //存储文件的路径 String storeDirectory=ServletActionContext.getServletContext().getRealPath("/files"); //存储上传的文件 FileUtils.copyFile(photo, new File(storeDirectory,photoFileName));return SUCCESS; }}</span>

               jsp页面

               2、多文件上传
//多文件上传public class Upload2Action extends ActionSupport {// 用数组或者listprivate String name;private File[] photo;// 和上传输入域名称一致 必须是File类型private String[] photoFileName;// 文件名: 上传的输入域名FileNameprivate String[] photoContentType;// 上传文件的MIME类型public String getName() {return name;}public void setName(String name) {this.name = name;}public File[] getPhoto() {return photo;}public void setPhoto(File[] photo) {this.photo = photo;}public String[] getPhotoFileName() {return photoFileName;}public void setPhotoFileName(String[] photoFileName) {this.photoFileName = photoFileName;}public String[] getPhotoContentType() {return photoContentType;}public void setPhotoContentType(String[] photoContentType) {this.photoContentType = photoContentType;}public String upload() throws IOException{//存储目录String storeDirectory =ServletActionContext.getServletContext().getRealPath("files");//存储if(photo!=null&&photo.length>0){for(int i=0;i<photo.length;i++){FileUtils.copyFile(photo[i], new File(storeDirectory,photoFileName[i])); }}return SUCCESS;}
              jsp
   3、FileUpload拦截器

         FileUpload 拦截器负责处理文件的上传操作, 它是默认的 defaultStack 拦截器栈的一员.
         FileUpload 拦截器有 3 个属性可以设置.
                     maximumSize: 上传文件的最大长度(以字节为单位), 默认值为 2 MB
                     allowedTypes: 允许上传文件的类型, 各类型之间以逗号分隔
                     allowedExtensions: 允许上传文件扩展名, 各扩展名之间以逗号分隔
                     可以在 struts.xml 文件中覆盖这 3 个属性

           

  4、参数配置及不符合要求时的错误提示

           a、如果出现上传失败的情况,框架自动转向一个input的逻辑视图。

            b、更改默认的消息提示:

                    struts2-core.jar org.apache.struts2.struts-message.properties      找到对应的参数

         

              改变:配置一个全局消息资源包

                            

  5、文件的下载

               动作类

public class DownLoad1Action extends ActionSupport {private InputStream photoIn;// 要下载的输入流private String filename;// 下载的文件名public InputStream getPhotoIn() {return photoIn;}public void setPhotoIn(InputStream photoIn) {this.photoIn = photoIn;}public String getFileName() {return filename;}public void setFileName(String fileName) {this.filename = fileName;}public String download() throws Exception {// 给输入流赋值String realPath = ServletActionContext.getServletContext().getRealPath("/中文.jpg");filename = FilenameUtils.getName(realPath);filename = URLEncoder.encode(filename, "UTF-8");// 中文文件名下载乱码 先编码 客户端再解码photoIn = new FileInputStream(realPath);return SUCCESS;}

         配置stream结果类型

             

<action name="download" class="it.test.action.DownLoad1Action" method="download">     <!-- 下载时由Stream结果类型负责 -->     <result type="stream">             <!-- 靠配置结果类型参数 -->             <param name="inputName">photoIn</param>             <!-- 告知客户端用下载的方式打开 -->             <!-- 动态获取下载的文件名:在该配置文件中使用OGNL表达式。就相当于调用当前动作的getFilename方法 -->             <param name="contentDisposition">attachment;filename=${filename}</param>             <!-- 告知客户端文件的MIME类型 -->             <param name="contentType">application/octet-stream</param>        </result>     </action>


四、OGNL表达式


               OGNL是Object Graphic Navigation Language(对象图导航语言)的缩写,
                  它是一个开源项目。 Struts2框架使用OGNL作为默认的表达式语言。
               OGNL相对其它表达式语言具有下面几大优势:
                          1、支持对象方法调用,如xxx.doSomeSpecial();
                           2、支持类静态的方法调用和值访问,表达式的格式:
                                         @[类全名(包括包路径)]@[方法名 |  值名],例如:
                                         @java.lang.String@format('foo %s', 'bar')
                                         或@tutorial.MyConstant@APP_NAME;
                                   在struts.xml中   设置常量 struts.ognl.allowStaticMethodAccess=true
                       3、支持赋值操作和表达式串联,如price=100, discount=0.8,
                                        calculatePrice(),这个表达式会返回80;
                         4、访问OGNL上下文(OGNL context)和ActionContext;
                      5、操作集合对象

  

五、ValueStack(重要理解)       

                        在jsp中使用struts标签的debug可以看到ValueStack

                      ValueStack实际是一个接口,在Struts2中利用OGNL时,实际上使用的是实现了该接口的OgnlValueStack类,这个类是Struts2利用OGNL的基础 

      OgnlValueStack 类包含两个重要的属性   一个root和一个context。
     
   *    其中root本质上是一个ArrayList.
         *    而context 是一个Map(更确切的说是一个OgnlContext对象)
       在这个OgnlContext对象(context)中,有一个默认的顶层对象 _root,OGNL访问context中这个默认顶层对象中的元素时,是不需要#号的,直接通过元素的名称来进问,
而访问其他对象时,如 request、session、attr等,则需要#号引用。
       注:Struts2将OgnlValueStack的root对象赋值给了OgnlContext 中的_root对象,在OgnlValueStack的root对象中,保存着调用Action的实例,因此,在页面上通过Struts2标签访问Action 的属性时,就不需要通过#号来引用
                    总结:ognl Context包含 ObjectStack属性和ContextMap属性

   

        1ValueStack的生命周期

           每次动作访问都会创建一个ValueStack。动作类的实例声明周期也是每次访问时都创建。

          2ValueStackActionContext的关系

                       相互引用

 

通过ValueStack操作Map和栈()

        OGNLcontextMapValueStack是作为他的一个叫做根(实际上是一个List)的形式存在的。

 3ValueStack常用的方法

          void set(String key,Object value):先获取根栈栈顶的Map,如果不存在,压入一个新的Map,把keyvalue放到这个Map中。如果存在,直接放keyvalue

     Object findValue(String expr):参数是一个OGNL表达式。如果以#开头,从contextMap中找key值所对应的对象。如果不是以#开头,搜索根栈中对象的属性(getter方          法)

         特别注意:如果编写的表达式不是以#开头,先搜索根栈对象的所有属性,如果没有找到,会把它当做key值到contextMap中找。

     String findString(String expr):findValue功能一样,但把OGNL表达式获取的对象转换成String


 练习

//练习public class Demo2Action extends ActionSupport {      private String name="gg";public String getName() {return name;}public void setName(String name) {this.name = name;}          public String execute(){    ValueStack vs1=ActionContext.getContext().getValueStack();        vs1.setValue("name","呐呐");//给栈中对象的name属性赋值    vs1.setValue("#name", "nana2");//相当于向contextMap中存放数据    //总结:操作跟中对象的属性,直接写属性名称。 操作contextMap中的数据,要加上#。        //向跟栈中压入2个Date对象    //跟栈中对象“属性"的设置:默认情况下,从栈顶底依次搜索属性名称,找到就赋值,不再往下找。找不到报错       //也可以指定从第几个开始找,索引从0开始    vs1.push(new Date());    vs1.push(new Date());        vs1.setValue("[1].month", 9);//修改第二个date的月属性        vs1.setValue("name", "ee");//修改属性    return SUCCESS;    }
4、ContextMap中存放的常用内容

           OGNL Context是struts2的数据中心  

                    当Struts2接受一个请求时,会迅速创建ActionContext,ValueStack,action 。然后把action存放进ValueStack,所以action的实例变量可以被OGNL访问。 
注意: Struts2中,OGNL表达式需要配合Struts标签才可以使用。如:<s:property value="name"/>

        

         request:存放的ServletRequest中的属性(attributes),他是一个Map<String,Object>

         session:存放的HttpSession中的属性(attributes),他是一个Map<String,Object>

          application:存放的ServletContext中的属性(attributes),他是一个Map<String,Object>

           action:当前的动作类

           parameters:请求参数的那个Map

         attr:依次从page\request\session\appliction范围依次搜索

    Demo:

    

         #号的用法

              用法1:访问OGNL上下文和Action上下文,#相当ActionContext.getContext()

                          1、  如果访问其他Context中的对象,由于他们不是根对象,所以在访问时,
                                  需要添加#前缀。

                          2 、OGNL会设定一个根对象(root对象),在Struts2中根对象就是ValueStack
       (值栈) 。如果要访问根对象(即ValueStack)中对象的属性,则可以省略
         #命名对象,直接访问该对象的属性即可。


为何使用EL表达式能够访问valueStack中对象的属性
          

从request范围中找不到那个属性,EL表达式就变成了OGNL表达式。其他EL功能都不变。

     

结论:

原来EL顺序${p}  page----->request----->session---->application

Struts2EL顺序:${p}  page------>request----->根栈中的属性getP()--->contextMap中找---->session---->application

从request范围中找不到那个属性,EL表达式就变成了OGNL表达式。其他EL功能都不变。


OGNL表达式其他用法
                集合的投影(只输出部分属性) (过滤)
                         1集合的过滤有以下三种方式:    
                  a.“?#”:过滤所有符合条件的集合,如:users.{?#this.age > 19};     
                  b.“^#”:过滤第一个符合条件的元素,如:users.{^#this.age > 19};    
                   c.“$#”:过滤最后一个符合条件的元素,如:users.{$#this.age > 19} 。
              this   表示集合中的元素;
demo
              


  #号 用法3
      :构造Map,如#{‘foo1’:‘bar1’, ‘foo2’:‘bar2’}。
             这种方式常用在给radio或select、checkbox等标签赋值上

demo



0 0
原创粉丝点击