Храните изображение в Blobstore от клиента android и извлекайте blobkey и загружайте URL-адрес для хранения в хранилище данных. - GAE
В моем приложении для Android я хочу загрузить изображение в Blobstore, а затем загрузить URL-адрес Upload и изображение Blobkey, чтобы я мог сохранить Blobkey в DataStore.
Я пробовал этот код, но мое изображение не загружается:
Сервлет (URL-адрес возврата)
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
UploadOptions uploadOptions = UploadOptions.Builder
.withGoogleStorageBucketName("photobucket11")
.maxUploadSizeBytes(1048576);
String blobUploadUrl = blobstoreService.createUploadUrl("/upload",
uploadOptions);
// String blobUploadUrl = blobstoreService.createUploadUrl("/uploaded");
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
out.print(blobUploadUrl);
}
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
doGet(req, resp);
}
Код: клиент Android
Bitmap bmp = BitmapFactory.decodeFile(imagePath);
ByteArrayOutputStream out = new ByteArrayOutputStream();
bmp.compress(CompressFormat.JPEG, 75, out);
byte[] imgByte = out.toByteArray();
String encodedImage = Base64.encodeToString(imgByte,
Base64.DEFAULT);
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet(
"app-url/ImgUpload");
HttpResponse response = httpClient.execute(httpGet);
HttpEntity urlEntity = response.getEntity();
InputStream in = urlEntity.getContent();
String str = "";
while (true) {
int ch = in.read();
if (ch == -1)
break;
str += (char) ch;
}
Это вернет URL-адрес загрузки в форме /_ah/upload/akjdhjahdjaudshgaajsdhjsdh
, который я могу использовать для хранения изображения.
Этот код использует url для хранения изображения:
httpClient = new DefaultHttpClient();
HttpPost postRequest = new HttpPost(str);
ByteArrayBody bab = new ByteArrayBody(imgByte, "forest.jpg");
MultipartEntity reqEntity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("uploaded", bab);
reqEntity.addPart("photoCaption", new StringBody("sfsdfsdf"));
postRequest.setEntity(reqEntity);
response = httpClient.execute(postRequest);
BufferedReader reader = new BufferedReader(
new InputStreamReader(
response.getEntity().getContent(), "UTF-8"));
String sResponse;
StringBuilder s = new StringBuilder();
while ((sResponse = reader.readLine()) != null) {
s = s.append(sResponse);
}
Здесь, если я проверяю значение String s
, он показывает null
. Это означает, что он возвращает нулевой ответ. Я не знаю, в чем проблема с этим кодом. Пожалуйста, помогите мне решить эту проблему.
Ответы
Ответ 1
После многих попыток я решил эту проблему. Чтобы сохранить изображение в blobstore, первому android нужно сделать запрос сервлету, который будет генерировать URL-адрес загрузки:
Клиент Android: он запросит генерировать URL-адрес и получит URL-адрес из сервлета
HttpClient httpClient = new DefaultHttpClient();
//This will invoke "ImgUpload servlet
HttpGet httpGet = new HttpGet("my-app-url/ImgUpload");
HttpResponse response = httpClient.execute(httpGet);
HttpEntity urlEntity = response.getEntity();
InputStream in = urlEntity.getContent();
String str = "";
while (true) {
int ch = in.read();
if (ch == -1)
break;
str += (char) ch;
}
ImgUpload.java - сервлет для генерации URL-адреса и отправки ответа клиенту
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
//"uploaded" is another servlet which will send UploadUrl and blobkey to android client
String blobUploadUrl = blobstoreService.createUploadUrl("/uploaded");
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
out.print(blobUploadUrl);
}
В клиенте android напишите ниже код, загружающий изображение, чтобы возвратить ответ от сервлета.
//Save image to generated url
HttpPost httppost = new HttpPost(str);
File f = new File(imagePath);
FileBody fileBody = new FileBody(f);
MultipartEntity reqEntity = new MultipartEntity();
reqEntity.addPart("file", fileBody);
httppost.setEntity(reqEntity);
response = httpClient.execute(httppost); //Here "uploaded" servlet is automatically invoked
urlEntity = response.getEntity(); //Response will be returned by "uploaded" servlet in JSON format
in = urlEntity.getContent();
str = "";
while (true) {
int ch = in.read();
if (ch == -1)
break;
str += (char) ch;
}
JSONObject resultJson = new JSONObject(str);
String blobKey = resultJson.getString("blobKey");
String servingUrl = resultJson.getString("servingUrl");
uploaded.java- servlet, который возвращает Uploadurl и Blobkey изображения
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
try {
List<BlobKey> blobs = blobstoreService.getUploads(req).get("file");
BlobKey blobKey = blobs.get(0);
ImagesService imagesService = ImagesServiceFactory
.getImagesService();
ServingUrlOptions servingOptions = ServingUrlOptions.Builder
.withBlobKey(blobKey);
String servingUrl = imagesService.getServingUrl(servingOptions);
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("application/json");
JSONObject json = new JSONObject();
json.put("servingUrl", servingUrl);
json.put("blobKey", blobKey.getKeyString());
PrintWriter out = resp.getWriter();
out.print(json.toString());
out.flush();
out.close();
} catch (JSONException e) {
e.printStackTrace();
}
}
Ответ 2
Благодаря zanky мне удалось это понять, и я хочу добавить свой код, потому что некоторый код устарел в его ответе, а также некоторый код нуждается в дополнительном объяснении, таком как переопределение и асинтеза. Кстати, код может не работать на локальном сервере из-за путаницы localhost и IP. Попытайтесь использовать движок приложения, когда будете готовы.
Servlet-1 BlobUrlGet. Это пойдет на сторону приложения. Этот сервлет создает URL-адрес загрузки для метода post в клиентском коде.
public class BlobUrlGet extends HttpServlet{
BlobstoreService blServ = BlobstoreServiceFactory.getBlobstoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
String blobUploadUrl = blServ.createUploadUrl("/blobupload");
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("text/plain");
PrintWriter out = resp.getWriter();
out.print(blobUploadUrl);
}
}
Servlet-2 BlobUpload Этот код будет автоматически вызываться, когда сообщение будет сделано для blobstore. В результате это даст нам blobkey и сервисный url для загрузки изображения позже.
public class BlobUpload extends HttpServlet {
BlobstoreService blobstoreService = BlobstoreServiceFactory
.getBlobstoreService();
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
try {
List<BlobKey> blobs = blobstoreService.getUploads(req).get("photo");
BlobKey blobKey = blobs.get(0);
ImagesService imagesService = ImagesServiceFactory.getImagesService();
ServingUrlOptions servingOptions = ServingUrlOptions.Builder.withBlobKey(blobKey);
String servingUrl = imagesService.getServingUrl(servingOptions);
resp.setStatus(HttpServletResponse.SC_OK);
resp.setContentType("application/json");
JSONObject json = new JSONObject();
json.put("servingUrl", servingUrl);
json.put("blobKey", blobKey.getKeyString());
PrintWriter out = resp.getWriter();
out.print(json.toString());
out.flush();
out.close();
} catch (JSONException e) {
e.printStackTrace();
}
}
}
Клиентский код клиента Android. Эта асинтеза вызовет сервлеты и отправит сообщение в blobstore с информацией, которую он получает.
private class GetBlobUrlTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... arg0){
HttpClient httpClient = new DefaultHttpClient();
//This will invoke "ImgUpload servlet
HttpGet httpGet = new HttpGet("http://PUT_YOUR_URL_HERE/bloburlget");
HttpResponse response;
try {
response = httpClient.execute(httpGet);
HttpEntity urlEntity = response.getEntity();
InputStream in = urlEntity.getContent();
String str = "";
StringWriter writer = new StringWriter();
String encoding = "UTF-8";
IOUtils.copy(in, writer, encoding);
str = writer.toString();
HttpPost httppost = new HttpPost(str);
File f = new File(picturePath);
MultipartEntityBuilder reqEntity = MultipartEntityBuilder.create();
reqEntity.addBinaryBody("photo", f, ContentType.create("image/jpeg"), "foto2.jpg");
httppost.setEntity(reqEntity.build());
response = httpClient.execute(httppost); //Here "uploaded" servlet is automatically invoked
str = EntityUtils.toString(response.getEntity());
JSONObject resultJson = new JSONObject(str);
blobKey = resultJson.getString("blobKey");
servingUrl = resultJson.getString("servingUrl");
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
}
В конце концов, нам нужно обновить web.xml, чтобы иметь возможность выполнять сервлеты.
<servlet>
<servlet-name>BlobUrlGet</servlet-name>
<servlet-class>PUT_YOUR_PACKAGE_NAME.BlobUrlGet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BlobUrlGet</servlet-name>
<url-pattern>/bloburlget</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>BlobUpload</servlet-name>
<servlet-class>PUT_YOUR_PACKAGE_NAME.BlobUpload</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BlobUpload</servlet-name>
<url-pattern>/blobupload</url-pattern>
</servlet-mapping>
Ответ 3
Я работаю с конечными точками в Android Studio, благодаря SAVANTE, я могу закончить свой код, но мне пришлось внести небольшие корректировки.
в Servlet 1:
Я использовал Endpoints, с этим я могу очень легко обрабатывать OAuth2 в моем методе:
@ApiMethod(name = "getBlobURL", scopes = {Constants.EMAIL_SCOPE},
clientIds = {Constants.WEB_CLIENT_ID,
Constants.ANDROID_CLIENT_ID,
com.google.api.server.spi.Constant.API_EXPLORER_CLIENT_ID},
audiences = {Constants.ANDROID_AUDIENCE})
public BlobAttributes getBlobURL(User user) throws UnauthorizedException,
ConflictException{
//If if is not null, then check if it exists. If yes, throw an Exception
//that it is already present
if (user == null){
throw new UnauthorizedException("User is Not Valid");
}
BlobstoreService blobstoreService = BlobstoreServiceFactory.getBlobstoreService();
String blobUploadUrl = blobstoreService.createUploadUrl("/blobupload");
//BlobAttributes is a class
BlobAttributes ba= new BlobAttributes();
ba.setBlobURL(blobUploadUrl);
return ba;
}
My Backend в конечных точках Android Studio, не позволяйте мне использовать JSONObject для этого rason Я создаю свой собственный Json:
в Servlet 2:
String myJson = "{'servingUrl': '" + servingUrl +
"', 'blobKey': '" + blobKey.getKeyString() + "'}";
PrintWriter out = resp.getWriter();
out.print(myJson);
out.flush();
out.close();
Я надеюсь работать для кого-то еще, я потратил 48 часов, пытаясь понять и управлять Blobstore.
Изменить:
Чтобы сделать аутентифицированный звонок от клиента, это способ использования учетных данных Google:
accountName = settings.getString(start.KEY_ACCOUNT_NAME, null); //Email account that you before save it
credential = GoogleAccountCredential.usingAudience(getActivity(),
start.WEB_CLIENT_ID); //WEB_CLIENT_ID is your WEB ID in Google Console
credential.setSelectedAccountName(accountName);
При создании вашей конечной точки введите свои учетные данные:
PostEndpoint.Builder builder = new PostEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), credential)
.setRootUrl(getActivity().getString(R.string.backend_url_connection));
myApiService = builder.build();
Для получения имени учетной записи клиента используйте Plus API
accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
Прочитайте ссылки в комментариях, с документацией Google, чтобы это понять.