Java系列学习笔记 --- 网络编程(3)URL
目录
一、URL
1.1、创建URL对象
① 使用完整字符串构造URL对象
② 由组成部分构造URL对象
③ 构造相对URL对象
1.2、从URL中获取数据
① InputStream openStream()方法
② URLConnection openConnection()方法
③ Object getContent()方法
④ 使用URLConnectiond对象获取URL信息
Ⅰ. 创建URLConnection对象
Ⅱ. 设置HttpURLConnection对象参数
Ⅲ. 通过HttpURLConnection写数据与发送数据问题
Socket通信实现步骤
1.3、分解URL
1.4、判断两个URL是否相等
1.5、比较两个URL
一、URL
URL是“统一资源定位符”,表示Internet上某一资源的地址。通过URL,开发人员可以访问Internet上的各种资源
完整的、带有授权部分的资源标志符语法为“协议://用户名:密码@子域名.域名.顶级域名:端口号/目录/路径/文件名.文件后缀?参数=值#标志”。
在Java中,java.net.URL类是对统一资源定位符的抽象。它扩展了java.lang.Object,是一个final类,不能对其派生子类。它不依赖于配置不同类型URL的实例,而使用了策略(strategy)设计模式。协议处理器就是策略,URL类构成上下文,通过它来选择不同的策略。
需要注意的是,URL是不可变的。构造URL对象之后,其字段不再改变,所以它们的线程是安全的。
1.1、创建URL对象
和InetAddress对象不同,我们可以构造java.net.URL的实例,这是因为IP地址是唯一的,而IP地址下的资源却是海量的。不同构造函数所需的信息有所不同,具体如下所示。
方法及描述 |
URL(String url) 通过给定的URL字符串创建URL |
URL(String protocol, String host, String file) |
URL(String protocol, String host, int port, String file) 通过给定的参数(协议、主机名、端口号、文件名)创建URL。 |
URL(URL context, String url) 使用基地址和相对URL创建 |
使用那个构造函数取决于你有那些信息,如果试图为一个不存在的URL创建对象,那么这些构造函数都会抛出一个MalformedURLException异常。
值得注意的是,Java除了验证能否识别URL模式之外,不会对它构造的URL完成任何正确性检查。所以,程序员应该要确保所创建的URL是合法的。
① 使用完整字符串构造URL对象
上述第一种构造函数URL(String url)只接受一个字符串形式的绝对URL作为唯一的参数。下面准备了一个很简单的程序,用来确定虚拟机支持那些协议。
public static void main(String[] args) {// 超文本传输协议test("http://www.baidu.com");// 安全httptest("https://www.baidu.com");// 文件传输协议test("ftp://ibiblio.org/pub/languages/java/javafaq/");// 简单邮件传输协议test("mailto:963766197@qq.com");// 本地文件访问test("file:///tec/password");
}
private static void test(String url){try{URL u = new URL(url);System.out.println("支持 "+u.getProtocol());}catch(MalformedURLException ex){String protocol = url.substring(0,url.indexOf(':'));System.out.println("不支持 "+protocol);}
}
输出结果如下所示
支持 http
支持 https
支持 ftp
支持 mailto
支持 file
② 由组成部分构造URL对象
通过指定协议、主机名和文件来创建URL对象。
URL(String protocol,String host,String file)
需要注意的是,file参数应当以斜线开头,包括路径、文件名和可选的片段标识符。下面准备了一个很简单的程序创建了URL对象。
try{URL u = new URL("http","www.baidu.com","/index.html#intro");
}catch(MalformedURLException ex){System.out.println("该URL不存在");
}
在默认端口不正确时,我们可以通过显式指定端口来创建URL对象
URL(String protocol,String host,int port,String file)
下面准备了一个很简单的程序创建了URL对象。
try{URL u = new URL("http","www.baidu.com",8080,"/index.html");
}catch(MalformedURLException ex){System.out.println("该URL不存在");
}
③ 构造相对URL对象
这个构造函数根据相对URL和基础URL构造一个绝对URL
URL(URL base,String relative)
例如,你可能正在解析HTML文档http://www.baidu.com/index.html,然后遇到一个名为login.html的文件连接,但没有进一步限定信息。这时,可以用包含该链接的文档的URL来提供缺少的信息。这个构造函数会计算出新的URL为http://www.baidu.com/login.html。下面准备了一个很简单的程序。
try{URL u1 = new URL("http://www.baidu.com/index.html");URL u2 = new URL(u1,"login.html");
}catch(MalformedURLException ex){System.out.println("该URL不存在");
}
如果希望循环处理位于同一个目录下的一组文件,这个构造函数特别有用。
1.2、从URL中获取数据
获取到URL对象之后,我们就可以获取URL所指向文档中所包含的数据。URL类有以下几个方法可以从URL获取数据。
返回值类型 |
方法及说明 |
InputStream |
openStream() 打开与此连接URL并返回一个InputStream以从该连接读取。 |
URLConnection |
openConnection() 返回一个URLConnection实例,该实例表示与该引用的远程对象的连接URL。 |
URLConnection |
openConnection(Proxy proxy) 相同openConnection(),不同之处在于连接将通过指定的代理建立;不支持代理的协议处理程序将忽略代理参数并进行正常连接。 |
Object |
getContent() 获取此URL的内容 |
Object |
getContent(Class[] classes) 获取此URL的内容 |
这些方法中,最常用的是openStream(),它返回一个inputStream,我们可以从这个流读取数据。如果需要更多地控制下载过程,应当调用openConnection方法,这会返回一个可以配置的URLConnection,再由它得到一个InputStream。最后,通过getContent()方法像URL请求其内容。下面我们介绍每个方法。
① InputStream openStream()方法
该方法链接到URL所引用的资源,在客户端和服务器之间完成必要的握手,然后返回一个InputStream对象,通过此对象可以使用InputStreamReader和BufferedReader来封装从而读取数据。
//获取URL对象
URL url = new URL("http://www.baidu.com");
//通过URL对象打开资源通道,返回InputStream原始资源字节流
InputStream is = url.openStream();
//InputStreamReader是字节流通向字符流的桥梁(也可以不用)
InputStreamReader isr = new InputStreamReader(is,"utf-8");
//BufferedReader从字符输入流中读取文本
BufferedReader br = new BufferedReader(isr);
String str;
while ((str = br.readLine()) != null) {System.out.println(str);
}
//关闭流并释放与之关联的所有资源
br.close();
isr.close();
is.close();
从上述案例中,首先创建了URL对象,通过URL对象的openStream()方法打开输入流获取InputStream对象,再由此对象创建BufferedReader对象,通过此对象获取URL所指定资源文件的数据。
需要注意的是,从这个InputStream获取的数据是URL引用的原始数据(即未经解释的内容):如果读取ASCII文件,文件则为ASCII;如果读取HTML文件,则为原始HTML;如果读取图像文件,则为二进制图片数据等。它不包括任何HTTP首部或与协议有关的任何其他信息。
② URLConnection openConnection()方法
URL对象使用OpenConnection()方法打开指定的URL的Socket链接,并返回一个URLConnection对象。该对象表示URL所引用的远程对象的连接,然后再通过该对象的connect()方法进行链接。简单的范例代码如下所示。
//获取URL对象
URL url = new URL("http://www.baidu.com");
//调用URL对象openConnection()方法,获取URLConnection对象
URLConnection URLconnection = url.openConnection();
//将URLConnection对象转换成HttpURLConnection对象
HttpURLConnection httpConnection = (HttpURLConnection)URLconnection;
//获取请求响应码,判断访问是否成功
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {System.err.println("成功"); InputStream is = httpConnection.getInputStream();InputStreamReader isr = new InputStreamReader(is,"utf-8");BufferedReader bufr = new BufferedReader(isr);String str;while ((str = bufr.readLine()) != null) {System.out.println(str);}bufr.close();isr.close();is.close();
} else {System.err.println("失败");
}
如果希望与服务器直接通信,应当使用这个方法。通过URLConnection对象,可以访问服务器发送的所有数据;除了原始的文档本身之外(如HTML、纯文本、二进制图像数据等),它还允许你向URL写入数据,还可以访问这个协议指定的所有元数据。例如,访问HTTP首部以及原始HTML。
③ Object getContent()方法
getContent()方法获取由URL引用的数据,尝试由它建立某种类型的对象。如果URL指示某种文本(如ASCII或HTML文件),返回的文件通常是InputStream;如果URL指示一个图像,则返回一个java.awt.ImageProducer。它们本身并不是数据对象,而是一种途径,程序可以利用它们构造数据对象。
getContent()的做法是,从服务器获取的数据首部中查找Content-type字段。如果服务器没有使用MIME首部,或者发送了一个不熟悉的Content-type,getContent()会返回某种InputStream对象,如果无法获取这个对象,就会抛出一个IOException异常。
④ 使用URLConnectiond对象获取URL信息
Ⅰ. 创建URLConnection对象
URL url = new URL("http://www.baidu.com");
// HTTP协议生成的URLConnection类可以将其转换为HttpURLConnection子类,以便用到HttpURLConnection更多的API
URLConnection urlConnt = url.openConnection();
HttpURLConnection httpUrlConnt = (HttpURLConnection) urlConnt;
Ⅱ. 设置HttpURLConnection对象参数
// 设置是否向httpUrlConnection输出,因为这个是post请求,参数要放在
// http正文内,因此需要设为true, 默认情况下是false;
httpUrlConnection.setDoOutput(true);
// 设置是否从httpUrlConnection读入,默认情况下是true;
httpUrlConnection.setDoInput(true);
// Post 请求不能使用缓存
httpUrlConnection.setUseCaches(false);// 设定传送的内容类型是可序列化的java对象
// (如果不设此项,在传送序列化对象时,当WEB服务默认的不是这种类型时可能抛java.io.EOFException)
httpUrlConnection.setRequestProperty("Content-type", "text/html");
// 设定请求的方法为"POST",默认是GET
httpUrlConnection.setRequestMethod("POST");
// 连接,从上述第2条中url.openConnection()至此的配置必须要在connect之前完成,
httpUrlConnection.connect();
Ⅲ. 通过HttpURLConnection写数据与发送数据问题
// 现在通过“输出流对象”构建“对象输出流对象”,以实现输出可序列化的对象。
ObjectOutputStream objOutputStrm = new ObjectOutputStream(outStream);
// 向对象输出流写出数据,这些数据将存到内存缓冲区中
objOutputStrm.writeObject(new String("我是测试数据"));
// 刷新对象输出流,将任何字节都写入潜在的流中(些处为ObjectOutputStream)
objOutputStm.flush();
// 关闭流对象。此时,不能再向对象输出流写入任何数据,先前写入的数据存在于内存缓冲区
// 在调用下边的getInputStream()函数时才把准备好的http请求正式发送到服务器
objOutputStm.close();// 调用HttpURLConnection连接对象的getInputStream()函数,
// 将内存缓冲区中封装好的完整的HTTP请求电文发送到服务端。
InputStream inStrm = httpUrlConnt.getInputStream();
// 上边的httpConn.getInputStream()方法已调用,本次HTTP请求已结束,下边向对象输出流的输出已无意义,
// 既使对象输出流没有调用close()方法,下边的操作也不会向对象输出流写入任何数据.
// 因此,要重新发送数据时需要重新创建连接、重新设参数、重新创建流对象、重新写数据、
// 重新发送数据(至于是否不用重新这些操作需要再研究)
objOutputStm.writeObject(new String(""));
httpUrlConnt.getInputStream();
Socket通信实现步骤
1. 创建ServerSocekt和Socket
2. 打开连接到Socket的输入/输出流
3. 依照协议对Socket进行读写操作
4. 关闭输入输出流、关闭Socket
1.3、分解URL
URL由5部分组成:协议、授权机构、路径、查询字符串、片段标识符。
例如,在http://www.baidu.com/index.html?id=220308#toc中,协议是http;授权机构是www.baidu.com;路径是index.html;查询字符串是id=220308;片段标识符是toc。
授权机构还可以进一步划分为用户信息、主机和端口。例如在http://admin@www.baidu.com:8080/中,授权机构包含用户信息admin、主机www.baidu.com和端口8080
java提供了下面9个公共方法对上述URL组成部分进行只读访问
返回类型 |
描述 |
描述 |
String |
getProtocal() |
返回URL的协议 |
String |
getHost() |
返回URL的主机 |
int |
getPort() |
返回URL端口部分 |
String |
getFile() |
返回URL文件名部分 |
String |
getQuery() |
返回URL查询部分。 |
String |
getPath() |
返回URL路径部分。 |
String |
getAuthority() |
获取此 URL 的授权部分。 |
int |
getDefaultPort() |
协议的默认端口号。 |
String |
getRef() |
返回URL片段标识符。 |
String |
getUserInfo() |
返回用户名或口令信息。 |
下面通过简单程序演示上面的这个方法
try{URL url = new URL("http://www.baidu.com/index.html?id=220308#Laoye");System.out.println("URL 为:" + url.toString());System.out.println("协议为:" + url.getProtocol());System.out.println("验证信息:" + url.getAuthority());System.out.println("文件名及请求参数:" + url.getFile());System.out.println("主机名:" + url.getHost());System.out.println("路径:" + url.getPath());System.out.println("端口:" + url.getPort());System.out.println("默认端口:" + url.getDefaultPort());System.out.println("请求参数:" + url.getQuery());System.out.println("定位位置:" + url.getRef());
}catch(IOException e){e.printStackTrace();
}
输出结果如下所示。
[URL: http://www.baidu.com/index.html?id=220308#Laoye]
[协议: http]
[验证信息: www.baidu.com]
[文件名及参数: /index.html?id=220308]
[主机名: www.baidu.com]
[资源路径: /index.html]
[端口: -1]
[默认端口: 80]
[请求参数: id=220308]
[片段标识符: Laoye]
1.4、判断两个URL是否相等
URL类包含通常的equals()和hashCode()方法,当且仅当两个URL都指向相同主机、端口和路径上的相同资源,而且具有相同的片段标识符和查询字符串,才认为这两个URL是相等。实际上equals()方法会尝试使用DNS解析主机,来判断两个主机是否相同。
另一方面,equals()还不够深入,不会具体比较两个URL标识的资源。例如,http://www.baidu.com/不等于http://www.baidu.com/index.html。
下面我们通过简单的范例程序来演示。
URL url1 = new URL("http://www.baidu.com");
URL url2 = new URL("http://baidu.com");
if(url1.equals(url2)){System.out.println("URL1 和 URL2 相等");
}else{System.out.println("URL1 和 URL2 不相等");
}
除此之外,URL类还有一个sanmeFile()方法,可以检查两个URL是否指向相同的资源。
try{URL url1 = new URL("http://www.baidu.com:80/index.html");URL url2 = new URL("http://www.baidu.com/index.html");if(url1.sameFile(url2)){System.out.println("URL1 和 URL2 指向相同的资源");}else{System.out.println("URL1 和 URL2 指向不同的资源");}
}catch(MalformedURLException ex){System.err.println(ex);
}
需要注意的是,sameFile()只有在两个URL路径几乎一样才会返回true,即使前面的请求路径完全一样,但是请求参数不一样也会返回false,例如下面范例程序所示的情况。
URL url1 = new URL("http://www.baidu.com/index.html");
URL url2 = new URL("http://baidu.com/index.html");
URL url3 = new URL("http://www.baidu.com/index.html?id=308");
URL url4 = new URL("http://www.baidu.com/index.html?id=309");
上述的4个对象两两互不相等。
1.5、比较两个URL
URL有3个方法可以将一个实例转换为另外一种形式,分别是toString()、toExternalForm()和toURI()。
toString()返回的是String类型的绝对URL。显示调用toString()并不常见,通过显示(打印)语句会隐式调用toString()方法,除了打印语句以外,使用toExternalForm()方法更合适。
toExternalForm()方法将一个URL对象转换为一个字符串(拼接方式)。该方法返回表示这个URL的刻度String,它等同于toString()方法。事实上,URL的toString()方法就是返回该方法。
最后,toURI()方法将URL对象转换为URI对象。值得注意的是,URI类提供了比URL类更精确、更符合规范的行为。对于像绝对化和编码等操作,在选择时应当首选URI类。如果需要把URL存储在一个散列表或其他数据结构中,也应当首选URI类,因为它equals()方法不会阻塞。 ⬅ 重点理解
Java系列学习笔记 --- 网络编程(3)URL相关推荐
- Java学习笔记-网络编程
Java提供了网络编程,并且在实际中有着大量运用 网络编程 网络编程概述 网络模型 OSI参考模型 TCP/IP参考模型 网络通讯要素 IP地址 端口号 传输协议 网络参考模型 网络通讯要素 IP地址 ...
- java 学习笔记-网络编程(八)
网络编程 标签:学习各种网络协议的桥梁 什么是计算机网络 计算机网络的作用:资源共享和信息传递. 计算机网络的组成: a) 计算机硬件:计算机(大中小型服务器,台式机.笔记本等).外部设备(路由器.交 ...
- Java 网络编程 03 —— URL下载资源
系列文章目录 Java 网络编程 01 -- Socket TCP通信 Java 网络编程 02 -- Socket UDP通信 Java 网络编程 03 -- URL下载资源 文章目录 系列文章目录 ...
- Java之HTTP网络编程(下篇:网页浏览器程序设计)
目录 一.本篇简介 二.URL类 三.基于URL类的网页下载 1.发送按钮 2.接收数据的多线程 四.URL网页下载客户端 五.编写web浏览器 1.WebEngine类 2.WebView类 3.W ...
- java程序设计之网络编程基础教程_Java程序设计之网络编程基础教程
基本信息 书名:Java程序设计之网络编程基础教程(21世纪高等学校计算机基础实用规划教材) :43.50元 作者:李芝兴 主编 出版社:清华大学出版社 出版日期:2012-12-1 ISBN:978 ...
- Java中的网络编程类(TCPUDP)
Java中的网络编程类 n Java.net包 – TCP协议 URL URLConnection Socket ServerSocket – UDP协议 DatagramPacket Datagra ...
- JAVA基础11 网络编程
JAVA基础 11.网络编程 1.什么是网络?网络模型?网络四要素? 1.网络 在计算机领域中网络是信息传输,接收,共享的虚拟平台,通过它把各个点,面,体的联系到一起,从而实现这些资源的共享. 资源的 ...
- [Java入门笔记] 面向对象编程基础(二):方法详解
2019独角兽企业重金招聘Python工程师标准>>> 什么是方法? 简介 在上一篇的blog中,我们知道了方法是类中的一个组成部分,是类或对象的行为特征的抽象. 无论是从语法和功能 ...
- Java进阶之网络编程
网络编程 网络编程对于很多的初学者来说,都是很向往的一种编程技能,但是很多的初学者却因为很长一段时间无法进入网络编程的大门而放弃了对于该部分技术的学习. 在 学习网络编程以前,很多初学者可能觉得网络编 ...
最新文章
- QCon2016旧金山大会焦点分享者确认
- C#/.Net判断是否为周末/节假日
- Python使用matplotlib可视化散点图、并在可视化图像的底部和右边添加边缘箱图(Marginal Boxplot)
- mysql大于等于怎么写_数据库中大于等于0小于等于100怎样表达
- python 之属性_Python之对象的属性
- C/C++中使用函数memset对int型数组赋值(0,-1,max,min)
- Java项目目录结构与解析
- php缓存accestoken_PHP获取微信access_token并缓存和自动更新
- 【SPSS】第十周-面板数据的线性回归
- 通过Java,Spring Boot应用程序将Gmail用作SMTP服务器
- postgresql 安装使用
- 使用手机访问 Office 文档
- Java获取指定时间前一小时、后一小时的时间
- 配置聚合连接 和 配置firewalld防火墙
- html img图片不变形等比例缩放,兼容ie6
- iOS最全的三方库、插件、博客汇总
- 信息技术的技术趋势和未来展望
- 多项式曲线拟合之最小二乘法推导
- 恢复W ndows10系统方法步骤,教你windows10的映像文件还原系统
- activiti的流程事件
热门文章
- 【已解决】Pycharm由于Zib版本问题无法import cv2-/lib/x86_64-linux-gnu/libz.so.1: version `ZLIB_1.2.9‘ not found
- 【搜索】[SCOI2009] 生日快乐 BZOJ 1024
- 力控液位控制增量式PID算法
- 深度|医疗行业勒索病毒防治解决方案
- 控制用计算机论文,计算机电子控制技术及应用论文
- matlab获取手机传感器,分享采集Android内置传感器数据到MATLAB的方法
- 关于c++中set集合的使用
- 移动App常见测试范围
- 从Excel表格中复制列数据并粘贴到Word表格中
- Docker核心技术(二):网络管理