2011-05-17 55 views
1

我試圖通過JSP文件上傳和驗證servlet將圖像上傳到Blobstore。 JSP的部分如下:Google app引擎:通過java servlet將圖像存儲在Blobstore中時的NullpointerException

<form action="/testuploadmimevalidation?provider-key=testprovider" method="post" enctype="multipart/form-data"> 
    <input type="text" name="foo"> 
    <input type="file" name="myfile" > 
    <input type="submit" value="Submit"> 
</form> 

Java類TestUploadMimeValidation如下:

public class TestUploadMimeValidation extends HttpServlet { 

    private BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService(); 
    private static final Logger log = Logger.getLogger(TestUploadMimeValidation.class.getName()); 
    private static final boolean PRODUCTION_MODE = SystemProperty.environment.value() == SystemProperty.Environment.Value.Production; 
    private static final String URL_PREFIX = PRODUCTION_MODE ? "" : "http://127.0.0.1:8080"; 

    public void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { 
     InputStream in = req.getInputStream(); 
     int formDataLength = req.getContentLength(); 
     byte dataBytes[] = new byte[formDataLength]; 
     int len; 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 

     while ((len = in.read(dataBytes, 0, formDataLength)) != -1) 
      bos.write(dataBytes, 0, len); 

     dataBytes = bos.toByteArray(); 
     String urlStr = URL_PREFIX + BlobstoreServiceFactory.getBlobstoreService().createUploadUrl("/testupload"); 
     URLFetchService urlFetch = URLFetchServiceFactory.getURLFetchService(); 
     HTTPRequest request = new HTTPRequest(new URL(urlStr), HTTPMethod.POST, FetchOptions.Builder.withDeadline(20.0)); 
     request.setHeader(new HTTPHeader("Content-Type", "multipart/form-data")); 
     request.setPayload(dataBytes); 

     System.out.println("step1"); 

     try { 
      HTTPResponse response = urlFetch.fetch(request); 
      System.out.println("step2"); 
     } catch (IOException e) { 

     } catch (NullPointerException e) { 

     } 

     System.out.println("step3"); 
    } 
} 

該類上傳圖像到Blob存儲區就好了,但我得到一個NullPointerException。堆棧跟蹤如下:

WARNING: /_ah/upload/ag5tOGJ5dXMtZGV2ZWxvcHIbCxIVX19CbG9iVXBsb2FkU2Vzc2lvbl9fGAIM 
java.lang.NullPointerException 
     at javax.mail.internet.MimeMultipart.writeTo(MimeMultipart.java:143) 
     at com.google.appengine.api.blobstore.dev.UploadBlobServlet.handleUpload(UploadBlobServlet.java:180) 
     at com.google.appengine.api.blobstore.dev.UploadBlobServlet.access$000(UploadBlobServlet.java:72) 
     at com.google.appengine.api.blobstore.dev.UploadBlobServlet$1.run(UploadBlobServlet.java:101) 
     at java.security.AccessController.doPrivileged(Native Method) 
     at com.google.appengine.api.blobstore.dev.UploadBlobServlet.doPost(UploadBlobServlet.java:98) 
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:637) 
     at javax.servlet.http.HttpServlet.service(HttpServlet.java:717) 
     at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511) 
     at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166) 
     at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:58) 
     at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) 
     at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43) 
     at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) 
     at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:122) 
     at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157) 
     at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388) 
     at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216) 
     at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182) 
     at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765) 
     at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418) 
     at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:70) 
     at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) 
     at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:351) 
     at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152) 
     at org.mortbay.jetty.Server.handle(Server.java:326) 
     at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542) 
     at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938) 
     at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755) 
     at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218) 
     at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404) 
     at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409) 
     at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582) 

由於這個NPE,我的代碼在TestUpload.java類沒有得到執行。 println出來罰款。它打印「step3」。圖像被存儲到數據存儲區中。但我不能讓TestUpload中的代碼運行。你有什麼想法可能會導致異常?我試圖搗亂多部分,但不是很成功。

任何有關這個問題的幫助將非常感激。

+1

是您上傳後發送電子郵件?爲什麼錯誤來自avax.mail – Kal 2011-05-17 17:47:16

+0

您的JSP不可能工作,它必須調用blobstoreservice.createUploadURL()作爲其操作的一部分。 – 2011-05-17 21:11:05

+0

@ Jarrod。 blobstoreservice。createUploadURL()在TestUploadMimeValidation servlet中被調用。當這個servlet完成時,我的Blob文件被存儲在blobstore中,但是我得到了這個空指針異常。它也不會轉發到testupload servlet(在TestUploadMimeValidation servlet的createUploadUrl()。第14行中指出的那個) – dant3InTrouble 2011-05-19 12:42:00

回答

4

我用

<form action="<%= blobstoreService.createUploadUrl("/catalog/actions/add") %>" method="post" enctype="multipart/form-data" > 
+0

我想打電話給在servlet中的blobstoreService.createUploadUrl(),因爲我想首先驗證blob的大小和內容類型,如果我在表單中使用blobstoreService.createUploadUrl,你建議blob將被存儲,我必須驗證大小和mime類型,我已經存儲在blobstore中。 – dant3InTrouble 2011-05-19 12:46:38

0

首先,你可以看到如何在這裏做你的POST請求: Using java.net.URLConnection to fire and handle HTTP requests

String param = "value"; 
File textFile = new File("/path/to/file.txt"); 
File binaryFile = new File("/path/to/file.bin"); 
String boundary = Long.toHexString(System.currentTimeMillis()); // Just 
// generate some unique random value. 
String CRLF = "\r\n"; // Line separator required by multipart/form-data. 
URLConnection connection = new URL(url).openConnection(); 
connection.setDoOutput(true); 
connection.setRequestProperty("Content-Type", 
    "multipart/form-data; boundary=" + boundary); 
PrintWriter writer = null; 
try { 
    OutputStream output = connection.getOutputStream(); 
    writer = new PrintWriter(new OutputStreamWriter(output, charset), 
      true); // true = autoFlush, important! 
    // Send normal param. 
    writer.append("--" + boundary).append(CRLF); 
    writer.append("Content-Disposition: form-data; name=\"param\"") 
      .append(CRLF); 
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); 
    writer.append(CRLF); 
    writer.append(param).append(CRLF).flush(); 
    // Send text file. 
    writer.append("--" + boundary).append(CRLF); 
    writer.append(
     "Content-Disposition: form-data; name=\"textFile\"; filename=\"" 
      + textFile.getName() + "\"").append(CRLF); 
    writer.append("Content-Type: text/plain; charset=" + charset).append(CRLF); 
    writer.append(CRLF).flush(); 
    BufferedReader reader = new BufferedReader(new InputStreamReader(
      new FileInputStream(textFile), charset)); 
    try { 
     for (String line; (line = reader.readLine()) != null;) { 
      writer.append(line).append(CRLF); 
     } 
    } finally { 
     try { reader.close(); } catch (IOException logOrIgnore) {} 
    } 
    writer.flush(); 
    // Send binary file. 
    writer.append("--" + boundary).append(CRLF); 
    writer.append(
     "Content-Disposition: form-data; name=\"binaryFile\"; filename=\"" 
      + binaryFile.getName() + "\"").append(CRLF); 
    writer.append(
     "Content-Type: " 
      + URLConnection.guessContentTypeFromName(binaryFile 
       .getName())).append(CRLF); 
    writer.append("Content-Transfer-Encoding: binary").append(CRLF); 
    writer.append(CRLF).flush(); 
    InputStream input = new FileInputStream(binaryFile); 
    try { 
     byte[] buffer = new byte[1024]; 
     for (int length = 0; (length = input.read(buffer)) > 0;) { 
      output.write(buffer, 0, length); 
     } 
     output.flush(); // Important! Output cannot be closed. Close of 
         // writer will close output as well. 
    } finally { 
     try { input.close(); } catch (IOException logOrIgnore) {} 
    } 
    writer.append(CRLF).flush(); // CRLF is important! It indicates end 
            // of binary boundary. 
    // End of multipart/form-data. 
    writer.append("--" + boundary + "--").append(CRLF); 
} finally { 
    if (writer != null) writer.close(); 
} 

我試着用的Apache HTTP客戶端庫和它的工作,但只能在本地。由於套接字的限制,我們無法使用它。 https://developers.google.com/appengine/docs/java/sockets/#limitations-and-restrictions 我們正在使用: java.net.URL; java.net.URLConnection;

對於圖像使用上面的鏈接二進制。這是痛苦的屁股,直到我得到工作代碼:)

0

TL; DR:對於那些誰試圖使用AJAX上傳,而不是傳統的表單提交路徑時,這個specfically奇怪的錯誤解決方案是到NOT在創建AJAX請求時設置「Content-Type」標題。一旦刪除它,它開始爲我工作。

更多信息:顯然,傳入一個FormData對象作爲AJAX請求的主體會自動設置「Content-Type」標題爲「multipart/form-data」,以及所需的邊界字符串(這是什麼如果我們只是自己設置內容類型,將會丟失)。

附加信息:這個邊界字符串是AFAIK,是隨機生成的,我們不能通過「Content-Type」頭部定義我們自己的邊界(我試過了,並且體內使用的邊界仍然是隨機生成的字符串,導致堆空間錯誤)。 AJAX請求必須在頭中分配隨機生成的邊界字符串,並設置我們自己的內容類型覆蓋該頭。

我從這裏的線索:html form enctype on ajax(雖然jQuery的關係,設置Content-type頭的邏輯是原生的webkit /瀏覽器邏輯)

相關問題