struts2学习笔记2

1、类型转换:

struts2的类型转换器实际上是基于OGNL实现的,自定义类型转换需要实现TypeConverter或者DefaultTypeConverter或者StrutsTypeConverter

------------------------------------------------

继承DefaultTypeConverter需要重写convertValue()

public Object convertValue(Map context, Object value, Class toType) {//value是原始字符串数组
	        if (toType == Locale.class ) {//转换成Locale类
	        	System.out.println( " Converting String to Locale " );
	           String locale = ((String[]) value)[0];
	            return new Locale(locale.substring( 0 , 2 ), locale.substring( 3 ));
	       } else if (toType == String.class ) {//转换成String
	    	   System.out.println( " Converting Locale to String " );
	           Locale locale = (Locale) value;
	            return locale.toString();
	       } 
	        return null ;
	   } 

   局部类型转换器:需创建ActionName-conversion.properties,ActionName是需要转化器生效的Action的类名,应该和Action是相同的路径下

propertyName=类型转换器类(需要包名)

 全局类型转换器:需要创建的是xwork-conversion.properties

-----------------------------------

基于struts2的类型转换器:StrutsTypeConverter,将DefaultTypeConverter中的双向转换变成了两个方法,其他的和其一样

数组属性转换和集合类型转换实现方法类似

------******************-----

另一种实现转换的原理是根据OGNL在表单域中写成Action属性名.属性名或者当属性为MAP类型时:Action属性名['Key'].属性名

--------------------------------

struts2 的colletion和Map支持

在Collection中:1)使用泛型来限制集合里面元素的类型,若不使用,类型转换就无法自动起作用了

                         2)使用struts2的配置文件:需要在局部类型转换文件中增加如下的Key-value对:

Element_xxx=复合类型

 Element是固定的,xxx是action中的集合属性名,复合类型是集合元素类型的权限定类名(包括包)

如果是Map类型的,则是

key_xxx=复合类型     ###map中的key类型
Element_xxx=复合类型  ##map中value的类型

 然后在jsp页面中输出

<s:property value="集合属性名[索引].集合元素属性名"/>

 但是set,map是无序的,所以不能用上面的索引,所以在没有泛型时,需要在局部转换文件中增加:

Element_xxx=复合类型
keyProperty_集合属性名=集合元素的索引属性名  ##

 2、类型转换错误的处理

当类型转换出现异常时,conversionError拦截器会处理该异常,然后转入名为input的逻辑视图

#改变默认的类型转换失败后的提示信息
xwork.default.invalid.fieldvalue={0}字段类型转换失败!
invalid.fieldvalue.属性名=提示信息

3、文件下载与上传

enctype="multipart/form-data"表示提交表单时不再以字符串方式提交而是以二进制编码的方式提交请求  

Java文件代码是:

    private File image;   //上传文件
    private String title;  //设置上传文件的标题
    private String imageFileName;  //设置上传文件名,必须应上传文件属性的名字开头,然后后面是FileName,即若private File image 改成upload,则相应改成uploadFileName
    private String imageContentType; //上传文件类型,同imageFileName
    private String savePath;  //上传文件的保存路径,在struts.xml中定义

 其中image和title是出现在jsp中的:

<form action="/fileUpload.action" enctype="multipart/form-data" method="post">
        <s:textfield name="title"></s:textfield>
        <s:file name="image"></s:file>
        <s:submit/>
    </form>

 savePath在struts.xml中定义即可:

        <package name="fileupload" extends="struts-default">
            <global-results>
                <result name="input">/jsp/fileupload/uploadError.jsp</result>                
            </global-results>
            <action name="fileUpload" class="com.leo.fileupload.FileUploadAction">
                <interceptor-ref name="fileUpload">
                    <param name="allowedTypes">image/bmp,image/x-png,image/gif,image/pjpeg</param>
                    <param name="maximumSize">2048000</param>
                </interceptor-ref>
                <interceptor-ref name="defaultStack" />
                 <result>/jsp/fileupload/uploadSucc.jsp</result>
                 <param name="savePath">/uploadFile</param>
            </action>
        </package> 

struts2可以配置上传解析器,在struts.properties,

#指定使用COS的文件上传解析器
#struts.multipart.parser=cos
#指定使用Pell的文件上传解析器
#struts.multipart.parser=pell
#默认使用jakarta的common-fileupload
struts.multipart.parser=jakarta

 同时上传多个文件 

     

<tr>
                <td> <s:textfield name="title" label="标题"></s:textfield></td>
                <td><s:file name="filelist" label="文件"></s:file></td>
                </tr>
            <tr>
                <td> <s:textfield name="title" label="标题2"></s:textfield></td>
                 <td><s:file name="filelist" label="文件2"></s:file></td>
            </tr>

 name保持一致,这样就可以直接处理,可以用数组:

   

 private List<String> title =new ArrayList<String>();
    private List<File> filelist =new ArrayList<File>();
    private List<String> filelistFileName=new ArrayList<String>();
    private List<String> filelistContentType=new ArrayList<String>();

下载

 

<action name="fileDown" class="com.leo.filedown.FileDownAction">
                <param name="inputPath">/uploadFile</param>
                <result type="stream" name="success">
                    <!--下载的文件类型-->
                     <param name="contentType">application/octet-stream;text/plain;image/gif</param>
                      <param name="inputName">targetFile</param>   <!--此处name="inputName" 容易写成name="inputStream"注意注意-->
                    <!--
                        文件下载的处理方式,包括内联(inline)和附件(attachment)两种方式,
                        而附件方式会弹出文件保存对话框,否则浏览器会尝试直接显示文件,默认为inline
                    -->
                    <param name="contentDisposition">attachment;filename="${fileName}"</param>
                    <param name="bufferSize">4096</param>
                </result>

 在action中需要返回InputStream,如果报异常

java.lang.IllegalArgumentException: Can not find a java.io.InputStream with the name [imageStream] in the invocation stack. Check the <param name="inputName"> tag specified for this action.

  则是inputStream返回的实例为null造成的,应该注意路径是不是对的。文件存在不存在

4、struts拦截器    

 定义拦截器: 

<interceptor name="拦截器名" class="">
    <param name="参数名">值</param>
</interceptor>

 定义拦截器栈:

<interceptor-stack name="拦截器栈名">
   <interceptor-ref name="拦截器一"/>
   <interceptor-ref name="拦截器二"/>
   ...
</interceptor-stack>

 默认拦截器:

<interceptors>
   <default-interceptor-ref name="">
      <param 。。。/>
   </default-interceptor-ref>
</interceptors>

 实现拦截器需要继承Interceptor接口,提供了三个方法,init(),destroy(),interceptor(ActionInvocation actionInvocation);

而如果我们的拦截器不需要申请资源,可则可以继承AbstractInterceptor类,它的init和desttory是空实现的;

而如果我们不是拦截该action的所有方法,则是继承MethodFilterInterceptor类,它是AbstractInterceptor的子类,我们重写doInterceptor方法

MethodFilterInterceptor里面有两个方法,

          setExcludeMethods(String excludeMethods):所有excludeMethods字符串中列出的方法都不会被拦截

          setIncludeMethods(String includeMethods):这里面的方法都会被拦截,

          如果两个方法里面都有的方法,则也会被拦截。

<param name="excludeMethods">execute,hh,method2</param>

 拦截结果的监听器:

     这个监听器是通过手动注册在拦截内部的,必须实现PreResultListener接口的beforeResult方法,同时在拦截器里面增加监听就可以了

public String intercept(ActionInvocation actionInvocation) throws Exception {
        //增加监听器
        actionInvocation.addPreResultListener(new MyPreResultListener());
        ActionContext ctx=actionInvocation.getInvocationContext();

覆盖拦截器里面的特定的方法,可以直接在引用栈的时候直接修改

<interceptor-ref name="my-stack"><!--my-stack是拦截器栈-->
    <param name="second.name">xiugai</param>
</interceptor-ref>

猜你喜欢

转载自flyweilai.iteye.com/blog/1172061