Struts2 文件上传下载

    Struts2默认使用Jakarta的Common-FileUpload实现文件上传.

一、文件上传

    1.简单上传

    上传页面(uploadForm.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
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>简单文件上传</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>
    <s:form action="upload" enctype="multipart/form-data"> <!-- 注意这里设置enctype -->
		<s:textfield name="title" label="文件标题"/>
		<s:file name="upload" label="选择文件"/>
		<s:submit value="上传"/>
    </s:form>
  </body>
</html>

实现上传的控制类(UploadAction.java)

package DeepUse;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.UUID;
import com.opensymphony.xwork2.ActionSupport;

public class UploadAction extends ActionSupport{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String title;//文件标题
	private File upload;//上传文件域
	private String uploadContentType;//封装上传文件类型
	private String uploadFileName;//上传文件名属性
	private String savePath;//保存路径
	public String getTitle() {//以下是set和get方法
		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 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 getSavePath() {
		return savePath;
	}
	public void setSavePath(String savePath) {
		this.savePath = savePath;
	}
	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		FileOutputStream fos=new FileOutputStream(getSavePath()+"/"+getUploadFileName());
		FileInputStream fis=new FileInputStream(getUpload());
		byte[] buffer=new byte[1024];
		int len=0;
		while((len=fis.read(buffer))>0){//以二进制进行读写
			fos.write(buffer,0,len);
		}
		return SUCCESS;
	}
}

配置文件(struts.xml)

<action name="upload" class="DeepUse.UploadAction">
		<param name="savePath">webapps/Structs2/uploadFiles</param>
		<result>/Struts2BaseUse/successforupload.jsp</result>
	</action>

上面savePath依据自己的路径进行配置,如果发现不怎么对,在UploadAction中使用绝对路径查看目录是否配置正确。参考

Java查看当前绝对路径

结果页面(successforupload.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
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>上传成功</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>
    上传成功!<br/>
    文件标题:<s:property value="title"/><br>
	文件为:<img src="<s:property value="'uploadFiles/' 
		+ uploadFileName"/>"/><br/><!-- 注意如果文件名有中文,则找不到文件-->
  </body>
</html>

为了避免文件名冲突,可以使用java.util.UUID类中的randomUUID方法来生成唯一的文件名,具体参考 UUID类的使用

我的uploadFiles文件夹是放在当前工程的目录下的



对于程序是如何取得文件类型以及文件名的? 这是采用约定的方式,类型File的xxx成员封装了文件域中的内容,类型为String的xxxFileName封装了对应的文件名,类型为String的xxxContentType封装了对应的文件类型.

(对于Action中的参数不仅可以通过页面参数来设置,还可以通过struts.xml配置文件的param来设置,同时还可以由地址栏访问action时带的对应get参数来设置)


    2、自定义文件过滤

    大部分时候,对于一个上传的文件系统需要实现过滤,不允许自由上传,这包括文件类型限制以及文件大小的限制.

    修改上面的控制类(UploadAction.java)

package DeepUse;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import com.opensymphony.xwork2.ActionSupport;

public class UploadAction extends ActionSupport{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String title;//文件标题
	private File upload;//上传文件域
	private String uploadContentType;//封装上传文件类型
	private String uploadFileName;//上传文件名属性
	private String savePath;//保存路径
	private String allowTypes ;//允许的上传类型
	public String getAllowTypes() {
		return allowTypes;
	}
	public void setAllowTypes(String allowTypes) {
		this.allowTypes = allowTypes;
	}
	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 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 getSavePath() {
		return savePath;
	}
	public void setSavePath(String savePath) {
		this.savePath = savePath;
	}
	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		FileOutputStream fos=new FileOutputStream(getSavePath()+"/"+getUploadFileName());
		FileInputStream fis=new FileInputStream(getUpload());
		byte[] buffer=new byte[1024];
		int len=0;
		while((len=fis.read(buffer))>0){
			fos.write(buffer,0,len);
		}
		return SUCCESS;
	}
	
	public String filterTypes(String[] types) {//文件名任意
		String fileType =getUploadContentType();
		for(String type:types){
			if(type.equals(fileType)){
				return null;
			}
		}
		return ERROR;
	}
	
	@Override
	public void validate() {
		// TODO Auto-generated method stub
		String filterResult=filterTypes(getAllowTypes().split(","));//调用判断方法
		if(filterResult!=null){
			addFieldError("upload", "您要上传的文件类型不正确");
		}
	}
}

因为失败返回到input逻辑视图,因此修改struts.xml文件

<action name="upload" class="DeepUse.UploadAction">
		<param name="savePath">webapps/Structs2/uploadFiles</param>
		<param name="allowTypes">image/png,image/gif,image/jpeg</param>
		<result>/Struts2BaseUse/successforupload.jsp</result>
		<result  name="input">/Struts2DeepUse/uploadForm.jsp</result>
	</action> 

为什么struts2对于文件上传失败会自动返回到input视图?这是因为在validate验证中,如果发现验证结果不符合预期,那么就会addFieldError方法调用,当struts2发现FieldError不为空就判断为程序出错,返回到input逻辑视图中.



    3.拦截器实现过滤

    将控制类还原成1中的控制类

    修改配置文件(struts.xml)

<action name="upload" class="DeepUse.UploadAction">
		<interceptor-ref name="fileUpload">
			<param name="allowedTypes">image/png,image/gif,image/jpeg</param>
			<param name="maximumSize">2000</param><!-- 最大2KB -->
		</interceptor-ref>
		<interceptor-ref name="defaultStack"/>
                        <!-- 由于过滤文件大小和文件内容必须要显示指明该引用,而且fileUpload必须在该引用的前面 -->
		<param name="savePath">webapps/Structs2/uploadFiles</param>
		<param name="allowTypes">image/png,image/gif,image/jpeg</param>
		<result>/Struts2BaseUse/successforupload.jsp</result>
		<result  name="input">/Struts2DeepUse/uploadForm.jsp</result>
	</action>

下面是文件大小超出

下面是文件类型不符合



上面的错误信息使用的key分别是struts.messages.error.file.too.large和struts.messages.error.content.type.not.allowed,只要在自己资源文件中加以配置即可.还有一个key是struts.messages.error.uploading,这是排除上面两个的一个未知错误.(局部资源文件这里不行)

文件上传时候的stuts.properties文件常量有stuts.multipart.saveDir来设置自定义的临时文件目录,否则在work/catalina/localhost. 常量struts.multipart.maxSize来自定义文件大小.

上面的两个对于资源文件分别在struts2-core-2.2.1.jar下的org.apache.struts2两个default.properties和struts.messages.properties中


二、文件下载

    1.一般下载

     控制类(FileDownloadAction.java)

package DeepUse;

import java.io.InputStream;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionSupport;

public class FileDownloadAction extends ActionSupport{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String inputPath ;
	public void setInputPath(String inputPath) {
		this.inputPath = inputPath;
	}
	public InputStream getTargetFile() throws Exception{
		InputStream in= ServletActionContext.getServletContext().getResourceAsStream(inputPath);
		return in;//返回输入流
	}
}

特别注意此处的getSevletContext()的路径,可以用.getRealPath(".")来查看,否则会找不到文件,报错没有输入流,错误信息参考 输入流Error

配置文件(struts.xml)

<action name="download" class="DeepUse.FileDownloadAction">
		<param name="inputPath">/uploadFiles/listbox_1.png</param><!-- 结合servletContext的路径 -->
		<result type="stream"> <!--这个类型很重要,否则不定义会报找不到result -->
			<param name="inputName">targetFile</param> <!-- 对于action中的getTargetFile方法 -->
			<param name="contentDisposition">filename="myimage.png"</param> <!-- 描述名称任意 -->
			<param name="bufferSize">4096</param><!-- 缓冲大小 -->
		</result>
	</action> 

这样在地址栏中输入.../download即可,因为这是action完成的下载,则网页左上角


2.授权下载

控制类(FileDownloadAction.java)

package DeepUse;

import java.io.InputStream;
import java.util.Map;

import org.apache.struts2.ServletActionContext;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class FileDownloadAction extends ActionSupport{

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private String inputPath ;
	public void setInputPath(String inputPath) {
		this.inputPath = inputPath;
	}
	public InputStream getTargetFile() throws Exception{
		InputStream in= ServletActionContext.getServletContext().getResourceAsStream(inputPath);
		return in;
	}
	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		ActionContext ctx=ActionContext.getContext();//获取ActionContext实例
		Map session=ctx.getSession(); //下面这些实现授权
		String user=(String)session.get("user");
		if(user!=null && user.equals("abc")){
			return SUCCESS;
		}
		return LOGIN;
	}
}

登录页面(loginForm.jsp)

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
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>登录界面</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>
    <s:form action="loginForm">
    	<s:textfield name="user" label="用户名"/>
    	<s:textfield name="pass" label="密码"/>
    	<s:submit value="登录"/>
    </s:form>
  </body>
</html>

下载页面(downloadForm.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>单击链接下载文件</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>
    这是一个图片链接: <a href="download.action">下载</a>
  </body>
</html>

配置文件(struts.xml)

<action name="download" class="DeepUse.FileDownloadAction">
		<param name="inputPath">/uploadFiles/listbox_1.png</param>
		<result type="stream">
			<param name="contentType">application/zip</param><!-- 指定文件的下载类型 -->
			<param name="inputName">targetFile</param>
			<param name="contentDisposition">filename="myimage.png"</param>
			<param name="bufferSize">4096</param><!-- 缓冲大小 -->
		</result>
		<result name="login">/Struts2DeepUse/loginForm.jsp</result>
	</action>
	
	<action name="loginForm" class="DeepUse.LoginPutSession">
		<result>/Struts2DeepUse/downloadForm.jsp</result>
	</action>

登录控制类(LoginPutSession)

package DeepUse;

import java.util.Map;

import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

public class LoginPutSession extends ActionSupport{
	private String user;

	public String getUser() {
		return user;
	}

	public void setUser(String user) {
		this.user = user;
	}
	
	@Override
	public String execute() throws Exception {
		// TODO Auto-generated method stub
		ActionContext ctx=ActionContext.getContext();
		Map session=ctx.getSession();//放入session 和上面的呼应
		session.put("user", user);
		return SUCCESS;
	}
}

流程是首先进入下载页面:


点击网页中下载,会进行验证,因为我们没有登录,因此验证失败,返回到登陆页面


当输入正确的用户名123之后,控制类LoginPutSession会将该用户名放入session中,并返回到之前下载的页面


此时进行再次下载,由于我们已经将用户abc放入session,因此这里会通过验证进行下载


下载成功,并且注意到这里的文件名正是在struts.xml中配置的filename.

猜你喜欢

转载自blog.csdn.net/whitenigt/article/details/80216395