1、概述
Struts2的很多核心功能都是由拦截器完成的。
拦截器很好的实现了AOP的编程思想,在动作的执行之前和结果的返回之后,做拦截处理。
2、struts2的默认拦截器栈
3、自定义拦截器
Struts2提供的拦截器有很多,有些并不是默认的,如果需要只能手动打开。当然,也可以自定义拦截器。
1、定义
创建一个类,继承AbstractInterceptor或者实现Interceptor。
public class TimerInterceptor extends AbstractInterceptor { public void init(){
System.out.println("TimerInterceptor初始化");
} /**
* struts会在请求Action之前和Action之后调用
*/
@Override
public String intercept(ActionInvocation invocation) throws Exception {
//请求Action之前的代码
long start=System.currentTimeMillis();//返回毫秒数 String ret=invocation.invoke();//invoke()执行Action组件 long end=System.currentTimeMillis();
System.out.println("用时"+(end-start)+"毫秒"+ret);
//返回结果字符串
return ret;
}
2、声明
在struts.xml配置文件中声明该拦截器。
<interceptors>
<interceptor name="CurrentTime" class="com.house.interceptor.TimerInterceptor"/>
</interceptor>
</interceptors>
3、使用
在动作中使用。
注意:使用了自定义的拦截器,默认的拦截器将不再起作用。如果需要使用它们,必须手动声明。
<action name="*HouserUserAction" class="com.house.action.HouserUserAction" method="{1}">
<interceptor-ref name="CurrentTime"></interceptor-ref>
<result name="register_success">/page/login.jsp</result>
</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>