(十五)struts2的文件上传和下载
文件上传的原理
我们以前学习上传的时候知道需要将表单的enctype属性设置为multipart/form-data. 表单的enctype属性指定的是表单数据的编码方式,有三个值: -application/x-www-form-urlencoded:这是默认的编码方式。只处理表单的value属性值。采用这种会将表单域的值处理为url编码方式。 -multipart/form-data:这种编码方式会以二进制流的方式来处理表单数据,会将文件域里指定文件内容也封装到请求参数里。 -text/plain:这种方式主要用于直接通过表单发送邮件的情况。
我们用一个简单的案例来说明一下application/x-www-form-urlencoded 和multipart/form-data的区别。
案例:上传表单
1 2 3 4 5 6 7 | <body> <form action= "${pageContext.request.contextPath }/DemoServlet" enctype= "application/x-www-form-urlencoded" method= "post" > 上传文件:<input type= "file" name= "file" ><br> 请求参数:<input type= "text" name= "username" ><br> <input type= "submit" value= "提交" name= "dd" > </form> </body> |
处理Servlet,这里的处理直接通过二进制流来处理http请求。这是底层的方式,当通过request的getParameter方法获取请求参数时,实际上是web服务器替我们处理了这种底层的二进制流,并转换成对应的请求参数值。
1 2 3 4 5 6 7 8 9 10 11 12 13 | public class DemoServlet extends HttpServlet { protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { InputStream is=request.getInputStream(); BufferedReader br= new BufferedReader( new InputStreamReader(is)); String buffer= null ; while ((buffer=br.readLine())!= null ) { System.out.println(buffer); } } } |
1 2 3 4 5 6 7 8 9 | 然后我们访问页面,选中file.txt文件 输入框中输入张三 ,点击提交 输出 file=file.txt&username=%E5%BC%A0%E4%B8% 89 &dd=%E6%8F% 90 %E4%BA%A4 这个字符串包含了三个属性,file,username 和 dd 浏览器会将表单里所有具有name属性的表单项转换成请求参数,因为提交按钮也有name属性,因此也被转换成请求参数。 这里的编码都是使用url编码。可以通过java提供的URLDecoder解码。 大部分时候,程序中通过getParameter方法即可获得参数,底层的二进制流处理,以及使用URLDecoder处理请求参数,都由web服务器帮我们完成了,。 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 显然,通过上面这种方式,只能获取到文件名,不能获取到文件的内容,所以为了实现文件上传,只能将enctype属性设置为multipart/form-data. 一旦设置了表单的 enctype属性设置为multipart/form-data getParameter方法就无法使用。 当我们设置完以后,再次点击提交,则输出 ------WebKitFormBoundary2lDSbdeEx3KW1Tup Content-Disposition: form-data; name= "file" ; filename= "file.txt" Content-Type: text/plain 我是上传文件 ------WebKitFormBoundary2lDSbdeEx3KW1Tup Content-Disposition: form-data; name= "username" zhangsan ------WebKitFormBoundary2lDSbdeEx3KW1Tup-- 这时我们发现文件的内容也获取到,我们只需要通过io流的知识将其分割然后获取指定的参数即可。 对于一个成熟的文件上传框架,需要完成的逻辑很简单,分析request请求的二进制流,解析出数据,然后允许开发者以简单的方式获取数据内容即可。 Servlet3. 0 给我们所提供了提供了更加简单的文件上传方法,我们可以查阅API进行使用,这里不再细说。 |
Struts2的文件上传
struts2并未提供自己的上传组件。在struts.properties配置文件中,可以看到底层配置的是Common-fileupload组件。
但struts在原有的组件上进行了封装,因此底层的上传组件可以随意切换,代码不用变化
(1)编写我们的Action动作类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | public class UploadAction extends ActionSupport { private String username; private File upload; //封装了文件内容,无法获得文件名和文件类型 private String uploadContentType; //封装了文件类型,xxxContentType private String uploadFileName; //用xxxFileName封装文件名字 public String getUsername() { return username; } public void setUsername(String username) { this .username = username; } public File getUpload() { return upload; } public void setUpload(File upload) { this .upload = upload; } public String getUploadContentType() { return uploadContentType; } public void setUploadContentType(String uploadContentType) { this .uploadContentType = uploadContentType; } public String getUploadFileName() { return uploadFileName; } public void setUploadFileName(String uploadFileName) { this .uploadFileName = uploadFileName; } public String upload(){ //获取真实路径 String savepath=ServletActionContext.getRequest().getRealPath( "/WEB-INF/files" ); File file= new File(savepath); //判断文件是否存在,不存在就创建相应的目录等 if (!file.exists()){ file.mkdirs(); } //将上传的临时文件重命名并且另存到指定地址 upload.renameTo( new File(file,uploadFileName)); return null ; } } |
(2)配置Action
1 2 3 4 | < package name= "p1" extends = "struts-default" > <action name= "upload" class = "com.cad.struts2.action.UploadAction" method= "upload" > </action> </ package > |
文件过滤
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | 我们可以自己手动判断文件大小,文件类型来进行文件过滤,但是比较繁琐。 struts2为我们提供了一个fileUpload拦截器,来帮我们实现文件过滤。 fileUpload拦截器也被配置在了默认的拦截器栈中 fileUpload拦截器有两个参数 -allowedTypes:该参数指定允许上传的文件类型,多个文件类型之间用逗号分割, -maximumSize:该属性指定允许上传的文件大小,单位是字节 struts2默认的允许上传文件大小为2MB。 设置最大允许上传文件大小为30M ,经过测试,这种方法行不通,不知道具体原因是什么。 <action name= "upload" class = "com.cad.struts2.action.UploadAction" method= "upload" > <interceptor-ref name= "defaultStack" > <param name= "fileUpload.allowedTypes" >image/jpg</param> <param name= "fileUpload.maximumSize" > 31457280 </param> </interceptor-ref> </action> 所以我们只能通过配置常量来修改允许上传文件的大小 <constant name= "struts.multipart.maxSize" value= "31457280" ></constant> |
同时上传多个文件
1 2 3 4 5 6 7 8 9 10 11 12 | 需要将文件表单项的name设置成相同的。 表单页面 <body> <form action= "${pageContext.request.contextPath }/upload.action" enctype= "multipart/form-data" method= "post" > 上传文件 1 :<input type= "file" name= "upload" ><br> 上传文件 2 :<input type= "file" name= "upload" ><br> 上传文件 3 :<input type= "file" name= "upload" ><br> 用户名:<input type= "text" name= "username" ><br> <input type= "submit" value= "提交" > </form> </body> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | 然后写Action类,需要将file,fileName,ContentType等用数组封装起来 然后遍历得到 public class UploadAction extends ActionSupport { private String username; private File upload[]; private String uploadContentType[]; private String uploadFileName[]; public String getUsername() { return username; } public void setUsername(String username) { this .username = username; } public File[] getUpload() { return upload; } public void setUpload(File[] upload) { this .upload = upload; } public String[] getUploadContentType() { return uploadContentType; } public void setUploadContentType(String[] uploadContentType) { this .uploadContentType = uploadContentType; } public String[] getUploadFileName() { return uploadFileName; } public void setUploadFileName(String[] uploadFileName) { this .uploadFileName = uploadFileName; } public String upload(){ String savepath=ServletActionContext.getRequest().getRealPath( "/WEB-INF/files" ); File file= new File(savepath); if (!file.exists()){ file.mkdirs(); } for ( int i= 0 ;i<upload.length;i++){ upload[i].renameTo( new File(file,uploadFileName[i])); } return null ; } } |
Struts2的文件下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | 创建下载的action类 public class DownloadAction extends ActionSupport { private InputStream input; public InputStream getInput() { return input; } public void setInput(InputStream input) { this .input = input; } public String download() throws Exception{ //获取文件路径 String path=ServletActionContext.getRequest().getRealPath( "/WEB-INF/files/photo.jpg" ); //读取文件 input= new FileInputStream(path); return SUCCESS; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 配置Action struts2指定了stream结果类型,专门用来处理下载。 contentType:被下载文件的文件类型。 contentDisposition:下载文件弹窗,文件名等 inputName:action类中流的名字 <action name= "download" class = "com.cad.struts2.action.DownloadAction" method= "download" > <result name= "success" type= "stream" > <param name= "contentType" >application/octet-stream</param> <param name= "contentDisposition" >attachment;filename=phpto.jpg</param> <param name= "inputName" >input</param> </result> </action> |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步