• 通过android 客户端上传图片到服务器


    昨天,(在我的上一篇博客中)写了通过浏览器上传图片到服务器(php),今天将这个功能付诸实践.(还完善了服务端的代码)

    不试不知道,原来通过android 向服务端发送图片还真是挺麻烦的一件事.

    上传代码:

    /* 上传文件至Server的方法 */
        private void uploadFile()
        {
            String end = "
    ";
            String twoHyphens = "--";
            String boundary = "*****";
            try
            {
                URL url = new URL(postUrl);
                HttpURLConnection con = (HttpURLConnection) url.openConnection();
              /* Output to the connection. Default is false,
                 set to true because post method must write something to the connection */
                con.setDoOutput(true);
              /* Read from the connection. Default is true.*/
                con.setDoInput(true);
              /* Post cannot use caches */
                con.setUseCaches(false);
              /* Set the post method. Default is GET*/
                con.setRequestMethod("POST");
              /* 设置请求属性 */
                con.setRequestProperty("Connection", "Keep-Alive");
                con.setRequestProperty("Charset", "UTF-8");
                con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
              /*设置StrictMode 否则HTTPURLConnection连接失败,因为这是在主进程中进行网络连接*/
                StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder().detectDiskReads().detectDiskWrites().detectNetwork().penaltyLog().build());
              /* 设置DataOutputStream,getOutputStream中默认调用connect()*/
                DataOutputStream ds = new DataOutputStream(con.getOutputStream());  //output to the connection
                ds.writeBytes(twoHyphens + boundary + end);
                ds.writeBytes("Content-Disposition: form-data; " +
                        "name="file";filename="" +
                        fileName + """ + end);
                ds.writeBytes(end);
              /* 取得文件的FileInputStream */
                FileInputStream fStream = new FileInputStream(uploadFile);
              /* 设置每次写入8192bytes */
                int bufferSize = 8192;
                byte[] buffer = new byte[bufferSize];   //8k
                int length = -1;
              /* 从文件读取数据至缓冲区 */
                while ((length = fStream.read(buffer)) != -1)
                {
                /* 将资料写入DataOutputStream中 */
                    ds.write(buffer, 0, length);
                }
                ds.writeBytes(end);
                ds.writeBytes(twoHyphens + boundary + twoHyphens + end);
              /* 关闭流,写入的东西自动生成Http正文*/
                fStream.close();
              /* 关闭DataOutputStream */
                ds.close();
              /* 从返回的输入流读取响应信息 */
                InputStream is = con.getInputStream();  //input from the connection 正式建立HTTP连接
                int ch;
                StringBuffer b = new StringBuffer();
                while ((ch = is.read()) != -1)
                {
                    b.append((char) ch);
                }
              /* 显示网页响应内容 */
    //            Toast.makeText(MainActivity.this, b.toString().trim(), Toast.LENGTH_SHORT).show();//Post成功
                System.out.println(b.toString());
            } catch (Exception e)
            {
                /* 显示异常信息 */
    //            Toast.makeText(MainActivity.this, "Fail:" + e, Toast.LENGTH_SHORT).show();//Post失败
                System.out.println(e);
            }
        }

    上篇博文有说上传图片必须使用POST方法,这里当然使用的就是post方法.这里上传跟普通上传写法没啥变化.

    不过我还是不习惯使用这个方法(我一直使用volley框架, 有兴趣可以百度一下.一个官方推出的很好用的框架,要不是需要用到传图我还不会研究这个写法)

    使用原生POST方法的基本步骤:

      1.使用 HttpURLConnection 建立连接

      2.设置请求属性

      3.根据请求格式组装参数(很麻烦 , 可以通过浏览器发送POST请求,取出调试信息对比)

      4.建立输入流,并写入数据(FileInputStream 和下面循环写入哪里)

      5.获取返回流,并处理返回参数

      6.关闭所有流

    该部分代码几乎完全借鉴大神的写法.里面注释也很多我也不多说了.

    值得一提的是在4.0(android 版本)以后就已经不支持在主线程中执行上传,下载等耗时操作了.

    这也很合理,假如你在上传文件的时候,突然你的网络不好,你就会一直在上传状态.体验很不好.

    所以调用上面的方法需要新建一个线程:

     new Thread(new Runnable() {
                        @Override
                        public void run() {
                            uploadFile();
                        }
                    }).start();

    这个调用方法是在上传方法与该方法同文件时可以这样写,如果上传方法在独立的class文件中需要先实例化然后通过

    实例化对象名.uploadFile();

    的方法调用.

    服务器端

      上篇博文里面只是简单的实现了,接收并转存图片.这里对该服务端进行完善:

    <?php
    /**
     * 接收上传的图片
     * 
     * ------------
     * 200 ok
     * 401 Error method
     * 500 Internal error
     * ------------
     */
    // ini_set("display_errors", "On");
    // error_reporting(E_ALL | E_STRICT);
    header('Access-Control-Allow-Origin: *');   // 解决前段javascript跨域请求
    
    $fileInfo = $_FILES['file'];
    $maxSize=2097152;//允许的最大值
    
    $allowExt=array('jpeg','jpg','png','gif','wbmp');
    $flag=true;//检测是否为真实图片类型
    
    if($fileInfo['error']==0){
        //判断上传文件的大小
        
        if($fileInfo['size']>$maxSize){
            $data = '上传文件过大';
            
            return Response::show(201,'error1', $data);
            
            exit();
        }
        //$ext=strtolower(end(explode('.',$fileInfo['name'])));获取后缀
        
        $ext=pathinfo($fileInfo['name'],PATHINFO_EXTENSION);
        if(!in_array($ext,$allowExt)){
            
            $data = '非法文件类型';
            
            return Response::show(202 , 'error2' , $data);
            
            exit();
            
        }
        //判断文件是否是通过HTTP POST方式上传来的
        
        if(!is_uploaded_file($fileInfo['tmp_name'])){
            
            $data = '文件不是通过HTTP POST方式上传来的';
            
            return Response::show(203 , 'error3' , $data);
            
            exit();
        }
        //检测是否为真实的图片类型
        
        if($flag){
            if(!getimagesize($fileInfo['tmp_name'])){
                
            $data = '不是真正图片类型';
                
            return Response::show(204 , 'error4' , $data);
                
            exit();
            
                
            }
        }
        
        //创建与id对应的文件夹 
        
        $id = $_GET['id'];
        if(!file_exists($id)){
            mkdir('../files/'.$id);
            //chmod($id , 0777);
        }
        
        if(@move_uploaded_file($fileInfo['tmp_name'],'../files/'.$id.'/'.$fileInfo['name'])){
            $data = '文件上传成功';
                
             return Response::show(200 , 'ok' , $data);
             
        }else{
            $data = '文件上传失败';
                
             return Response::show(404 , 'error5' , $data);
        }
    }else{
        switch($fileinfo['error']){
            case 1:
                $data = '上传文件超过了PHP配置文件中upload_max_filesize选项的值';
                
                return Response::show(401 , 'error5' , $data);
                
                break;
                
            case 2:
                
                $data = '超过了表单MAX_FILE_SIZE限制的大小';
                
                return Response::show(402 , 'error5' , $data);
                
                break;
            case 3:
                
                $data = '文件部分被上传';
                
                return Response::show(403 , 'error5' , $data);
                
                break;
            case 4:
            
                $data = '没有选择上传文件';
                
                return Response::show(405 , 'error5' , $data);
                
                break;
            case 6:
                
                $data = '没有找到临时目录';
                
                return Response::show(405 , 'error5' , $data);
                
                break;
            case 7:
            case 8:
                
                $data = '系统错误';
                
                return Response::show(405 , 'error5' , $data);
                
                break;
        }
    }

    这里对图片进行了各种检测.比昨天的更可靠了是吧.还统一了返回的json格式方便客户端进行解析.(还有就是,上面的服务端的代码也是借鉴了慕课大神的写法,略作修改)

  • 相关阅读:
    用户之间imp的问题
    Java的面向AOP编程
    【Samza系列】实时计算Samza中文教程(四)—API概述
    Objective-C基础笔记(8)Foundation经常使用类NSString
    多校第六场 HDU 4927 JAVA大数类+模拟
    走进windows编程的世界-----对话框、文本框、button
    mysql中的触发器和事务的操作
    《这个医生不干了:一个名医硕士的十年江湖路》:一个聪明、勤奋、上进、友善的医学硕士在医药广告界的十年打拼,难得的是基本是真事 五星
    《致命接触》:人畜共患传染病的故事,SARS一章非常精彩,四星推荐
    《再造医疗:向最好的医院学管理(实践篇)》离中国情况太远,个案太多,概括总结太少 二星,不推荐 。
  • 原文地址:https://www.cnblogs.com/wobeinianqing/p/5484035.html
Copyright © 2020-2023  润新知