Struts2学习第四天——拦截器及文件上传
1、概述
Struts2的很多核心功能都是由拦截器完成的。
拦截器很好的实现了AOP的编程思想,在动作的执行之前和结果的返回之后,做拦截处理。
2、struts2的默认拦截器栈
3、自定义拦截器
Struts2提供的拦截器有很多,有些并不是默认的,如果需要只能手动打开。当然,也可以自定义拦截器。
1、定义
创建一个类,继承AbstractInterceptor或者实现Interceptor。
1 public class TimerInterceptor extends AbstractInterceptor { 2 3 public void init(){ 4 System.out.println("TimerInterceptor初始化"); 5 } 6 7 /** 8 * struts会在请求Action之前和Action之后调用 9 */ 10 @Override 11 public String intercept(ActionInvocation invocation) throws Exception { 12 //请求Action之前的代码 13 long start=System.currentTimeMillis();//返回毫秒数 14 15 String ret=invocation.invoke();//invoke()执行Action组件 16 17 long end=System.currentTimeMillis(); 18 System.out.println("用时"+(end-start)+"毫秒"+ret); 19 //返回结果字符串 20 return ret; 21 }
2、声明
在struts.xml配置文件中声明该拦截器。
1 <interceptors> 2 <interceptor name="CurrentTime" class="com.house.interceptor.TimerInterceptor"/> 3 </interceptor> 4 </interceptors>
3、使用
在动作中使用。
注意:使用了自定义的拦截器,默认的拦截器将不再起作用。如果需要使用它们,必须手动声明。
1 <action name="*HouserUserAction" class="com.house.action.HouserUserAction" method="{1}"> 2 <interceptor-ref name="CurrentTime"></interceptor-ref> 3 <result name="register_success">/page/login.jsp</result> 4 </action>
4、拦截器栈
默认的拦截器是以拦截器栈的形式存在的。如果使用了非默认的拦截器(包括自定义的拦截器和框架提供的其它拦截器),需要将默认的拦截器栈手动声明才可以继续使用。拦截器的拦截顺序,遵守其在拦截器栈中的声明顺序。
拦截器的继承体系
自定义拦截器栈及引入
<!-- 自定义拦截器 --> <interceptors> <interceptor name="CurrentTime" class="com.house.interceptor.TimerInterceptor"/> <interceptor name="Permission" class="com.house.interceptor.PermissionInterceptor"> <param name="excludeMethods">login,reg</param><!--拦截时过滤这两个页面 --> </interceptor> <!-- 拦截器栈 --> <interceptor-stack name="myStack"> <interceptor-ref name="defaultStack"></interceptor-ref> <interceptor-ref name="CurrentTime"></interceptor-ref> <!-- <interceptor-ref name="Permission"/> --> </interceptor-stack> </interceptors>
<!-- 引入拦截器栈 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
文件上传
struts2为文件上传下载提供了更好的实现机制,在这里我分别就单文件上传和多文件上传的源代码进行一下讲解,这里需要导入文件下载上传的两个jar文件,一个是commons-fileupload-1.2.2.jar,另一个是commons-io-2.0.1.jar
struts2单文件上传:
<!--在进行文件上传时,表单提交方式一定要是post的方式,因为文件上传时二进制文件可能会很大,还有就是enctype属性,这个属性一定要写成multipart/form-data, 不然就会以二进制文本上传到服务器端--> <form action="fileUpload.action" method="post" enctype="multipart/form-data"> username: <input type="text" name="username"><br> file: <input type="file" name="file"><br> <input type="submit" value="submit"> </form>
FileUploadAction
public class FileUploadAction extends ActionSupport { private String username; //注意,file并不是指前端jsp上传过来的文件本身,而是文件上传过来存放在临时文件夹下面的文件 private File file; //提交过来的file的名字 private String fileFileName; //提交过来的file的MIME类型 private String fileContentType; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public File getFile() { return file; } public void setFile(File file) { this.file = file; } public String getFileFileName() { return fileFileName; } public void setFileFileName(String fileFileName) { this.fileFileName = fileFileName; } public String getFileContentType() { return fileContentType; } public void setFileContentType(String fileContentType) { this.fileContentType = fileContentType; } @Override public String execute() throws Exception { String root = ServletActionContext.getServletContext().getRealPath("/upload"); InputStream is = new FileInputStream(file); OutputStream os = new FileOutputStream(new File(root, fileFileName)); System.out.println("fileFileName: " + fileFileName); // 因为file是存放在临时文件夹的文件,我们可以将其文件名和文件路径打印出来,看和之前的fileFileName是否相同 System.out.println("file: " + file.getName()); System.out.println("file: " + file.getPath()); byte[] buffer = new byte[500]; int length = 0; while(-1 != (length = is.read(buffer, 0, buffer.length))) { os.write(buffer); } os.close(); is.close(); return SUCCESS; } }
这里的file并不是真正指代jsp上传过来的文件,当文件上传过来时,struts2首先会寻找struts.multipart.saveDir(这个是在default.properties里面有)这个name所指定的存放位置,我们可以新建一个struts.properties属性文件来指定这个临时文件存放位置,如果没有指定,那么文件会存放在tomcat的apache-tomcat-7.0.29\work\Catalina\localhost\目录下,然后我们可以指定文件上传后的存放位置,通过输出流将其写到流里面就行了,这时我们就可以在文件夹里看到我们上传的文件了。
在实际开发中,经常需要限制上传文件的大小和类型。这是因为如果客户端上传的文件过大会影响服务器性能,消耗服务器存储空间。
要实现限制上传文件的大小有两种常用方法。第一种是在<strutr>节点下添加struts.multiparty.maxSize常量,代码如下
<constant name="struts.multiparty.maxSize" value="50000000"/>
它是一个全局配置,可以实现对所有<action>文件上传大小的限制,value的单位是字节。默认值是2MB,如果大于2M一定要修改该值。
第二种方法是在<action>中配置拦截器,它可以限制单个<action>的文件上传大小。
<interceptor-refname="fileUpload">
<paramname="allowedTypes">
image/png,image/gif,image/jpeg
</param>
</interceptor-ref>
上面配置的是上传文件类型的限制,其实共有两个参数
maximumSize(可选)-这个拦截器允许的上传到action中的文件最大长度(以byte为单位).注意这个参数和在webwork.properties中定义的属性没有关系。
allowedTypes(可选)-以逗号分割的contentType类型列表(例如text/html),这些列表是这个拦截器允许的可以传到action中的contentType.如果没有指定就是允许任何上传类型.
多文件上传
public class UploadAction extends ActionSupport { /** private String title; private File upload;//和上传输入的域名称必须一致,类型必须是file //注意,file并不是指前端jsp上传过来的文件本身,而是文件上传过来存放在临时文件夹下面的文件 private String uploadFilename;//用于接收输入域上传的文件名 //注意:文件名称和文件类型的名称前缀必须相同 private String uploadContentType;//上传文件的MIME类型 public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public File getUpload() { return upload; } public void setUpload(File upload) { this.upload = upload; } public String getUploadFilename() { return uploadFilename; } public void setUploadFilename(String uploadFilename) { this.uploadFilename = uploadFilename; } public String getUploadContentType() { return uploadContentType; } public void setUploadContentType(String uploadContentType) { this.uploadContentType = uploadContentType; } */ private File[] upload;//多文件上传对应数组 private String[] uploadFilename;//多文件对应的名字 private String[] uploadContentType; public File[] getUpload() { return upload; } public void setUpload(File[] upload) { this.upload = upload; } public String[] getUploadFilename() { return uploadFilename; } public void setUploadFilename(String[] uploadFilename) { this.uploadFilename = uploadFilename; } public String[] getUploadContentType() { return uploadContentType; } public void setUploadContentType(String[] uploadContentType) { this.uploadContentType = uploadContentType; } @Override public String execute() throws Exception{ FileInputStream fis=null; FileOutputStream fos=null; //获取需要上传文件的文件路径 String basePath= ServletActionContext.getServletContext().getRealPath("/upload");//服务器upload下 //判断文件是否上传,如果上传的话将会创建该目录 if(upload!=null&&upload.length>0){ for(int i=0;i<upload.length;i++){ File file=upload[i]; fis=new FileInputStream(file); String fileName=basePath+"/upload"+uploadFilename[i]; fos=new FileOutputStream(fileName); int c=0; while((c=fis.read())!=-1){ fos.write(c); } fis.close(); fos.close(); } } return "upload"; } //第二种文件上传的方法 //FileUtils.copyFile(upload,new File(uploadFile+"\\"+uploadFileName)); //FileUtils.copyFile(upload,new File(uploadFile,uploadFileName)); //第三种方法 // BufferedReader bReader=new BufferedReader(new InputStreamReader(new FileInputStream(upload))); // BufferedWriter bWriter=new BufferedWriter(new OutputStreamWriter(new FileOutputStream(uploadFile+"\\"+uploadFileName))); // try{ // char[] str=new char[1024]; // int i=0; // while((i=bReader.read(str))>0){ // bWriter.write(str,0,i); // } // }catch(Exception e){ // e.printStackTrace(); // }finally{ // bReader.close(); // bWriter.close(); // uploadFile.delete(); // }
文件下载
定义一个Action类,FileDownload.java
package com.struts2.filedownload; import java.io.InputStream; import org.apache.struts2.ServletActionContext; import com.opensymphony.xwork2.ActionSupport; //文件下载 public class FileDownload extends ActionSupport{ private int number ; private String fileName; public int getNumber() { return number; } public void setNumber(int number) { this.number = number; } public String getFileName() { return fileName; } public void setFileName(String fileName) { this.fileName = fileName; } //返回一个输入流,作为一个客户端来说是一个输入流,但对于服务器端是一个 输出流 public InputStream getDownloadFile() throws Exception { if(1 == number) { this.fileName = "Dream.jpg" ; //获取资源路径 return ServletActionContext.getServletContext().getResourceAsStream("upload/Dream.jpg") ; } else if(2 == number) { this.fileName = "jd2chm源码生成chm格式文档.rar" ; //解解乱码 this.fileName = new String(this.fileName.getBytes("GBK"),"ISO-8859-1"); return ServletActionContext.getServletContext().getResourceAsStream("upload/jd2chm源码生成chm格式文档.rar") ; } else return null ; } @Override public String execute() throws Exception { return SUCCESS; } }
在struts.xml文件中配置相关信息
<struts> <package name="struts2" extends="struts-default"> <action name="FileDownload" class="com.struts2.filedownload.FileDownload"> <result name="success" type="stream"> <param name="contentType">text/plain</param> <param name="contentDisposition">attachment;fileName="${fileName}"</param> <param name="inputName">downloadFile</param> <param name="bufferSize">1024</param> </result> </action> </package> </struts>
1.结果类型必须要写成 type="stream" ,与之对应的处理类是 org.apache.struts2.dispatcher.StreamResult
2.涉及到的参数:
3.
1) <param name="contentDisposition">attachment;fileName="${fileName}"</param>
contentDisposition默认是 inline(内联的), 比如说下载的文件是文本类型的,就直接在网页上打开,不能直接打开的才会打开下载框自己选择
2) attachment :下载时会打开下载框
3) fileName="${fileName}" :在这定义的名字是一个动态的,该名字是显示在下载框上的文件名字
4.<param name="inputName">downloadFile</param>,这个downloadFile名字要和FileDownload.java类中的getDownloadFile()方法名去掉get 一致
三)用于显示下载的链接界面 filedownload.jsp
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%> <% String path = request.getContextPath(); String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/"; %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <base href="<%=basePath%>"> <title>My JSP 'filedownload.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keywords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> <!-- <link rel="stylesheet" type="text/css" href="styles.css"> --> </head> <body> <h2>文件下载内容:</h2><br/> Dream.jpg:<a href="FileDownload.action?number=1">点击下载</a><br/> jd2chm源码生成chm格式文档.rar:<a href="FileDownload.action?number=2">点击下载2</a> </body> </html>