目录
一.Internet下载流程... 1
二.下载管理器概述... 2
三.Download、DownloadsTableModel、ProgressRenderer、DownloadManager四个类的代码清单及功能说明... 3
1、Download.java. - 4 -
2、DownloadManager.java. - 8 -
3、DownloadsTableModel.java. - 15 -
4、ProgressRenderer.java. - 17 -
四.编译并运行下载管理器... 18
五.实训体会. - 19 -
一.Internet下载流程
其工作过程可分为四步:
首先客户机与服务器需要建立连接。只要单击某个超级链接,HTTP的工作就开始了。
建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可能的内容。
服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。
客户端接收服务器所返回的信息通过浏览器显示在用户的显示屏上,然后客户机与服务器断开连接。
工作流程图
如果在以上过程中的某一步出现错误,那么产生错误的信息将返回到客户端,由显示屏输出。对于用户来说,这些过程是由HTTP自己完成的,用户只要用鼠标点击,等待信息显示就可以了。
许多HTTP通讯是由一个用户代理初始化的并且包括一个申请在源服务器上资源的请求。最简单的情况可能是在用户代理和服务器之间通过一个单独的连接来完成。在Internet上,HTTP通讯通常发生在TCP/IP连接之上。缺省端口是TCP 80,但其它的端口也是可用的。但这并不预示着HTTP协议在Internet或其它网络的其它协议之上才能完成。HTTP只预示着一个可靠的传输。
在WWW中,“客户”与“服务器”是一个相对的概念,只存在于一个特定的连接期间,即在某个连接中的客户在另一个连接中可能作为服务器。基于HTTP协议的客户/服务器模式的信息交换过程,它分四个过程:建立连接、发送请求信息、发送响应信息、关闭连接。这就好像上面的例子,我们电话订货的全过程。
其实简单说就是任何服务器除了包括HTML文件以外,还有一个HTTP驻留程序,用于响应用户请求。你的浏览器是HTTP客户,向服务器发送请求,当浏览器中输入了一个开始文件或点击了一个超级链接时,浏览器就向服务器发送了HTTP请求,此请求被送往由IP地址指定的URL。驻留程序接收到请求,在进行必要的操作后回送所要求的文件。在这一过程中,在网络上发送和接收的数据已经被分成一个或多个数据包(packet),每个数据包包括:要传送的数据;控制信息,即告诉网络怎样处理数据包。TCP/IP决定了每个数据包的格式。如果事先不告诉你,你可能不会知道信息被分成用于传输和再重新组合起来的许多小块。
HTTP/1.0
这是第一个在通讯中指定版本号的 HTTP 协议版本,至今仍被广泛采用,特别是在代理服务器中。
HTTP/1.1
当前版本。持久连接被默认采用,并能很好地配合代理服务器工作。还支持以管道方式在同时发送多个请求和断点继传,这是ftp不法实现的。以便降低线路负载,提高传输速度。
二.下载管理器概
Downkoad 下载管理器它可以暂停下载并恢复,还可以同时实现多个下载,此外它还可以从下载的中断点恢复下载。此下载器不仅实现了文件下载功能,它还可以进行功能扩充,只要增加一些类和方法就可以实现。
Download的主要工作由Download类[完成。它的主要作用是下载 一个文件并将其内容保存到磁盘,每次向Download添加一个新的下载任务时,就会有一个新的Download对象被实例化,已处理这个下载。
Download具有同时下载多个文件的能力。为此,每个进行的下载任务都必须独立进行,且每个单独的下载还管理自己的状态,以便反映在GUI中。
Download类首先声明几个静态的final变量,用来指定类中将使用的几个变量,变量URL用来保存被下载文件的URL,变量size用来指定下载文件的字节数大小,变量Download用来保存已经下载的字节数
主要功能按钮介绍
文本域:用于输入你要下载的文件的URL地址。
addDownioad:此按钮被点击时GUI会注册一个监听对象。
url:用于显示当前正在下载的任务的网络地址。
size:用于显示下载对象的文件大小。
progress:用于显示下载完成的百分比。
status:用于显示当前的下载状态。
pause:暂停当前的下载任务。
resume:继续当前的下载任务。
cancel:取消当前的下载任务。
clear:将当前的下载任务从列表中删除。
GUI管理当前的下载列表。列表中的每个下载都会报告它的URL,文件大小(字节形式),完成的百分比进度及当前状态。
根据功能组件的会划分,Downkoad 可以分为几个类,Downkoad Manager 类负责GUI。Downkoad TableModel 和ProgressRenderer 类显示当前的下载列表。Downkoad 负责执行文件的实际下载操作。
三.Download、DownloadsTableModel、ProgressRenderer、DownloadManager四个类的代码清单及功能说明
Download类负责执行文件下载操作,它主要作用是下载一个文件并将其保存到磁盘。
DownloadsTableMode类主要用于容纳下载列表,并且是GUI实例的后台数据源。
ProgressRenderer类是一个小的工具类,用于显示列与GUI下载列表的下载的当前速度。
Download类负责创建并运行GUI实例,同时利用DownloadsTableMode和ProgressRenderer,以显示当前的下载列表。
四个类的代码如下
1、 Download.java
import java.io.*;
import java.net.*;
import java.util.*;
//这个类用于从一个URL地址下载文件
class Download extends Observable implements Runnable {
// 下载缓冲区最大大小
private static final int MAX_BUFFER_SIZE = 1024;
// 这些是状态名称
public static final String STATUSES[] = {"Downloading",
"Paused", "Complete", "Cancelled", "Error"};
// 这些是状态代码
public static final int DOWNLOADING = 0;
public static final int PAUSED = 1;
public static final int COMPLETE = 2;
public static final int CANCELLED = 3;
public static final int ERROR = 4;
private URL url; // 下载地址
private int size; // 文件大小(字节)
private int downloaded; // 已下载大小(字节)
private int status; // 当前下载状态
// 构造下载函数.
public Download(URL url) {
this.url = url;
size = -1;
downloaded = 0;
status = DOWNLOADING;
// 开始下载
download();
}
// 获取这个下载的地址
public String getUrl() {
return url.toString();
}
// 获取该下载的文件大小
public int getSize() {
return size;
}
// 获取该下载的下载进度
public float getProgress() {
return ((float) downloaded / size) * 100;
}
// 获取该下载的下载状态
public int getStatus() {
return status;
}
// 暂停下载
public void pause() {
status = PAUSED;
stateChanged();
}
// 恢复下载
public void resume() {
status = DOWNLOADING;
stateChanged();
download();
}
// 取消下载
public void cancel() {
status = CANCELLED;
stateChanged();
}
// 标记该下载,因为下载出错
private void error() {
status = ERROR;
stateChanged();
}
// 开始或恢复下载
private void download() {
Thread thread = new Thread(this);
thread.start();
}
// 从URL地址中获取文件名
private String getFileName(URL url) {
String fileName = url.getFile();
return fileName.substring(fileName.lastIndexOf('/') + 1);
}
// 下载文件
public void run() {
RandomAccessFile file = null;
InputStream stream = null;
try {
// 连接URL
HttpURLConnection connection =
(HttpURLConnection) url.openConnection();
// 指定下载文件的开始位置(应该是断点续传的意思)
connection.setRequestProperty("Range",
"bytes=" + downloaded + "-");
// 连接
connection.connect();
// 确定回应代码在200以内
if (connection.getResponseCode() / 100 != 2) {
error();
}
// 检查有效的内容长度
int contentLength = connection.getContentLength();
if (contentLength < 1) {
error();
}
// 设置下载的大小如果尚未设置
if (size == -1) {
size = contentLength;
stateChanged();
}
// 打开文件并查找文件尾
file = new RandomAccessFile(getFileName(url), "rw");
file.seek(downloaded);
stream = connection.getInputStream();
while (status == DOWNLOADING) {
// 缓冲区大小根据剩余文件大小调整
byte buffer[];
if (size - downloaded > MAX_BUFFER_SIZE) {
buffer = new byte[MAX_BUFFER_SIZE];
} else {
buffer = new byte[size - downloaded];
}
// 从服务器读取并存入缓冲区
int read = stream.read(buffer);
if (read == -1)
break;
// 从缓冲区读取并写入文件
file.write(buffer, 0, read);
downloaded += read;
stateChanged();
}
// 如果文件下载完成,改变下载状态为complete
if (status == DOWNLOADING) {
status = COMPLETE;
stateChanged();
}
} catch (Exception e) {
error();
} finally {
// 关闭文件
if (file != null) {
try {
file.close();
} catch (Exception e) {}
}
// 关闭与服务器的连接
if (stream != null) {
try {
stream.close();
} catch (Exception e) {}
}
}
}
// 提醒使用者下载状态已经改变
private void stateChanged() {
setChanged();
notifyObservers();
}
}
}
2、DownloadManager.java
import java.awt.*;//引入所以的包
import java.awt.event.*;//引入所以事件包
import java.net.*;//引入网络
import java.util.*;//引入所需的使用的包
import javax.swing.*;//引入swing文件夹
import javax.swing.event.*;//引入swing文件夹下的事件包
// 下载管理
public class DownloadManager extends JFrame//定义下载管理类继承窗口
implements Observer//实现观察者
{
// 下载文本域
private JTextField addTextField;//定义文本域增加域
// 下载表数据模型
private DownloadsTableModel tableModel;//定义下载表格模型
// 下载表格列表
private JTable table;//定义表格
// 这些按钮为管理选定的下载
private JButton pauseButton, resumeButton;//定义按钮
private JButton cancelButton, clearButton;//定义按钮
// 当前选择的下载
private Download selectedDownload;//定义选择下载
// 表的选择标记是否被清除
private boolean clearing;//定义类型
// 构造函数可下载管理
public DownloadManager()//定义下载管理
{
// 设置应用主题
setTitle("Download Manager");//主题名称
// 设置窗口尺寸
setSize(640, 480);//窗口大小
// 处理窗口关闭事件
addWindowListener(new WindowAdapter() //增加窗口监听器
{
public void windowClosing(WindowEvent e) //定义空窗口
{
actionExit();//操作出口
}
});
// 建立文件菜单
JMenuBar menuBar = new JMenuBar();//定义菜单栏
JMenu fileMenu = new JMenu("File");//定义文件菜单
fileMenu.setMnemonic(KeyEvent.VK_F);//建立文件菜单
JMenuItem fileExitMenuItem = new JMenuItem("Exit",
KeyEvent.VK_X);//菜单文件出口
fileExitMenuItem.addActionListener(new ActionListener()//增加退出窗口
{
public void actionPerformed(ActionEvent e)//定义空菜单出口
{
actionExit();//操作出口
}
});
fileMenu.add(fileExitMenuItem);//文件菜单
menuBar.add(fileMenu);//在文件才单中增加菜单条
setJMenuBar(menuBar);//建立菜单条
// 建立增加面板
JPanel addPanel = new JPanel();//定义面板
addTextField = new JTextField(30);//增加文本文件
addPanel.add(addTextField);//增加面板
JButton addButton = new JButton("Add Download");//面板名称
addButton.addActionListener(new ActionListener()//增加操作监听器
{
public void actionPerformed(ActionEvent e) //定义所做的操作空间,
{
actionAdd();//增加操作
}
});
addPanel.add(addButton);//增加面板
// 建立下载表
tableModel = new DownloadsTableModel();//定义表格模型
table = new JTable(tableModel);//定义表格
table.getSelectionModel().addListSelectionListener(new
ListSelectionListener() //建立表格
{
public void valueChanged(ListSelectionEvent e) //定义值的变化
{
tableSelectionChanged();//表格选择变化
}
});
// 只允许一排在同一时间来挑选
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);//建立表格模型
// 建立进度条为描绘器为进度的专栏
ProgressRenderer renderer = new ProgressRenderer(0, 100);//定义进度描绘器
renderer.setStringPainted(true); // 显示文本进度
table.setDefaultRenderer(JProgressBar.class, renderer);//表格建立默认进度
// 设定的表的行高足够大适合进度条
table.setRowHeight(
(int) renderer.getPreferredSize().getHeight());//定义表格行高
// 建立下载面板
JPanel downloadsPanel = new JPanel();//定义下载面板
downloadsPanel.setBorder(
BorderFactory.createTitledBorder("Downloads"));//下载面板,建立边框
downloadsPanel.setLayout(new BorderLayout());//下载面板,建立布局
downloadsPanel.add(new JScrollPane(table),//创建滚动窗口
BorderLayout.CENTER);//边框布局
// 设置按钮面板
JPanel buttonsPanel = new JPanel();//定义按钮面板
pauseButton = new JButton("Pause");//显示暂停按钮
pauseButton.addActionListener(new ActionListener() //暂停按钮,增加监听器
{
public void actionPerformed(ActionEvent e)//定义按钮单击方法
{
actionPause();//操作暂停
}
});
pauseButton.setEnabled(false);//暂停按钮,建立启用
buttonsPanel.add(pauseButton);//按钮控制面板,增加暂停按钮
resumeButton = new JButton("Resume");//定义重新开始按钮
resumeButton.addActionListener(new ActionListener() //重新开始按钮,增加监听器
{
public void actionPerformed(ActionEvent e) //定义监听器
{
actionResume();//重新开始操作
}
});
resumeButton.setEnabled(false);//重新开始按钮,建立启用
buttonsPanel.add(resumeButton);//按钮控制面板,增加重新开始按钮
cancelButton = new JButton("Cancel");//定义取消按钮
cancelButton.addActionListener(new ActionListener()// 取消按钮,增加监听器
{
public void actionPerformed(ActionEvent e) //定义监听器
{
actionCancel();//重新取消操作
}
});
cancelButton.setEnabled(false);//取消按钮,建立启动
buttonsPanel.add(cancelButton);//按钮控制板,增加取消按钮
clearButton = new JButton("Clear");//定义清除按钮
clearButton.addActionListener(new ActionListener()// 清除按钮,增加监听器
{
public void actionPerformed(ActionEvent e)//定义监听器
{
actionClear();//清除操作
}
}
);
clearButton.setEnabled(false);//清除按钮,建立启动
buttonsPanel.add(clearButton);//按钮控制板,增加清除按钮
// Add panels to display.
getContentPane().setLayout(new BorderLayout());
getContentPane().add(addPanel, BorderLayout.NORTH);
getContentPane().add(downloadsPanel, BorderLayout.CENTER);
getContentPane().add(buttonsPanel, BorderLayout.SOUTH);
}
// 添加面板显示
private void actionExit() //定义操作出口
{
System.exit(0);//退出系统
}
// 增加一个新的下载
private void actionAdd() //定义操作增加
{
URL verifiedUrl = verifyUrl(addTextField.getText());//定义连接地址
if (verifiedUrl != null) //条件判断语句
{
tableModel.addDownload(new Download(verifiedUrl));//表格模型,增加下载
addTextField.setText(""); // 重置添加文本域
} else //条件判断语句
{
JOptionPane.showMessageDialog(this,
"Invalid Download URL", "Error",
JOptionPane.ERROR_MESSAGE);//定义消息对话框
}
}
// 确认下载网址
private URL verifyUrl(String url) //定义下载地址
{
// 只允许HTTP的网站链接。
if (!url.toLowerCase().startsWith("http://"))//判断地址是否正确
return null;//返回空地址
// 确认链接地址的格式
URL verifiedUrl = null;//连接地址是否为空
try {
verifiedUrl = new URL(url);//确定新连接地址
} catch (Exception e) //抓捕异常
{
return null;//返回空地址
}
// Make sure URL specifies a file.
if (verifiedUrl.getFile().length() < 2)
return null;
return verifiedUrl;
}
// 确保链接地址指定一个文件
private void tableSelectionChanged() //定义表格选择
{
/* 注销从接受通知从最后选择下载 */
if (selectedDownload != null)
selectedDownload.deleteObserver(DownloadManager.this);//条件判断语句,选择下载
/* 如果不在明确的中间一个下载,使选择下载,注册收到通知 */
if (!clearing) //条件判断语句,清除
{
selectedDownload =
tableModel.getDownload(table.getSelectedRow());//建立下载
selectedDownload.addObserver(DownloadManager.this);//增加观察员
updateButtons();//更新按钮
}
}
// 暂停选择下载
private void actionPause()//定义操作暂停
{
selectedDownload.pause();//选择下载,暂停
updateButtons();//更新按钮
}
// 恢复选择下载
private void actionResume() //定义恢复操作
{
selectedDownload.resume();//选择下载,恢复
updateButtons();//更新按钮
}
// 取消选择下载
private void actionCancel() //定义取消操作
{
selectedDownload.cancel();//选择下载,取消
updateButtons();//更新按钮
}
// 清除选择下载
private void actionClear()//定义清除操作
{
clearing = true;//清除为真
tableModel.clearDownload(table.getSelectedRow());//表格模型,清除下载
clearing = false;//清除为假
selectedDownload = null;//选择下载为空
updateButtons();//更新按钮
}
/* 更新每个按钮的基本关闭当前选择下载的任务 */
private void updateButtons()//定义跟新按钮
{
if (selectedDownload != null) //条件语句,选择下载!为空
{
int status = selectedDownload.getStatus();//建立选择下载状态
switch (status)//状态
{
case Download.DOWNLOADING://管理下载,下载
pauseButton.setEnabled(true);//启用暂停按钮
resumeButton.setEnabled(false);//启用恢复按钮
cancelButton.setEnabled(true);//启用取消按钮
clearButton.setEnabled(false);//启用清除按钮
break;//中断
case Download.PAUSED://管理下载,停止
pauseButton.setEnabled(false);//启用暂停按钮
resumeButton.setEnabled(true);//启用恢复按钮
cancelButton.setEnabled(true);//启用取消按钮
clearButton.setEnabled(false);//启用清除按钮
break;//中断
case Download.ERROR://管理下载,错误
pauseButton.setEnabled(false);//启用暂停按钮
resumeButton.setEnabled(true);//启用恢复按钮
cancelButton.setEnabled(false);//启用取消按钮
clearButton.setEnabled(true);//启用清除按钮
break;//中断
default: // 完成或取消
pauseButton.setEnabled(false);//启用暂停按钮
resumeButton.setEnabled(false);//启用恢复按钮
cancelButton.setEnabled(false);//启用取消按钮
clearButton.setEnabled(true);//启用清除按钮
}
} else //条件语句
{
// 没有下载被选择表。
pauseButton.setEnabled(false);//启用暂停按钮
resumeButton.setEnabled(false);//启用恢复按钮
cancelButton.setEnabled(false);//启用取消按钮
clearButton.setEnabled(false);//启用清除按钮
}
}
/* 更新被呼叫当一个下载通知它的检查员在所有的变化当中 */
public void update(Observable o, Object arg)//定义更新
{
// 更新按钮如果选择下载改变了
if (selectedDownload != null && selectedDownload.equals(o))//条件判断语句,定义选择下载
updateButtons();//更新按钮
}
// 下载管理。
public static void main(String[] args) //定义主要
{
DownloadManager manager = new DownloadManager();//下载管理
manager.show();//管理显示
}
}
3、DownloadsTableModel.java
import java.util.*;//引入包下的所有类
import javax.swing.*;//引入swing文件夹
import javax.swing.table.*;//引入swing文件夹下的所有表
// 这个类管理下载表格的数据
class DownloadsTableModel extends AbstractTableModel//下载表模式添加到文字表模式中
implements Observer//观察员执行
{
// 这些都为表的列名
private static final String[] columnNames = {"URL", "Size",
"Progress", "Status"};//定义消息框("地址","大小","进度","状态")
// 这些是每个列的值的类
private static final Class[] columnClasses = {String.class,
String.class, JProgressBar.class, String.class};//定义类("字符串类","按钮类","字符串类","字符串类")
// 表的下载列表
private ArrayList downloadList = new ArrayList();//定义下载的类
// 在表中增加新的下载
public void addDownload(Download download) //定义增加下载的观察
{
// 记录并通知下载的变化
download.addObserver(this);//增加下载的观察
downloadList.add(download);//增加下载
// 表下载插入到行的通知
fireTableRowsInserted(getRowCount() - 1, getRowCount() - 1);//得到插入通知
}
// 得到一个指定的行下载
public Download getDownload(int row)//定义获得下载的行
{
return (Download) downloadList.get(row);//返回获得下载的行
}
// 从清单删除下载
public void clearDownload(int row)//定义清除下载的行
{
downloadList.remove(row);//从下载列表中删除行
// 消除表行删除通知表
fireTableRowsDeleted(row, row);//删除表行
}
// 获得表的列计数
public int getColumnCount()//定义获得列数
{
return columnNames.length;//返回列数
}
// 获取列的名称
public String getColumnName(int col)//定义获取列的类型
{
return columnNames[col];//返回列的名称
}
// 获得列的名称
public Class getColumnClass(int col)//定义获得列的类型
{
return columnClasses[col];//返回列的类
}
// 获得表的行数
public int getRowCount()//定义得到的行
{
return downloadList.size();//返回得到的行
}
// 获得值为一个具体行和栏组合
public Object getValueAt(int row, int col)//定义对象的值
{
Download download = (Download) downloadList.get(row);//获得下载类表
switch (col) //条件语句
{
case 0: //判断语句
return download.getUrl();//返回连接地址
case 1: //判断语句
int size = download.getSize();//获得下载的大小
return (size == -1) ? "" : Integer.toString(size);//返回判断结果
case 2: //判断语句
return new Float(download.getProgress());//返回下载的进度
case 3: // 判断语句
return Download.STATUSES[download.getStatus()];//返回下载的状态
}
return "";//返回空值
}
/* 下载更新通知时调用观察家的任何变化*/
public void update(Observable o, Object arg)//定义空的更新对象
{
int index = downloadList.indexOf(o);//显示下载列表的指数
// 启动通知表格行表
fireTableRowsUpdated(index, index);//启动更新表行
}
}
4、ProgressRenderer.java
import java.awt.*;//引入所以的java包
import javax.swing.*;//引入swing文件夹
import javax.swing.table.*;//引入swing文件夹下的所有表
// 在这个类提出一个进度条在一个表格
class ProgressRenderer extends JProgressBar//在进程描绘器继承进度条
implements TableCellRenderer//实现表格描绘器
{
// 构造函数为进程描绘器
public ProgressRenderer(int min, int max)//定义进程描绘器
{
super(min, max);//定义大小
}
/* 返回回这个进程条为描绘器对于给定的表格 */
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column)//定义组件得到表格描绘器的组成部分
{
// 集进度条的完成百分比值
setValue((int) ((Float) value).floatValue());//定义设定值
return this;//返回组件
}
}
四.编译并运行下载管理器
程序编写完以后双击工具栏上的RUN按钮,就会弹出下载管理器窗口程序即可运行如图示:
(程序正常运行)
在文本域中输入一张图片的ip地址
单击adddownioad按钮,会在下面的progress顷中显示进程。
当输入不符合的ip地址时就会出现url顷有问题
当没有在文本框中输入任何信息时或输入非ip地址时就会出现提示
五.实训体会
通过一周的实练,使我明白了语言是互相连通的,在大体上或思想上是一致的,无非是表现形式的不同,比如c语言的构成是函数,vb的基本构成是过程,java的基本构成是类,,它们所完成的功能是一样的。Java在事先就定义了许多的类,用来帮助我们开发程序,我们只需引用这些类即可,不过java也有繁琐的地方,就是有些方法不能直接使用,或需要构造方法来创建对象才能使用的,一个简单的动作变得得很复杂,歌舞剧以我在学习的过程中遇到了不小的问题。
这次实练又使我明白了开发程序其实不需要完全读懂一段程序,只要能明白这一段程序的意思和改变哪些设置就能出现其它的效果就可以了,我们不可能明白所有的程序的表达的意思,但如果能读懂就可以利用它了。
我们肯定是读不懂没有学过的程序的,这个时候就需要利用网络上资源了,我选择加入专业的网站,从网上查找答案,找到我们要的东西。
Java是嵌入式型的语言,可以将它放在网页中,给网页添加动态的效果,同时还能与网络协议连通,实现更加强大的用途,为以为的网络编程提供了基础。