[英]Store image to Blobstore from android client and retrieve blobkey and upload url to store in Datastore. - GAE
In my Android application, I want to upload image to the Blobstore, then retrieve an Upload url and the image's Blobkey, so I can store the Blobkey in the DataStore. 在我的Android应用程序中,我想将图像上传到Blobstore,然后检索上传URL和图像的Blobkey,这样我就可以将Blobkey存储在DataStore中。
I've tried this code, but my image isn't uploading: 我试过这段代码,但我的图片没有上传:
Servlet (Return upload url) Servlet(返回上传网址)
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);
}
Code : Android client 代码: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;
}
This will return upload url in form of /_ah/upload/akjdhjahdjaudshgaajsdhjsdh
which I can use to store the image. 这将以/_ah/upload/akjdhjahdjaudshgaajsdhjsdh
形式返回上传URL,我可以使用它来存储图像。
This code uses the url to store the image: 此代码使用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);
}
Here, if I check value of the String s
, it shows null
. 在这里,如果我检查String s
值,它显示为null
。 That means it is returning a null response. 这意味着它返回一个null响应。 I don't know what the problem is with this code. 我不知道这段代码有什么问题。 Please guide me to solve this problem. 请指导我解决这个问题。
After many tries i solved this problem. 经过多次尝试,我解决了这个问题。 To store image in blobstore, first android needs to make request to servlet which will generate upload url : 要在blobstore中存储图像,首先需要向servlet发出请求,这将生成上传URL:
Android client : It will request to generate url and gets url from servlet Android客户端:它将请求生成url并从servlet获取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 - Servlet to generate url and sends response to client ImgUpload.java - 生成url并向客户端发送响应的Servlet
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);
}
In android client,write below code upload image to returned response from above servlet. 在android客户端中,将下面的代码上传图像写入从上面的servlet返回的响应。
//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 which returns Uploadurl and Blobkey of image 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();
}
}
Thanks to zanky I managed to understand it and I want to add my code because some code is deprecated in his answer and also some code need more explanation like overriding and asynctask. 感谢zanky我设法理解它并且我想添加我的代码,因为在他的答案中不赞成某些代码,并且一些代码需要更多解释,如覆盖和asynctask。 By the way the code may not work on local server because of the localhost and IP confusion. 顺便说一下,由于localhost和IP混淆,代码可能无法在本地服务器上运行。 Try on the app engine when you are ready. 准备好后试试app引擎。
Servlet-1 BlobUrlGet. Servlet-1 BlobUrlGet。 This will go to appengine side. 这将是appengine方面。 This servlet produces upload url for the post method in the client code. 此servlet为客户端代码中的post方法生成上传URL。
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 This code will be automatically called when the post is done to blobstore. Servlet-2 BlobUpload当帖子完成blobstore时,将自动调用此代码。 As a result it will give us blobkey and serving url to download the image later. 因此,它将为我们提供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 Client side code. Android客户端端代码。 This asynctask will call the servlets and do the post to blobstore with the info it gets. 这个asynctask将调用servlet并使用它获得的信息向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;
}
}
After all we need to update web.xml to be able to execute servlets. 毕竟我们需要更新web.xml才能执行servlet。
<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>
I am working with endpoints in Android Studio, thanks to SAVANTE, I can finish my code but I had to make small adjustments. 我在Android Studio中使用端点,感谢SAVANTE,我可以完成我的代码,但我不得不进行小的调整。
in Servlet 1: I used Endpoints, with this I can handle very easy the OAuth2 in my method: 在Servlet 1中:我使用了端点,我可以在我的方法中轻松处理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 in endpoints Android Studio, do not let me use JSONObject for this rason I make my own Json: in Servlet 2: 我的后端在端点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();
I hope works for somebody else, I spent 48 hours trying to understand and operate Blobstore. 我希望为其他人工作,我花了48个小时试图理解和操作Blobstore。
Edit: 编辑:
For make a authenticated call from client this is the way using Google credentials: 要从客户端进行经过身份验证的呼叫,这是使用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);
When build your Endpoint put your credential: 构建您的Endpoint时,请填写您的凭证:
PostEndpoint.Builder builder = new PostEndpoint.Builder(AndroidHttp.newCompatibleTransport(), new AndroidJsonFactory(), credential)
.setRootUrl(getActivity().getString(R.string.backend_url_connection));
myApiService = builder.build();
For Get the Account Name of the client, use Plus API 要获取客户端的帐户名称,请使用Plus API
accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
Read the links down in the comments, with Google documentation for good understand this. 阅读评论中的链接,使用Google文档可以很好地理解这一点。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.