通过appengine将文件上传到Google云端存储

问题描述:

我试图将文件上传到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") 

最后我能够通过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”权限? –

首先,你需要在飞行前请求处理解决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 
       }) 

对不起,这并不直接解决您的问题,但我仍要指出来。我建议使用其中一个常规端点来生成临时上传URL,Angular客户端可以使用该临时上传URL将文件直接发送到云端存储,而无需通过您的应用。一种方法是通过blobstore API,如here所述。您可以通过here(进一步在同一页面)描述的API通过该API上传到云端存储。

这减少了上传代码,你需要在你的服务器上的金额,不受32MB的限制GAE的请求,并与谷歌的建议(如上面的文档链接看到)。

这里是根据上传到存储的正确方法

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://*.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

使用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); 
    
    }