Android经验和架构Android开发Android知识

Retrofit2.0上传多张图片,PHP接收图片(包含前后端代

2017-04-25  本文已影响395人  alexis_zyp
Kapture 2017-04-25 at 10.55.gif

1.先列出Android端使用的library:


dependencies {
    ...
    compile fileTree(dir: 'libs', include: ['*.jar'])
    compile 'com.android.support:appcompat-v7:23.1.0'
    compile 'com.jakewharton:butterknife:7.0.1'
    compile 'com.squareup:otto:1.3.5'
    compile 'cn.finalteam:galleryfinal:1.4.8.4'
    compile 'com.github.bumptech.glide:glide:3.6.1'
    compile 'com.jcodecraeer:xrecyclerview:1.2.6'
    compile 'com.baoyz.actionsheet:library:1.1.5'
    compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'
    compile 'org.xutils:xutils:3.1.22'
    compile 'io.reactivex:rxjava:1.0.6'
    compile 'io.reactivex:rxandroid:0.23.0'
    compile files('libs/fastjson-1.2.7.jar')
    compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0'
    compile 'com.squareup.retrofit2:converter-gson:2.2.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.2.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
    ...
   
}

Android端代码:

public interface ApiService {

    /**上传单张及多张图片与文本*/
    @Multipart
    @POST("/PHP/uploads.php")
    Observable<Message> updateImages(@PartMap() Map<String, RequestBody> maps);

    /**上传单张及多张图片与文本*/
    @Multipart
    @POST("/PHP/uploads.php")
    Observable<Message> updateImages(@Part("filename") String description, @PartMap() Map<String, RequestBody> maps);


    /**上传单张及多张图片与文本*/
    @Multipart
    @POST("/PHP/uploads.php")
    Observable<Message> updateImages2(@Part MultipartBody.Part[] parts);

    /**上传单张及多张图片与文本*/
    @Multipart
    @POST("/PHP/uploads.php")
    Observable<Message> updateImages2(@Part("description") RequestBody description, @Part("key") String value  ,@Part MultipartBody.Part[] parts);

    /**上传单张图片*/
    @Multipart
    @POST("/PHP/uploads.php")
    Observable<Message> updateImage(
            @QueryMap Map<String, String> usermaps,
            @Part("avatar\"; filename=\"avatar.jpg") RequestBody avatar);

public class Client {

    public static String API_URL = Constant.API_URL;

    public static ExecutorService mExecutorService;

    private static ApiService instance;

    public static ApiService getServiceClient() {
        if (instance == null) {
            synchronized (Client.class) {
                okhttp3.OkHttpClient okHttpClient = new okhttp3.OkHttpClient.Builder()
//                            .addNetworkInterceptor(
//                                    new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
//                            .cookieJar(new NovateCookieManger(context))
//                            .cache(cache)
                            .addInterceptor(new ApiHeaders())
//                            .addInterceptor(new CaheInterceptor(context))
//                            .addNetworkInterceptor(new CaheInterceptor(context))
                            .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                            .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                            .connectionPool(new ConnectionPool(8, 15, TimeUnit.SECONDS))
                            // 这里你可以根据自己的机型设置同时连接的个数和时间,我这里8个,和每个保持时间为10s
                            .build();
                    Retrofit retrofit = new Retrofit.Builder()
                            .client(okHttpClient)
                            .addConverterFactory(GsonConverterFactory.create())
                            .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                            .baseUrl(API_URL)
                            .build();

                    mExecutorService = Executors.newCachedThreadPool();
                    instance = retrofit.create(ApiService.class);
                }
            }
        }
        return instance;
    }

    public static void stopAll() {
        List<Runnable> pendingAndOngoing = mExecutorService.shutdownNow();
    }

    static class ApiHeaders implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Request.Builder builder = request.newBuilder();
            builder.addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
                    .addHeader("User-Agent", "Mozilla/5.0 (Linux; U; Android 4.1.1; zh-cn; HTC One X - 4.1.1 - API 16 - 720x1280 Build/JRO03S) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30")
                    .addHeader("Accept-Encoding", "gzip")
                    .addHeader("Accept", "*/*")
                    .addHeader("Accept-Language", "zh-cn,zh")
                    .addHeader("Authorization", "");

            Request newRequest = builder.build();

            return chain.proceed(newRequest);
        }

    }

上传关键代码:

    public void uploadFiles(List<String> paths) {
//        retrofit1 的上传
//        MultipartTypedOutput multipartTypedOutput = new MultipartTypedOutput();
//        for (String imgPath : paths){
//            multipartTypedOutput.addPart("uploadfile[]", new TypedFile("image/*", new File(imgPath)));
//        }
//        mApi.uploadFiles(multipartTypedOutput)
//                .subscribeOn(Schedulers.computation())
//                .subscribe(response -> handleUploadFile(response), error -> handleFailure(error));

        if (true) { //retrofit2第一种@PartMap() Map<String, RequestBody>方式上传多张图片

            HashMap<String, RequestBody> map = new HashMap<>();
            MultipartBody.Part[] parts = new MultipartBody.Part[paths.size()];
            for (String imgPath : paths) {
                final File file = new File(imgPath);
                map.put("uploadfile[]\"; filename=\"" + file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
            }
            // create a map of data to pass along
            RequestBody tokenBody = RequestBody.create(
                    MediaType.parse("multipart/form-data"), "xxxx");
            map.put("token", tokenBody);
//实测,zyp传过去的值有引号"zyp",所以要用body传值
//            mApi.updateImages(map)
            mApi.updateImages("zyp",map)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(response -> handleUploadFile(response), error -> handleFailure(error));

        } else {//第二种MultipartBody.Part[]方式上传多张图片

            MultipartBody.Part[] parts = new MultipartBody.Part[paths.size()];
            int cnt = 0;
            for (String imgPath : paths) {
                final File file = new File(imgPath);
                RequestBody requestFile = RequestBody.create(MediaType.parse("multipart/form-data"), file);
                MultipartBody.Part filePart = MultipartBody.Part.createFormData("uploadfile[]", file.getName(), requestFile);
                parts[cnt] = filePart;
                cnt++;
            }

            // create a map of data to pass along
            RequestBody body = RequestBody.create(
                    MediaType.parse("multipart/form-data"), "xxxx");

//            mApi.updateImages2(parts)
            //实测,value传过去的值有引号"value",所以要用body传值
            mApi.updateImages2(body,"value", parts)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(response -> handleUploadFile(response), error -> handleFailure(error));

        }
//        //okhttp上传图片
//        RequestBody requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM)
//                .addFormDataPart("name", "zyp")
//                .addFormDataPart("file", file.getName(), RequestBody.create(MediaType.parse("image/*"), file))
//                .build();


    }


    private void handleUploadFile(Message message) {


        //otto事件传递
        mBus.post(message);

    }

//接收事件代码
 @Subscribe //需要注解@Subscribe ,表明在这个函数接收数据
    public void uploadFileResponse(Message msg) {
        Log.i("@@@","uploadFileResponse: "+msg.getMessage());
        Toast.makeText(this, msg.getMessage(), Toast.LENGTH_SHORT).show();
        List<String> imgUrls = msg.getImgUrls();
        if (msg.getCode() == 1) {
            if (choosePhotoListAdapter == null) {
                choosePhotoListAdapter = new ChoosePhotoListAdapter(this, null, imgUrls);
                lvPhotoShow.setAdapter(choosePhotoListAdapter);
            }
            choosePhotoListAdapter.notifyDataSetChanged();
        }
    }

Php端代码:

//初学php,写的比较简单,不太健壮,像图片是否已经上传过,都没有判断,大家自己补充啊^_^

<?php
/**
 * Created by PhpStorm.
 * User: zhangyipeng
 * Date: 16/2/18
 * Time: 下午3:48
 */

$base_path = "./upload_file/"; //接收文件目录
$imgs = array();  //定义一个数组存放上传图片的路径
$isSave = false;
if (!file_exists($base_path)) {
    mkdir($base_path);
}

foreach ($_FILES["uploadfile"]["error"] as $key => $error) {
    if ($error == UPLOAD_ERR_OK) {
        $tmp_name = $_FILES["uploadfile"]["tmp_name"][$key];
        $name = $_FILES["uploadfile"]["name"][$key];
        $uploadfile = $base_path . $name;
        $isSave = move_uploaded_file($tmp_name, $uploadfile);
        if ($isSave){
            $imgs[]=$uploadfile;
        }
    }
}

if ($isSave) {
    $array = array("code" => "1", "message" =>"上传图片成功"
    , "imgUrls" => $imgs);
    echo json_encode($array);
} else {
    $array = array("code" => "0", "message" => "上传图片失败," . $_FILES ['uploadfile'] ['error']
    , "imgUrls" => $imgs);
    echo json_encode($array);
}

其实上传多张图片成功的关键是key(uploadfile)需要带[],即uploadfile[] 。

map.put("uploadfile[]\"; filename=\"" + file.getName(), RequestBody.create(MediaType.parse("image/*"), file));
//下面的这种上传方式其实内部也是拼接成了"uploadfile[]\"; filename=\"" + file.getName()这个字符串
MultipartBody.Part filePart = MultipartBody.Part.createFormData("uploadfile[]", file.getName(), requestFile);


代码资源下载


Paste_Image.png Paste_Image.png Paste_Image.png Paste_Image.png

补充:�PHP环境使用的是MAMP,默认文件所在目录如下,想要测试的可以看看,这里我使用了ln命令的软链接,指向到上图中得目录了,这样就不必把PHP代码放到下图目录下了,指向下就可以了,方便很多。本人对PHP了解不多,就这点小技巧,希望能帮到Android的同学。

php.png
1.超级简单的Android Studio jni 实现(无需命令行)
2.让Android开发者相见恨晚的软件及插件
3.GitHub上一些超炫的Android开源项目推荐
上一篇下一篇

猜你喜欢

热点阅读