前言:在数据库中,我们一般都是保存文件的信息(保存的路径,文件名等等),而不会把文件当作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中配置几个属性
其实,不是对属性的格式要求规范,而是对属性的get,set方法格式要求严格,所以,我们可以养成把属性格式写好, set,get方法自动生成的习惯就0了
- //上传的附件,和<s:file>标签中的name属性值对应
- private File myfile;
- //上传文件的文件名,属性名后面的格式固定:myfile+"FileName"
- private String myfileFileName;
- //上传文件的类型
- private String myfileContentType;
- /**
- * 以及相对应的setter和getter方法
- */
- public String execute(){
- InputStream is = new FileInputStream(myfile);
- //长传到服务器目录
- String path = "c:\\upload";
- File newfile = new File(path,this.getMyfileFileName());
- OutputStream os = new FileOutputStream(newFile);
- byte[] buffer = new byte[2048];
- int length=0;
- // 读取myfile文件输出到toFile文件中
- while ((length = is.read(buffer)) > 0) {
- os.write(buffer, 0, length);
- }
- // 关闭输入流
- is.close();
- // 关闭输出流
- os.close();
- //保存文件信息到数据库中
- //注意事务控制,如果文件上传失败,则文件信息保存到数据库中也没有意义了
- biz.save(file);
- return "success";
- }
3、struts.xml
- <!--设置上传文件的最大值配置,默认是2097152,即2M-->
- <constant name="struts.multipart.maxSize" value="2097152"/>
这样就完成了上传操作。
下载:
因为struts2对文件下载有支持,所以只需要配置一下配置文件,手动代码比较少,比较方便。
1、struts.xml配置文件
- <action name="download" class="example.FileDownloadAction">
- <!--type改为stream-->
- <result name="success" type="stream">
- <!--这是下载文件的类型-->
- <param name="contentType">text/plain</param>
- <!--这是获取文件的输入流,在Action中是核心点-->
- <param name="inputName">inputStream</param>
- <!--下载文件的处理方式-->
- <param name="contentDisposition">attachment;filename="${downFileName}"</param>
- <!--缓存区大小-->
- <param name="bufferSize">4096</param>
- </result>
- </action>
对于上面的配置文件,下载文件的类型有很多,可以推荐晨雨潇潇的博客
http://blog.sina.com.cn/s/blog_48a2b6680100iuxl.html
inputName属性,其值可以自定义,但是Action中必须提供一个符合命名规范,返回值为InputStream类型的get方法,而且就是通过这个get方法获得文件下载的输入流,也是页面文件下载的接口。
关于下载文件的处理方式,attachment是附件下载,还有一种内联(inline)下载方式,如果下载的文件不想被浏览器打开或者不能被浏览器打开,建议使用attachment方式。filename属性指的是下载文件的文件名,可以写死,指定一个名字:filename="aa.java",也可以动态获取,filename="${downFileName}",这个downFileName属性名字可以自定义,但是必须在Action中设置一个这样的属性,并给出setter和getter方法。
2、Action
①如上面所说,要先设置相应属性和setter和getter方法
- //contentDisposition属性filename的值
- private String downFileName;
- //inputName属性的值对应的get方法,注意返回值和方法命名规范
- public InputStream getInputStream(){
- //先从数据库中获得文件的路径和文件名,拼凑成完整路径名file
- //此处可能需要编码,也可以在配置文件中配置?
- String file="".....
- return new FileInputStream(file);
- }
- /*
- * downFileName的setter和getter方法
- */
就这样,页面会得到一个输入流,就可以获取文件了。
需要注意的问题或异常:
1、中文乱码问题
解决办法有很多种,对获取的文件名进行编码即可。如:
- //第一种办法
- ...new String(file.getBytes(),"ISO-8859-1");
- //第二种办法:URL编码
- 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的基础上进行相应的配置,配置如下例
在这种方式下,只需添加一个result-type,将原有的result中type改为“streamx”,其他一律不变,在这种情况下,点击“取消”的同时也关闭了流,不会再报出该异常。 之后的执行“取消”后的结果如下:(配置了"log4j.properties"才能看到该结果) 01.21:23:44,676 WARN StreamResult:45 - StreamResultX Warn : socket write error 如果出现该警告说明正确执行,该警告说明,Socket非正常中断,但是流确实已经关闭,自此再也不用看到上面出现的讨厌异常结果。 还有一种方法就是捕获异常并抛出:
- <package name="default" namespace="/" extends="struts-default"> <!-- 添加如下内容 -->
- <result-types>
- <result-type name="streamx" class="com.sunspoter.lib.web.struts2.dispatcher.StreamResultX"/> </result-types>
- <action name="download" class="com.DownloadAction">
- <!-- type改写 -->
- <result name="success" type="streamx">
- <param name="inputName">inputStream</param>
- <param name="bufferSize">4096</param>
- <param name="contentDisposition">filename="${downFileName}" </param>
- <param name=".....">.....</param>
- </result>
- </action>
- </package>
- <!--struts.xml里的package标签里加 -->
- <global-results>
- <result name="client-abort-exception">/ignored.jsp</result><!-- 全局 -->
- </global-results>
- <!--在Action标签里加 -->
- <exception-mapping result="client-abort-exception" exception="org.apache.catalina.connector.ClientAbortException"></exception-mapping><!-- 抓异常 -->
- <result name="success" type="stream">
- .....
- </result>
- 然后写一个ignored.jsp空页面,就可以了