Загрузите файл в облачное хранилище Google через 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.");
}
}
Паутина.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>
Функция FileUpload для сохранения файла в 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
Далее после интеграции его с UI, который находится в Angular и тестирования его локально, я столкнулся с этой проблемой
Cross-Origin Request Blocked Reason: CORS header 'Access-Control-Allow-Origin' missing
Я попытался решить эту проблему, но не нашел решения, соответствующего google appengine.
Первоначально я пытаюсь загрузить изображение через этот код, но в ближайшем будущем этот же код будет использоваться для загрузки .pdf И.html файлы в GCS.
Для справки:
Я использую конечные точки Google для других моих потребностей в передаче данных с клиентским концом. Client End-это веб-приложение, построенное в Angular, но оно будет распространено на android и ios.
Любая помощь будет оценена по достоинству.
Спасибо
Обновление 1/8/2016
Теперь я получаю файл на сервер, но я не знаю, где я должен временно сохранить файл, прежде чем отправить его в Google Cloud Storage. О хранении файла в
warWEB-INI
И исключение, с которым я сталкиваюсь, - это
java.security.AccessControlException: access denied ("java.io.FilePermission" "warWEB-INIprofile.png" "read")
5 ответов:
Наконец, я могу загрузить файл с клиентского конца в облачное хранилище Google через 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." ); } }Шаг 2: Ваша Фабрика Хранения
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>
Вот правильный способ для загрузки в хранилище в соответствии с docs
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())); }Вы найдете полный код здесь
Сначала вам нужно решить проблему CORS в предварительной обработке запроса на полет, вам нужно сделать это на задней стороне: на Google App Engine это делается путем добавления метода
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, иначе ваш файл будет закодирован неправильно. В angular2 заголовки запросов устанавливаются в качестве третьего(необязательного) параметра в вашем запросе post, например:let headers = new Headers(); headers.append('content-type', 'multipart/form-data'); http.post(url, body, { headers:headers })
Я сожалею, что это не касается непосредственно вашего вопроса, но я все равно хочу указать на него. Я рекомендую использовать одну из ваших обычных конечных точек для создания временного URL-адреса загрузки, который ваш клиент Angular может использовать для отправки файла непосредственно в облачное хранилище, не проходя через ваше приложение. Один из способов сделать это-через API blobstore, как описано здесь. Вы можете загрузить в облачное хранилище через этот API, как описано здесь (Далее на той же странице).
Это уменьшает объем загружаемого кода, необходимый для вашего сервера, не ограничен 32 МБ для запросов GAE и соответствует рекомендациям Google (см. ссылки на документацию выше).
Используйте com.гугл.облако.хранение
- при работе на appengine-нет необходимости в аутентификации
При локальном запуске выполните команду
gcloud auth application-default loginсм. аутентификация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); }
Comments