android 上传图片到后端,刚开始学android 感觉好难啊,一步一个坑,而且网上的大多数资料都很老,安卓更新的又快,不像javaweb开发,不用管发布年限,找到方法就行,android这玩意有的方法启用了等等特麻烦android转androidx啊,对新手特不友好,废话少说,开始进入正题

 

 

第一步引入网络
   //请求网络相关
    //okhttp
    //https://github.com/square/okhttp
    implementation 'com.squareup.okhttp3:okhttp:4.2.0'

    //用来打印okhttp请求日志
    //当然也可以自定义
    implementation("com.squareup.okhttp3:logging-interceptor:4.2.0")

    //retrofit
    //https://github.com/square/retrofit
    implementation 'com.squareup.retrofit2:retrofit:2.6.2'

    //使用gson解析json
    //https://github.com/google/gson
    implementation 'com.google.code.gson:gson:2.8.5'

    //适配retrofit使用gson解析
    //版本要和retrofit一样
    implementation 'com.squareup.retrofit2:converter-gson:2.6.2'

    //适配retrofit支持rxjava
    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.2'

    //使用了Android响应式编程
    //RxJava和RxAndroid区别?
    //简单来说:就是RxAndroid在RxJava的基础上
    //优化了一些功能
    //增强了Android特有的功能
    //https://github.com/ReactiveX/RxAndroid
    implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
    //end 请求网络相关
<!-- 网络权限 -->
    <uses-permission android:name="android.permission.INTERNET" />

加入 
android:usesCleartextTraffic="true"  不然无法访问网络
封装网络接口
定义一个api


package com.ynrd.tycoon.api;


import com.ynrd.tycoon.domain.Ad;
import com.ynrd.tycoon.domain.Session;
import com.ynrd.tycoon.domain.User;
import com.ynrd.tycoon.domain.UserMessage;
import com.ynrd.tycoon.domain.response.DetailResponse;
import com.ynrd.tycoon.domain.response.ListResponse;
import com.ynrd.tycoon.utils.Constant;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

public class Api {

    private final Service service;

    /**
     * 返回当前对象的唯一实例
     *
     * 单例设计模式
     * 由于移动端很少有高并发
     * 所以这个就是简单判断
     *
     * @return
     */
    public static Api getInstance() {
        Api instance = null;
        if (instance == null){
            instance = new Api();
        }
        return instance;
    }

    public Api() {
        //初始化okhttp
        OkHttpClient.Builder okhttpClientBuilder = new OkHttpClient.Builder();

        //初始化retrofit
        Retrofit retrofit = new Retrofit.Builder()
                //让retrofit使用okhttp
                .client(okhttpClientBuilder.build())

                //api地址
                .baseUrl(Constant.ENDPOINT)

                //适配rxjava
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

                //使用gson解析json
                //包括请求参数和响应
                .addConverterFactory(GsonConverterFactory.create())

                //创建retrofit
                .build();

        //创建service
        service = retrofit.create(Service.class);
    }

    /**
     * 用户注册
     * @param user
     * @return
     */
    public Observable<DetailResponse<Session>> register(User user){
        return service.register(user)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 用户注册
     * @param user
     * @return
     */
    public Observable<DetailResponse<Session>> perfectMessage(UserMessage user){
        return service.perfectMessage(user)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 上传头像
     * @param file
     * @return
     */
    public Observable<DetailResponse<Session>> updateImage(RequestBody file){
        return service.updateImage(file)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }
    /**
     * 发送验证码
     * @return
     */
    public Observable<DetailResponse<Session>> verificationCode(User user){
        return service.verificationCode(user)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }


    public Observable<DetailResponse<Session>> login(User user){
        return service.login(user)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * 广告列表
     * @return
     */
    public Observable<ListResponse<Ad>> ads(){
        return service.ads()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

}
定义接口

package com.ynrd.tycoon.api;

import com.ynrd.tycoon.domain.Ad;
import com.ynrd.tycoon.domain.Session;
import com.ynrd.tycoon.domain.User;
import com.ynrd.tycoon.domain.UserMessage;
import com.ynrd.tycoon.domain.response.DetailResponse;
import com.ynrd.tycoon.domain.response.ListResponse;

import io.reactivex.Observable;
import okhttp3.MultipartBody;
import okhttp3.RequestBody;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Multipart;
import retrofit2.http.POST;
import retrofit2.http.Part;

public interface Service {

    /**
     * 用户注册
     * @param data
     * @return
     */
    @POST("userdata/register")
    Observable<DetailResponse<Session>> register(@Body User data);


    /**
     * 登录
     * @param data
     * @return
     */
    @POST("v1/sessions")
    Observable<DetailResponse<Session>> login(@Body User data);

    /**
     * 广告列表
     * @return
     */
    @GET("v1/ads")
    Observable<ListResponse<Ad>> ads();

    /**
     * 发送验证码
     * @param user
     * @return
     */
    @POST("userdata/sendSmsValid")
    Observable<DetailResponse<Session>> verificationCode(@Body User user);

    /**
     * 完善用户信息
     * @param user
     * @return
     */
    @POST("userdata/perfectMessage")
    Observable<DetailResponse<Session>> perfectMessage(@Body UserMessage user);

    /**
     * 上传头像
     * @param file
     * @return
     */

    @POST("userdata/updateImage")
    Observable<DetailResponse<Session>> updateImage(@Body RequestBody file);

}

在方法里调用请求

private void UpLoadIcon(File file) {
        
        //传值
        MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("id", "15")
                .addFormDataPart("name", "name");
        //如果是多个file[]
        builder.addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
        RequestBody requestBody = builder.build();
        Api.getInstance().updateImage(requestBody)
                .subscribe(new HttpObserver<DetailResponse<Session>>() {
            @Override
            public void onSucceeded(DetailResponse<Session> data) {
                //成功走这里
            }
        });

    }

如果上传多个 参考
https://www.jianshu.com/p/e4a7478689ce

之后是我定义的返回类型和错误判断

package com.ynrd.tycoon.listener;



import com.ynrd.tycoon.activity.BaseCommonActivity;
import com.ynrd.tycoon.domain.response.BaseResponse;
import com.ynrd.tycoon.utils.HttpUtil;
import com.ynrd.tycoon.utils.LoadingUtil;

import io.reactivex.disposables.Disposable;
import retrofit2.Response;

/**
 * 网络请求observer
 * @param <T>
 */
public abstract class HttpObserver<T> extends ObserverAdapter<T> {
    private static final String TAG = "HttpObserver";

    /**
     * 是否显示加载对话框
     */
    private boolean isShowLoading;
    /**
     * 界面
     */
    private BaseCommonActivity activity;

    /**
     * 无参构造方法
     */
    public HttpObserver (){

    }

    /**
     * 构造方法
     * @param activity
     * @param isShowLoading
     */
    public HttpObserver(BaseCommonActivity activity, boolean isShowLoading){
        this.activity = activity;
        this.isShowLoading = isShowLoading;
    }

    /**
     * 请求成功
     * @param data
     */
    public abstract void onSucceeded(T data);

    /**
     * 请求失败
     * @param data
     * @param e
     * @return
     */
    public boolean onFailed(T data,Throwable e){
        return false;
    }

    @Override
    public void onSubscribe(Disposable d) {
        super.onSubscribe(d);
        if (isShowLoading){
            LoadingUtil.showLoading(activity);
        }
    }

    @Override
    public void onNext(T t) {
        super.onNext(t);

        //检查是否需要隐藏加载提示框
        checkHideLoading();
        if (isSucceeded(t)){
            //请求正常
            onSucceeded(t);
        }else{
            handlerRequest(t,null);
        }
    }

    @Override
    public void onError(Throwable e) {
        super.onError(e);
       // LogUtil.d(TAG, "onError:" + e.getLocalizedMessage());

        //检查是否需要隐藏加载提示框
        checkHideLoading();

        //处理错误
        handlerRequest(null, e);
    }

    /**
     * 网络请求是否成功了
     *
     * @param t
     * @return
     */
    private boolean isSucceeded(T t) {
        if (t instanceof Response) {
            //retrofit里面的响应对象

            //获取响应对象
            Response response = (Response) t;

            //获取响应码
            int code = response.code();

            //判断响应码
            if (code >= 200 && code <= 299) {
                //网络请求正常
                return true;
            }

        } else if (t instanceof BaseResponse) {
            //判断具体的业务请求是否成功
            BaseResponse response = (BaseResponse) t;

            //状态码为200表示成功
            //这是我们和服务端的一个规定
            return response.getStatus() == 200;
        }

        return false;
    }

    /**
     * 处理错误网络请求
     *
     * @param data
     * @param error
     */
    private void handlerRequest(T data, Throwable error) {
        if (onFailed(data, error)) {
            //回调了请求失败方法
            //并且该方法返回了true

            //返回true就表示外部手动处理错误
            //那我们框架内部就不用做任何事情了
        } else {
            HttpUtil.handlerRequest(data, error);
        }

    }

    /**
     * 检查是否需要隐藏加载提示框
     */
    private void checkHideLoading() {
        if (isShowLoading) {
            LoadingUtil.hideLoading();
        }
    }
}
package com.ynrd.tycoon.listener;

import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;

/**
 * 通用实现observer里面的方法
 * @param <T>
 */
public class ObserverAdapter<T> implements Observer<T> {
    /**
     * 开始定义了执行
     * @param d
     */
    @Override
    public void onSubscribe(Disposable d) {

    }

    /**
     * 当前observer
     * @param t
     */
    @Override
    public void onNext(T t) {

    }

    /**
     * 执行失败了
     * @param e
     */
    @Override
    public void onError(Throwable e) {

    }

    /**
     * 调用onNext方法后调用
     */
    @Override
    public void onComplete() {

    }
}
package com.ynrd.tycoon.domain.response;

/**
 * 通用网络请求响应模型
 */
public class BaseResponse {

    /**
     * 状态码
     * 只有发生了错误才会有值
     */
    private int status;
    /**
     * 出错的提示信息
     * 发生了错误不一定有
     */
    private String message;

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
package com.ynrd.tycoon.domain.response;

/**
 * 通用网络请求响应模型
 */
public class BaseResponse {

    /**
     * 状态码
     * 只有发生了错误才会有值
     */
    private int status;
    /**
     * 出错的提示信息
     * 发生了错误不一定有
     */
    private String message;

    public Integer getStatus() {
        return status;
    }

    public void setStatus(Integer status) {
        this.status = status;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
package com.ynrd.tycoon.domain.response;

/**
 * 详情网络请求解析类
 * 继承BaseResponse
 * 定义了一个泛型T
 * @param <T>
 */
public class DetailResponse<T> extends BaseResponse {
    /**
     * 真实的数据 类型是泛型
     */
    private T data;

    private String msg;


    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}
package com.ynrd.tycoon.domain.response;

import java.util.List;

/**
 * 解析列表网络请求
 * @param <T>
 */
public class ListResponse<T> extends BaseResponse {
    /**
     * 定义一个列表
     * 里面的对象使用了泛型
     */
    private List<T> data;

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }
}

 

 

package com.ynrd.tycoon.utils;

import com.ynrd.tycoon.BuildConfig;

public class Constant {

    /**
     * 端口
     */
    public static final String ENDPOINT = BuildConfig.ENDPOINT;

    public static final String RESOURCE_ENDPOINT = BuildConfig.RESOURCE_ENDPOINT;

}
//配置不同的环境
    productFlavors {
        //开发环境
        dev {
            buildConfigField('String', "ENDPOINT", '"http://192.168.1.124"')
            //资源断点
            //资源端点
            buildConfigField 'String', 'RESOURCE_ENDPOINT', '"http://dev-courses-misuc.ixuea.com/%s"'
            dimension = minSdkVersion
        }

        //正式环境
        prod {
            //API端点
            buildConfigField 'String', 'ENDPOINT', '"http://api-courses-misuc.ixuea.com/"'
            //资源断点
            //资源端点
            buildConfigField 'String', 'RESOURCE_ENDPOINT', '"http://dev-courses-misuc.ixuea.com/%s"'

            dimension = minSdkVersion
        }


    }

 

fleet跑springboot项目_User

fleet跑springboot项目_ide_02

 

加入这段话不然会报错

 


flavorDimensions "versionCode"


没看明白的同学可以都复制到自己项目里试一试,都复制进去应该可以运行成功,有问题可以留言解决

springboot如何接收

/**
     * 接收安卓图片接口
     * @param request
     * @return
     */
    @RequestMapping(value = "/updateImage", method = RequestMethod.POST)
    @ResponseBody
    public JSONResult handleFileUpload(HttpServletRequest request) {
        MultipartHttpServletRequest params=((MultipartHttpServletRequest) request);
        List<MultipartFile> files = ((MultipartHttpServletRequest) request)
                .getFiles("file");
        String name=params.getParameter("name");
        System.out.println("name:"+name);
        String id=params.getParameter("id");
        System.out.println("id:"+id);
        MultipartFile file = null;
        BufferedOutputStream stream = null;
        for (int i = 0; i < files.size(); ++i) {
            file = files.get(i);
            if (!file.isEmpty()) {
                try {
                    String filePath = Global.getUploadPath();
                    // 上传并返回新文件名称
                    String fileName = FileUploadUtils.upload(filePath, file);
                    String url = serverConfig.getUrl() + fileName;
                    System.out.println(url);
                } catch (Exception e) {
                    stream = null;
                    return JSONResult.errorMsg("服务器异常");
                }
            } else {
                return JSONResult.errorMsg("图片上传失败");
            }
        }
        return JSONResult.build(500,"没有上传图片",new User());
    }