Struts2 框架(四) —— Struts2 表单上传文件、AJAX 文件上传、下载文件、Struts2 拦截器

一、Struts2 文件上传和下载

Struts 推荐我们使用 commons-upload 的包来完成文件上传,所以 struts2 的 jar 包中已经包含了commons 一些列的相关包。

1、Struts2 表单上传文件

(1)新建表单,通过表单提交上传文件,注意上传文件时,提交方式必须为 post,表单必须添加 enctype 属性,enctype=“multipart/form-data”。

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>表单文件上传</title>
		<script type="text/javascript" src="/StrutsDemo/js/jquery-3.4.1.min.js" ></script>
	</head>
	<body>
		<form action="upload.action" method="post" enctype="multipart/form-data">
		   <input type="button" value="选择文件" class="choose">
		   <input type="submit" value="上传">
	   </form>
	   <script type="text/javascript">
	    window.onload = function(){
	    	$(".choose").click(function(){
	    		$(this).before("<input type='file' name='doc' οnchange='selected(this)'><span></span><br />")
	    	});
	    }
	    //显示文件名字和大小
	    function selected(f){
	    	//获取文件的大小,转换成M单位
	    	var size = f.files[0].size/1024/1024;
	    	//将文件大小显示在文件名字的后面,toFixed()方法保留显示的小数位数
	    	$(f).next().html(" " + size.toFixed(2) + "M");
	    }
	   </script>
	</body>
</html> 

(2)在 struts.xml 文件中定义 action 标签处理表单请求,因为 Struts2 对上传的文件设置了最大长度限制,默认是2M,如果要上传2M以上的文件需要在 struts.xml 中进行配置,总共有两个地方需要配置,第一个是 default.properties 中定义的文件最大长度,第二个是文件上传拦截器中定义的最大文件长度,具体配置方式如下:

<struts>
	<!-- 设置文件最大长度 -->
    <constant name="struts.multipart.maxSize" value="524288000"></constant>
    <package name="default" namespace="/" extends="json-default">
     <action name="upload" class="struts.demo.FileUpAction" method="upload">
         <!-- 文件上传拦截器中定义的最大文件长度 -->
         <interceptor-ref name="fileUpload">
             <param name="maximumSize">524288000</param>
         </interceptor-ref>
         <interceptor-ref name="defaultStack"></interceptor-ref>
         <result>success.html</result>
     </action>
 </package>
</struts>
  • constant 标签修改的是 default.properties 中定义的最大文件长度
  • 在 action 中重新引入拦截器是为了,修改文件上传拦截器中的文件最大长度。
  • 524288000=10241024500,也就是500M。

(3)定义对应的 Action 类来出处理请求,在 Action 类中定义3个成员变量,分别是:
private File 文件域的 name属性;
private String 文件域的 name属性+ContentType;
private String 文件域的 name属性+FileName;
并提供 get、set方法。这三个属性分别用来接收上传的文件对象,文件类型,文件名称。

public class FileUpAction extends ActionSupport{
	private File doc;
	private String docFileName;
	private String docContentType;
	private String code;
	private String filename;
	private InputStream is;
	
	//文件上传
	public String upload() {
		HttpServletRequest request = ServletActionContext.getRequest();
		//获取服务器项目的根目录
		String projectPath = request.getServletContext().getRealPath("/");
		//将反斜杠替换为正斜杠
		projectPath = projectPath.replace("\\", "/");	
		//截取服务器webapps的硬盘地址
		projectPath = projectPath.substring(0, projectPath.length()-1);	
		String webapps = projectPath.substring(0, projectPath.lastIndexOf("/"));
		//在webapps文件夹中创建一个upload文件夹
		String uploadPath = webapps + "/upload";	
	
		//新建File对象,判断该文件夹是否存在,不存在则创建该文件夹
		File file = new File(uploadPath);
		if(!file.exists()) {
			file.mkdirs();
		}
		
		String suffix=docFileName.substring(docFileName.lastIndexOf("."));
		String filename=UUID.randomUUID().toString().replace("-", "");
		File targetFile=new File(uploadPath+"/"+filename+suffix);
		
		try {
			targetFile.createNewFile();
			FileUtils.copyFile(doc, targetFile);
		} catch (IOException e) {
			e.printStackTrace();
		}
		code="success";
		return Action.SUCCESS;
	}
}

在请求对应执行的方法中,使用 Commons-upload 将文件对象 doc 保存到服务器中。

FileUtils.copyFile(doc, targetFile);

copyFile 方法是 Commons-upload 提供的文件复制方法,可以把 doc 文件中的内容复制到targetFile 文件中。

2、Struts2 AJAX 文件上传

(1)定义前端页面,用于发送 ajsx 请求

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>Insert title here</title>
		<script type="text/javascript" src="/StrutsDemo/js/jquery-3.4.1.min.js" ></script>
		<style type="text/css">
		  .processDiv{
		      width: 150px;
		      height: 20px;
		      border-radius: 13px;
		      border: 1px #ccc solid;
		  }
		  .process{
			  height: 20px;
			  width: 0;
			  border-radius: 13px;
	          background-color:green;
		  }
		  
		</style>
	</head>
	<body>
	   <form enctype="multipart/form-data" id="form">
	       <input id="file" type="file" name="doc" multiple="multiple" onchange="ajaxSelected(this)"><br />
	       <input type="button" value="ajax上传" onclick="upload()">
	   </form>
	   <script type="text/javascript">
		   function ajaxSelected(f){
			   var files = f.files;
			   for(var i = 0; i < files.length; i++){
				   var size = files[i].size/1024/1024;
				   size = size.toFixed(2);
				   $(f).after('<div>文件名称:<span class="name">'+files[i].name+'</span>&nbsp;&nbsp;文件大小:<span class="size">'+size+"M"+'</span><div class="processDiv"><div class="process"></div></div></div>');
				   
			   }
		   }
		   var index = 0;
		   function upload(){
			   //取出文件域中的所有文件
			   var files = $("#file")[0].files;
			   //创建表单数据对象
			   var formData = new FormData();
			   //将一个文件放入到表单数据对象中
			   formData.append("doc",files[index]);
			   $.ajax({
				   url:"ajaxUpload.action",
			       type:"post",
			       data:formData,
			       processData:false,
			       contentType:false,
			       //jQuery提供了一个属性可以用于操作原生XMLHttpRequest对象
			       xhr:function(){
			    	   //取出用于发送本次ajax请求的xhr对象
			    	   var myxhr = $.ajaxSettings.xhr();
			    	   myxhr.upload.addEventListener("progress",progressChange,false);
 			    	   return myxhr;
			       },
			       success:function(data){
			    	   index++;
			    	   //递归调用文件上传
			    	   if(files.length > index){
	    			    	upload();
			    	   }else{
			    		   alert(data);
			    	   }
			       }
			   });
		   }
			//修改进度条
			function progressChange(event) {
				var width = parseInt(event.loaded/event.total * 100) + "%";
		        console.log(width);
				$(".process").eq(index).css("width",width);
				$(".process").html(width);
			}
	   </script>
	</body>
</html>

(2)配置 struts.xml 文件

<struts>
       <constant name="struts.multipart.maxSize" value="524288000"></constant>
       <package name="default" namespace="/" extends="json-default">
        <action name="ajaxUpload" class="struts.demo.FileUpAction" method="upload">
            <result type="json"></result>
        </action>
    </package>
   </struts>

(3)AJAX 文件上传对应的 Action 类与表单文件上传对应的 Action 类一致

扫描二维码关注公众号,回复: 9633902 查看本文章

3、Struts2 下载文件

(1)用户从服务器下载文件的文件,需要由开发者提供,一般可以在 tomcat 的 webapps 中新建文件夹 download 用来保存用户需要下载的文件,然后将一些测试文件保存到 download 文件夹之下,在网页中提供超链接,通过超链接发送下载文件的请求并 将文件名称作为参数传递给服务器,如:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8">
		<title>文件下载</title>
	</head>
	<body>
	    <a href="download.action?filename=2df184b26be8466288af97f9f7e5f75e.xls">下载</a>
	</body>
</html>

(2)在 struts.xml 中针对于 success 逻辑视图进行配置。

<action name="download" class="struts.demo.FileUpAction" method="download">
    <result type="stream">
        <param name="inputName">is</param>
        <param name="bufferSize">1024</param>
        <param name="contentDisposition">attachment;filename=${filename}</param>
    </result>
</action>
  • type=”success” 表示本次响应类型为流的方式
  • result 标签下的3个 param 标签用来配置响应文件信息时的参数
    • inputName 指的是在 Action 中用来保存下载的文件的输出流对象的名称,Struts2 会将该对象的信息使用输出流响应到浏览器
    • bufferSize 表示 Struts2 在循环读写文件时的缓存数组长度
    • contentDisposition 表示响应的文件类型信息
    • attachment 表示响应的是一个附件,浏览器默认不会自动打开
    • filename 表示下载时显示的文件名称,${filename} 是从 Action 中读取到的 filename 属性。

(3)在 Action 中定义字符串类型的成员变量 filename 接收用户下载的文件名称和输入流对象并提供 get、set方法。

public class FileUpAction extends ActionSupport{
	private String filename;	//用于保存文件名
	private InputStream is;	//文件下载输入流
	//省略get、set方法
	
	//文件下载
	public String download() {
		//获取下载目录
		HttpServletRequest request = ServletActionContext.getRequest();
		//获取服务器项目的根目录
		String projectPath = request.getServletContext().getRealPath("/");
		//将反斜杠替换为正斜杠
		projectPath = projectPath.replace("\\", "/");
		//截取服务器webapps的硬盘地址
		projectPath = projectPath.substring(0, projectPath.length()-1);
		String webapps = projectPath.substring(0, projectPath.lastIndexOf("/"));
		//在webapps文件夹中创建一个download文件夹
		String downloadPath = webapps + "/download";
		try {
			is=new FileInputStream(downloadPath+"/"+filename);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return Action.SUCCESS;
	}
}
  • 输入流对象是为了保存从服务器文件夹中读取到的文件信息,Struts2 会将该输入流中的信息使用一个输出流响 应到客户端。
  • 在 Action 的方法中根据文件名称获取输入流对象,并赋值给 is 对象,然后响应 success 逻辑视图。
is=new FileInputStream(downloadPath+"/"+filename);

(4)如果有中文的文件需要下载,需要将文件名做一个转码处理,如下:

filename = new String(filename.getBytes(), "ISO8859-1");

二、Struts2 拦截器

1、Struts2 拦截器概述

拦截器允许你在 action 的执行前后插入代码执行 Struts2 中的拦截器是一个强有力的工具,它可以为 action 动态添加输入验证(验证用户的输入是否正确)、对象组装(将用户输入的数据转换为对象的属性)、权限控制〔确保访问者是登录用户)、日志记录(记录action的执行情况)等功能,而不需要修改 action。

2、配置拦截器时常用的标签

  • <interceptors>:该标签位于 package 标签之下,是定义拦截器的最外层标签,该标签内部必须至少定义一个拦截器。拦截器都是在 package 中定义的,在一个包中不能引用其他包中定义的拦截器,除非这两个包有继承关系,“子”包可以引用“父”包中的拦截器。
  • <interceptor>:该标签位于<interceptors>之下,是定义拦截器的标签,包含2个属性 name 和 class,name 代表拦截器的名称,class 代表拦截器的类名,该类可以是 Struts2 提供的拦截器类,也可以是自定义拦截器类。
  • <interceptor-stack>:该标签位于<interceptors>之下,是定义拦截器栈的标签,有时为了方便引用可以将多个拦截器定义为一个拦截器栈,该标签的 name 属性表示拦截器栈的名称。
  • <interceptor-ref>:该标签可以位于<interceptor-stack><action>标签之下,如果是放在<interceptor-stack> 中是将拦截器引入到拦截器栈中,如果是 action 标签之下则是在执行该 action 请求时执行该拦截器,该标签的 name 属性表示,需要引用的拦截器或者拦截器栈的名称,注意,如果我们在 action 中手动引用了一个拦截器,则 Struts2 将不再自动引用默认拦截器栈,所以为了保证 Struts2 正常执行,当我们引用了一个拦截器之后,需要手动将默认拦截器栈引入到 action 中。拦截器的执行顺序依据引入顺序而定。

3、自定义拦截器

(1)创建拦截器类
自定义拦截器需要继承 MethodFilterInterceptor 抽象类,并重写 doIntercept 方法,该方法中有 actionInvocation 类型的参数,该参数表示的执行顺序在该拦截器后面的拦截器代理对象或者 Action 代理对象。
通过该对象可以执行 invoke 方法,表示继续执行下面的拦截器或者 Action,该方法的返回值就是下面的拦截器返回回来的字符串,正常情况下该字符串表示的是最终的 Action 执行完毕之后返回的逻辑视图名称,当然也有例外,例如当参数校验拦截器验证参数不正确时就会直接返回 input 而不会在去执行 Action了。

(2)在 package 中定义该拦截器

<struts>
    <package name="base" extends="struts-default">
        <interceptors>
            <interceptor name="my" class="struts.a.demo0619.interceptor.MyInterceptor">
            </interceptor>
        </interceptors>
        <action name="interceptor" class="struts.a.demo0619.action.InterceptorAction" method="test">
            <interceptor-ref name="my"></interceptor-ref>
            <interceptor-ref name="defaultStack"></interceptor-ref>
            <result>success.html</result>
        </action>
    </package>
</struts>
发布了75 篇原创文章 · 获赞 10 · 访问量 2891

猜你喜欢

转载自blog.csdn.net/baidu_27414099/article/details/104440418