ajax上传文件java报错,java Servlet与 Ajax显示上传文件进度

");

while (iterator.hasNext()){

out.print("

");

FileItem fileItem = iterator.next();

//                判断当前的fileItem是表单还是文件

boolean isFormField = fileItem.isFormField();

if (isFormField){

//                    fileItem.getFieldName(),打印jsp中form字段,即

//                    fileItem.getString(),打印的字段的值

out.println("regular form fieldFIELD NAME: " + fileItem.getFieldName() +

"

STRING: " + fileItem.getString()

);

out.println("");

}else {

//                  如果html页面上可以上传三个文件,而我只填写了一个文件,这样就会导致获取不到文件名,从而导致new File的时候报错

String fileName = fileItem.getName();

if (  !"".equals(fileName) ){

//                    将文件保存到指定的目录

File saveFile = new File(UPLOAD_DIRECTORY,fileName);

fileItem.write(saveFile);

//fileItem.getFieldName()  , 获取jsp中表单上传文件时候的字段名。这里就是 “file”。

//                    fileItem.getString()   打印字节流,只是为了测试。

//fileItem.getName(),获取文件名

//fileItem.getContentType() 获取文件的类型

//fileItem.getSize() ,获取文件的大小

//fileItem.toString() ,将fileItem的所有信息打印出来

out.println("file form fieldFIELD NAME: " + fileItem.getFieldName() +

//       "

STRING: " + fileItem.getString() +

"

NAME: " + fileItem.getName() +

"

CONTENT TYPE: " + fileItem.getContentType() +

"

SIZE (BYTES): " + fileItem.getSize() +

"

TO STRING: " + fileItem.toString()

);

out.println("");

}else {

continue;

}

}

out.println("");

}

} catch (FileUploadException e) {

out.println("Error: " + e.getMessage());

e.printStackTrace();

} catch (Exception e) {

e.printStackTrace();

}

}

}

TestProgressListener.java:

该类实现了ProgressListener接口的update()方法。

但是为了效率,我们设置为每次读取大于100KB的字节数的时候,才执行一次getMessage()方法。

package jspUpload;

import org.apache.commons.fileupload.ProgressListener;

/**

* Created by AlexY on 2016/6/27.

*/

public class TestProgressListener implements ProgressListener{

//    每次读取100KB的时候,就将读取过的字节数/100 赋值给num100ks

private long num100ks = 0;

//     已经读取的字节

private long theBytesRead = 0;

//    文件大小

private long theContentLength = -1;

private int whichItem = 0;

//    读取文件的百分比

private int percentDone = 0;

public void update(long bytesRead, long contentLength, int items) {

//        判断文件大小是否可知

if ( contentLength > -1){

contentLengthKnown = true;

}

//        已经读取的字节

theBytesRead = bytesRead;

//        文件的大小

theContentLength = contentLength;

//        当前的FileItem对象

whichItem = items;

long nowNum100Ks = bytesRead / 100000;

//        每次读取100k才执行一次getMessage方法

if ( nowNum100Ks > num100ks){

num100ks = nowNum100Ks;

if ( contentLengthKnown){

percentDone = (int)Math.round(100.00 * bytesRead / contentLength);

}

System.out.println(getMessage());

}

}

public String getMessage(){

if (theContentLength == -1){

return ""+ theBytesRead + " of Unknown-Total bytes have been read.";

}else {

return "" + theBytesRead + " of " + theContentLength + " bytes have been read ("+ percentDone + "% done).";

}

}

//    文件大小是否已知

private boolean contentLengthKnown = false;

public boolean isContentLengthKnown() {

return contentLengthKnown;

}

public void setContentLengthKnown(boolean contentLengthKnown) {

this.contentLengthKnown = contentLengthKnown;

}

public long getNum100ks() {

return num100ks;

}

public void setNum100ks(long num100ks) {

this.num100ks = num100ks;

}

public long getTheBytesRead() {

return theBytesRead;

}

public void setTheBytesRead(long theBytesRead) {

this.theBytesRead = theBytesRead;

}

public long getTheContentLength() {

return theContentLength;

}

public void setTheContentLength(long theContentLength) {

this.theContentLength = theContentLength;

}

public int getWhichItem() {

return whichItem;

}

public void setWhichItem(int whichItem) {

this.whichItem = whichItem;

}

public int getPercentDone() {

return percentDone;

}

public void setPercentDone(int percentDone) {

this.percentDone = percentDone;

}

}

ProgressServlet.java:

用于显示上传的进度。

这里就是这种方法不实用的地方,因为只有刷新该ProgressServlet后,才能看到新的进度。这也是我们后面要改进的地方。

package jspUpload;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import java.io.IOException;

import java.io.PrintWriter;

/**

* Created by AlexY on 2016/6/27.

*/

public class ProgressServlet extends HttpServlet {

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

doPost(req,resp);

}

@Override

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

resp.setContentType("text/html");

PrintWriter out = resp.getWriter();

HttpSession session = req.getSession();

if ( null == session ){

//            为了安全

out.print("Sorry, session is null");

return;

}

TestProgressListener listener = (TestProgressListener) session.getAttribute("testProgressListener");

if ( null == listener){

out.print("Progress listener is null");

return;

}

//        输出上传进度百分比

out.print(listener.getMessage());

}

}

web.xml:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

version="3.1">

Servlet for file uploads

TestServlet

demo1.TestServlet

ProgressServlet

demo1.ProgressServlet

TestServlet

/demo1test

ProgressServlet

/progress

测试:

2f29b090531d4f4756bc543a1d32030e.png

在demo1.html页面上传文件,前台页面:

后台就能看到进度:

fc6c43be7b65c73a5c389a59b4331018.png

访问:ProgressServlet.java 就可以看到进度,但是必须手动刷新页面才能看到更新后的进度,这不是我们想要的。

方法二:(见demo2)

客户端上传使用servlet的doPost方法,然后为了从服务器获取上传的进度,使用js来调用Servlet的doGet方法。我们在服务端将监听器存放到session中,这样保证同一个会话都能访问到进度信息。就有了方法二。

截图:

dd29cb19f9fa8f58ccaa30f60c4454a9.png

demo2.html:

该页面增加了js,通过js从服务端获取进度,并显示在页面上。

Ajax File Upload

integrity="sha256-JmvOoLtYsmqlsWxa7mDSLMwa6dZ9rrIdtrrVYRnDRH0="

crossorigin="anonymous">

$(document).ready(function () {

var requestXML;

function ajaxFunction() {

var url = "/servlet/FileUploadServlet";

// 判断是否是IE 还是其他浏览器

if (window.XMLHttpRequest) // Non-IE browsers

{

requestXML = new XMLHttpRequest();

//  设置状态函数

requestXML.onreadystatechange = processStateChange;

try {

requestXML.open("GET", url, true);

}

catch (e) {

alert(e);

}

requestXML.send(null);

}

else if (window.ActiveXObject) // IE Browsers

{

requestXML = new ActiveXObject("Microsoft.XMLHTTP");

if (requestXML) {

requestXML.onreadystatechange = processStateChange;

requestXML.open("GET", url, true);

requestXML.send();

}

}

console.log("ajaxfun");

}

function processStateChange( ) {

/**

*    State    Description

*    0        The request is not initialized

*    1        The request has been set up

*    2        The request has been sent

*    3        The request is in process

*    4        The request is complete  响应已经完成

*/

if (requestXML.readyState == 4) {

if (requestXML.status == 200) // OK response

{

var xml = requestXML.responseXML;

console.log("xml"+xml );

//不需要遍历,因为只会得到含有一个元素的集合。

var isFinished = xml.getElementsByTagName("finished")[0];

var myBytesRead = xml.getElementsByTagName("bytes_read")[0];

var myContentLength = xml.getElementsByTagName("content_length")[0];

var percentCompplete = xml.getElementsByTagName("percent_complete")[0];

var bar = document.getElementById("myBar");

var label = document.getElementById("label");

//                        显示pregress

document.getElementById("progress").style.visibility = "visible";

//                        判断上传是否完整,如果完整,则将进度条设置为100%

if ((isFinished != null || isFinished !=  undefined) && (percentCompplete == null || percentCompplete == undefined )) {

console.log("finish:");

bar.style.width =   "100%";

label.innerHTML =  "100%";

}

else {        //上传未完整,则将已经上传的进度显示出来

if (percentCompplete != null)

{

var myPercent = percentCompplete.textContent;

console.log("percent:"+myPercent  );

bar.style.width = myPercent + "%";

label.innerHTML = myPercent+ "%";

//这是最关键的地方

//100ms后再次调用ajaxFunction(),这样Form的内容就可以给action中后台页面处理了。

setTimeout( function () {

ajaxFunction();

}, 100);

}

else {

//                                document.getElementById("bytesRead").style.visibility = "hidden";

//                                document.getElementById("progressBar").style.width = "100%";

//                                document.getElementById("percentComplete").innerHTML = "Done!";

}

}

}

else {

alert(requestXML.statusText);

}

}

}

//            为Form设置onsubmit事件

$("#myForm").submit( ajaxFunction);

});

action="/servlet/FileUploadServlet" >

0%

FileUploadServlet :

js调用该servlet的doGet方法获取进度,调用doPost方法上传文件。

package demo2;

import org.apache.commons.fileupload.FileItem;

import org.apache.commons.fileupload.FileItemFactory;

import org.apache.commons.fileupload.FileUploadException;

import org.apache.commons.fileupload.disk.DiskFileItemFactory;

import org.apache.commons.fileupload.servlet.ServletFileUpload;

import javax.servlet.Servlet;

import javax.servlet.ServletContext;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import javax.servlet.http.HttpSession;

import java.io.File;

import java.io.IOException;

import java.io.PrintWriter;

import java.util.Iterator;

import java.util.List;

/**

* 这个实现客户端更新进度的方法的关键是:

* 将post请求中的上传进度 封装到  get请求中,然后由js发起get请求,来获得xml,解析后显示到html页面

*

*

*/

public class FileUploadServlet extends HttpServlet implements Servlet {

private static final long serialVersionUID = 2740693677625051632L;

public FileUploadServlet() {

super();

}

protected void doGet(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

PrintWriter out = response.getWriter();

HttpSession session = request.getSession();

FileUploadListener listener = null;

StringBuffer buffy = new StringBuffer();

long bytesRead = 0, contentLength = 0;

// Make sure the session has started

if (session == null)

{

System.out.println("session null");

return;

}

else {

System.out.println("session not null");

// Check to see if we've created the listener object yet

listener = (FileUploadListener)session.getAttribute("LISTENER");

//                listener = (FileUploadListener) context.getAttribute("LISTENER");

if (listener == null)

{

System.out.println("listener: null");

return;

}

else

{

// Get the meta information

bytesRead = listener.getBytesRead();

contentLength = listener.getContentLength();

}

}

/*

* XML Response Code   servlet返回的是xml

*/

response.setContentType("text/xml");

buffy.append("\n");

buffy.append("\n");

buffy.append("\t" + bytesRead + "\n");

buffy.append("\t" + contentLength + "\n");

// Check to see if we're done

if (bytesRead == contentLength)

{

buffy.append("\t\n");

// No reason to keep listener in session since we're done

session.setAttribute("LISTENER", null);

}

else

{

// Calculate the percent complete

long percentComplete = ((100 * bytesRead) / contentLength);

buffy.append("\t" + percentComplete + "\n");

}

buffy.append("\n");

System.out.println("xml:"+ buffy.toString());

out.println(buffy.toString());

out.flush();

out.close();

}

protected void doPost(HttpServletRequest request,

HttpServletResponse response)

throws ServletException, IOException {

// create file upload factory and upload servlet

FileItemFactory factory = new DiskFileItemFactory();

ServletFileUpload upload = new ServletFileUpload(factory);

// set file upload progress listener

FileUploadListener listener = new FileUploadListener();

HttpSession session = request.getSession();

ServletContext context =  request.getServletContext();

context.setAttribute("LISTENER", listener);

session.setAttribute("LISTENER", listener);

// upload servlet allows to set upload listener

upload.setProgressListener(listener);

List uploadedItems = null;

FileItem fileItem = null;

// Path to store file on local system

String   filePath = "D:\\files";

try {

// iterate over all uploaded files

uploadedItems = upload.parseRequest(request);

Iterator i = uploadedItems.iterator();

while (i.hasNext()) {

fileItem = (FileItem) i.next();

if (fileItem.isFormField() == false) {

if (fileItem.getSize() > 0) {

File uploadedFile = null;

String myFullFileName = fileItem.getName(),

myFileName = "",

//                                有的浏览器,如opera会把文件在客户端上的路径一起作为文件名上传

//                                所以需要特别处理,分理处真正的文件名,这里要区分下是从unix/linux 还是windows上传的

slashType = (myFullFileName.lastIndexOf("\\") > 0) ? "\\" : "/";    // Windows or UNIX

int startIndex = myFullFileName.lastIndexOf(slashType);

// Ignore the path and get the filename

myFileName = myFullFileName.substring

(startIndex + 1, myFullFileName.length());

// Create new File object

uploadedFile = new File(filePath, myFileName);

// Write the uploaded file to the system

fileItem.write(uploadedFile);

}

}

}

} catch (FileUploadException e) {

e.printStackTrace();

} catch (Exception e) {

e.printStackTrace();

}

}

}

FileUploadListener:

进度监听器

package demo2;

import org.apache.commons.fileupload.ProgressListener;

/**

* This is a File Upload Listener that is used by Apache

* Commons File Upload to monitor the progress of the

* uploaded file.

*/

public class FileUploadListener

implements ProgressListener {

private volatile long

bytesRead = 0L,

contentLength = 0L,

item = 0L;

public FileUploadListener() {

super();

}

public void update(long aBytesRead, long aContentLength,

int anItem) {

bytesRead = aBytesRead;

contentLength = aContentLength;

item = anItem;

}

public long getBytesRead() {

return bytesRead;

}

public long getContentLength() {

return contentLength;

}

public long getItem() {

return item;

}

}

web.xml:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"

version="3.1">

Servlet for file uploads

File Upload Servlet

>FileUploadServlet

demo2.FileUploadServlet

>FileUploadServlet

/servlet/FileUploadServlet

方法三:(见demo3)

方法一和方法二中,因为进度监听器都是放在服务端的,所以只能从从服务端获取进度信息,这样客户端要发起多次http请求,显然不是理想方案。那么,我们可以试着将监听器放到本地,即XMLHttpRequest对象可以设置两个监听器:

设置上传监听器:   xhr.upload.addEventListener("progress", function (evt) {});

设置下载监听器:   xhr.addEventListener("progress", function (evt) {});

这样,我们就可以直接在客户端获取到上传进度信息,http请求只需一次即可。

效果:

179d1cf129f4506650b0a3009e58310f.png

demo3.html:

使用Jquery Ajax上传文件和显示进度

这个已经能获取到进度,至于进度条的css之类的,可以自己定制了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值