第十章_文件上传

10.1、客户端编程

要上传文件,必须利用multipart/form-data设置HTML表单的enctype的属性值,像下面这样:

<form action="action" enctype="multipart/form-data" method="post">
  		Select a file<input type="file" name="fieldName" />
  		<input type="submit" value="Upload" />
  	</form>

10.2、服务器端编程

Servlet中的服务器端文件上传编程主要围绕着MultipartConfig注解类型和javax.servlet.http.Part接口进行。

处理上传文件的Servlet必须用@MultipartConfig进行标注。MultipartConfig可以带有以下属性,这些都是可选的。

maxFileSize,表示最多可上传的文件容量。超过设定值的文件将会遭到拒绝。默认值为-1,表示不受限制。

maxRequestSize,表示允许多部分HTTP请求的最大容量。它的默认值为-1,不受限制。

Location,上传的文件保存到磁盘的指定位置,调用Part中的write方法将用到它。

fileSizeThreshold,设定一个溢出尺寸,超过这个值之后,上传的文件将被写入磁盘。

在一个由多部分组成的请求中,每一个表单域,包括非文件域,都会被转换成一个PartHttpServletRequest接口定义了以下方法来处理多部分的请求:

Part getPart(java.lang.String name)

返回与指定名称相关的Part

java.util.Collection<Part> getParts()

返回这个请求中所有的part

Part接口中还具有以下方法:

java.lang.String getName()

获取到这部分的名称,例如相关表单域的名称

java.lang.String getContentType()

如果Part是一个文件,那么将返回Part的内容类型,否则返回null

java.util.Collection<java.lang.String> getHeaderNames()

返回这个Part中的所有标头名称

java.lang.String getHeader(java.lang.String headerName)

返回指定标头名称的值

java.util.Collection<java.lang.String> getHeaders(java.lang.String headerName)

返回这个Part中所有标头的名称

Void write(java.lang.String path)

将上传的文件写入磁盘中。如果path是一个绝对路径,那么将写入指定的路径。如果path是一个相对路径,那么将被写入相对于MultiConfig注解的location属性值的指定路径。

Void delete()

删除该文件对应的存储,包括相关的临时文件。

java.io.InputStream getInputStream()

inputStream的形式返回上传文件的内容

如果相关的HTML输入时一个文件input元素,则Part将返回这些标头:

content-type:contentType

content-disposition:form-data; name=”fieldName”; fileName=”fileName” 

例如,上传输入域中一个名称documentnote.txt文件时,将导致相关的部门也具有这些标头:

content-type:text/plain

content-disposition:form-data; name=”document”; fileName=”note.txt”

如果没有选择任何文件,还是会为该文件域创建一个Part,但是相关标头如下:

content-type:application/octet-stream

content-disposition:form-data; name=”document”; fileName=””

Part接口的getName返回与这部分有关的域的名称,而不是上传文件的名称。要想返回后者,需要解析content-disposition标头,其格式如下:

content-disposition:form-data; name=”fieldName”

Servlet中处理上传文件时,需要:

1、查看石头存在content-type标头,检验一个Part是属于普通的表单域买还是文件域。你也可以通过在Part中调用getContentType方法或者getHeader(“content-type”)来完成检查。

2、如果有content-type标头,那么将查看上传文件名称是否为空。文件名为空,表示有文件类型的域存在,但是没有选择要上传的文件。

3、如果文件存在,就可以调用Part中的write方法来写入磁盘,调用时同时传递一个绝对路径,或是相对于MultipartConfig注解的location属性的路径。

 

11.3、上传Servlet范例

SingleUploadServlet.java

package app11a.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet(urlPatterns = {"/singleUpload"})
@MultipartConfig
public class SingleUploadServlet extends HttpServlet{
	private static final long serialVersionUID = 1L;
	/**
	 * 通过part过得文件名称
	 * @param part
	 * @return
	 */
	private String getFileName(Part part){
		String contentDispositionHeader = part.getHeader("content-disposition") ;
		String[] elements = contentDispositionHeader.split(";") ;
		for(String element: elements){
			if(element.trim().startsWith("filename")){
				return element.substring(element.indexOf('=') + 1).trim().replace("\"", "") ;
			}
		}
		return null ;
	}
	@Override
	public void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws ServletException, IOException {
		req.setCharacterEncoding("utf-8") ;
		resp.setCharacterEncoding("utf-8") ;
		Part part = req.getPart("filename") ;
		String fileName = getFileName(part) ;
		if(fileName != null && !fileName.isEmpty()){
			part.write(getServletContext().getRealPath("/WEB-INF") + "/" + fileName) ;
		}
		resp.setContentType("text/html") ;
		PrintWriter writer = resp.getWriter() ;
		writer.print("<br/>Upload file name: " + fileName) ;
		writer.print("<br/>Size: " + part.getSize()) ;
		String author = req.getParameter("author") ;
		writer.print("<br/>Author: " + author) ;
	}
	
}

singleUplpad.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
  <head>
    <title>My JSP 'singleUpload.jsp' starting page</title>
  </head>
  
  <body>
  	<h1>Select a file to upload</h1>
  	<form action="singleUpload" method="post" enctype="multipart/form-data">
  		Author: <input type="text" name="author"/><br/>
  		Select file to upload <input type="file" name="filename"/><br/>
  		<input type="submit" value="上传"/>
  	</form>
  </body>
</html>



11.4、多文件上传

MultipleUploadsServlet.java

package app11a.servlet;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;

import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
@WebServlet(urlPatterns = {"/multipleUploads"})
@MultipartConfig
public class MultipleUploadsServlet extends HttpServlet{
	
	private static final long serialVersionUID = 1L;
	
	private String getFileName(Part part){
		String contentDispositionHeader = part.getHeader("content-disposition") ;
		String[] elements = contentDispositionHeader.split(";") ;
		for(String element: elements){
			if(element.trim().startsWith("filename")){
				return element.substring(element.indexOf('=') + 1).trim().replace("\"", "") ;
			}
		}
		return null ;
	}
	
	public void doPost(HttpServletRequest request, HttpServletResponse response)
		throws ServletException, IOException{
		request.setCharacterEncoding("utf-8") ;
		response.setCharacterEncoding("utf-8") ;
		response.setContentType("text/html") ;
		PrintWriter writer = response.getWriter() ;
		
		Collection<Part> parts = request.getParts() ;
		for(Part part : parts){
			//通过getContentType获得是否是文件域
			if(part.getContentType() != null){
				String fileName = getFileName(part) ;
				//通过文件名获得是否有文件
				if(fileName != null && ! fileName.isEmpty()){
					part.write(getServletContext().getRealPath("/WEB-INF") + "/" + fileName) ;
					writer.print("<br/>Uploaded file name: " + fileName) ;
					writer.print("<br/>Size: " + part.getSize()) ;
				}
			}else{
				String partName = part.getName() ;
				String fieldValue = request.getParameter(partName) ;
				writer.print("<br/>" + partName + ": " + fieldValue) ;
			}
		}
	}
	
}

multipleUploads.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
  <head>
    <title>My JSP 'multipleUploads.jsp' starting page</title>
  </head>
  
  <body>
    <h1>Select a file to upload</h1>
    <form action="multipleUploads" enctype="multipart/form-data" method="post">
    	Author: <input name="author"/><br/>
    	First file to upload <input type="file" name="uploadFile"/>
    	<br/>
    	Second file to upload <input type="file" name="uploadFile2"/>
    	<br/>
    	<input type="submit" value="上传"/>
    </form>
  </body>
</html>

运行截图:



11.5、上传客户端

本例中利用javascriptHTML5 File API来提供进度条,以报告上传的进度。

html5.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<html>
  <head>
    <title>My JSP 'html5.jsp' starting page</title>
    <script type="text/javascript">
    	var totalFileLength, totalUploaded, fileCount, filesUploaded ;
    	window.onload = function(){
    		document.getElementById("files").addEventListener('change', onFileSelect, false) ;
    		document.getElementById("uploadButton").addEventListener('click', startUpload, false) ;
    	}
    	function onFileSelect(e){
    		var files = e.target.files ;//FileList object
    		var output = [] ;
    		fileCount = files.length ;
    		totalFileLength = 0 ;
    		for( var i=0; i<fileCount; i++){
    			var file = files[i] ;
    			output.push(file.name, ' (', file.size, ' bytes, ',
    				file.lastModifiedDate.toLocaleDateString(), ')');
    			output.push("<br/>") ;
    			debug('add ' + file.size) ;
    			totalFileLength += file.size ;
    		}
    		document.getElementById("selectedFiles").innerHTML = output.join('') ;
    		debug('totalFileLength:' + totalFileLength) ;
    	}
    	function debug(s){
    		var debug = document.getElementById("debug") ;
    		if(debug){
    			debug.innerHTML = debug.innerHTML + '<br/>' + s ;
    		}
    	}
    	function startUpload(){
    		totalUploaded = filesUploaded = 0 ;
    		uploadNext() ;
    	}
    	function uploadNext(){
    		var xhr = new XMLHttpRequest() ;
    		var fd = new FormData() ;
    		var file = document.getElementById('files').files[filesUploaded] ;
    		fd.append("fileToUpload", file) ;
    		xhr.upload.addEventListener("progress", onUploadProgress, false) ;
    		xhr.addEventListener("load", onUploadComplete, false) ;
    		xhr.addEventListener("error", onUploadFailed, false) ;
    		xhr.open("POST", "multipleUploads") ;
    		debug("uploading " + file.name) ;
    		xhr.send(fd) ;
    	}
    	function onUploadProgress(e){
    		if(e.lengthComputable){
    			var percentComplete = parseInt(e.loaded + totalUploaded) * 100/totalFileLength ;
    			var bar = document.getElementById("bar") ;
    			bar.style.width = percentComplete + "%" ;
    			bar.innerHTML = percentComplete + " %complete" ;
    		}else{
    			debug("unable to compute") ;
    		}
    	}
    	function onUploadComplete(e){
    		totalUploaded += document.getElementById("files").files[filesUploaded].size ;
    		filesUploaded ++ ;
    		debug("complete " + filesUploaded + " of " + fileCount) ;
    		debug("totalUploaded: " + totalUploaded) ;
    		if(filesUploaded < fileCount){
    			uoloadNext() ;
    		}else{
    			alert("Finished uploading file(s)") ;
    		}
    	}
    	function onUploadFailed(e){
    		alert("Error uploading file") ;
    	}
    </script>
  </head>
  
  <body>
    <h1>Multiple file uploads with progress bar</h1>
    <div id="progressBar" style="height:20px;border:2px solid green">
    	<div id="bar" style="height:100%;background:#33dd33;width:0%">
    	</div>
    </div>
    <form id="form1" action="multipleUploads" enctype="multiple/form-data" method="post">
    	<input type="file" id="files" multiple/>
    	<br/>
    	<output id="selectedFiles"></output>
    	<input id="uploadButton" type="button" value="Upload"/>
    </form>
    <div id="debug" style="height:100px; border:2px solid green; overflow:auto"></div>
  </body>
</html>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值