Struts2下利用JSON結合jQuery Form插件實現文件上傳的問題與解決辦法

這兩天要實現一個文件上傳的功能。

開發環境是:服務器端Struts2,客戶端jQuery,需要使用Ajax來實現,我在用Struts2開發Ajax應用時,都是基於JSON來實現的。

 

理論上文件上傳是無法用Ajax來實現的:ajax基於javascript和xmlhtttp,其與服務器通信都是通過傳遞字符串。另外出於安全考慮,javascript是不能操作文件的,因此從理論上來說javascript是無法實現文件上傳的。

 

實際上只能實現一種無刷新文件上傳,從實現效果上類似於Ajax的無刷新與服務器進行通信。

 

其原理是:給file控件所在的form加上 target 屬性,將返回結果頁面定向到一個隱藏的 iframe。

 

在具體的實現上,我使用了jQuery的form插件來完成,該插件對文件上傳的功能進行了封裝,其實現原理也類似於上面的分析。但可以方面的在進行提交之前與提交之後添加callback函數。

 

在實現中出現了一個問題是:如果用Struts2的JSON返回結果,上傳完成以後,不會調用form插件success對應的callback函數,並自動彈出JSON信息的下載頁面,使用記事本打開可以看到對應的JSON信息。


對於這個問題有兩個解決辦法:

1. 不使用JSON方法,將Struts2的結果類型換成redirect

2. 不使用JSON方法,將Struts2的結果類型換成plaintext,直接輸出處理情況信息

 

其他的一些解決辦法是:可以使用Flex相關的技術來實現,看了一下Google Doc的文件上傳,就是使用flash來實現的。

plaintext可以直接將處理結果信息寫到Response,不需要另外創建新的結果頁面,最後我採用了這種辦法。 具體如下:

代碼情況如下:

JSP頁面:uploadDoc.jsp

<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>上傳文件</title>
<script src="../js/jquery.js" type="text/javascript"></script>
<script src="../js/jquery.form.js" type="text/javascript"></script>
	<script language="javascript">	
      $(document).ready(function(){
          var validateForm = function() {
	        	var fileName = $('#theFile').val();
	  			var m=parseInt(fileName.toString().lastIndexOf("."))+1;
	  		    var extVal=fileName.toString().substr(m);
	  			if(extVal!="doc") {
	  				alert('文件類型必須爲Word文件!');
	  				return false;
	  			}
	  			$('#upMessage').html('文件上傳中,請等待... ...');
	  			return true;	
        };

          var showResponse = function(data,status) { 
              $('#upMessage').fadeIn("fast",function(){
             	 
              });
     		return true;
           };
    	  var options={		
    	    	target : '#upMessage',	
  				url : 'AjaxUploadProductDoc!upload.action',
  				beforeSubmit: validateForm,
  				success : showResponse,
  				resetForm:true
  			};
    	  $('#upForm').ajaxForm(options);    	  
      });     
	</script>
</head>
<body>
	<form id="upForm" method="POST" enctype="multipart/form-data">
		上傳文件:<input type="file" name="file" id="theFile"/>
		<br/>
		<input type="submit" value="提交" />
		<div id="upMessage" style="displan:hidden"></div>
	</form>
	</body>
</html>

 

後臺Java類: AjaxUploadProductDocAction.java

package org.xtwh.product.action;

import org.apache.log4j.Logger;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Map;

import javax.servlet.http.HttpServletResponse;

import org.apache.struts2.ServletActionContext;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;

/**
 * 處理上傳DOC文件
 * @author user
 *
 */
public class AjaxUploadProductDocAction extends ActionSupport{
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger
			.getLogger(AjaxUploadProductDocAction.class);

	
	private static final int BUFFER_SIZE = 16 * 1024;
	
	private File file;
	private String contentType;	//上傳文件的MIME類型
	private String fileName;	//上傳文件的文件名,該文件名不包括文件的後綴
		
	private boolean success;	//標識上傳是否成功
	private static final String TEXT = "text";
	
//訪問頁面
	public String execute() {
		return INPUT;
	}

//上傳文件
	public String upload() throws IOException {
		if(fileName == null || fileName.equals("")) {
			success = false;
			printMessage();
			return TEXT;
		}		
			
		if (file != null) {
			//保存文件					
			copy(file, docFile);
			
			//進行其他處理
		} 		
		success = true;
		message = "上傳文件成功。";
		printMessage();
		return TEXT;
	}
	
/**
 * 判斷上傳文件夾中是否有同名文件
 * @return
 */
	private boolean hasSameFile() {
		
		return false;
	}
	
//輸出信息到response
	private void printMessage() throws IOException {
		ActionContext ctx = ActionContext.getContext();
		HttpServletResponse response = (HttpServletResponse)ctx.get(ServletActionContext.HTTP_RESPONSE); 
		response.setContentType("text/plain;charset=utf-8");
		response.setHeader("Cache-Control", "no-cache");
		
		PrintWriter pw = null;
		try {
			StringBuffer sb = new StringBuffer();
			if(success) {
				sb.append("上傳文件成功!");				
			}else {
				sb.append("上傳文件失敗");
			}
			
			pw = response.getWriter();
			pw.print(sb.toString());
			
		} catch (IOException e) {
			logger.error("輸出 錯誤!");
			e.printStackTrace();
		} 
		finally {
			if(pw != null) {
				pw.close();
				pw = null;
			}
		}
	}

//copy file
	private static void copy(File src, File dst)  {
        try  {
           InputStream in = null ;
           OutputStream out = null ;
            try  {                
               in = new BufferedInputStream( new FileInputStream(src), BUFFER_SIZE);
               out = new BufferedOutputStream( new FileOutputStream(dst), BUFFER_SIZE);
                byte [] buffer = new byte [BUFFER_SIZE];
                while (in.read(buffer) > 0 )  {
                   out.write(buffer);
               } 
            } finally  {
                if ( null != in)  {
                   in.close();
               } 
                 if ( null != out)  {
                   out.close();
               } 
           } 
        } catch (Exception e)  {
           e.printStackTrace();
       } 
   } 
	
	

	public boolean isSuccess() {
		return success;
	}
	public void setFile(File file) {
		this.file = file;
	}
	public void setFileContentType(String contentType) {
		this.contentType = contentType;
	}
	public void setFileFileName(String fileName) {
		this.fileName = fileName;
	}


	
}

 配置文件:

<action name="AjaxUploadProductDoc" class="org.xtwh.product.action.AjaxUploadProductDocAction">
	<result name="input">/product/uploadDoc.jsp</result>
	<result name="xml" type="plaintext"></result>
</action>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章