dax圣经 翻新

In this tutorial, we’ll be creating an android application that uploads an image using Retrofit MultiPart Request to the localhost server. We’ll create a simple server using Node JS first. Let’s get started.

在本教程中,我们将创建一个Android应用程序,该应用程序使用Retrofit MultiPart Request将图像上传到本地服务器。 我们将首先使用Node JS创建一个简单的服务器。 让我们开始吧。

设置节点JS服务器 (Setting Up Node JS Server)

Let’s set up a simple Node JS localhost server where we can upload files.

让我们设置一个简单的Node JS localhost服务器,在其中可以上传文件。

We’ll start by creating a separate directory for the node js server. Let’s name it jdserver
Inside the directory, we’ll install the following packages using npm. Ensure that node and npm are installed.

我们将从为节点js服务器创建一个单独的目录开始。 让我们将其命名为jdserver
在目录内,我们将使用npm安装以下软件包。 确保已安装nodenpm

mkdir jdserver
cd jdserver
npm install express
npm install multer

Multer: is an image upload library. It handles getting formdata from requests.
Express is a popular web framework.

Multer:是图像上传库。 它处理从请求获取formdata
Express是一种流行的Web框架。

Let’s create a subfolder uploads which will contain the uploaded images by doing mkdir uploads.

让我们创建一个子文件夹uploads ,通过执行mkdir uploads来包含上载的图像。

Inside the jdserver directory, we’ll create a multipart.js file which contains the code for the server setup and uploading the image:

jdserver目录中,我们将创建一个multipart.js文件,其中包含服务器设置和上传图像的代码:

var express = require("express");
var app = express();
var multer, storage, path, crypto;
multer = require('multer')
path = require('path');
crypto = require('crypto');var form = "<!DOCTYPE HTML><html><body>" +
"<form method='post' action='/upload' enctype='multipart/form-data'>" +
"<input type='file' name='upload'/>" +
"<input type='submit' /></form>" +
"</body></html>";app.get('/', function (req, res){res.writeHead(200, {'Content-Type': 'text/html' });res.end(form);});// Include the node file module
var fs = require('fs');storage = multer.diskStorage({destination: './uploads/',filename: function(req, file, cb) {return crypto.pseudoRandomBytes(16, function(err, raw) {if (err) {return cb(err);}return cb(null, "" + (raw.toString('hex')) + (path.extname(file.originalname)));});}});// Post files
app.post("/upload",multer({storage: storage}).single('upload'), function(req, res) {console.log(req.file);console.log(req.body);res.redirect("/uploads/" + req.file.filename);console.log(req.file.filename);return res.status(200).end();});app.get('/uploads/:upload', function (req, res){file = req.params.upload;console.log(req.params.upload);var img = fs.readFileSync(__dirname + "/uploads/" + file);res.writeHead(200, {'Content-Type': 'image/png' });res.end(img, 'binary');});app.listen(3000);

The upload file name is changed using the crypto package and stored in the uploads directory.
The server would run on 3000 port on the localhost.

使用加密软件包更改上传文件名,并将其存储在上载目录中。
服务器将在本地主机上的3000端口上运行。

In order to start the server, do the following:
node multipart.js from the jdserver directory on the terminal.

为了启动服务器,请执行以下操作:
终端上jdserver目录中的node multipart.js

When you open your localhost in the web browser (127.0.0.1:3000), this is what you should see:

当您在网络浏览器(127.0.0.1:3000)中打开本地主机时,应该看到以下内容:

Thus we are able to upload an image to the server. It gets saved in the uploads dir as shown below:

因此,我们能够将图像上传到服务器。 它被保存在上uploads目录中,如下所示:

In order to test whether the POST works, we can install the httpie in the terminal.

为了测试POST是否有效,我们可以在终端中安装httpie 。

One way is by using homebrew.

一种方法是使用自制程序。

brew install httpie

To test the POST for multipart image upload we can run the following on the terminal:

要测试用于多部分图像上传的POST,我们可以在终端上运行以下命令:

http -f POST 127.0.0.1:3000/upload name='upload' upload@wallpaper.png

wallpaper.png if exists in the current directory in the terminal would be uploaded.

如果存在于终端的当前目录中,则将上载wallpaper.png文件。

This gets logged in the terminal:

这将登录到终端:

Now that all is set on the server side, let’s implement the same in our Android Application.

现在,所有操作都在服务器端进行了设置,让我们在我们的Android应用程序中实现相同的功能。

改造多部分上传 (Retrofit MultiPart Upload)

Sending an Image via a network call is different from sending text/plain or x-www-urlencoded requests which are essentially texts/key value pairs respectively.

通过网络呼叫发送图像不同于发送文本/纯文本或x-www-urlencoded请求,它们本质上分别是文本/键值对。

In order to send an Image, we need to create a MultiPartRequest.
In Retrofit, we need to use MultipartBody.Part and RequestBody for uploading the image.
MultipartBody.Part is used to pass the file and RequestBody is used to pass the plain text here.

为了发送图像,我们需要创建一个MultiPartRequest
在Retrofit中,我们需要使用MultipartBody.Part和RequestBody来上传图像。
MultipartBody.Part用于传递文件,而RequestBody用于传递纯文本。

In order to use MultiPart we need to annotate the POST request in retrofit with @Multipart

为了使用MultiPart我们需要在@Multipart改造中注释POST请求。

In the following section, we’ll use MultiPart for Image Uploading to the Node JS server hosted locally.

在以下部分中,我们将使用MultiPart将图像上传到本地托管的Node JS服务器。

项目结构 (Project Structure)

The build.gradle includes the following dependencies:

build.gradle包括以下依赖项:

implementation 'com.android.support:design:28.0.0'
implementation 'com.squareup.retrofit2:retrofit:2.4.0'

The AndroidManifest.xml looks like this:

AndroidManifest.xml如下所示:

We’ve added the relevant permissions and FileProvider is needed since Android Nougat for fetching image path.

自Android Nougat以来,我们已经添加了相关权限,并且需要FileProvider来获取图像路径。

码 (Code)

The code for the activity_main.xml layout is given below:

下面给出了activity_main.xml布局的代码:

<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="https://schemas.android.com/apk/res/android"xmlns:app="https://schemas.android.com/apk/res-auto"xmlns:tools="https://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:fitsSystemWindows="true"><RelativeLayoutandroid:id="@+id/content_main"android:layout_width="match_parent"android:layout_height="match_parent"android:padding="16dp"app:layout_behavior="@string/appbar_scrolling_view_behavior"><TextViewandroid:id="@+id/textView"android:layout_centerHorizontal="true"android:textAppearance="@style/TextAppearance.AppCompat.Display1"android:layout_width="wrap_content"android:layout_height="wrap_content" /><ImageViewandroid:id="@+id/imageView"android:layout_width="250dp"android:layout_height="250dp"android:layout_centerInParent="true"android:adjustViewBounds="true"android:scaleType="centerCrop" /></RelativeLayout><android.support.design.widget.FloatingActionButtonandroid:id="@+id/fab"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom|end"android:layout_margin="16dp"app:srcCompat="@android:drawable/ic_menu_camera" /><android.support.design.widget.FloatingActionButtonandroid:id="@+id/fabUpload"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_gravity="bottom|center_horizontal"android:layout_margin="16dp"app:srcCompat="@android:drawable/ic_menu_upload" /></android.support.design.widget.CoordinatorLayout>

ApiService.java

ApiService.java

package com.journaldev.androiduploadimageretrofitnodejs;import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;interface ApiService {@Multipart@POST("/upload")Call<ResponseBody> postImage(@Part MultipartBody.Part image, @Part("upload") RequestBody name);
}

Inside @Part annotation name we must specify the key which is the same as the one defined in the js file earlier i.e. “upload” along with the File.

@Part批注名称中,我们必须指定与js文件中先前定义的键相同的键,即“ upload”和File。

MainActivity.java

MainActivity.java

package com.journaldev.androiduploadimageretrofitnodejs;import android.annotation.TargetApi;
import android.app.Activity;
import android.content.ComponentName;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.os.Parcelable;
import android.provider.MediaStore;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import retrofit2.Retrofit;import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;public class MainActivity extends AppCompatActivity implements View.OnClickListener {ApiService apiService;Uri picUri;private ArrayList<String> permissionsToRequest;private ArrayList<String> permissionsRejected = new ArrayList<>();private ArrayList<String> permissions = new ArrayList<>();private final static int ALL_PERMISSIONS_RESULT = 107;private final static int IMAGE_RESULT = 200;FloatingActionButton fabCamera, fabUpload;Bitmap mBitmap;TextView textView;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);fabCamera = findViewById(R.id.fab);fabUpload = findViewById(R.id.fabUpload);textView = findViewById(R.id.textView);fabCamera.setOnClickListener(this);fabUpload.setOnClickListener(this);askPermissions();initRetrofitClient();}private void askPermissions() {permissions.add(CAMERA);permissions.add(WRITE_EXTERNAL_STORAGE);permissions.add(READ_EXTERNAL_STORAGE);permissionsToRequest = findUnAskedPermissions(permissions);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (permissionsToRequest.size() > 0)requestPermissions(permissionsToRequest.toArray(new String[permissionsToRequest.size()]), ALL_PERMISSIONS_RESULT);}}private void initRetrofitClient() {OkHttpClient client = new OkHttpClient.Builder().build();apiService = new Retrofit.Builder().baseUrl("https://192.168.88.65:3000").client(client).build().create(ApiService.class);}public Intent getPickImageChooserIntent() {Uri outputFileUri = getCaptureImageOutputUri();List<Intent> allIntents = new ArrayList<>();PackageManager packageManager = getPackageManager();Intent captureIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);List<ResolveInfo> listCam = packageManager.queryIntentActivities(captureIntent, 0);for (ResolveInfo res : listCam) {Intent intent = new Intent(captureIntent);intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));intent.setPackage(res.activityInfo.packageName);if (outputFileUri != null) {intent.putExtra(MediaStore.EXTRA_OUTPUT, outputFileUri);}allIntents.add(intent);}Intent galleryIntent = new Intent(Intent.ACTION_GET_CONTENT);galleryIntent.setType("image/*");List<ResolveInfo> listGallery = packageManager.queryIntentActivities(galleryIntent, 0);for (ResolveInfo res : listGallery) {Intent intent = new Intent(galleryIntent);intent.setComponent(new ComponentName(res.activityInfo.packageName, res.activityInfo.name));intent.setPackage(res.activityInfo.packageName);allIntents.add(intent);}Intent mainIntent = allIntents.get(allIntents.size() - 1);for (Intent intent : allIntents) {if (intent.getComponent().getClassName().equals("com.android.documentsui.DocumentsActivity")) {mainIntent = intent;break;}}allIntents.remove(mainIntent);Intent chooserIntent = Intent.createChooser(mainIntent, "Select source");chooserIntent.putExtra(Intent.EXTRA_INITIAL_INTENTS, allIntents.toArray(new Parcelable[allIntents.size()]));return chooserIntent;}private Uri getCaptureImageOutputUri() {Uri outputFileUri = null;File getImage = getExternalFilesDir("");if (getImage != null) {outputFileUri = Uri.fromFile(new File(getImage.getPath(), "profile.png"));}return outputFileUri;}@Overrideprotected void onActivityResult(int requestCode, int resultCode, Intent data) {if (resultCode == Activity.RESULT_OK) {ImageView imageView = findViewById(R.id.imageView);if (requestCode == IMAGE_RESULT) {String filePath = getImageFilePath(data);if (filePath != null) {mBitmap = BitmapFactory.decodeFile(filePath);imageView.setImageBitmap(mBitmap);}}}}private String getImageFromFilePath(Intent data) {boolean isCamera = data == null || data.getData() == null;if (isCamera) return getCaptureImageOutputUri().getPath();else return getPathFromURI(data.getData());}public String getImageFilePath(Intent data) {return getImageFromFilePath(data);}private String getPathFromURI(Uri contentUri) {String[] proj = {MediaStore.Audio.Media.DATA};Cursor cursor = getContentResolver().query(contentUri, proj, null, null, null);int column_index = cursor.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);cursor.moveToFirst();return cursor.getString(column_index);}@Overrideprotected void onSaveInstanceState(Bundle outState) {super.onSaveInstanceState(outState);outState.putParcelable("pic_uri", picUri);}@Overrideprotected void onRestoreInstanceState(Bundle savedInstanceState) {super.onRestoreInstanceState(savedInstanceState);picUri = savedInstanceState.getParcelable("pic_uri");}private ArrayList<String> findUnAskedPermissions(ArrayList<String> wanted) {ArrayList<String> result = new ArrayList<String>();for (String perm : wanted) {if (!hasPermission(perm)) {result.add(perm);}}return result;}private boolean hasPermission(String permission) {if (canMakeSmores()) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {return (checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED);}}return true;}private void showMessageOKCancel(String message, DialogInterface.OnClickListener okListener) {new AlertDialog.Builder(this).setMessage(message).setPositiveButton("OK", okListener).setNegativeButton("Cancel", null).create().show();}private boolean canMakeSmores() {return (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1);}@TargetApi(Build.VERSION_CODES.M)@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {switch (requestCode) {case ALL_PERMISSIONS_RESULT:for (String perms : permissionsToRequest) {if (!hasPermission(perms)) {permissionsRejected.add(perms);}}if (permissionsRejected.size() > 0) {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (shouldShowRequestPermissionRationale(permissionsRejected.get(0))) {showMessageOKCancel("These permissions are mandatory for the application. Please allow access.",new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {requestPermissions(permissionsRejected.toArray(new String[permissionsRejected.size()]), ALL_PERMISSIONS_RESULT);}});return;}}}break;}}private void multipartImageUpload() {try {File filesDir = getApplicationContext().getFilesDir();File file = new File(filesDir, "image" + ".png");ByteArrayOutputStream bos = new ByteArrayOutputStream();mBitmap.compress(Bitmap.CompressFormat.PNG, 0, bos);byte[] bitmapdata = bos.toByteArray();FileOutputStream fos = new FileOutputStream(file);fos.write(bitmapdata);fos.flush();fos.close();RequestBody reqFile = RequestBody.create(MediaType.parse("image/*"), file);MultipartBody.Part body = MultipartBody.Part.createFormData("upload", file.getName(), reqFile);RequestBody name = RequestBody.create(MediaType.parse("text/plain"), "upload");Call<ResponseBody> req = apiService.postImage(body, name);req.enqueue(new Callback<ResponseBody>() {@Overridepublic void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {if (response.code() == 200) {textView.setText("Uploaded Successfully!");textView.setTextColor(Color.BLUE);}Toast.makeText(getApplicationContext(), response.code() + " ", Toast.LENGTH_SHORT).show();}@Overridepublic void onFailure(Call<ResponseBody> call, Throwable t) {textView.setText("Uploaded Failed!");textView.setTextColor(Color.RED);Toast.makeText(getApplicationContext(), "Request failed", Toast.LENGTH_SHORT).show();t.printStackTrace();}});} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.fab:startActivityForResult(getPickImageChooserIntent(), IMAGE_RESULT);break;case R.id.fabUpload:if (mBitmap != null)multipartImageUpload();else {Toast.makeText(getApplicationContext(), "Bitmap is null. Try again", Toast.LENGTH_SHORT).show();}break;}}
}

In the above code, we need to ask for runtime permissions before anything.
The image bitmap retrieved from the camera/gallery image is eventually passed to the server in the multipart Retrofit request.

在上面的代码中,我们需要先获得运行时权限。
从摄像机/图库图像检索到的图像位图最终在多部分改造请求中传递到服务器。

The base URL is the same as the IP of your system if you’re running the application on your phone connected via USB.

如果您正在通过USB连接的手机上运行应用程序,则基本URL与系统的IP地址相同。

In the above code, the base URL is my current IP. You need to change it to yours when running the project.

在上面的代码中,基本URL是我当前的IP。 运行项目时,需要将其更改为您自己的。

Make sure that the server is up and running!

确保服务器已启动并正在运行!

The output of the above application in action is given below:

上面应用程序的输出如下:

And the file is now visible in the uploads directory:

现在,该文件在uploads目录中可见:

That brings an end to this tutorial. You can download the project from the link below. It contains the multipart.js file which you can use to set up the server as explained at the beginning.

这样就结束了本教程。 您可以从下面的链接下载项目。 它包含multipart.js文件,您可以使用该文件来设置服务器,如开头所述。

AndroidUploadImageRetrofitNodeJSAndroidUploadImageRetrofitNodeJS
Github Project LinkGithub项目链接

翻译自: https://www.journaldev.com/23709/android-image-uploading-with-retrofit-and-node-js

dax圣经 翻新

dax圣经 翻新_使用翻新和Node JS的Android图像上传相关推荐

  1. Building and running Node.js for Android

    转自: http://www.goland.org/nodejsonandroid/ Building and running Node.js for Android October 14, 2014 ...

  2. 来自Android客户端什么意思,如何通过回调函数中的Node.js来自Android客户端

    我想从插座Android客户端将数据发送到服务器的Node.js .. 在服务器端做了什么香港专业教育学院:如何通过回调函数中的Node.js来自Android客户端 socket.on('new u ...

  3. node js 写按键精灵_带有按键的Node.js Raw模式

    node js 写按键精灵 I find the stuff that people are doing with Node.js incredibly interesting.  You here ...

  4. 构建node.js基础镜像_我如何使用Node.js构建工作抓取网络应用

    构建node.js基础镜像 by Oyetoke Tobi Emmanuel 由Oyetoke Tobi Emmanuel 我如何使用Node.js构建工作抓取网络应用 (How I built a ...

  5. node 升级_技术周刊( Node.js 12 性能大提升 2019-04-30)

    前端快爆 Node.js 12 发布,该版本带来了巨大的性能提升.V8 升级到 7.4 带来了诸多新特性,比如 Private Class Fields.Array#{flat,flatMap} 等: ...

  6. 83998 连接服务器出错_新生福利 | 使用 Node.Js 开发服务器

    点击蓝字关注,创智助你长姿势 Node.js 是一个 Javascript 运行环境 (runtime),发布于 2009 年 5 月,由 Ryan Dahl 开发.实际上它是对 Google V8 ...

  7. js数组截取前5个_想用好 Node.js?这 5 个经典国产项目值得细品

    凭借着高并发性能优秀.异步事件驱动.入门简单等优势,Node.js 受到了不少开发者们的青睐.但不得不承认的是,如果用不好 Node.js,它的坑就会非常多,为了帮助各位 Node.js 的开发者们更 ...

  8. js获取ip地址_(原创)Node.JS实战31:大名鼎鼎的Express!

    Express (http://expressjs.com)是Node.JS中一个简洁.灵活.强大的Web应用框架, 它提供了一系列强大特性,可以帮助我们快速创建各种Web 应用,也可用来编写各种的W ...

  9. js提交出现post错误_阿里云的 Node.js 稳定性实践

    整理人:前端自习课 前言 如果你看过 2018 Node.js 的用户报告,你会发现 Node.js 的使用有了进一步的增长,同时也出现了一些新的趋势. Node.js 的开发者更多的开始使用容器并积 ...

最新文章

  1. MAML-Tracker:用目标检测思路做目标跟踪?小样本即可得高准确率丨CVPR 2020
  2. 解决django配合nginx部署后admin样式丢失
  3. spring mvc DispatcherServlet详解之四---视图渲染过程
  4. intitle:客服机器人代码_游戏客服能影响企业发展?千万别大意
  5. (Z)托尼?施瓦茨:六大关键几乎可以改变一切
  6. 这款耳机性价比值得你看一下
  7. Redis4.0之持久化存储
  8. 开发比软件测试好吗,前端开发比软件测试发展好吗?
  9. Git小乌龟合并代码
  10. 大数据学长面试之华为面试题
  11. cad调了比例因子没反应_10个常见cad问题的解决方法!学会了这几招不再求人
  12. 微信视频通话怎么美颜
  13. Gartner:VPT技术原理 ——如何确定网络攻击面上的风险优先级
  14. Shader实现马赛克
  15. 四种编程命名规则:驼峰命名法,帕斯卡命名法,匈牙利命名法,下划线命名法
  16. 互斥锁、临界区和事件
  17. PacketTracer使用及网络测试命令
  18. android6支持内存卡,诺基亚6可以插内存卡吗 Nokia 6支持内存卡扩展吗
  19. 购买mysql服务器时需要考虑的问题
  20. jade怎么查计算机用户名,干货 | 黄继武老师手把手教你利用Jade进行物相检索

热门文章

  1. oracle PL/SQL(procedure language/SQL)程序设计(在PL/SQL中使用SQL)
  2. Delphi学习之函数 ⑨汉字拼音功能函数
  3. 检查用户是否有访问权限
  4. [转载] Java中为什么要有重载现象
  5. 关于这个错误的不明原因的解决之道
  6. BZOJ.5093.[Lydsy1711月赛]图的价值(NTT 斯特林数)
  7. BZOJ3295 [Cqoi2011]动态逆序对 分治 树状数组
  8. hive-0.11.0安装方法具体解释
  9. scala学习--难点
  10. 推荐算法和机器学习入门