




已阅读5页,还剩9页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
struts2 文件上传 和部分源码解析,以及一般上传原理 (1) 单文件上传 一.简介 Struts2并未提供自己的请求解析器,也就是就Struts2不会自己去处理multipart/form-data的请求,它需要调用其他请求解析器,将HTTP请求中的表单域解析出来。但Struts2在原有的上传解析器基础 上做了进一步封装,更进一步简化了文件上传。 Struts2默认使用的是Jakarta的Common-FileUpload框架来上传文件,因此,要在web应用中增加两个Jar文件:commons-fileupload-1.2.jar和commons-io-1.3.1.jar。它在原上传框架上做了进一步封装 ,简化了文件上传的代码实现,取消了不同上传框架上的编程差异。 如果要改成其它的文件上传框架,可以修改struts.multipart.parser常量的值为cos/pell,默认值是jakata。并在classpath中增加相应上传组件的类库 例如配置成cos上传 struts.multipart.parser=cos struts.multipart.maxSize=1024 指定文件的最大字结数 二.原理 不管用common-fileUPload框架,还是用cos,都是通过将HTTP的数据保存到临时文件夹,然后Struts使用fileUpload拦截器将文件绑定到Action的实例中。 也就是配置文件的 我们可以通过源代码struts2-code-XX.jar的struts-default.xml文件找到 打开这个类的源代码可以看见相关如下: /* * * * Interceptor that is based off of link MultiPartRequestWrapper, which is automatically applied for any request that * includes a file. It adds the following parameters, where File Name is the name given to the file uploaded by the * HTML form: * * * * File Name : File - the actual File * * File NameContentType : String - the content type of the file * * File NameFileName : String - the actual name of the file uploaded (not the HTML name) * * * 也就是说我们需要三个变量File(表单的name),其他两个参数通过set个体方法有strtus调用 接着下面是一些国际化提示的东西: * processed for all i18n requests. You can override the text of these messages by providing text for the following * keys: * struts.messages.error.uploading - a general error that occurs when the file could not be uploaded * * struts.messages.error.file.too.large - occurs when the uploaded file is too large * * struts.messages.error.content.type.not.allowed - occurs when the uploaded file does not match the expected * content types specified * * struts.messages.error.file.extension.not.allowed - occurs when the uploaded file does not match the expected * file extensions specified * 例如struts.messages.error.content.type.not.allowed 表示文件类型错误:也就是说如果我们给拦截器配置了属性allowedTypes 例如: image/bmp,image/png,image/gif,image/jpeg,image/jpg 但是上传的时候没有上传规定的类型 struts2就会去我们的资源文件去找key为struts.messages.error.content.type.not.allowed的国际化资源给与提示这时候我们可以在我们的资源中配置这个key: 例如:struts.messages.error.content.type.not.allowed=您上传的文件类型只能为.!请重新选择! (当然需要)globalMessages为资源前缀,然后通过:来显示提示 * * * * maximumSize (optional) - the maximum size (in bytes) that the interceptor will allow a file reference to be set * on the action. Note, this is not related to the various properties found in perties. * Default to approximately 2MB. * * allowedTypes (optional) - a comma separated list of content types (ie: text/html) that the interceptor will allow * a file reference to be set on the action. If none is specified allow all types to be uploaded. * * allowedExtensions (optional) - a comma separated list of file extensions (ie: .html) that the interceptor will allow * a file reference to be set on the action. If none is specified allow all extensions to be uploaded. * * 上面则是拦截器的相关参数,一目了然:maximumSize 上传文件最大多少 默认:2MB。allowedTypes容许的上传类型。allowedExtensions容许的扩展名 接着是相关action的代码说明: * package com.example; * * import java.io.File; * import com.opensymphony.xwork2.ActionSupport; * * public UploadAction extends ActionSupport * private File file; * private String contentType; * private String filename; * * public void setUpload(File file) * this.file = file; * * * public void setUploadContentType(String contentType) * this.contentType = contentType; * * * public void setUploadFileName(String filename) * this.filename = filename; * * * public String execute() * /. * return SUCCESS; * * 其实最主要的是set方法的确定:我们跟踪到大约238行: String contentTypeName = inputName + ContentType; String fileNameName = inputName + FileName; 最终确定我们的private File file;属性名称可以随便, 但是filenam和contenttype的set方法要有规定 例如: 如果private File myFile; 则对应的其他的两个属性set方法如下: public void setMyFileContentType(String contentType) this.contentType = contentType;/当然contentType可以随便起名 最终要的是set+MyFile+ContentType方法 public void setMyFileFileName(String filename) this.filename = filename;/当然filename可以随便起名 最终要的是set+MyFile+FileName方法 以下是实例: 三.需要的jar包(默认使用commons-fileupload,如果使用cos,要将jar引进来) commons-logging-1.1.jar freemarker-2.3.8.jar ognl-2.6.11.jar struts2-core-2.0.6.jar xwork-2.0.1.jar commons-io-1.3.1.jar commons-fileupload-1.2.jar 四.实例 1.首先,创建上传页面 Html代码 1. 2. 3. 4. 5. 6. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 2.action 1.package com; 2. 3.import java.io.BufferedInputStream; 4.import java.io.BufferedOutputStream; 5.import java.io.File; 6.import java.io.FileInputStream; 7.import java.io.FileOutputStream; 8.import java.io.InputStream; 9.import java.io.OutputStream; 10.import java.util.Date; 11. 12.import org.apache.struts2.ServletActionContext; 13. 14.import com.opensymphony.xwork2.ActionSupport; 15. 16.public class FileUploadAction extends ActionSupport 17. 18. private static final long serialVersionUID = 6452146812454l; 19. 20. private File upload; 21. 22. private String uploadContentType; 23. 24. private String uploadFileName; 25. 26. private String imageFileName; 27. 28. public String getUploadContentType() 29. return uploadContentType; 30. 31. 32. public void setUploadContentType(String uploadContentType) 33. this.uploadContentType = uploadContentType; 34. 35. 36. public File getUpload() 37. return upload; 38. 39. 40. public void setUpload(File upload) 41. this.upload = upload; 42. 43. 44. public String getUploadFileName() 45. return uploadFileName; 46. 47. 48. public void setUploadFileName(String uploadFileName) 49. this.uploadFileName = uploadFileName; 50. 51. 52. public void setImageFileName(String imageFileName) 53. this.imageFileName = imageFileName; 54. 55. 56. public String getImageFileName() 57. return imageFileName; 58. 59. 60. private static void copy(File src, File dst) 61. try 62. InputStream in = null; 63. OutputStream out = null; 64. try 65. in = new BufferedInputStream(new FileInputStream(src); 66. out = new BufferedOutputStream(new FileOutputStream(dst); 67. byte buffer = new byte1024*10; 68. while (in.read(buffer) 0) 69. out.write(buffer); 70. 71. finally 72. if (null != in) 73. in.close(); 74. 75. if (null != out) 76. out.close(); 77. 78. 79. catch (Exception e) 80. e.printStackTrace(); 81. 82. 83. 84. Override 85. public String execute() 86. System.out.println(uploadFileName); 87. 88. imageFileName = System.currentTimeMillis() + uploadFileName.substring(uploadFileName.lastIndexOf(.); 89. File imageFile = new File(ServletActionContext.getServletContext() 90. .getRealPath(/uploadImages) 91. + / + imageFileName); /我们自己重新定义的文件名,也可以直接用 uploadFileName 92. copy(upload, imageFile); 93. return SUCCESS; 94. 95. 96. 97 表单的enctype =multipart/form-data,与一般的上传一样 会将upload绑定到action的upload,其次他还会将上传记文件的MIME类型绑定到uploadContentType,文件名绑定到uploadFileName中,他们是通过 setUploadContentType和setUploadFileName进行绑定的,下面进行的多文件上传也是同个道理,不过要用数组或者是list来进行绑定,然后多个文件的MIME类型也会绑定到以数组 名字加ContentType和FileName的字符串数组中。 比如说上传的文件的数组名为:File uploads,则它们的MIME类型绑定的对应的数组是uploadsFileName和uploadsContentType. 3.struts.xml的配置 Xml代码 Xml代码 1. 2. 5. 6. 7. 8. 9. 10. 11. 12. image/bmp,image/png,image/gif,image/jpeg,image/jpg 13. 14. 15. 16. /fileUpload.jsp 17. /showUpload.jsp 18. 19. 20. 4.最后是web.xml的配置 Xml代码 1. 2. 7. 8. 9. struts-cleanup 10. 11. org.apache.struts2.dispatcher.ActionContextCleanUp 12. 13. 14. 15. 16. struts2 17. 18. org.apache.struts2.dispatcher.FilterDispatcher 19. 20. 21. 22. 23. struts-cleanup 24. /* 25. 26. 27. 28. struts2 29. /* 30. 31. 32. 33. index.jsp 34. 35. (2) 多文件上传 多文件上传 与单文件上传相似,实现多文件你可以将多个绑定Action的数组或列表。如下例所示。 清单14 多文件上传JSP代码片段 如果你希望绑定到数组,Action的代码应类似: private File uploads; private String uploadSFileName; private String uploadSContentType; 多文件上传数组绑定Action代码片段 如果你想绑定到列表,则应类似: private List uploads ; private List uploadSFileName ; private List uploadSContentType ; 多文件上传列表绑定Action代码片段 另外是一般上传文件的原理:当然具体可以看http协议的rfc文档: 关于multipart/form-data 相关资料可以看;/rfc/rfc1867.txt 大约在Page 1的地方有介绍 表单配置multipart/form-data 说明以二进制流的方式传输表单字段的数据: 我们通过以下代码看到request数据流中的内容: PrintWriter out = response.getWriter(); InputStream is = request.getInputStream(); BufferedReader br = new BufferedReader( new InputStreamReader(is); String buffer = null; while( (buffer = br.readLine() != null) /在页面中显示读取到的请求参数 out.println(buffer + ); out.flush(); out.close(); 例如:我上传一个文件D:apache-tomcat-6018binversion.sh (tomcat版本文件) 最终页面显示: -7da1052ec05fe Content-Disposition: form-data; name=ff; filename=D:apache-tomcat-6018binversion.sh Content-Type: text/plain #!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the License); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # /licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an AS IS BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # resolve links - $0 may be a softlink PRG=$0 while -h $PRG ; do ls=ls -ld $PRG link=expr $ls : .*- (.*)$ if expr $link : /.* /dev/null; then PRG=$link else PRG=dirname $PRG/$link fi done PRGDIR=dirname $PRG EXECUTABLE=catalina.sh # Check that target executable exists if ! -x $PRGDIR/$EXECUTABLE ; then echo Cannot find $PRGDIR/$EXECUTABLE echo This file is needed to run this program exit 1 fi exec $PRGDIR/$EXECUTABLE version $ -7da1052ec05fe- 我们发现我们上传的内容在 -7da1052ec05fe Content-Disposition: form-data; name=ff; filename=D:apache-tomcat-6018binversion.sh Content-Type: text/plain和-7da1052ec05fe-中间 因此我们可以通过以下代码来获取上传内容并保存: /取得HttpServletRequest的InputStream输入流 InputStream is = request.getInputStream(); BufferedReader br = new BufferedReader(new InputStreamReader(is); String buffer = null; /循环读取请求内容的每一行内容 while( (buffer = br.readLine() != null) /如果读到的内容以-开始, /且以-结束,表明已到请求内容尾 if(buffer.endsWith(-) & buffer .startsWith(-)/length为29 /跳出循环 break; /如果读到的内容以-开始,表明开始了一个表单域 if(buffer.startsWith(-) /如果下一行内容中有filename字符串,表明这是一个文件域 if (br.readLine().indexOf(filename) 1) /跳过两行,开始处理上传的文件内容 br.readLine(); br.readLine(); /以系统时间为文件名,创建一个新文件 File file = new File(request.getRealPath(/) + System.currentTimeMillis(); /当然我们可以读取filenam来保存这里简化 /创建一个文件输出流 PrintStream ps = new PrintStream(new FileOutputStream(file); String content = null; /接着开始读取文件内容 while( (content = br.readLine() != null) /如果读取的内容以-开始, /表明开始了下一个表单域内容 if(content.startsWith(-)length为29 /跳出处理 break; /将读到的内容输出到文件中 ps.println(content); /关闭输出 ps.flush(); ps.close(); br.close(); 关于strtus2下载: 下载最终是通过contentType和数据流将数据输出到客户端来实现,在struts中也是通过InputStream和相关的配置来实现: 同样最终到strtus的下载相关的源代码:org.apache.struts2.dispatcher.StreamResult我们看到 public static final String DEFAULT_PARAM = inputName; protected String contentType = text/plain; protected String contentLength; protected String contentDisposition = inline;/在线 protected String contentCharSet ; protected String inputName = inputStream; protected InputStream inputStream; protected int bufferSize = 1024; protected boolean allowCaching = true; 当然这些参数都可以在 中配置 例如; uploadsdocument.pdf Application/pdf targetFile attachment;filename=document.pdf 2048 其中: contentType:指定被下载文件的文件类型。 application/octet-stream 默认值,可以下载所有类型 inputName:指定被下载文件的入口输入流, 和DownloadAction中的getInputStream()对应,主要是获得实际资源文件 contentDisposition:指定下载的文件名和显示方式,一般和文件名一致,但是要注意中文件名保存时乱码问题,解决办法就是进行编码处理 targetFile 是下载的入口 我们不需要在我们的action里面配置targetFile变量 但需要getTargetFile方法,默认需要getInputStream()方法 也就是:inputName参数的值就是入口方法去掉get前缀、首字母小写的 字符串 我们的action里面的代码如下: private String inputPath;/通过strtus获取文件地址 也可以直接写例如:String inputPath = Serv
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 解析卷人教版(五四制)6年级数学下册期末试题附完整答案详解(名师系列)
- 骨科护理学选择题试题与答案
- 2025年新能源汽车二手车市场评估与流通政策法规解读与应对策略报告
- 2025年在线教育平台教学资源库建设与教学效果评估策略报告
- 解析卷福建省永安市七年级上册有理数及其运算章节训练试题
- 养老服务协议范本
- 威海市编导岗位国企招聘笔试题
- 2025地形图保密承诺合同涉及国家重要交通线路规划
- 2025版智慧城市照明系统日常维护及升级合同
- 2025版智慧农业管理系统软件销售与技术服务协议
- 国际脓毒症与脓毒症休克指南
- 《展示设计》课程教案
- 市政道路雨污水管道工程施工技术详细课件
- 环境管理标准化手册
- 村集体经济组织财务及会计知识讲座课件
- 热集成-4.夹点技术基础理论
- 银屑病教学讲解课件
- SMART200与ACS510通过modbus通信控制启停
- 山西省临汾市各县区乡镇行政村村庄村名居民村民委员会明细及行政区划代码
- 项目领导班子竞聘面试评分表
- 皮肤科常见疾病学习课件
评论
0/150
提交评论