突然接到实验室的活,自己也好久没有写Android了加上最近真的是太忙了,本想去网上随便找代码把这个活完成去做自己的事情来着,毕竟网上代码的年代都有些古老,Android的版本不一样,给的东西也不全,所以也是一拖再拖,最后还是自己静下心来慢慢看代码,慢慢解决问题解决的。

这是我的Android studio版本信息

android 图片上传服务器压缩 安卓上传图片到服务器_Text


下面是代码

一、 xml布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scrollbars="none">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">

            <LinearLayout
                android:id="@+id/activity_main"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="添加图片:"
                    android:textSize="20dp"/>

                <ImageView
                    android:id="@+id/imageView"
                    android:layout_width="match_parent"
                    android:layout_height="300dp"
                    />
                <LinearLayout
                    android:layout_gravity="center"
                    android:layout_width="wrap_content"
                    android:layout_height="match_parent"
                    android:orientation="horizontal">
                    <Button
                        android:id="@+id/take_photo"
                        android:layout_width="wrap_content"
                        android:layout_height="wrap_content"
                        android:background="@mipmap/paizhao" />
                    <Button
                        android:id="@+id/choose_image"
                        android:layout_width="wrap_content"
                        android:layout_height="match_parent"
                        android:background="@mipmap/xiangce" />
                </LinearLayout>
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="生长性描述:"
                    android:textSize="20dp" />

                <EditText
                    android:id="@+id/Picture_GrowExpre"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="请输入生长性描述"
                    android:inputType="textMultiLine"
                    android:minLines="5" />
            </LinearLayout>

            <LinearLayout

                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="病虫害描述:"
                    android:textSize="20dp" />

                <EditText
                    android:id="@+id/Picture_DiseaseExpre"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="请输入病虫害描述"
                    android:inputType="textMultiLine"
                    android:minLines="5" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:orientation="vertical">

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:text="异常性描述:"
                    android:textSize="20dp" />

                <EditText
                    android:id="@+id/Picture_AbnormalExpre"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="请输入异常性描述"
                    android:inputType="textMultiLine"
                    android:minLines="5" />
            </LinearLayout>
            <Button
                android:id="@+id/submit"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:text="提交" />
        </LinearLayout>
    </ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>

二、 实现代码

package com.example.zhaopian;

import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.ContentValues;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import java.io.ByteArrayOutputStream;
import android.util.Base64;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.RequestParams;


import cz.msebera.android.httpclient.Header;
@SuppressLint("NewApi")
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ProgressDialog prgDialog;

    private int RESULT_LOAD_IMG = 1;
    private RequestParams params = new RequestParams();
    private String encodedString;
    private Bitmap bitmap;
    private String imgPath;
    private Button submit;

    private EditText Picture_GrowExpre;
    private EditText Picture_DiseaseExpre;
    private EditText Picture_AbnormalExpre;


//下面是拍照
    private int SELECT_PIC_BY_TACK_PHOTO = 99;
    private Uri photoUri;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        prgDialog= new ProgressDialog(this);
        prgDialog.setCancelable(false);

        Picture_GrowExpre = findViewById(R.id.Picture_GrowExpre);
        Picture_DiseaseExpre = findViewById(R.id.Picture_DiseaseExpre);
        Picture_AbnormalExpre = findViewById(R.id.Picture_AbnormalExpre);

        findViewById(R.id.submit).setOnClickListener(this);
        findViewById(R.id.choose_image).setOnClickListener(this);
        findViewById(R.id.take_photo).setOnClickListener(this);
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.choose_image://从相册选照片
                loadImage();break;
            case R.id.take_photo://拍照
                takephoto();break;
            case R.id.submit:
                uploadImage();break;
        }
    }

    public void takephoto() {
        //执行拍照前,应该先判断SD卡是否存在

        //TODO 设置读写权限
        if (Build.VERSION.SDK_INT >= 23) {
            int REQUEST_CODE_CONTACT = 101;
            String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
            //验证是否许可权限
            for (String str : permissions) {
                if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
                    //申请权限
                    this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
                }
            }
        }
        String SDState = Environment.getExternalStorageState();
        if(SDState.equals(Environment.MEDIA_MOUNTED))
        {
            if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions((Activity) MainActivity.this, new String[]{Manifest.permission.CAMERA}, 1);
            } else {
                //权限已经被授予,在这里直接写要执行的相应方法即可
                Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);//"android.media.action.IMAGE_CAPTURE"
                /**
                 * 需要说明一下,以下操作使用照相机拍照,拍照后的图片会存放在相册中的
                 * 这里使用的这种方式有一个好处就是获取的图片是拍照后的原图
                 * 如果不实用ContentValues存放照片路径的话,拍照后获取的图片为缩略图不清晰
                 */
                ContentValues values = new ContentValues();
                photoUri = this.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
                intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, photoUri);
                /**-----------------*/
                startActivityForResult(intent,SELECT_PIC_BY_TACK_PHOTO);
            }
        }else{
            Toast.makeText(this,"内存卡不存在", Toast.LENGTH_LONG).show();
        }

    }

    public void loadImage() {
        //TODO 设置读写权限
        if (Build.VERSION.SDK_INT >= 23) {
            int REQUEST_CODE_CONTACT = 101;
            String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
            //验证是否许可权限
            for (String str : permissions) {
                if (this.checkSelfPermission(str) != PackageManager.PERMISSION_GRANTED) {
                    //申请权限
                    this.requestPermissions(permissions, REQUEST_CODE_CONTACT);
                }
            }
        }
       //这里就写了从相册中选择图片,相机拍照的就略过了
        Intent galleryIntent = new Intent(Intent.ACTION_PICK,
                android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
        startActivityForResult(galleryIntent, RESULT_LOAD_IMG);
    }
    //当图片被选中的返回结果
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        try {
            //这是从相机选择
            if (requestCode == RESULT_LOAD_IMG && resultCode == RESULT_OK && null != data ) {
                Uri selectedImage = data.getData();
                String[] filePathColumn = { MediaStore.Images.Media.DATA };
                // 获取游标
                Cursor cursor = getContentResolver().query(selectedImage, filePathColumn, null, null, null);
                cursor.moveToFirst();
                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                imgPath = cursor.getString(columnIndex);
                //4.0以上的版本会自动关闭 (4.0--14;; 4.0.3--15)
                if(Integer.parseInt(Build.VERSION.SDK) < 14)
                {
                    //只有4.0以下才需要手动关闭
                    cursor.close();
                }
                ImageView imgView = (ImageView) findViewById(R.id.imageView);
                imgView.setImageBitmap(BitmapFactory.decodeFile(imgPath));
            }
            //这是用相机拍照
            if (requestCode == SELECT_PIC_BY_TACK_PHOTO && resultCode == RESULT_OK) {
                String[] pojo = {MediaStore.Images.Media.DATA};
                Cursor cursor = managedQuery(photoUri, pojo, null, null,null);
                cursor.moveToFirst();
                if(cursor != null )
                {
                    int columnIndex = cursor.getColumnIndexOrThrow(pojo[0]);
                    String picPath="";
                    imgPath = cursor.getString(columnIndex);
                    //4.0以上的版本会自动关闭 (4.0--14;; 4.0.3--15)
                    if(Integer.parseInt(Build.VERSION.SDK) < 14)
                    {
                        //只有4.0以下才需要手动关闭
                        cursor.close();
                    }
                    ImageView imgView = (ImageView) findViewById(R.id.imageView);
                    imgView.setImageBitmap(BitmapFactory.decodeFile(imgPath));
                } else{
                    Toast.makeText(this, "选择图片文件不正确", Toast.LENGTH_LONG).show();
                }
            }
        } catch (Exception e) {
            Toast.makeText(this, "Something went wrong", Toast.LENGTH_LONG).show();
        }
    }

    //开始上传图片
    private void uploadImage() {
        if (imgPath != null && !imgPath.isEmpty()) {
            prgDialog.setMessage("Converting Image to Binary Data");
            prgDialog.show();
            encodeImagetoString();
        } else {
            Toast.makeText(getApplicationContext(), "You must select image from gallery before you try to upload",
                    Toast.LENGTH_LONG).show();
        }
    }


    public void encodeImagetoString() {
        new AsyncTask<Void, Void, String>() {

            protected void onPreExecute() {

            };

            @Override
            protected String doInBackground(Void... params) {
                BitmapFactory.Options options = null;
                options = new BitmapFactory.Options();
                options.inSampleSize = 3;
                bitmap = BitmapFactory.decodeFile(imgPath,
                        options);

                ByteArrayOutputStream stream = new ByteArrayOutputStream();
                // 压缩图片
                bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);// 质量压缩方法,这里100表示不压缩,把压缩后的数据存放到baos中

                while (stream.toByteArray().length / 1024 > 1024*2) { // 循环判断如果压缩后图片是否大于100kb,大于继续压缩
                    stream.reset();// 重置stream即清空stream
                    bitmap.compress(Bitmap.CompressFormat.JPEG, 80, stream);// 这里压缩options%,把压缩后的数据存放到baos中
                }

                byte[] byte_arr = stream.toByteArray();
                // Base64图片转码为String
                encodedString = Base64.encodeToString(byte_arr, 0);
                return "";
            }

            @Override
            protected void onPostExecute(String msg) {
                prgDialog.setMessage("Calling Upload");
                // 将转换后的图片添加到上传的参数中
                params.put("image", encodedString);
                params.put("imagePath", imgPath);
                params.put("Picture_GrowExpre", Picture_GrowExpre.getText().toString());
                params.put("Picture_DiseaseExpre", Picture_DiseaseExpre.getText().toString());
                params.put("Picture_AbnormalExpre", Picture_AbnormalExpre.getText().toString());
                // 上传图片
                imageUpload();
            }
        }.execute(null, null, null);
    }

    public void imageUpload() {
        prgDialog.setMessage("Invoking JSP");
        String url = "http://39.99.159.184:8080/upload_war/cucumber_picture_uploadimg.jsp";
        AsyncHttpClient client = new AsyncHttpClient();
        client.post(url, params, new AsyncHttpResponseHandler() {
            @Override
            public void onSuccess(int statusCode, Header[] headers, byte[] bytes) {
                prgDialog.hide();
                Toast.makeText(getApplicationContext(), "upload success", Toast.LENGTH_LONG).show();
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] bytes, Throwable throwable) {
                prgDialog.hide();
                if (statusCode == 404) {
                    Toast.makeText(getApplicationContext(),
                            "Requested resource not found", Toast.LENGTH_LONG).show();
                }
                // 当 Http 响应码'500'
                else if (statusCode == 500) {
                    Toast.makeText(getApplicationContext(),
                            "Something went wrong at server end", Toast.LENGTH_LONG).show();
                }
                // 当 Http 响应码 404, 500
                else {
                    Toast.makeText(
                            getApplicationContext(), "Error Occured n Most Common Error: n1. Device " +
                                    "not connected to Internetn2. Web App is not deployed in App servern3." +
                                    " App server is not runningn HTTP Status code : "
                                    + statusCode, Toast.LENGTH_LONG).show();
                }
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (prgDialog != null) {
            prgDialog .dismiss();
        }
    }
}

三、用到依赖

implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'androidx.appcompat:appcompat:1.0.2'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.0'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
    implementation 'cz.msebera.android:httpclient:4.3.6'
    implementation 'com.loopj.android:android-async-http:1.4.9'
    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

四、Android端需要获取的权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:uses-permissionandroid="http://schemas.android.com/tools"
    package="com.example.zhaopian">

    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.INTERNET"/>

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme"
        android:requestLegacyExternalStorage="true">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

五、服务器代码

1.jsp代码

<%@page import="com.eric.UploadImage"%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>图片上传</title>
</head>
<body>

<%
    String imgEncodedStr = request.getParameter("image");
    String imgPath = request.getParameter("imagePath");
    String picture_GrowExpre = request.getParameter("Picture_GrowExpre");
    String Picture_DiseaseExpre = request.getParameter("Picture_DiseaseExpre");
    String picture_AbnormalExpre = request.getParameter("Picture_AbnormalExpre");
    System.out.println("Filename: "+ imgPath);
    if(imgEncodedStr != null){
        UploadImage.convertStringtoImage(imgEncodedStr, imgPath,request,picture_GrowExpre,Picture_DiseaseExpre,picture_AbnormalExpre);
        out.print("Image upload complete, Please check your directory");
    } else{
        out.print("Image is empty");
    }
%>
</body>
</html>

2.java代码

package com.eric;

import com.utils.JdbcUtil;
import org.apache.commons.codec.binary.Base64;

import javax.servlet.http.HttpServletRequest;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.*;

public class UploadImage {

    public static void convertStringtoImage(String encodedImageStr, String fileName,HttpServletRequest request,String picture_GrowExpre,String Picture_DiseaseExpre,String picture_AbnormalExpre){

        try {
            // Base64解码图片
            byte[] imageByteArray = Base64.decodeBase64(encodedImageStr);

            /**
             * 获取当前相对路径,将图片存到服务器img文件夹下面
             * */
            String contextPath = request.getContextPath()+"/img";
            System.out.println(contextPath+"----------");
            //
            String[] idArry = fileName.trim().split("\\ ");
            String imagePath =  "D:/uploads/" + idArry[idArry.length-1];
            // FileOutputStream imageOutFile = new FileOutputStream(contextPath);
            FileOutputStream imageOutFile = new FileOutputStream(imagePath);
            imageOutFile.write(imageByteArray);
            imageOutFile.close();
            //将图片信息写入数据库
            Connection connection = JdbcUtil.getConnection();
            PreparedStatement preparedStatement = null;
            String sql = "insert into cucumber_picture values(null,?,?,?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1,"1");
            preparedStatement.setString(2,picture_GrowExpre);
            preparedStatement.setString(3,Picture_DiseaseExpre);
            preparedStatement.setString(4,picture_AbnormalExpre);
            int i = preparedStatement.executeUpdate();
            JdbcUtil.close(connection);
            connection.close();
            if(i>0){
                System.out.println("Image Successfully Stored");
            }
        } catch (FileNotFoundException fnfe) {
            System.out.println("Image Path not found" + fnfe);
        } catch (IOException ioe) {
            System.out.println("Exception while converting the Image " + ioe);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

其中照片已经存到对应的路径里了,我是因为工作需要也放到了服务器里面。

自己遇到的一些问题

自己遇到了很多问题其中印象比较深的发了博客比如:
动态申请读写权限
动态申请打开摄像头等