3

我試圖將文件上傳到Google雲端存儲。我的servlet代碼是通過appengine將文件上傳到Google雲端存儲

public class UploadFile extends HttpServlet { 

    private final String BUCKET = "XXXXXXXXX"; 
     private boolean isMultipart; 
     private String filePath; 
     private int maxFileSize = 5 * 1024 * 1024; 
     private int maxMemSize = 5 * 1024 * 1024; 
     private File file ; 

     public void init(){ 
      // Get the file location where it would be stored. 
      filePath = 
       getServletContext().getInitParameter("file-upload"); 
     } 
     public void doPost(HttpServletRequest request, 
        HttpServletResponse response) 
        throws ServletException, java.io.IOException { 
      // Check that we have a file upload request 
      isMultipart = ServletFileUpload.isMultipartContent(request); 
      response.setContentType("text/html"); 
      java.io.PrintWriter out = response.getWriter(); 
      if(!isMultipart){ 
      out.println("<html>"); 
      out.println("<head>"); 
      out.println("<title>Servlet upload</title>"); 
      out.println("</head>"); 
      out.println("<body>"); 
      out.println("<p>No file uploaded</p>"); 
      out.println("</body>"); 
      out.println("</html>"); 
      return; 
      } 
      DiskFileItemFactory factory = new DiskFileItemFactory(); 
      // maximum size that will be stored in memory 
      factory.setSizeThreshold(maxMemSize); 
      // Location to save data that is larger than maxMemSize. 
      factory.setRepository(new File("/temp/image/")); 

      // Create a new file upload handler 
      ServletFileUpload upload = new ServletFileUpload(factory); 
      // maximum file size to be uploaded. 
      upload.setSizeMax(maxFileSize); 

      try{ 
      // Parse the request to get file items. 
      List fileItems = upload.parseRequest(request); 

      // Process the uploaded file items 
      Iterator i = fileItems.iterator(); 

      out.println("<html>"); 
      out.println("<head>"); 
      out.println("<title>Servlet upload</title>"); 
      out.println("</head>"); 
      out.println("<body>"); 
      while (i.hasNext()) 
      { 
      FileItem fi = (FileItem)i.next(); 
      if (!fi.isFormField()) 
      { 
       // Get the uploaded file parameters 
       String fieldName = fi.getFieldName(); 
       String fileName = fi.getName(); 
       String contentType = fi.getContentType(); 
       boolean isInMemory = fi.isInMemory(); 
       long sizeInBytes = fi.getSize(); 
       // Write the file 
       if(fileName.lastIndexOf("\\") >= 0){ 
        file = new File(filePath + 
        fileName.substring(fileName.lastIndexOf("\\"))) ; 
       }else{ 
        file = new File(filePath + 
        fileName.substring(fileName.lastIndexOf("\\")+1)) ; 
       } 

       String path = Events.uploadFile (fileName, "image/*", file, BUCKET); 

       // fi.write(file) ; 
       out.println("Uploaded Filename: " + fileName + "<br>"+ " File Path:"+ path); 
      } 
      } 
      out.println("</body>"); 
      out.println("</html>"); 
     }catch(Exception ex) { 
      System.out.println(ex); 
     } 
     } 
     public void doGet(HttpServletRequest request, 
          HttpServletResponse response) 
      throws ServletException, java.io.IOException { 

      throw new ServletException("GET method used with " + 
        getClass().getName()+": POST method required."); 
     } 
    } 

的web.xml

<servlet> 
     <servlet-name>UploadFile</servlet-name> 
     <servlet-class>XXXXXXXXXX.UploadFile</servlet-class> 
    </servlet> 

    <servlet-mapping> 
     <servlet-name>UploadFile</servlet-name> 
     <url-pattern>/uploadManager/UploadFile</url-pattern> //Based on your original URL 
    </servlet-mapping> 

文件上傳功能,文件保存到GCS

public static String uploadFile (String name, String contentType, File file, String bucketName) 
      throws IOException, GeneralSecurityException 
    { 

     InputStreamContent contentStream = new InputStreamContent (contentType, new FileInputStream (file)); 

     // Setting the length improves upload performance 
     contentStream.setLength (file.length()); 

     StorageObject objectMetadata = new StorageObject() 
       // Set the destination object name 
       .setName (name) 
       // Set the access control list to publicly read-only 
       .setAcl (Arrays.asList (new ObjectAccessControl().setEntity ("allUsers").setRole ("READER"))); 

     // Do the insert 
     Storage client = StorageFactory.getService(); 
     Storage.Objects.Insert insertRequest = client.objects().insert (bucketName, objectMetadata, contentStream); 

     insertRequest.execute(); 
     return "https://storage.cloud.google.com/" + BUCKET + "/" + file.getName(); 
    } 

但是當我嘗試了一些API測試客戶端來測試這個提示錯誤

org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found 

Furt她與UI這是在角整合,並在本地測試之後,我面臨這個問題

Cross-Origin Request Blocked Reason: CORS header 'Access-Control-Allow-Origin' missing 

我試圖解決這個問題,但發現相當於谷歌AppEngine上無解。


最初我試圖通過這個代碼,但在不久的將來,同樣的代碼上傳圖像將被用來.pdf和.html文件上傳到GCS。

僅供參考: 我正在使用Google Endpoints來滿足客戶端的其他數據通信需求。客戶端是一個在Angular中構建的webapp,但它將被擴展到android和ios。

任何幫助將不勝感激。

謝謝

UPDATE 2016年1月8日

現在我得到的服務器上的文件,但我不知道我要的文件臨時保存它發送到谷歌雲存儲前。在

war\WEB-INI\ 

和我面臨的例外存儲文件

java.security.AccessControlException: access denied ("java.io.FilePermission" "\war\WEB-INI\profile.png" "read") 

回答

4

最後我能夠通過AppEngine上上傳從客戶端文件到谷歌雲存儲。

我認爲在執行這些步驟之前,你有以下的東西準備好

  • JSON文件從您的服務帳戶。
  • 創建一個默認的水桶。

第1步:製作這樣

package XXXXXXXXX; 

import java.io.IOException; 
import java.io.InputStream; 
import java.security.GeneralSecurityException; 
import java.util.Arrays; 

import javax.servlet.ServletException; 
import javax.servlet.http.HttpServlet; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import com.google.api.client.http.InputStreamContent; 
import com.google.api.services.storage.Storage; 
import com.google.api.services.storage.model.ObjectAccessControl; 
import com.google.api.services.storage.model.StorageObject; 

import XXXXXXXXXXXXX.StorageFactory; 

//@author Umesh Chauhan 

/** 
* Save File to GCS 
* 
* @param fileName  File Name with format 
* @header Content-Type "*/*" 
* @return file path 
* @throws Exception  Any Error during upload 
*/ 
public class UploadFile extends HttpServlet 
{ 

    private static final long serialVersionUID = 1L; 
    private final String BUCKET = "YOUR BUCKET NAME"; 
    private int maxFileSize = 6 * 1024 * 1024; 

    @Override 
    protected void doOptions (HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
    { 
     // pre-flight request processing 
     resp.setHeader ("Access-Control-Allow-Origin", "*"); 
     resp.setHeader ("Access-Control-Allow-Methods", "*"); 
     resp.setHeader ("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 
    } 

    @Override 
    public void doPost (HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, java.io.IOException 
    { 

     try 
     { 
      String path = uploadFile (request.getParameter ("fileName"), request.getContentType(), 
        request.getInputStream(), BUCKET, request.getInputStream().available()); 
      // Sending Response 
      response.setStatus (HttpServletResponse.SC_OK); 
      response.getWriter().write (path); 
      response.getWriter().flush(); 
      response.getWriter().close(); 

     } 
     catch (GeneralSecurityException e) 
     { 
      e.printStackTrace(); 
     } 
    } 

    public String uploadFile (String name, String contentType, InputStream input, String bucketName, 
      int contentLength) throws IOException, GeneralSecurityException 
    { 

     InputStreamContent contentStream = new InputStreamContent (contentType, input); 

     if (contentLength < maxFileSize) 
     { 

      // It is done Automatically. 
      /* 
      * // Setting the length improves upload performance 
      * contentStream.setLength (contentLength); 
      */ 

      StorageObject objectMetadata = new StorageObject() 
        // Set the destination object name 
        .setName (name) 
        // Set the access control list to publicly read-only 
        .setAcl (Arrays.asList (
          new ObjectAccessControl().setEntity ("allUsers").setRole ("READER"))); 

      // Do the insert 
      Storage client = StorageFactory.getService(); 

      Storage.Objects.Insert insertRequest = client.objects() 
        .insert (bucketName, objectMetadata, contentStream); 

      insertRequest.execute(); 

      return "https://storage.cloud.google.com/" + BUCKET + "/" + name; 
     } 
     else 
     { 
      throw new GeneralSecurityException ("File size canot be more then 6 MB !"); 
     } 
    } 

    public void doGet (HttpServletRequest request, HttpServletResponse response) 
      throws ServletException, java.io.IOException 
    { 
     throw new ServletException ("GET method used with " + getClass().getName() + ": POST method required."); 
    } 

} 

第二步一個Servlet:存儲廠

package XXXXXXXXXXXX; 

import java.io.IOException; 
import java.net.URL; 
import java.security.GeneralSecurityException; 
import java.util.Collection; 

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential; 
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport; 
import com.google.api.client.http.HttpTransport; 
import com.google.api.client.json.JsonFactory; 
import com.google.api.client.json.jackson2.JacksonFactory; 
import com.google.api.services.storage.Storage; 
import com.google.api.services.storage.StorageScopes; 

//@author Umesh Chauhan 

public class StorageFactory 
{ 

    private static Storage instance = null; 

    public static synchronized Storage getService() throws IOException, GeneralSecurityException 
    { 
     if (instance == null) 
     { 
      instance = buildService(); 
     } 
     return instance; 
    } 

    private static Storage buildService() throws IOException, GeneralSecurityException 
    { 

     HttpTransport transport = GoogleNetHttpTransport.newTrustedTransport(); 
     JsonFactory jsonFactory = new JacksonFactory(); 

     GoogleCredential credential = GoogleCredential.fromStream (
       new URL ("HERE GOES THE URL FOR YOUR SERVICE ACCOUNT JSON - I USED GOOGLE DRIVE DIRECT DOWNLOAD LINK TO MY JSON FILE") 
         .openStream()); 

     // Depending on the environment that provides the default credentials 
     // (for 
     // example: Compute Engine, App Engine), the credentials may require us 
     // to 
     // specify the scopes we need explicitly. Check for this case, and 
     // inject 
     // the Cloud Storage scope if required. 
     if (credential.createScopedRequired()) 
     { 
      Collection<String> scopes = StorageScopes.all(); 
      credential = credential.createScoped (scopes); 
     } 

     return new Storage.Builder (transport, jsonFactory, credential).setApplicationName ("YOUR PROJECT NAME").build(); 
    } 
} 

第3步:更新你web.xml

<servlet> 
     <servlet-name>UploadFile</servlet-name> 
     <servlet-class>PACKAGE.UploadFile</servlet-class> 
    </servlet> 

    <servlet-mapping> 
     <servlet-name>UploadFile</servlet-name> 
     <url-pattern>/uploadManager/UploadFile</url-pattern> //Based on your original URL 
    </servlet-mapping> 
+0

「這裏是你的服務帳戶JSON的URL - 我使用GOOGLE DRIVE直接下載鏈接到我的JSON文件」如何生成服務帳戶JSON?你能舉一個結構的例子嗎? – dina

+0

@ user5980143你必須從谷歌控制檯下載它。 –

+0

如果我已經在谷歌應用程序引擎中運行,我不需要「GoogleCreditial」權限? –

1

首先,你需要在飛行前請求處理解決CORS問題,你需要做的是在後端:在谷歌應用程序引擎它通過增加doOptions方法像做:

@Override 
protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException 
{ 
    resp.setHeader("Access-Control-Allow-Origin", "*"); 
    resp.setHeader("Access-Control-Allow-Methods", "*"); 
    resp.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"); 
} 

,那麼你需要確保你發送你喜歡Content-Type: multipart/form-data頭請求,否則你的文件的Wi會被錯誤地編碼。在angular2請求頭在你的崗位要求如設置爲第三個參數(可選):

let headers = new Headers(); 
headers.append('content-type', 'multipart/form-data'); 
http.post(url, body, { 
        headers:headers 
       }) 
1

對不起,這並不直接解決您的問題,但我仍要指出來。我建議使用其中一個常規端點來生成臨時上傳URL,Angular客戶端可以使用該臨時上傳URL將文件直接發送到雲端存儲,而無需通過您的應用。一種方法是通過blobstore API,如here所述。您可以通過here(進一步在同一頁面)描述的API通過該API上傳到雲端存儲。

這減少了上傳代碼,你需要在你的服務器上的金額,不受32MB的限制GAE的請求,並與谷歌的建議(如上面的文檔鏈接看到)。

2

這裏是根據上傳到存儲的正確方法

import com.google.appengine.tools.cloudstorage.*; 

public void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { 
    String buffer = "the data to be saved in GCS bla bla"; 
    GcsFileOptions instance = GcsFileOptions.getDefaultInstance(); 
    GcsFilename fileName = new GcsFilename("bucketName", "fileName"); 
    GcsOutputChannel outputChannel; 
    gcsService.createOrReplace(fileName, instance, ByteBuffer.wrap(buffer.getBytes())); 
} 

,你會發現完整的代碼here

+0

這是100%正確的方式做到這一點,原來的問題說他的應用程序運行在'谷歌應用程序引擎!「 –

+0

我張貼另一個選項https://stackoverflow.com/questions/38590971/ upload-file-to-google-cloud-storage-via-appengine/47546249?s = 4 | 31.2540#47546249 com.google.cloud.storage庫比'com.google.appengine' – dina

1

使用com.google.cloud.storage

  • AppEngine上運行時 - 無需認證
  • 在本地運行時運行gcloud auth application-default login命令 看到authentication

    import com.google.cloud.storage.*; 
    
    
    public static void upload(String bucketName, String fileId, String content) throws IOException { 
        Storage storage = StorageOptions.newBuilder().build().getService(); 
    
        BlobInfo fileInfo = BlobInfo.newBuilder(bucketName, fileId) 
          .build(); 
    
        InputStream fileIS = IOUtils.toInputStream(content, "UTF-8"); 
        storage.create(fileInfo, fileIS); 
    
    } 
    
相關問題