码迷,mamicode.com
首页 > 移动开发 > 详细

Android网络通信的基本实现

时间:2015-01-19 12:50:27      阅读:177      评论:0      收藏:0      [点我收藏+]

标签:android   网络通信   httpclient   httpurlconnection   http   

似乎很久没有写博客了,今天看了无意间看了下半年前写的代码,设计似乎很有局限性,但基本的通信也算是实现了。

不知道以后看到现在写的代码会不会也会有这样的想法呢?

进入正题,android网络通信的基本实现的有两种方式,一种是通过HttpClient来实现,一种是通过HttpURLConnection来实现。

直接上代码:

首先是一个抽象的http类

/**
 * 抽象的Http
 * @author Jenly
 * @date 2014-8-7
 *
 */
public abstract class AbstractHttp {
	
	/** 默认编码  (UTF-8) */
	public static final String DEFAULT_ENCODING = "UTF-8";
    /** GET请求时 url和 参数的分隔符 */
    public static final String URL_AND_PARA_SEPARATOR = "?";
	/** 是否取消请求 */
    protected boolean isCancel = false;
    
	public static final int DEFAULT_BYTE_LENGTH = 8192;
	
	protected static final int LONG_TIME = 0;
	
	protected int connectionTimeOut = LONG_TIME;
	
	protected int soTimeOut = LONG_TIME;

	public enum HttpMethod{
		/** GET请求 */
		GET,	
		/** POST请求 */
		POST
	}
	
	/**
	 * 构造
	 */
	public AbstractHttp(){
		super();
	}
	
	public AbstractHttp(int connectionTimeOut,int soTimeOut){
		super();
		if(connectionTimeOut<0 || soTimeOut <0){
			throw new RuntimeException("connectionTimeOut<0 || soTimeOut<0");
		}
		
		if(connectionTimeOut>0)
			this.connectionTimeOut = connectionTimeOut;
		if(soTimeOut>0)
			this.soTimeOut = soTimeOut;
	}
	
	//-----------------------------------------
	
	/**
	 * 取消请求
	 */
	protected void cancel(){
		isCancel = true;
	}
	
	/**
	 * 异步线程
	 * @param runnable
	 */
	protected void asyncThread(Runnable runnable){
		new Thread(runnable).start();
	}
	
	
	/**
	 * 异步连接  默认GET请求
	 * @param url
	 * @param httpEntity
	 * @param httpCallBack
	 */
	public abstract void asyncConnect(String url,HttpCallBack<String> httpCallBack);
	
	/**
	 * 异步连接  默认GET请求
	 * @param url
	 * @param httpEntity
	 * @param httpCallBack
	 */
	public abstract void asyncConnect(String url,Map<String,String> params,HttpCallBack<String> httpCallBack);
	/**
	 * 异步连接
	 * @param url
	 * @param httpEntity
	 * @param httpMethod
	 * @param httpCallBack
	 */
	public abstract void asyncConnect(String url,Map<String,String> params,HttpMethod httpMethod,HttpCallBack<String> httpCallBack);
	
	/**
	 * 同步连接  默认GET请求
	 * @param url
	 * @param httpEntity
	 * @param httpCallBack
	 */
	public abstract String syncConnect(String url);
	
	/**
	 * 同步连接  默认GET请求
	 * @param url
	 * @param httpEntity
	 */
	public abstract String syncConnect(String url,Map<String,String> params);
	
	/**
	 * 同步连接  默认GET请求
	 * @param url
	 * @param httpEntity
	 * @param httpMethod
	 */
	public abstract String syncConnect(String url,Map<String,String> params,HttpMethod httpMethod);
	
	/**
	 * 同步连接  默认GET请求
	 * @param url
	 * @param httpEntity
	 * @param httpCallBack
	 */
	public abstract String syncConnect(String url,Map<String,String> params,HttpCallBack<String> httpCallBack);
	
	/**
	 * 同步连接
	 * @param url
	 * @param httpEntity
	 * @param httpMethod
	 * @param httpCallBack
	 */
	public abstract String syncConnect(String url,Map<String,String> params,HttpMethod httpMethod,HttpCallBack<String> httpCallBack);
	
	
	/**
	 * 异步下载文件
	 * @param url
	 * @param fileName
	 * @param httpDownloadCallBack
	 * @return
	 */
	public abstract void asyncDownloadFile(String url,String fileName,HttpCallBack<File> httpDownloadCallBack);
	
	/**
	 * 同步下载文件
	 * @param url
	 * @param fileName
	 * @return
	 */
	public abstract File syncDownloadFile(String url,String fileName);
	
	/**
	 * 同步下载文件
	 * @param url
	 * @param fileName
	 * @param httpDownloadCallBack
	 * @return
	 */
	public abstract File syncDownloadFile(String url,String fileName,HttpCallBack<File> httpDownloadCallBack);
	
	
	
}


监听回调接口:

/**
 * Http连接回调接口
 * @author Jenly
 * @date 2014-8-7
 */
public interface HttpCallBack<T>{
	
	/**
	 * 开始
	 * @param url
	 */
	void onStart(String url);
	
	/**
	 * 加载…
	 * @param progress
	 * @param count
	 */
	void onLoading(long progress,long count);
	
	/**
	 * 成功
	 * @param t 返回的对象
	 */
	void onSuccess(T t);
	
	/**
	 * 失败
	 * @param error
	 * @param e
	 */
	void onFailure(String error,Throwable e);
	

	/**
	 * 取消
	 */
	void onCancel();
}


/**
 * Http连接请求回调
 * @author Jenly
 * @date 2014-8-7
 */
public abstract class HttpConnectCallBack implements HttpCallBack<String>{

	@Override
	public abstract void onSuccess(String content);
	
}


/**
 * Http下载回调
 * @author Jenly
 * @date 2014-8-7
 */
public abstract class HttpDownloadCallBack implements HttpCallBack<File>{

	@Override
	public abstract void onSuccess(File file);
}

通过HttpClient实现的方式

/**
 * Http网络通信(httpClient实现)
 * @author Jenly
 * @date 2014-8-7
 */
public class Http extends AbstractHttp{
	

	public Http() {
		super();
	}

	public Http(int connectionTimeOut, int soTimeOut) {
		super(connectionTimeOut, soTimeOut);
	}


	/**
	 * 获得一个HttpClient
	 * @return
	 */
	private HttpClient getHttpClient(){
		
		HttpParams httpParams = new BasicHttpParams();
		
		if(connectionTimeOut != LONG_TIME && soTimeOut != LONG_TIME){
			HttpConnectionParams.setConnectionTimeout(httpParams,connectionTimeOut);
			HttpConnectionParams.setSoTimeout(httpParams, soTimeOut);
		}
		
		HttpConnectionParams.setTcpNoDelay(httpParams, true);
		HttpConnectionParams.setSocketBufferSize(httpParams,DEFAULT_BYTE_LENGTH);

		HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);

		SchemeRegistry schemeRegistry = new SchemeRegistry();
		schemeRegistry.register(new Scheme("http", PlainSocketFactory
				.getSocketFactory(), 80));
		schemeRegistry.register(new Scheme("https", SSLSocketFactory
				.getSocketFactory(), 443));
		ThreadSafeClientConnManager threadSafeClientConnManager = new ThreadSafeClientConnManager(
				httpParams, schemeRegistry);
		
		return new DefaultHttpClient(threadSafeClientConnManager,httpParams);
	}
	
	
	/**
	 * 获得HttpUriRequest
	 * @param url
	 * @param httpMethod
	 * @param params
	 * @return
	 */
	private HttpUriRequest getHttpUriRequest(String url,HttpMethod httpMethod,Map<String,String> params){
		
		if(HttpMethod.POST == httpMethod){
			
			HttpPost httpPost = new HttpPost(url);
			if(params!=null){
				List<NameValuePair> list = new ArrayList<NameValuePair>();
				for(String key : params.keySet()){
					list.add(new BasicNameValuePair(key, params.get(key)));
				}
				try {
					httpPost.setEntity(new UrlEncodedFormEntity(list,DEFAULT_ENCODING));
				} catch (UnsupportedEncodingException e) {
					LogUtils.e(e);
				}
			}
			return httpPost;
		}else{
			if(params!=null){
				List<NameValuePair> list = new ArrayList<NameValuePair>();
				
				for(String key : params.keySet()){
					list.add(new BasicNameValuePair(key, params.get(key)));
				}
				url += URL_AND_PARA_SEPARATOR;
				
				url += URLEncodedUtils.format(list,DEFAULT_ENCODING);
			}
			
			LogUtils.v("GET:"+ url);
			HttpGet httpGet = new HttpGet(url);
			
			return httpGet;
		}
		
		
	}

	@Override
	public void asyncConnect(String url,HttpCallBack<String> httpCallBack) {
		asyncConnect(url, null, HttpMethod.GET, httpCallBack);
	}
	
	@Override
	public void asyncConnect(String url, Map<String,String> params,HttpCallBack<String> httpCallBack) {
		asyncConnect(url, params, HttpMethod.GET, httpCallBack);
	}
	
	@Override
	public void asyncConnect(final String url,final Map<String,String> params,final HttpMethod httpMethod,final HttpCallBack<String> httpCallBack) {
		asyncThread(new Runnable(){
			@Override
			public void run() {
				syncConnect(url, params,httpMethod, httpCallBack);
			}
		});
	}
	
	@Override
	public String syncConnect(String url) {
		return syncConnect(url, null, HttpMethod.GET, null);
	}
	
	@Override
	public String syncConnect(String url, Map<String,String> params) {
		return syncConnect(url, params, HttpMethod.GET, null);
	}
	
	@Override
	public String syncConnect(String url, Map<String,String> params,HttpCallBack<String> httpCallBack) {
		return syncConnect(url, params, HttpMethod.GET, httpCallBack);
	}
	
	@Override
	public String syncConnect(String url, Map<String,String> params,HttpMethod httpMethod) {
		return syncConnect(url, params,httpMethod, null);
	}

	@Override
	public String syncConnect(String url, Map<String,String> params,HttpMethod httpMethod,HttpCallBack<String> httpCallBack) {
		
		if(TextUtils.isEmpty(url)){
			return null;
		}
		
		BufferedReader reader = null;
		
		HttpClient httpClient = null;
		
		int statusCode = -1;
		try {
			LogUtils.v(url);
			
			if(httpCallBack != null)
				httpCallBack.onStart(url);
			
			HttpUriRequest request = getHttpUriRequest(url,httpMethod,params);
			httpClient = getHttpClient();
			HttpResponse httpResponse = httpClient.execute(request);
			statusCode = httpResponse.getStatusLine().getStatusCode();
			if(statusCode==HttpStatus.SC_OK){
				
				reader = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent()));
				
				StringBuffer buffer = new StringBuffer();
				String line = null;
				
				long progress = 0;
				
				long count = httpResponse.getEntity().getContentLength();
				isCancel = false;
				if(httpCallBack != null && count!=-1)
					httpCallBack.onLoading(progress, count);
				while ((!isCancel) && (line = reader.readLine())!=null) {
					buffer.append(line);
					
					if(httpCallBack != null && count!=-1){
						progress+= line.getBytes().length;
						httpCallBack.onLoading(progress, count);
					}
				}
				
				
				if(httpCallBack != null){
					if(!isCancel){
						progress = count;
						httpCallBack.onLoading(progress, count);
					}else{
						reader.close();
						httpCallBack.onCancel();
						return null;
					}
				}
				reader.close();
				if(httpCallBack != null && !isCancel)
					httpCallBack.onSuccess(buffer.toString());
				
				if(httpClient!=null)
					httpClient.getConnectionManager().shutdown();
				
				return buffer.toString();
			}else{
				if(httpCallBack != null)
					httpCallBack.onFailure(String.valueOf(statusCode), null);
			}
		} catch (ClientProtocolException e) {
			LogUtils.e(e);
			if(httpCallBack != null)
				httpCallBack.onFailure(String.valueOf(statusCode),e);
		} catch (IOException e) {
			LogUtils.e(e);
			if(httpCallBack != null)
				httpCallBack.onFailure(String.valueOf(statusCode),e);
		}catch (Exception e) {
			LogUtils.e(e);
			if(httpCallBack != null)
				httpCallBack.onFailure(String.valueOf(statusCode),e);
		}finally{
			if(httpClient!=null)
				httpClient.getConnectionManager().shutdown();
		}
		
		return null;
		
	}

	@Override
	public void asyncDownloadFile(final String url,final String fileName,final HttpCallBack<File> httpDownloadCallBack) {
		
		asyncThread(new Runnable() {
			@Override
			public void run() {
				syncDownloadFile(url,fileName,httpDownloadCallBack);
			}
		});
	}

	@Override
	public File syncDownloadFile(String url,String fileName) {
		return syncDownloadFile(url, fileName, null);
	}
	
	public File syncDownloadFile(String url,String fileName,HttpCallBack<File> httpDownloadCallBack) {
		
		
		if(TextUtils.isEmpty(url)){
			return null;
		}
		
		File file = null;
		
		BufferedInputStream bis = null;
		
		FileOutputStream fos = null;
		
		HttpClient httpClient = null;
		
		int statusCode = -1;
		try {
			LogUtils.v(url);
			
			if(TextUtils.isEmpty(fileName)){
				return null;
			}
			
			if(httpDownloadCallBack!=null)
				httpDownloadCallBack.onStart(url);
			
			HttpUriRequest httpUriRequest = getHttpUriRequest(url, HttpMethod.GET, null);
			httpClient = getHttpClient();
			HttpResponse httpResponse = httpClient.execute(httpUriRequest);
			statusCode = httpResponse.getStatusLine().getStatusCode();
			if(statusCode == HttpStatus.SC_OK){

				file = new File(fileName);
				fos = new FileOutputStream(file);
				
				long progress = 0;
				
				long count = httpResponse.getEntity().getContentLength();
				
				bis = new BufferedInputStream(httpResponse.getEntity().getContent());
				
				isCancel = false;
				byte[] buffer = new byte[DEFAULT_BYTE_LENGTH];
				int len = 0;
				if(httpDownloadCallBack!=null && count!=-1)
					httpDownloadCallBack.onLoading(progress, count);
				long time = System.currentTimeMillis();
				while((!isCancel) && (len = bis.read(buffer))!=-1){
					fos.write(buffer, 0, len);
					long temp = System.currentTimeMillis();
					if(temp-time>=1000){
						time = temp;
						if(httpDownloadCallBack!=null && count!=-1){
							progress += len;
							httpDownloadCallBack.onLoading(progress, count);
						}
					}
				}
				
				if(httpDownloadCallBack!=null ){
					if(!isCancel){
						progress = count;
						httpDownloadCallBack.onLoading(progress, count);
					}else{
						bis.close();
						fos.close();
						httpDownloadCallBack.onCancel();
						
						if(httpClient!=null)
							httpClient.getConnectionManager().shutdown();
						
						return file;
					}
				}
				
				bis.close();
				fos.close();
				
				if(httpDownloadCallBack!=null && !isCancel)
					httpDownloadCallBack.onSuccess(file);;
				
			}else{
				if(httpDownloadCallBack!=null)
					httpDownloadCallBack.onFailure(String.valueOf(statusCode), null);
			}
			
		} catch (ClientProtocolException e) {
			LogUtils.e(e);
			if(httpDownloadCallBack!=null)
				httpDownloadCallBack.onFailure(String.valueOf(statusCode), e);
			e.printStackTrace();
		} catch (IOException e) {
			LogUtils.e(e);
			if(httpDownloadCallBack!=null)
				httpDownloadCallBack.onFailure(String.valueOf(statusCode), e);
			e.printStackTrace();
		}catch (Throwable e) {
			LogUtils.e(e);
			if(httpDownloadCallBack!=null)
				httpDownloadCallBack.onFailure(String.valueOf(statusCode), e);
		}finally{
			if(httpClient!=null)
				httpClient.getConnectionManager().shutdown();
		}
		
		return file;
	}

	
}

通过HttpURLConnection实现的方式:

/**
 * Http网络通信(HttpURLConnection实现)
 * @author Jenly
 * @date 2014-8-7
 */
public class KingHttp extends AbstractHttp{
	

	public KingHttp() {
		super();
	}

	public KingHttp(int connectionTimeOut, int soTimeOut) {
		super(connectionTimeOut, soTimeOut);
	}

	private HttpURLConnection getHttpURLConnection(String url,HttpMethod httpMethod,Map<String,String> params) throws MalformedURLException, IOException{
		
		String paras = null;
		if(params!=null){
			List<NameValuePair> list = new ArrayList<NameValuePair>();
			for(String key : params.keySet()){
				list.add(new BasicNameValuePair(key, params.get(key)));
			}
			paras = URLEncodedUtils.format(list, DEFAULT_ENCODING);
		}
		
		if(HttpMethod.GET ==httpMethod && paras!=null){
			url += URL_AND_PARA_SEPARATOR;
			url += paras;
		}
		HttpURLConnection httpURLConnection = (HttpURLConnection)new URL(url).openConnection();
		httpURLConnection.setConnectTimeout(connectionTimeOut);
		httpURLConnection.setReadTimeout(soTimeOut);
		httpURLConnection.setUseCaches(false);
		if(HttpMethod.POST ==httpMethod){
			httpURLConnection.setDoOutput(true);
			httpURLConnection.setRequestMethod("POST");
			LogUtils.v("POST:"+ url);
			if(paras!=null)
				httpURLConnection.getOutputStream().write(paras.getBytes());
		}else{
			httpURLConnection.setRequestMethod("GET");
			LogUtils.v("GET:"+ url);
		}
		
		return httpURLConnection;
	}

	@Override
	public void asyncConnect(String url, HttpCallBack<String> httpCallBack) {
		asyncConnect(url, null, httpCallBack);
	}

	@Override
	public void asyncConnect(String url, Map<String, String> params,
			HttpCallBack<String> httpCallBack) {
		asyncConnect(url, params, HttpMethod.GET, httpCallBack);
		
	}

	@Override
	public void asyncConnect(final String url,final Map<String, String> params,
			final HttpMethod httpMethod,final HttpCallBack<String> httpCallBack) {
		asyncThread(new Runnable() {
			@Override
			public void run() {
				syncConnect(url, params, httpMethod, httpCallBack);
			}
		});
		
	}

	@Override
	public String syncConnect(String url) {
		return syncConnect(url, null);
	}

	@Override
	public String syncConnect(String url, Map<String, String> params) {
		return syncConnect(url, params, HttpMethod.GET);
	}

	@Override
	public String syncConnect(String url, Map<String, String> params,
			HttpMethod httpMethod) {
		return syncConnect(url, params, httpMethod, null);
	}

	@Override
	public String syncConnect(String url, Map<String, String> params,
			HttpCallBack<String> httpCallBack) {
		return syncConnect(url, params, HttpMethod.GET, httpCallBack);
	}

	@Override
	public String syncConnect(String url, Map<String, String> params,
			HttpMethod httpMethod, HttpCallBack<String> httpCallBack) {
		
		if(TextUtils.isEmpty(url)){
			return null;
		}
		
		BufferedReader reader = null;
		
		HttpURLConnection httpURLConnection = null;
		
		int statusCode = -1;
		try {
			LogUtils.v(url);
			
			if(httpCallBack!=null){
				httpCallBack.onStart(url);
			}
			httpURLConnection = getHttpURLConnection(url,httpMethod,params);
			httpURLConnection.connect();
			statusCode = httpURLConnection.getResponseCode();
			if(statusCode==HttpURLConnection.HTTP_OK){
				
				reader = new BufferedReader(new InputStreamReader(httpURLConnection.getInputStream()));
				
				StringBuffer buffer = new StringBuffer();
				String line = null;
				
				long progress = 0;
				
				long count = httpURLConnection.getContentLength();
				isCancel = false;
				if(httpCallBack != null && count!=-1)
					httpCallBack.onLoading(progress, count);
				while ((!isCancel) && (line = reader.readLine())!=null) {
					buffer.append(line);
					
					if(httpCallBack != null && count!=-1){
						progress+= line.getBytes().length;
						httpCallBack.onLoading(progress, count);
					}
				}
				
				
				if(httpCallBack != null){
					if(!isCancel){
						progress = count;
						httpCallBack.onLoading(progress, count);
					}else{
						reader.close();
						httpCallBack.onCancel();
						return null;
					}
				}
				reader.close();
				if(httpCallBack != null && !isCancel)
					httpCallBack.onSuccess(buffer.toString());
				
				if(httpURLConnection!=null)
					httpURLConnection.disconnect();
				
				return buffer.toString();
			}else{
				if(httpCallBack != null)
					httpCallBack.onFailure(String.valueOf(statusCode), null);
			}
		} catch (MalformedURLException e) {
			LogUtils.e(e);
			if(httpCallBack != null)
				httpCallBack.onFailure(String.valueOf(statusCode), e);
		} catch (IOException e) {
			LogUtils.e(e);
			if(httpCallBack != null)
				httpCallBack.onFailure(String.valueOf(statusCode), e);
		} catch (Exception e) {
			LogUtils.e(e);
			if(httpCallBack != null)
				httpCallBack.onFailure(String.valueOf(statusCode), e);
		}finally{
			
			if(httpURLConnection!=null){
				httpURLConnection.disconnect();
			}
		}
		
		return null;
	}

	@Override
	public void asyncDownloadFile(final String url,final String fileName,
			final HttpCallBack<File> httpDownloadCallBack) {
		asyncThread(new Runnable() {
			@Override
			public void run() {
				syncDownloadFile(url,fileName,httpDownloadCallBack);
			}
		});
	}

	@Override
	public File syncDownloadFile(String url, String fileName) {
		return syncDownloadFile(url, fileName, null);
	}

	@Override
	public File syncDownloadFile(String url, String fileName,
			HttpCallBack<File> httpDownloadCallBack) {
		
		if(TextUtils.isEmpty(url)){
			return null;
		}
		
		File file = null;
		
		BufferedInputStream bis = null;
		
		FileOutputStream fos = null;
		
		HttpURLConnection httpURLConnection = null;
		
		int statusCode = -1;
		try {
			LogUtils.v(url);
			
			if(TextUtils.isEmpty(fileName)){
				return null;
			}
			
			if(httpDownloadCallBack!=null)
				httpDownloadCallBack.onStart(url);
			
			httpURLConnection = getHttpURLConnection(url,HttpMethod.GET,null);
			httpURLConnection.connect();
			statusCode = httpURLConnection.getResponseCode();
			if(statusCode == HttpURLConnection.HTTP_OK){

				file = new File(fileName);
				fos = new FileOutputStream(file);
				
				long progress = 0;
				
				long count = httpURLConnection.getContentLength();
				
				bis = new BufferedInputStream(httpURLConnection.getInputStream());
				
				isCancel = false;
				byte[] buffer = new byte[DEFAULT_BYTE_LENGTH];
				int len = 0;
				if(httpDownloadCallBack!=null && count!=-1)
					httpDownloadCallBack.onLoading(progress, count);
				long time = System.currentTimeMillis();
				while((!isCancel) && (len = bis.read(buffer))!=-1){
					fos.write(buffer, 0, len);
					long temp = System.currentTimeMillis();
					if(temp-time>=1000){
						time = temp;
						if(httpDownloadCallBack!=null && count!=-1){
							progress += len;
							httpDownloadCallBack.onLoading(progress, count);
						}
					}
				}
				
				if(httpDownloadCallBack!=null ){
					if(!isCancel){
						progress = count;
						httpDownloadCallBack.onLoading(progress, count);
					}else{
						bis.close();
						fos.close();
						httpDownloadCallBack.onCancel();
						
						if(httpURLConnection!=null)
							httpURLConnection.disconnect();
						
						return file;
					}
				}
				
				bis.close();
				fos.close();
				
				if(httpDownloadCallBack!=null && !isCancel)
					httpDownloadCallBack.onSuccess(file);;
				
			}else{
				if(httpDownloadCallBack!=null)
					httpDownloadCallBack.onFailure(String.valueOf(statusCode), null);
			}
			
		} catch (ClientProtocolException e) {
			LogUtils.e(e);
			if(httpDownloadCallBack!=null)
				httpDownloadCallBack.onFailure(String.valueOf(statusCode), e);
		} catch (IOException e) {
			LogUtils.e(e);
			if(httpDownloadCallBack!=null)
				httpDownloadCallBack.onFailure(String.valueOf(statusCode), e);
		}catch (Throwable e) {
			LogUtils.e(e);
			if(httpDownloadCallBack!=null)
				httpDownloadCallBack.onFailure(String.valueOf(statusCode), e);
		}finally{
			if(httpURLConnection!=null)
				httpURLConnection.disconnect();
		}
		
		return file;
	}

}







Android网络通信的基本实现

标签:android   网络通信   httpclient   httpurlconnection   http   

原文地址:http://blog.csdn.net/jenly121/article/details/42871477

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!