基于HttpURLConnection的网络访问工具

来源:互联网 发布:逍遥问道登录器源码 编辑:程序博客网 时间:2024/06/11 13:24

出于完善我个人的理论了解面,再加上google在6.0之后取消了HttpClient,所以我特地抽了点时间针对HttpUrlConnection做了一点连接,并写了个工具类,方便以后可以用上,那么话不多说,直接上代码,我再代码中注释已经做得很详细了


基于对于代码结构的我个人的结构优化思维,所以并不是直接将下载的代码写好,而是搭建了一下大概的结构,大致来说分为了   模型层、数据层、控制层


首先是模型层

/** * 用来存放网络返回数据的类 * @author yjh * */public class UrlResponseBean {//idprivate String mId;//响应结果:成功、网络出错、服务器出错private int mResponseResult;//具体的响应返回码private int mResponseCode;//响应成功后返回的内容,这里返回流//private InputStream mIs;//获取网的网络数据,已经转化为输出流了private ByteArrayOutputStream mBaos;//响应成功后返回的数据private String mResponseData;private HttpURLConnection mConnectBean;public int getResponseResult() {return mResponseResult;}public void setResponseResult(int responseResult) {this.mResponseResult = responseResult;}public int getResponseCode() {return mResponseCode;}public void setResponseCode(int responseCode) {this.mResponseCode = responseCode;}public String getId() {return mId;}public void setId(String id) {this.mId = id;}public String getResponseData() {return mResponseData;}public void setResponseData(String responseData) {this.mResponseData = responseData;}protected HttpURLConnection getConnectBean() {return mConnectBean;}protected void setConnectBean(HttpURLConnection connectBean) {this.mConnectBean = connectBean;}public ByteArrayOutputStream getBaos() {return mBaos;}public void setBaos(ByteArrayOutputStream mBaos) {this.mBaos = mBaos;}}
然后是数据层:

public class UrlConnectTool {private static final int TIMEOUT_IN_MILLIONS = 5000;/** * 在2.3以上,想要卡主进程运行访问网络时,需要设置这个 */@SuppressLint("NewApi")public void downloadInit(){StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()          .detectDiskReads()          .detectDiskWrites()          .detectNetwork()          .penaltyLog()          .build());   StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()          .detectLeakedSqlLiteObjects()          .detectLeakedClosableObjects()          .penaltyLog()          .penaltyDeath()          .build());  }/** * 卡主线程的get下载方式 * 这里返回的bean里面是下载结果以及下载内容 */public UrlResponseBean doGet(String urlStr) {UrlResponseBean bean = new UrlResponseBean();URL url = null;HttpURLConnection conn = null;try {url = new URL(urlStr);conn = (HttpURLConnection) url.openConnection();//这里在写的时候我就一直想着在设置好超时之后,当超时时是怎么个反馈方式,网上大都是设置完了就不管了,也没有说超时//时是怎么个响应方式,我好不容易看到个说是会在抛出的错误里面返回的,但是也需要验证,但我没有可以用于测试//超时的网址!需要测试!conn.setReadTimeout(TIMEOUT_IN_MILLIONS);conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);conn.setRequestMethod("GET");conn.setRequestProperty("accept", "*/*");conn.setRequestProperty("connection", "Keep-Alive");conn.setRequestProperty("Charset", "UTF-8");//设置编码格式int connectCode = conn.getResponseCode();//这里获取之后,如果需要统计,则可以在这里统计连接之后的错误信息码bean.setResponseCode(connectCode);bean.setConnectBean(conn);//在这里,对于控制层来说,只需要知道是成功,还是网络不好(让用户调整网络状态),或者是连接失败(让用户刷新)switch ((connectCode/100)) {case 2://表示成功bean.setResponseResult(UrlResponseConsts.DOWNLOAD_SUCCESS);bean.setBaos(inputToByteArrayOutputStream(conn.getInputStream()));//bean.setIs(conn.getInputStream());return bean;case 4://表示访问网址出错bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;case 5://表示服务器出错bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;}} catch (ProtocolException e) {//如果没有建立连接并执行getInputStream//在调用getResponseCode的时候,该函数会自动执行getInputStream并获取Response Code//所以你在此函数后再设置Request Type就会造成Connection already established错误。e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}//这个抛出的错我是针对连接超时时做的处理catch (SocketTimeoutException e) {//连接超时,Socket读数据的超时,https://twitter.com/我用的推特来测试出来了e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}//这个抛出的错我是针对连接超时时做的处理catch (ConnectTimeoutException e) {//响应超时,通过网络与服务器建立连接的超时e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}catch (IOException e) {//错误1:连接失败,没有网络在我用推特主页测试的时候,此时我关闭了网络,这里的报错为java.net.UnknownHostExceptione.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}finally {try {if (conn.getInputStream() != null)conn.getInputStream().close();} catch (IOException e) {}conn.disconnect();}//此时是既不是成功也不是失败,应该属于服务器问题bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;}/** * 采用post方式访问网络 */public UrlResponseBean doPost(String urlStr,String param){PrintWriter out = null;  //        BufferedReader in = null;          UrlResponseBean bean = new UrlResponseBean();        HttpURLConnection conn = null;        try          {              URL realUrl = new URL(urlStr);              // 打开和URL之间的连接              conn = (HttpURLConnection) realUrl                      .openConnection();              // 设置通用的请求属性              conn.setRequestProperty("accept", "*/*");              conn.setRequestProperty("connection", "Keep-Alive");              conn.setRequestMethod("POST");              //设置文件类型            // application/x-www-form-urlencoded: 窗体数据被编码为名称/值对。这是标准的编码格式。            //multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分。            //text/plain: 窗体数据以纯文本形式进行编码,其中不含任何控件或格式字符。                        //form的enctype属性为编码方式,常用有两种:application/x-www-form-urlencoded和            //multipart/form-data,默认为application/x-www-form-urlencoded。             //当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2...),            //然后把这个字串append到url后面,用?分割,加载这个新的url。 当action为post时候,浏览器把form数据封装到http body中,然后发送到server。            //如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。 但是如果有type=file的话,就要用到multipart/form-data了。            //浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符(boundary)。            conn.setRequestProperty("Content-Type",                      "application/x-www-form-urlencoded");              conn.setRequestProperty("charset", "utf-8");             //设置不使用缓存            conn.setUseCaches(false);              // 发送POST请求必须设置如下两行              //设置容许输出,设置了之后才能用post            conn.setDoOutput(true);           // 设置是否从httpUrlConnection读入,默认情况下是true;              conn.setDoInput(true);              conn.setReadTimeout(TIMEOUT_IN_MILLIONS);              conn.setConnectTimeout(TIMEOUT_IN_MILLIONS);                if (param != null && !param.trim().equals(""))              {                  // 获取URLConnection对象对应的输出流                  out = new PrintWriter(conn.getOutputStream());                  // 发送请求参数                  out.print(param);                  // flush输出流的缓冲                  out.flush();              }              int connectCode = conn.getResponseCode();//这里获取之后,如果需要统计,则可以在这里统计连接之后的错误信息码bean.setResponseCode(connectCode);bean.setConnectBean(conn);//在这里,对于控制层来说,只需要知道是成功,还是网络不好(让用户调整网络状态),或者是连接失败(让用户刷新)switch ((connectCode/100)) {case 2://表示成功bean.setResponseResult(UrlResponseConsts.DOWNLOAD_SUCCESS);bean.setBaos(inputToByteArrayOutputStream(conn.getInputStream()));//bean.setIs(conn.getInputStream());return bean;case 4://表示访问网址出错bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;case 5://表示服务器出错bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);return bean;}        } catch (ProtocolException e) {//如果没有建立连接并执行getInputStream//在调用getResponseCode的时候,该函数会自动执行getInputStream并获取Response Code//所以你在此函数后再设置Request Type就会造成Connection already established错误。e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}//这个抛出的错我是针对连接超时时做的处理catch (SocketTimeoutException e) {//连接超时,Socket读数据的超时,https://twitter.com/我用的推特来测试出来了e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}//这个抛出的错我是针对连接超时时做的处理catch (ConnectTimeoutException e) {//响应超时,通过网络与服务器建立连接的超时e.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}catch (IOException e) {//错误1:连接失败,没有网络在我用推特主页测试的时候,此时我关闭了网络,这里的报错为java.net.UnknownHostExceptione.printStackTrace();bean.setResponseResult(UrlResponseConsts.NET_ERROR);return bean;}         // 使用finally块来关闭输出流、输入流          finally          {                  try {                if (out != null)                      {                          out.close();                      }    if (conn.getInputStream() != null)    conn.getInputStream().close();    } catch (IOException e) {    }                if(null != conn)                conn.disconnect();        }          //此时是既不是成功也不是失败,应该属于服务器问题      bean.setResponseResult(UrlResponseConsts.SERVER_ERROR);        return bean;}private ByteArrayOutputStream inputToByteArrayOutputStream(InputStream is) throws IOException{if (null != is) {ByteArrayOutputStream baos = new ByteArrayOutputStream();int len = -1;byte[] buf = new byte[128];while ((len = is.read(buf)) != -1) {baos.write(buf, 0, len);}baos.flush();return baos;}return null;}}


目前这个类还没有完善,还差一个下载文件,我会在近期补充完整


下一个是控制层:

public class UrlConnectCenter {private UrlConnectTool mConnectTool;private DataKeepTool mDataTool;public UrlConnectCenter() {mConnectTool = new UrlConnectTool();mDataTool = new DataKeepTool();}/** * 卡滞主线程的网络连接,这里处理好post和get方式以及返回来的结果,过滤下载结果 这里是UrlConnectTool之后的第二层处理 */public UrlResponseBean startConnectUi(UrlConnectDescription description) {systemAdjustment();UrlResponseBean response = new UrlResponseBean();// 这里获取到访问后的结果if (!description.getIsPost()) {// get方式String connectUrl = description.getConnectUrl();// get方式时拼起来if(null != description.getConnectData())connectUrl +="?"+ description.getConnectData();response = mConnectTool.doGet(connectUrl);} else {// post方式response = mConnectTool.doPost(description.getConnectUrl(), description.getConnectData());}// 设置下载的idresponse.setId(description.getId());// 下载成功时if (response.getResponseResult() == UrlResponseConsts.DOWNLOAD_SUCCESS) {// 在这一层处理好数据,是作为数据返回还是文件存储等try {if (null == description.getFilePath()) {// 将流转化为字符String backInfo = mDataTool.getDataBackInfo(response.getBaos());response.setResponseData(backInfo);} else {// 将流转化为文件并保存mDataTool.getDataSaveFile(response.getBaos(),description.getFilePath());}} catch (IOException e) {//这里报错就是流转化时的流报错e.printStackTrace();}// 用完之后将流关闭try {response.getBaos().close();} catch (IOException e) {e.printStackTrace();}}return response;}/** * 在2.3之前可以直接在主进程之中卡主线程下载 * 但是2.3之后需要设置过后才能在主线程下载 */private void systemAdjustment(){if (android.os.Build.VERSION.SDK_INT > 9) {mConnectTool.downloadInit();}}}


控制层中也有一个bean,用于存放任务的描述

/** * 网络连接描述,用于需要发起网络连接时填充所需数据之后使用 * @author yjh * */public class UrlConnectDescription {//idprivate String mId;//需要访问的网址private String mConnectUrl;//是否是post方式private boolean mIsPost = false;//文件下载的路径,当需要下载为文件时private String mFilePath;//网址之后需要添加的参数,这里单独传入,以便于内部处理post或者getprivate String mConnectData;public String getId() {return mId;}public void setId(String mId) {this.mId = mId;}public String getConnectUrl() {return mConnectUrl;}public void setConnectUrl(String mConnectUrl) {this.mConnectUrl = mConnectUrl;}public boolean getIsPost() {return mIsPost;}public void setIsPost(boolean mIsPost) {this.mIsPost = mIsPost;}public String getFilePath() {return mFilePath;}public void setFilePath(String mFilePath) {this.mFilePath = mFilePath;}public String getConnectData() {return mConnectData;}public void setConnectData(String mConnectData) {this.mConnectData = mConnectData;}}

然后有一个工具类,用于转换流成为String 内容以及保存为文件

/** * 处理数据 *  * @author yjh *  */public class DataKeepTool {/** * 将访问后返回的数据转化为String类型并返回 *  * @param conn * @param is * @param baos * @return * @throws IOException */public String getDataBackInfo(ByteArrayOutputStream boas) throws IOException {if (null != boas) {//采用这种方式防止出现乱码byte[] lens = boas.toByteArray();return new String(lens);}return null;}/** * 用于将流保存为文件 *  * @param is */public void getDataSaveFile(ByteArrayOutputStream baos, String filePath) {FileOutputStream fos = null;        try {            fos = new FileOutputStream(new File(filePath));            baos.writeTo(fos);            fos.close();            baos.flush();            baos.close();        } catch (IOException ioe) {            ioe.printStackTrace();        }  finally {         }}}




代码到这边基本就够用了,还有一个的话是常亮类,这个类内容很简单,就三个访问状态的常量而已


由于在代码中注释已经写得很多了,我再这里就不再做多的描述了


这里还差的最后一个文件上传的话我再找时间补充完整





0 0
原创粉丝点击