1. 程式人生 > >Android HTTP通訊封裝(包括WebService的呼叫)

Android HTTP通訊封裝(包括WebService的呼叫)

第一個物件:

該物件是呼叫WebService用的一個物件基類。

package Entity;

import com.google.gson.Gson;

import org.json.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.Method;


/**
 * Created by 王彥鵬 on 2017-09-01.
 */

public class BaseEnity {
    public String toString() {
        Gson gson=new Gson();
        return gson.toJson(this);
    }
    public void LoadJson(String jsonStr)
    {
        try {
            JSONObject json = new JSONObject(jsonStr);
            Field[] field = this.getClass().getDeclaredFields(); // 獲取實體類的所有屬性,返回Field陣列

            for (int j = 0; j < field.length; j++) { // 遍歷所有屬性
                String name = field[j].getName(); // 獲取屬性的名字
                name = name.substring(0, 1).toUpperCase() + name.substring(1); // 將屬性的首字元大寫,方便構造get,set方法
                // // 獲取屬性的型別
                try {
                    if (!name.equals("$change") && !name.equals("SerialVersionUID")){
                        Method m = this.getClass().getMethod("set" + name, field[j].getType());
                        String type = field[j].getType().getName();// getGenericType().toString();

                        switch (type) {
                            case "byte": {
                                m.invoke(this, (byte)json.getInt(field[j].getName()));
                                break;
                            }
                            case "int":
                            {
                                m.invoke(this, json.getInt(field[j].getName()));
                                break;
                            }
                            case "char":
                            {
                                m.invoke(this, json.getString(field[j].getName()).charAt(0));
                                break;
                            }
                            case "String":
                            {
                                m.invoke(this, json.getString(field[j].getName()));
                                break;
                            }
                            case "boolean":
                            {
                                m.invoke(this, json.getBoolean(field[j].getName()));
                                break;
                            }
                            case "double":
                            {
                                m.invoke(this, json.getDouble(field[j].getName()));
                                break;
                            }
                            case "long":
                            {
                                m.invoke(this, json.getLong(field[j].getName()));
                                break;
                            }
                            default: {
                                m.invoke(this, json.get(field[j].getName()));
                                break;
                            }
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getPropertyValue(String PName) throws Exception
    {
        Field[] fields = this.getClass().getDeclaredFields(); // 獲取實體類的所有屬性,返回Field陣列
        for (Field field : fields) {
            if (field.getName().equalsIgnoreCase(PName))
            {
                String name = field.getName(); // 獲取屬性的名字
                name = name.substring(0, 1).toUpperCase() + name.substring(1); // 將屬性的首字元大寫,方便構造get,set方法
                Method m = this.getClass().getMethod("get" + name);
                return m.invoke(this);
            }
        }
        return null;
    }
}

第二個物件:

該物件是Http通訊物件的介面封裝。

package Interface;

import org.json.JSONObject;

import Entity.BaseEnity;

/**
 * Created by 王彥鵬 on 2017/9/28.
 */

public interface IHttp extends IInterface {
     String  Get(String url) throws Exception;
     String Post(String url, String postData) throws Exception;
     void Post(String url, String postData,IAsynCallBackListener callback) throws Exception;
     String Post(String url, String postData,IAsynCallBackListener callback,String contentType) throws Exception;
     JSONObject CallWebService(String url, String IName, BaseEnity... entity) throws Exception;
     String  Get(String url,IAsynCallBackListener callback) throws Exception;
     void CallWebService(String url, String IName,IAsynCallBackListener callback, BaseEnity... entity) throws Exception;
}

第三個物件是IHttp介面的實現,是Http通訊的核心部分:

package Helper;

import android.accounts.NetworkErrorException;
import android.support.annotation.NonNull;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import Annotation.*;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.List;
import java.util.concurrent.TimeoutException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

//import Const.PublicDefine;
import Entity.BaseEnity;
import Interface.IAsynCallBackListener;
import Interface.IHttp;
import Helper.Log;

/**
 * Created by 王彥鵬 on 2017-09-02.
 */

class HttpAsynResponseData
{
    private String response="";
    private Throwable exception;

    public String getResponse() {
        return response;
    }

    public void setResponse(String response) {
        this.response = response;
    }

    public Throwable getException() {
        return exception;
    }

    public void setException(Throwable exception) {
        this.exception = exception;
    }
}

public class Http implements IHttp {

    /**
     * 用Get方式請求伺服器
     *
     * @param url         url 地址
     * @param contentType 請求資料型別
     * @return 伺服器返回的資料
     */
    @NonNull
    private  String httpMethod(String url, String contentType, String method, String postData) throws Exception {
        HttpURLConnection conn = null;
        try {
            long t1,t2=0;
            t1=System.currentTimeMillis();
            URL murl = new URL(url);
            //1.得到HttpURLConnection例項化物件
            conn = (HttpURLConnection) murl.openConnection();
            //2.設定請求資訊(請求方式... ...)
            //設定請求方式和響應時間
            conn.setRequestMethod(method);
            conn.setRequestProperty("Content-Type", contentType);
            conn.setRequestProperty("Content-Length", String.valueOf(postData.getBytes().length));
            conn.setRequestProperty("encoding", "UTF-8"); //可以指定編碼
            conn.setConnectTimeout(5000);
            conn.setReadTimeout(5000);
            //不使用快取
            conn.setUseCaches(false);
            // 設定可取
            conn.setDoInput(true);
            // 設定可讀
            conn.setDoOutput(true);
            if (method.toUpperCase() == "POST") {
                //4.向伺服器寫入資料
                conn.getOutputStream().write(postData.getBytes());
            }
            //3.讀取響應
            if (conn.getResponseCode() == 200) {
                InputStream in = conn.getInputStream();
                // 建立高效流物件
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                // 建立StringBuilder物件儲存資料
                StringBuilder response = new StringBuilder();
                String line;// 一次讀取一行
                while ((line = reader.readLine()) != null) {
                    response.append(line);// 得到的資料存入StringBuilder
                }
                t2= System.currentTimeMillis();
                Log.write("Http",String.format("%s 請求(%s)\r\nUrl:%s\r\n請求資料:%s\r\n返回資料:%s\r\n請求用時:%3f",
                        method,contentType,url,postData, response.toString(),(t2-t1)/Double.valueOf(1000)));
                return response.toString();
            } else {
                Log.write("Http",String.format("%s 請求(%s):%s\r\n請求失敗。",method,contentType,url));
                throw new Exception("請求失敗");
            }
        } catch (TimeoutException e)
        {
            Log.write("Http",String.format("%s 請求(%s):%s\r\n連線超時。",method,contentType,url));
            throw new Exception("請求超時或網路已斷開。");
        }catch (SocketTimeoutException e)
        {
            throw new Exception("請求超時或網路已斷開。");
        }
        catch (NetworkErrorException e)
        {
            throw new Exception("網路斷開");
        }
        catch (Exception e) {
            Log.write("Http",String.format("%s 請求(%s):%s\r\n請求異常:%s",method,contentType,url,e.getMessage()));
            e.printStackTrace();
            if(e.getMessage().indexOf("Network is unreachable")>=0)
            {
                throw new Exception("網路斷開");
            }
            else {
                throw e;
            }
        } finally {
            //4.釋放資源
            if (conn != null) {
                //關閉連線 即設定 http.keepAlive = false;
                conn.disconnect();
            }
        }
    }

    /**
     * 用Get方式請求伺服器
     *
     * @param url         url 地址
     * @param callback    非同步回撥地址,當不為null時為非同步呼叫
     * @param contentType 請求資料型別
     * @return 伺服器返回的資料
     */
    public  String Get(final String url,
                             final String contentType,
                             final IAsynCallBackListener callback) throws Exception {
        if (callback == null) {
            return httpMethod(url, contentType, "GET", "");
        } else {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        String httpResponse = httpMethod(url, contentType, "GET", "");
                        // 回撥onFinish()方法
                        callback.onFinish("",httpResponse);

                    } catch (Exception e) {
                        // 回撥onError()方法
                        callback.onError(this,e);
                    }
                }
            }).start();
            return "";
        }

    }


    /**
     * 用Get方式請求伺服器
     *
     * @param url 網路地址
     * @return
     */
    public  String Get(final String url) throws Exception {
        
        final Object synObj = new Object();
        final HttpAsynResponseData res = new HttpAsynResponseData();
        Thread getthread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (synObj) {
                    try {
                        res.setResponse(Get(url, "application/x-www-form-urlencoded", null));
                        res.setException(null);
                    } catch (Exception e) {
                        e.printStackTrace();
                        res.setException(e);
                    }
                    synObj.notify();
                }
            }
        });
        getthread.start();
        try {
            //Thread.sleep(1);
            synchronized (synObj) {
                synObj.wait();
                if (res.getException()==null) {
                    return res.getResponse();
                }
                else
                {
                    throw new Exception(res.getException());
                }
            }
            //return res[0];
        } catch (Exception e) {
            throw new Exception(e);
        }
    }


    /**
     * 用 Post 方式請求伺服器
     *
     * @param url         網路地址
     * @param postData    提交資料
     * @param callback    回撥地址
     * @param contentType 請求資料型別
     * @return 伺服器返回資料
     */
    public  String Post(final String url,
                              final String postData,
                              final IAsynCallBackListener callback,
                              final String contentType) throws Exception {
        if (callback == null) {
            return httpMethod(url, contentType, "POST", postData);
        } else {
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        String httpResponse = httpMethod(url, contentType, "POST", postData);
                        // 回撥onFinish()方法
                        callback.onFinish("",httpResponse);
                    } catch (Exception e) {
                        // 回撥onError()方法
                        callback.onError(this,e);
                    }
                }
            }).start();
            return "";
        }
    }


    /**
     * 用 Post 方式請求伺服器
     *
     * @param url      網路地址
     * @param postData 提交資料
     * @return
     */
    public  String Post(final String url,
                              final String postData) throws Exception {
       
        final Object synObj = new Object();
        final String[] res = {""};
        Thread getthread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (synObj) {
                    try {
                        res[0] = Post(url, postData,null,"application/x-www-form-urlencoded");
                    } catch (Exception e) {
                        e.printStackTrace();
                        res[0]=e.getMessage();
                    }

                    synObj.notify();
                }
            }
        });
        getthread.start();

        try {
            //Thread.sleep(1);
            synchronized (synObj) {
                synObj.wait();
                return res[0];
            }
            //return res[0];
        } catch (Exception e) {
            throw new Exception(res[0]);
        }

    }

    @Override
    public void Post(String url, String postData, IAsynCallBackListener callback) throws Exception {
        
        Post(url, postData,callback,"application/x-www-form-urlencoded");

    }

    /**
     * 用 Post 方式請求伺服器
     *
     * @param url      網路地址
     * @param postData 提交資料
     * @return
     */
    public  String Post(final String url,
                              final String postData,
                              final String contentType) throws Exception {
        if (!PublicDefine.NetworkConnState)
        {
            throw new Exception("網路連線已斷開,請先檢查網路。");
        }
        final Object synObj = new Object();
        final String[] res = {""};
        Thread getthread = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (synObj) {
                    try {
                        res[0] = Post(url, postData,null,contentType);
                    } catch (Exception e) {
                        e.printStackTrace();
                        res[0]=e.getMessage();
                    }

                    synObj.notify();
                }
            }
        });
        getthread.start();

        try {
            //Thread.sleep(1);
            synchronized (synObj) {
                synObj.wait();
                return res[0];
            }
            //return res[0];
        } catch (Exception e) {
            return res[0];
        }
    }

    private static JSONObject LoadNodeChild(Node node) throws JSONException {
        JSONObject json = new JSONObject();
        for (int i = 0; i < node.getChildNodes().getLength(); i++) {
            Node subnode=node.getChildNodes().item(i);
            String key =subnode.getNodeName();
            Object value = null;
            if (subnode.hasChildNodes()&& (!subnode.getChildNodes().item(0).getNodeName().equals("#text"))) {
                value = LoadNodeChild(subnode);
            } else {
                value = subnode.getTextContent();
            }
            if (json.has(key)){
                Object oldJson = json.get(key);
                if (oldJson instanceof JSONObject){
                    JSONArray jsonArray = new JSONArray();
                    jsonArray.put(oldJson);
                    jsonArray.put(value);
                    json.remove(key);
                    json.put(key, jsonArray);
                }else{
                    ((JSONArray)oldJson).put(value);
                    json.put(key,oldJson);
                }
            }else{
                json.put(key, value);
            }
        }
        return json;
    }

    private static String GetPropertyName(Field f)
    {
        PropertyName pname = f.getAnnotation(PropertyName.class);
        if (pname==null)
        {
            return f.getName();
        }
        else
        {
            return pname.value();
        }
    }

    private static String GetKeyValue(BaseEnity enity) throws Exception {
        String values = "";
        Field[] field = enity.getClass().getDeclaredFields(); // 獲取實體類的所有屬性,返回Field陣列

        for (int j = 0; j < field.length; j++) { // 遍歷所有屬性
            String name = field[j].getName(); // 獲取屬性的名字
            name = name.substring(0, 1).toUpperCase() + name.substring(1); // 將屬性的首字元大寫,方便構造get,set方法

            try {
                Method m = enity.getClass().getMethod("get" + name);
                Object instance = m.invoke(enity);
                if (instance.getClass().getSimpleName().equals("ArrayList")){
                    for (int i = 0; i < ((List)instance).size(); i++) {
                        if (((List) instance).get(i).getClass().getSuperclass().getSimpleName().equals("BaseEnity")) {
                            values += "<" + GetPropertyName(field[j]) + ">" + GetKeyValue((BaseEnity) ((List) instance).get(i)) + "</" + GetPropertyName(field[j]) + ">\n";
                        } else {
                            values += "<" + GetPropertyName(field[j]) + ">" + ((List) instance).get(i).toString() + "</" + GetPropertyName(field[j]) + ">\n";
                        }
                    }
                }else if (instance.getClass().getSuperclass().getSimpleName().equals("BaseEnity")) {
                    values += "<" + GetPropertyName(field[j]) + ">" + GetKeyValue((BaseEnity) instance) + "</" + GetPropertyName(field[j]) + ">\n";
                } else {
                    values += "<" + GetPropertyName(field[j]) + ">" + instance.toString() + "</" + GetPropertyName(field[j]) + ">\n";
                }
            }
            catch (Exception e)
            {

            }
        }
        return values;
    }
    /**
     * 呼叫WebService介面
     *
     * @param IName
     * @param args
     * @return
     */
    public  JSONObject CallWebService(String url, String IName, BaseEnity... args)
            throws Exception {
        
        String pdata = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
                /*"<soap:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\""+*/
                "  <soap:Body xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" >\n" +
                "<%s xmlns=\"http://tempuri.org/\">\n";
        if (args!=null) {
            for (BaseEnity entity:args ) {
                pdata+=GetKeyValue(entity);
            }

        }
        pdata += "</%s>\n" +
                "  </soap:Body>\n" +
                "</soap:Envelope>";
        pdata = String.format(pdata, IName, IName);

        String resxml = Post(url, pdata,"text/xml");
        DocumentBuilderFactory xml = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = xml.newDocumentBuilder();
        Document dom = builder.parse(new InputSource(new ByteArrayInputStream(resxml.getBytes("utf-8"))));

        Element root = dom.getDocumentElement();
        NodeList items = root.getElementsByTagName(IName + "Response");//查詢所有person節點
        Node response = items.item(0);
        JSONObject resJson = LoadNodeChild(response);
        return resJson;
    }

    @Override
    public String Get(String url, IAsynCallBackListener callback) throws Exception {
        return Get(url,"application/x-www-form-urlencoded",callback);
    }

    @Override
    public void CallWebService(String url, final String IName, final IAsynCallBackListener callback, BaseEnity... args) throws Exception {
       
        String pdata = "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
                "<soap:Envelope xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\">\n" +
                /*"<soap:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\""+*/
                "  <soap:Body xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" >\n" +
                "<%s xmlns=\"http://tempuri.org/\">\n";
        if (args!=null) {
            for (BaseEnity entity:args ) {
                pdata+=GetKeyValue(entity);
            }

        }
        pdata += "</%s>\n" +
                "  </soap:Body>\n" +
                "</soap:Envelope>";
        pdata = String.format(pdata, IName, IName);

        Post(url, pdata, new IAsynCallBackListener() {
            @Override
            public void onFinish(Object sender,Object data) {
                try {
                    String resxml = data.toString();
                    DocumentBuilderFactory xml = DocumentBuilderFactory.newInstance();
                    DocumentBuilder builder = xml.newDocumentBuilder();
                    Document dom = builder.parse(new InputSource(new ByteArrayInputStream(resxml.getBytes("utf-8"))));

                    Element root = dom.getDocumentElement();
                    NodeList items = root.getElementsByTagName(IName + "Response");//查詢所有person節點
                    Node response = items.item(0);
                    JSONObject resJson = LoadNodeChild(response);
                    callback.onFinish("",resJson);
                }
                catch (Exception e)
                {

                }
            }

            @Override
            public void onError(Object sender, Exception e) {
                callback.onError(this,e);
            }
        }, "text/xml");

    }
}