超级完整版android 图片上传,包括客户端和后台服务器

想必看到这篇文章你也在网上找了不少的相关博客或代码了,我也是这么过来的,不过我现在已经形成了自己的一套工具

说明:前台用的封装Okhttp上传图片,后台用的springBoot(亲测ssm等框架也可以使用,可能代码会有部分变动,所以后台请酌情借鉴)

图片选择,当然是用第三方框架,好用还方便


第一个是图片选择框架

第二个是图片加载工具


需要引用jitpack的库

具体使用我就不多讲了,gIthub地址--->https://github.com/LuckSiege/PictureSelector

需要注意的是要用到gitbub  demo包里的一个工具类


所以建议你把demo项目下载,里面的具体调用方法和注释写的很详细

但我们不要繁杂的写在一个Activity里,所以我们自己封装,上代码

这是调用相册的方法,具体其他api可以自己依照我的方法往下加方法即可

package com.xqb.photography_app.tool;

import android.app.Activity;

import android.util.Log;

import androidx.core.content.ContextCompat;

import com.luck.picture.lib.PictureSelector;

import com.luck.picture.lib.config.PictureConfig;

import com.luck.picture.lib.config.PictureMimeType;

import com.luck.picture.lib.entity.LocalMedia;

import com.luck.picture.lib.listener.OnResultCallbackListener;

import com.luck.picture.lib.style.PictureWindowAnimationStyle;

import com.xqb.photography_app.R;

import java.util.List;

/*

*create by xqb on 2020/9/8

*/

public class MyPictureSelector{

private static MyPictureSelectormyPictureSelector;

    private MyPictureSelector() {

}

//实现单例

    public static MyPictureSelectorgetInstance() {

if (myPictureSelector ==null) {

synchronized (MyPictureSelector.class) {

if (myPictureSelector ==null) {

return myPictureSelector =new MyPictureSelector();

                }

}

}

return myPictureSelector;

    }

//启动推出动画,demo包里也有具体说明

    private PictureWindowAnimationStylepictureWindowAnimationStyle;

    //具体调用方法

    public void openAlbum(Activity activity,int maxSelectNum,boolean isOneSelect,boolean isCrop,boolean isCircleCrop,boolean isCropBorder,final OnSelectorResult onSelectorResult){

pictureWindowAnimationStyle =new PictureWindowAnimationStyle();

        pictureWindowAnimationStyle.ofAllAnimation(R.anim.picture_anim_up_in, R.anim.picture_anim_down_out);

        int selectionMode;

        if (isOneSelect){

selectionMode=PictureConfig.SINGLE;

        }else{

selectionMode=PictureConfig.MULTIPLE;

        }

PictureSelector.create(activity)

.openGallery(PictureMimeType.ofImage())

.imageEngine(GlideEngine.createGlideEngine())//这是需要用到demo包里的一个工具类

                .theme(R.style.picture_white_style)//style配置demo包里也有

                .maxSelectNum(maxSelectNum)

.selectionMode(selectionMode)//单选 PictureConfig.SINGLE

                .isSingleDirectReturn(true)// 单选模式下是否直接返回,PictureConfig.SINGLE模式下有效

                .isCamera(false)//是否使用相机

                .setPictureWindowAnimationStyle(pictureWindowAnimationStyle)// 自定义相册启动退出动画

                .circleDimmedLayer(isCircleCrop)// 是否圆形裁剪

                .isEnableCrop(isCrop)// 是否裁剪

                .showCropFrame(isCropBorder)// 是否显示裁剪矩形边框 圆形裁剪时建议设为false

                .isCompress(true)// 是否压缩

                .compressQuality(100)// 图片压缩后输出质量 0~ 100

                .synOrAsy(false)//同步true或异步false 压缩 默认同步

//                        .compressSavePath(getPath())//压缩图片保存地址

                .setCropDimmedColor(ContextCompat.getColor(activity, R.color.black80Color))// 设置裁剪背景色值

                .withAspectRatio(1, 1)// 裁剪比例 如16:9 3:2 3:4 1:1 可自定义

//                .renameCompressFile("icon-" + PrefTool.getString(activity, "userPhone", "") + ".jpg")// 重命名压缩文件名、 如果是多张压缩则内部会自动拼上当前时间戳防止重复

                .forResult(new MyResultCallback(onSelectorResult));//自定义回调接口

    }

//因为这里把调用方法写出来了,所以在activity里的OnActivityResult方法里是监听不到的

//这是后需要自己实现回调接口

    public interface OnSelectorResult{

void onResult(List result);

    }

//这是demo里自定义的回调类,我稍作了修改,让它变成具体调用方法的实现回调监听接口

    private static class MyResultCallbackimplements OnResultCallbackListener{

private OnSelectorResultonSelectorResult;

        public MyResultCallback(OnSelectorResult onSelectorResult) {

super();

            this.onSelectorResult=onSelectorResult;

        }

@Override

        public void onResult(List result) {

onSelectorResult.onResult(result);

        }

@Override

        public void onCancel() {

Log.d("----->图片选择", "onCancel: 退出了");

        }

}

}



调用方法

比起demo里的调用方法整洁了不少,看着舒服,尤其是哪个回调接口的实现,我瞬间有自豪的感觉了,哈哈哈哈

result里就是装的图片信息了,如何获取,demo包里也写的清楚,具体我不多说了


最重要的一部要来了,如何上传,因为图片可选一张可选多张,还需携带用户字符信息,上代码

这里的okhttp也是封装了的,带我的大佬写的,感觉还蛮实用,我在他的基础上改成了图片上传请求


public void doGetForPic(String url,JSONObject object, final OkCallback okCallback) {

Log.i("TAG", "" + object.toString());

        final MultipartBody.Builder builder =new MultipartBody.Builder();

        try {

builder.addFormDataPart("data",object.getString("data"));

            JSONArray array=object.getJSONArray("pic");

            for (int i=0;i

JSONObject object1=array.getJSONObject(i);

                //文件路径中文转码,否者会报错

//                StringBuffer stringBuffer = new StringBuffer();

//                for (int j = 0, length = object1.getString("picPath").length(); j < length; j++) {

//                    char c = object1.getString("picPath").charAt(i);

//                    if (c <= '\u001f' || c >= '\u007f') {

//                        stringBuffer.append(String.format("\\u%04x", (int) c));

//                    } else {

//                        stringBuffer.append(c);

//                    }

//                }

                builder.addFormDataPart("img[]",object1.getString("picName"), RequestBody.create(MediaType.parse("image/jpeg"), new File(object1.getString("picPath"))));

            }

}catch (JSONException e) {

e.printStackTrace();

            Log.e("------>图片上传异常",e+"");

        }

RequestBody requestBody = builder.build();

        Request.Builder reqBuilder =new Request.Builder();

        Request request =reqBuilder

.post(requestBody)

.url(url)

.build();

        final Call call =mOkHttpClien.newCall(request);

        call.enqueue(new Callback() {

@Override

            public void onFailure(Call call, final IOException e) {

if (okCallback !=null) {

//切换到主线程

                    mHandler.post(new Runnable() {

@Override

                        public void run() {

okCallback.onFailure(e);

                        }

});

                }

}

@Override

            public void onResponse(Call call, final Response response)throws IOException {

try {

if (response !=null && response.isSuccessful()) {

final String json = response.body().string();

                        if (okCallback !=null) {

Log.i(TAG, "onResponse: " + Thread.currentThread().getName());

                            mHandler.post(new Runnable() {

@Override

                                public void run() {

Log.i(TAG, "onResponse: " + Thread.currentThread().getName());

                                    okCallback.onResponse(json);

                                }

});

return;

                        }

}

}catch (IOException e) {

e.printStackTrace();

                }

if (okCallback !=null) {

mHandler.post(new Runnable() {

@Override

                        public void run() {

okCallback.onFailure(new Exception("请求失败"));

                        }

});

                }

}

});

    }



是不是有点看不懂,其实很好理解,除了上传的参数解析外,其余的操作就是让请求跑在子线程上,请求完成让它回到当前主UI线程


请求调用


private void uploadUserIcon(List result) {

JSONObject object =new JSONObject();

    JSONArray array =new JSONArray();

    try {

for (LocalMedia media : result) {

JSONObject object1 =new JSONObject();

            object1.put("picName", media.getFileName()).put("picPath", media.getCompressPath());

            array.put(object1);

        }

object.put("pic", array);

        object.put("data", new JSONObject()

.put("userPhone", PrefTool.getString(context, "userPhone", ""))

.put("picType", "icon")

.put("userId", PrefTool.getInt(context, "userId", 0)));

    }catch (Exception e) {

e.printStackTrace();

    }

OkhttpUtil.getInstance().doGetForPic(IP.requestPicUrl, object, new OkhttpUtil.OkCallback() {

@Override

        public void onFailure(Exception e) {

e.printStackTrace();

            MyToast.toast(context, ToastTextHelper.okhttpOnFailText);

        }

@Override

        public void onResponse(String json) {

try {

Log.e(TAG, "onResponse: " + json);

                JSONObject responseJson =new JSONObject(json);

                if (responseJson.getBoolean("status")) {

PrefTool.setString(context, "userIcon",responseJson.getString("data"));

                    Picasso.get().load(IP.requestImgUrl + PrefTool.getString(context, "userIcon", "")).transform(new CircleTransform()).into(myInfoIcon);

                }else {

MyToast.toast(context, responseJson.getString("message"));

                }

}catch (JSONException e) {

e.printStackTrace();

                Log.e(TAG, ToastTextHelper.okhttpOnResponseErrText);

            }

}

});

}



后台服务器解析

添加依赖包


然后以下这是写在service层具体实现的代码

@Override

public MapuploadUserIcon(HttpServletRequest request) {

MultipartRequest multipartRequest = (MultipartRequest) request;

    List list = multipartRequest.getFiles("img[]");

    JSONObject requestJson =new JSONObject(request.getParameter("data"));

    System.out.println("图片参数"+requestJson);

    switch (requestJson.getString("picType")) {

case "icon":

MultipartFile file = list.get(0);

            if (file ==null || file.getSize() ==0) {

map.put("status",false);

                map.put("message","文件损坏");

            }else{

String fileName="icon-"+requestJson.getString("userPhone")+".jpg";

                String filePath=iconSavePath+fileName;

                try {

file.transferTo(new File(filePath));

                    UserTb userId=new UserTb();

                    userId.setUserId(requestJson.getInt("userId"));

                    userId.setUserIcon("/myInfoImg/"+fileName);

                    int update =userTbMapper.updateByPrimaryKeySelective(userId);

                    if (update>0){

userTb=userTbMapper.selectByPrimaryKey(requestJson.getInt("userId"));

                        map.put("status",true);

                        map.put("message","图片上传成功");

                        map.put("data",userTb.getUserIcon());

                    }else{

map.put("status",false);

                        map.put("message","图片上传失败");

                    }

}catch (IOException e) {

e.printStackTrace();

                    map.put("status",false);

                    map.put("message","图片上传失败");

                }

}

break;

        case "photo":

break;

    }

return map;

}


基本上就完成了,我因为之前写过一个类似的版本,写起现在这个来就很容易了,所以没有写很多注释,但是代码并不难,所以仔细看,不懂的可以再找我要demo,到时候要的多,我写个demo放github,到此结束

你可能感兴趣的:(超级完整版android 图片上传,包括客户端和后台服务器)