前言:在数据库中,我们一般都是保存文件的信息(保存的路径,文件名等等),而不会把文件当作Clob打字段保存在数据库中。所以上传文件和下载文件的思路就清晰了很多。限于时间,这里只记录大概思路,具体详细内容可以根据根据文中提到的关键字google,相信很快能解决,有时间再完善吧。

上传:

1、把文件通过InputStream传送到服务器指定的磁盘或文件夹

2、把文件的对应信息(存储路径,文件名等等)存入数据库

    具体步骤:

1、JSP页面很简单

①<s:file label="浏览.." name="myfile"></s:file>
label是指上传文件按钮上的字,name是跟Action中的一个属性相对应的。其他属性或事件可以自己添加,上面两个属性是最基本的。

②<form>标签设置两个属性:enctype="multipart/form-data"  method="post"

2、Action中

①如上所说,要先在Action中配置几个属性

 

  1. //上传的附件,和<s:file>标签中的name属性值对应   
  2. private File myfile;   
  3. //上传文件的文件名,属性名后面的格式固定:myfile+"FileName"   
  4. private String myfileFileName;   
  5. //上传文件的类型 
  6. private String myfileContentType; 
  7. /**  
  8. * 以及相对应的setter和getter方法  
  9. */ 
其实,不是对属性的格式要求规范,而是对属性的get,set方法格式要求严格,所以,我们可以养成把属性格式写好, set,get方法自动生成的习惯就0了
  1. public String execute(){ 
  2.     InputStream is = new FileInputStream(myfile); 
  3.             //长传到服务器目录 
  4.             String path = "c:\\upload"
  5.             File newfile = new File(path,this.getMyfileFileName()); 
  6.             OutputStream os = new FileOutputStream(newFile); 
  7.             byte[] buffer = new byte[2048]; 
  8.             int length=0
  9.             // 读取myfile文件输出到toFile文件中 
  10.             while ((length = is.read(buffer)) > 0) { 
  11.                 os.write(buffer, 0, length); 
  12.             } 
  13.             // 关闭输入流 
  14.             is.close(); 
  15.             // 关闭输出流 
  16.             os.close(); 
  17.             //保存文件信息到数据库中 
  18. //注意事务控制,如果文件上传失败,则文件信息保存到数据库中也没有意义了 
  19.             biz.save(file); 
  20.     return "success"

3、struts.xml

  1. <!--设置上传文件的最大值配置,默认是2097152,即2M--> 
  2. <constant name="struts.multipart.maxSize" value="2097152"/>

这样就完成了上传操作。

下载

因为struts2对文件下载有支持,所以只需要配置一下配置文件,手动代码比较少,比较方便。

1、struts.xml配置文件

  1. <action name="download" class="example.FileDownloadAction">  
  2.    <!--type改为stream--> 
  3.    <result name="success" type="stream">   
  4.        <!--这是下载文件的类型-->   
  5.        <param name="contentType">text/plain</param>  
  6.        <!--这是获取文件的输入流,在Action中是核心点-->   
  7.        <param name="inputName">inputStream</param>  
  8.        <!--下载文件的处理方式-->    
  9.        <param name="contentDisposition">p_w_upload;filename="${downFileName}"</param>  
  10.        <!--缓存区大小-->    
  11.        <param name="bufferSize">4096</param>     
  12.    </result>     
  13. </action>  

对于上面的配置文件,下载文件的类型有很多,可以推荐晨雨潇潇的博客

http://blog.sina.com.cn/s/blog_48a2b6680100iuxl.html

inputName属性,其值可以自定义,但是Action中必须提供一个符合命名规范,返回值为InputStream类型的get方法,而且就是通过这个get方法获得文件下载的输入流,也是页面文件下载的接口。

关于下载文件的处理方式,p_w_upload是附件下载,还有一种内联(inline)下载方式,如果下载的文件不想被浏览器打开或者不能被浏览器打开,建议使用p_w_upload方式。filename属性指的是下载文件的文件名,可以写死,指定一个名字:filename="aa.java",也可以动态获取,filename="${downFileName}",这个downFileName属性名字可以自定义,但是必须在Action中设置一个这样的属性,并给出setter和getter方法。

2、Action

①如上面所说,要先设置相应属性和setter和getter方法

  1.  
    1. //contentDisposition属性filename的值  
    2. private String downFileName;  
    3. //inputName属性的值对应的get方法,注意返回值和方法命名规范  
    4. public InputStream getInputStream(){  
    5.    //先从数据库中获得文件的路径和文件名,拼凑成完整路径名file 
    6.    //此处可能需要编码,也可以在配置文件中配置? 
    7.     String file="".....  
    8.     return new FileInputStream(file);  
    9. }  
    10. /*  
    11. *  downFileName的setter和getter方法  
    12. */  
  2.  

就这样,页面会得到一个输入流,就可以获取文件了。

需要注意的问题或异常:

1、中文乱码问题

解决办法有很多种,对获取的文件名进行编码即可。如:

  1. //第一种办法 
  2. ...new String(file.getBytes(),"ISO-8859-1"); 
  3. //第二种办法:URL编码 
  4. URLEncoder.encode(fname, "UTF-8"); 

2、当取消下载的时候出现异常:ERROR [org.apache.struts2.dispatcher.StreamResult] - Can not find a java.io.InputStream with the name [inputStream] in the invocation stack. Check the <param name="inputName"> tag specified for this action.

查看StreamResult源代码:可以发现是因为InputStream是null,也就是为空,就会报这个异常。

而InputStream为空,无非是路径不正确或是路径中乱码。

原因分析:

①配置其中result标签下的各个参数
②从服务器中获取输入流,并同时与客户端建立输出流(服务器与客户端链接通过Socket进行连接)
③当点击“保存”或“打开”时,开始传输数据。如果点击“取消”,关闭所有的流。
这里要注意的是,但是实际发现Socket并没有断开!并且流也没有关闭!这一点非常重要!
所以在JSP容器通过Response获取输出流之前,前面的流并没有关闭,所以会造成该异常的报出。

解决办法有多种,介绍两种:

第一种:增加插件:

1。将附件解压获取struts2-sunspoter-stream-1.0.jar(附件中有下),并复制在/WEB-INF/lib下
2。在原有的struts.xml的基础上进行相应的配置,配置如下例

  1. <package name="default" namespace="/" extends="struts-default">   <!-- 添加如下内容 -->   
  2.   <result-types>   
  3.   <result-type   name="streamx" class="com.sunspoter.lib.web.struts2.dispatcher.StreamResultX"/>    </result-types>    
  4.   <action name="download" class="com.DownloadAction">   
  5.   <!-- type改写 -->                
  6.     <result name="success" type="streamx">                  
  7.       <param name="inputName">inputStream</param>                   
  8.       <param name="bufferSize">4096</param>                   
  9.       <param name="contentDisposition">filename="${downFileName}" </param>                  
  10.       <param name=".....">.....</param>               
  11.   </result>   
  12. </action>   
  13. </package> 
  在这种方式下,只需添加一个result-type,将原有的result中type改为“streamx”,其他一律不变,在这种情况下,点击“取消”的同时也关闭了流,不会再报出该异常。   之后的执行“取消”后的结果如下:(配置了"log4j.properties"才能看到该结果) 01.21:23:44,676  WARN StreamResult:45 - StreamResultX Warn : socket write error   如果出现该警告说明正确执行,该警告说明,Socket非正常中断,但是流确实已经关闭,自此再也不用看到上面出现的讨厌异常结果。 还有一种方法就是捕获异常并抛出:
  1. <!--struts.xml里的package标签里加 --> 
  2. <global-results>    
  3. <result name="client-abort-exception">/ignored.jsp</result><!-- 全局 -->    
  4. </global-results>    
  5. <!--在Action标签里加   --> 
  6. <exception-mapping result="client-abort-exception" exception="org.apache.catalina.connector.ClientAbortException"></exception-mapping><!-- 抓异常 -->    
  7. <result name="success" type="stream">    
  8. .....    
  9. </result>  
  10. 然后写一个ignored.jsp空页面,就可以了