今天学习了Android开发中比較难的一个环节,就是断点续传下载,非常多人看到这个标题就感觉头大。的确,假设没有良好的逻辑思维,这块的确非常难搞明确。以下我就将自己学到的知识和一些见解写下供那些在这个环节还烦恼的人參考。这里我以下载mp3文件为例。

断点续传下载,顾名思义。那就是我们在一次下载未结束时。退出下载,第二次下载时会接着第一次下载的进度继续下载。那么怎么记录第一次下载的数据呢。这里肯定就要用到数据库了。以下就是我创建数据库的一个SQLiteOpenHelper类。用来首次执行时创建数据库。

DBHelper类:

 1 package cn.yj3g.DBHelper;
2
3 import android.content.Context;
4 import android.database.sqlite.SQLiteDatabase;
5 import android.database.sqlite.SQLiteOpenHelper;
6
7 /**
8 * 建立一个数据库帮助类
9 */
10 public class DBHelper extends SQLiteOpenHelper {
11 //download.db-->数据库名
12 public DBHelper(Context context) {
13 super(context, "download.db", null, 1);
14 }
15
16 /**
17 * 在download.db数据库下创建一个download_info表存储下载信息
18 */
19 @Override
20 public void onCreate(SQLiteDatabase db) {
21 db.execSQL("create table download_info(_id integer PRIMARY KEY AUTOINCREMENT, thread_id integer, "
22 + "start_pos integer, end_pos integer, compelete_size integer,url char)");
23 }
24 @Override
25 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
26
27 }
28
29 }

以下来看主界面的布局,在这里。我仅仅设计了一个ListView来显示下载的音乐的名称,和一个開始下载button和一个暂停button。

布局文件例如以下:

main.xml:

 1 <?

xml version="1.0" encoding="utf-8"?

>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="fill_parent"
6 android:id="@+id/llRoot">
7 <ListView android:id="@android:id/list"
8 android:layout_width="fill_parent"
9 android:layout_height="fill_parent">
10 </ListView>
11 </LinearLayout>

list_item.xml:

 1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:orientation="vertical"
4 android:layout_width="fill_parent"
5 android:layout_height="wrap_content">
6 <LinearLayout
7 android:orientation="horizontal"
8 android:layout_width="fill_parent"
9 android:layout_height="wrap_content"
10 android:layout_marginBottom="5dip">
11 <TextView
12 android:layout_width="fill_parent"
13 android:layout_height="wrap_content"
14 android:layout_weight="1"
15 android:id="@+id/tv_resouce_name"/>
16 <Button
17 android:layout_width="fill_parent"
18 android:layout_height="wrap_content"
19 android:layout_weight="1"
20 android:text="下载"
21 android:id="@+id/btn_start"
22 android:onClick="startDownload"/>
23 <Button
24 android:layout_width="fill_parent"
25 android:layout_height="wrap_content"
26 android:layout_weight="1"
27 android:text="暂停"
28 android:id="@+id/btn_pause"
29 android:onClick="pauseDownload"/>
30 </LinearLayout>
31 </LinearLayout>

主界面执行效果例如以下:

以下我们来看详细实现下载的方法。首先。我们要定义一个记录在下载时各个时期的数据的类。这里我创建了一个DownloadInfo类来记录。代码例如以下:

DownloadInfo:

 1 package cn.yj3g.entity;
2 /**
3 *创建一个下载信息的实体类
4 */
5 public class DownloadInfo {
6 private int threadId;//下载器id
7 private int startPos;//開始点
8 private int endPos;//结束点
9 private int compeleteSize;//完毕度
10 private String url;//下载器网络标识
11 public DownloadInfo(int threadId, int startPos, int endPos,
12 int compeleteSize,String url) {
13 this.threadId = threadId;
14 this.startPos = startPos;
15 this.endPos = endPos;
16 this.compeleteSize = compeleteSize;
17 this.url=url;
18 }
19 public DownloadInfo() {
20 }
21 public String getUrl() {
22 return url;
23 }
24 public void setUrl(String url) {
25 this.url = url;
26 }
27 public int getThreadId() {
28 return threadId;
29 }
30 public void setThreadId(int threadId) {
31 this.threadId = threadId;
32 }
33 public int getStartPos() {
34 return startPos;
35 }
36 public void setStartPos(int startPos) {
37 this.startPos = startPos;
38 }
39 public int getEndPos() {
40 return endPos;
41 }
42 public void setEndPos(int endPos) {
43 this.endPos = endPos;
44 }
45 public int getCompeleteSize() {
46 return compeleteSize;
47 }
48 public void setCompeleteSize(int compeleteSize) {
49 this.compeleteSize = compeleteSize;
50 }
51
52 @Override
53 public String toString() {
54 return "DownloadInfo [threadId=" + threadId
55 + ", startPos=" + startPos + ", endPos=" + endPos
56 + ", compeleteSize=" + compeleteSize +"]";
57 }
58 }

在下载时,我们有进度条来显示运行进度,怎么确定进度条的进度,大小和起始位置呢?这里我定义了一个LoadInfo类来记录下载器具体信息。代码例如以下:

LoadInfo:

 1 package cn.yj3g.entity;
2 /**
3 *自己定义的一个记载下载器具体信息的类
4 */
5 public class LoadInfo {
6 public int fileSize;//文件大小
7 private int complete;//完毕度
8 private String urlstring;//下载器标识
9 public LoadInfo(int fileSize, int complete, String urlstring) {
10 this.fileSize = fileSize;
11 this.complete = complete;
12 this.urlstring = urlstring;
13 }
14 public LoadInfo() {
15 }
16 public int getFileSize() {
17 return fileSize;
18 }
19 public void setFileSize(int fileSize) {
20 this.fileSize = fileSize;
21 }
22 public int getComplete() {
23 return complete;
24 }
25 public void setComplete(int complete) {
26 this.complete = complete;
27 }
28 public String getUrlstring() {
29 return urlstring;
30 }
31 public void setUrlstring(String urlstring) {
32 this.urlstring = urlstring;
33 }
34 @Override
35 public String toString() {
36 return "LoadInfo [fileSize=" + fileSize + ", complete=" + complete
37 + ", urlstring=" + urlstring + "]";
38 }
39 }

以下是最最重要的一步,那就是定义一个下载器来进行下载了,这里我就不多说。详细解释在代码中都有注解。我就直接将代码附下。供大家研究參考

Downloader:

  1 package cn.yj3g.service;
2
3 import java.io.File;
4 import java.io.InputStream;
5 import java.io.RandomAccessFile;
6 import java.net.HttpURLConnection;
7 import java.net.URL;
8 import java.util.ArrayList;
9 import java.util.List;
10 import android.content.Context;
11 import android.os.Handler;
12 import android.os.Message;
13 import android.util.Log;
14 import cn.yj3g.Dao.Dao;
15 import cn.yj3g.entity.DownloadInfo;
16 import cn.yj3g.entity.LoadInfo;
17
18 public class Downloader {
19 private String urlstr;// 下载的地址
20 private String localfile;// 保存路径
21 private int threadcount;// 线程数
22 private Handler mHandler;// 消息处理器
23 private Dao dao;// 工具类
24 private int fileSize;// 所要下载的文件的大小
25 private List<DownloadInfo> infos;// 存放下载信息类的集合
26 private static final int INIT = 1;//定义三种下载的状态:初始化状态,正在下载状态。暂停状态
27 private static final int DOWNLOADING = 2;
28 private static final int PAUSE = 3;
29 private int state = INIT;
30
31 public Downloader(String urlstr, String localfile, int threadcount,
32 Context context, Handler mHandler) {
33 this.urlstr = urlstr;
34 this.localfile = localfile;
35 this.threadcount = threadcount;
36 this.mHandler = mHandler;
37 dao = new Dao(context);
38 }
39 /**
40 *推断是否正在下载
41 */
42 public boolean isdownloading() {
43 return state == DOWNLOADING;
44 }
45 /**
46 * 得到downloader里的信息
47 * 首先进行推断是否是第一次下载。假设是第一次就要进行初始化。并将下载器的信息保存到数据库中
48 * 假设不是第一次下载,那就要从数据库中读出之前下载的信息(起始位置,结束为止。文件大小等),并将下载信息返回给下载器
49 */
50 public LoadInfo getDownloaderInfors() {
51 if (isFirst(urlstr)) {
52 Log.v("TAG", "isFirst");
53 init();
54 int range = fileSize / threadcount;
55 infos = new ArrayList<DownloadInfo>();
56 for (int i = 0; i < threadcount - 1; i++) {
57 DownloadInfo info = new DownloadInfo(i, i * range, (i + 1)* range - 1, 0, urlstr);
58 infos.add(info);
59 }
60 DownloadInfo info = new DownloadInfo(threadcount - 1,(threadcount - 1) * range, fileSize - 1, 0, urlstr);
61 infos.add(info);
62 //保存infos中的数据到数据库
63 dao.saveInfos(infos);
64 //创建一个LoadInfo对象记载下载器的详细信息
65 LoadInfo loadInfo = new LoadInfo(fileSize, 0, urlstr);
66 return loadInfo;
67 } else {
68 //得到数据库中已有的urlstr的下载器的详细信息
69 infos = dao.getInfos(urlstr);
70 Log.v("TAG", "not isFirst size=" + infos.size());
71 int size = 0;
72 int compeleteSize = 0;
73 for (DownloadInfo info : infos) {
74 compeleteSize += info.getCompeleteSize();
75 size += info.getEndPos() - info.getStartPos() + 1;
76 }
77 return new LoadInfo(size, compeleteSize, urlstr);
78 }
79 }
80
81 /**
82 * 初始化
83 */
84 private void init() {
85 try {
86 URL url = new URL(urlstr);
87 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
88 connection.setConnectTimeout(5000);
89 connection.setRequestMethod("GET");
90 fileSize = connection.getContentLength();
91
92 File file = new File(localfile);
93 if (!file.exists()) {
94 file.createNewFile();
95 }
96 // 本地訪问文件
97 RandomAccessFile accessFile = new RandomAccessFile(file, "rwd");
98 accessFile.setLength(fileSize);
99 accessFile.close();
100 connection.disconnect();
101 } catch (Exception e) {
102 e.printStackTrace();
103 }
104 }
105
106 /**
107 * 推断是否是第一次 下载
108 */
109 private boolean isFirst(String urlstr) {
110 return dao.isHasInfors(urlstr);
111 }
112
113 /**
114 * 利用线程開始下载数据
115 */
116 public void download() {
117 if (infos != null) {
118 if (state == DOWNLOADING)
119 return;
120 state = DOWNLOADING;
121 for (DownloadInfo info : infos) {
122 new MyThread(info.getThreadId(), info.getStartPos(),
123 info.getEndPos(), info.getCompeleteSize(),
124 info.getUrl()).start();
125 }
126 }
127 }
128
129 public class MyThread extends Thread {
130 private int threadId;
131 private int startPos;
132 private int endPos;
133 private int compeleteSize;
134 private String urlstr;
135
136 public MyThread(int threadId, int startPos, int endPos,
137 int compeleteSize, String urlstr) {
138 this.threadId = threadId;
139 this.startPos = startPos;
140 this.endPos = endPos;
141 this.compeleteSize = compeleteSize;
142 this.urlstr = urlstr;
143 }
144 @Override
145 public void run() {
146 HttpURLConnection connection = null;
147 RandomAccessFile randomAccessFile = null;
148 InputStream is = null;
149 try {
150 URL url = new URL(urlstr);
151 connection = (HttpURLConnection) url.openConnection();
152 connection.setConnectTimeout(5000);
153 connection.setRequestMethod("GET");
154 // 设置范围,格式为Range:bytes x-y;
155 connection.setRequestProperty("Range", "bytes="+(startPos + compeleteSize) + "-" + endPos);
156
157 randomAccessFile = new RandomAccessFile(localfile, "rwd");
158 randomAccessFile.seek(startPos + compeleteSize);
159 // 将要下载的文件写到保存在保存路径下的文件里
160 is = connection.getInputStream();
161 byte[] buffer = new byte[4096];
162 int length = -1;
163 while ((length = is.read(buffer)) != -1) {
164 randomAccessFile.write(buffer, 0, length);
165 compeleteSize += length;
166 // 更新数据库中的下载信息
167 dao.updataInfos(threadId, compeleteSize, urlstr);
168 // 用消息将下载信息传给进度条,对进度条进行更新
169 Message message = Message.obtain();
170 message.what = 1;
171 message.obj = urlstr;
172 message.arg1 = length;
173 mHandler.sendMessage(message);
174 if (state == PAUSE) {
175 return;
176 }
177 }
178 } catch (Exception e) {
179 e.printStackTrace();
180 } finally {
181 try {
182 is.close();
183 randomAccessFile.close();
184 connection.disconnect();
185 dao.closeDb();
186 } catch (Exception e) {
187 e.printStackTrace();
188 }
189 }
190
191 }
192 }
193 //删除数据库中urlstr相应的下载器信息
194 public void delete(String urlstr) {
195 dao.delete(urlstr);
196 }
197 //设置暂停
198 public void pause() {
199 state = PAUSE;
200 }
201 //重置下载状态
202 public void reset() {
203 state = INIT;
204 }
205 }

在这边下载器类的定义中,我们用到了很多关于进行数据库操作的方法,这里我定义了一个数据库工具类,来提供这些方法。代码例如以下:

Dao:

 1 package cn.yj3g.Dao;
2
3 import java.util.ArrayList;
4 import java.util.List;
5 import android.content.Context;
6 import android.database.Cursor;
7 import android.database.sqlite.SQLiteDatabase;
8 import cn.yj3g.DBHelper.DBHelper;
9 import cn.yj3g.entity.DownloadInfo;
10
11 /**
12 *
13 * 一个业务类
14 */
15 public class Dao {
16 private DBHelper dbHelper;
17
18 public Dao(Context context) {
19 dbHelper = new DBHelper(context);
20 }
21
22 /**
23 * 查看数据库中是否有数据
24 */
25 public boolean isHasInfors(String urlstr) {
26 SQLiteDatabase database = dbHelper.getReadableDatabase();
27 String sql = "select count(*) from download_info where url=? ";
28 Cursor cursor = database.rawQuery(sql, new String[] { urlstr });
29 cursor.moveToFirst();
30 int count = cursor.getInt(0);
31 cursor.close();
32 return count == 0;
33 }
34
35 /**
36 * 保存 下载的详细信息
37 */
38 public void saveInfos(List<DownloadInfo> infos) {
39 SQLiteDatabase database = dbHelper.getWritableDatabase();
40 for (DownloadInfo info : infos) {
41 String sql = "insert into download_info(thread_id,start_pos, end_pos,compelete_size,url) values (?,? ,?,?,?)";
42 Object[] bindArgs = { info.getThreadId(), info.getStartPos(),
43 info.getEndPos(), info.getCompeleteSize(), info.getUrl() };
44 database.execSQL(sql, bindArgs);
45 }
46 }
47
48 /**
49 * 得到下载详细信息
50 */
51 public List<DownloadInfo> getInfos(String urlstr) {
52 List<DownloadInfo> list = new ArrayList<DownloadInfo>();
53 SQLiteDatabase database = dbHelper.getReadableDatabase();
54 String sql = "select thread_id, start_pos, end_pos,compelete_size,url from download_info where url=?";
55 Cursor cursor = database.rawQuery(sql, new String[] { urlstr });
56 while (cursor.moveToNext()) {
57 DownloadInfo info = new DownloadInfo(cursor.getInt(0),
58 cursor.getInt(1), cursor.getInt(2), cursor.getInt(3),
59 cursor.getString(4));
60 list.add(info);
61 }
62 cursor.close();
63 return list;
64 }
65
66 /**
67 * 更新数据库中的下载信息
68 */
69 public void updataInfos(int threadId, int compeleteSize, String urlstr) {
70 SQLiteDatabase database = dbHelper.getReadableDatabase();
71 String sql = "update download_info set compelete_size=? where thread_id=? and url=? ";
72 Object[] bindArgs = { compeleteSize, threadId, urlstr };
73 database.execSQL(sql, bindArgs);
74 }
75 /**
76 * 关闭数据库
77 */
78 public void closeDb() {
79 dbHelper.close();
80 }
81
82 /**
83 * 下载完毕后删除数据库中的数据
84 */
85 public void delete(String url) {
86 SQLiteDatabase database = dbHelper.getReadableDatabase();
87 database.delete("download_info", "url=?", new String[] { url });
88 database.close();
89 }
90 }

下来就是要进行下载和暂停button的响应事件了。

详细代码和解释例如以下。

MainActivity:

  1 package cn.yj3g.AndroidDownload;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7 import android.app.ListActivity;
8 import android.os.Bundle;
9 import android.os.Handler;
10 import android.os.Message;
11 import android.view.View;
12 import android.widget.LinearLayout;
13 import android.widget.LinearLayout.LayoutParams;
14 import android.widget.ProgressBar;
15 import android.widget.SimpleAdapter;
16 import android.widget.TextView;
17 import android.widget.Toast;
18 import cn.yj3g.entity.LoadInfo;
19 import cn.yj3g.service.Downloader;
20
21 public class MainActivity extends ListActivity {
22 // 固定下载的资源路径,这里能够设置网络上的地址
23 private static final String URL = "http://192.168.1.105:8080/struts2_net/";
24 // 固定存放下载的音乐的路径:SD卡文件夹下
25 private static final String SD_PATH = "/mnt/sdcard/";
26 // 存放各个下载器
27 private Map<String, Downloader> downloaders = new HashMap<String, Downloader>();
28 // 存放与下载器相应的进度条
29 private Map<String, ProgressBar> ProgressBars = new HashMap<String, ProgressBar>();
30 /**
31 * 利用消息处理机制适时更新进度条
32 */
33 private Handler mHandler = new Handler() {
34 public void handleMessage(Message msg) {
35 if (msg.what == 1) {
36 String url = (String) msg.obj;
37 int length = msg.arg1;
38 ProgressBar bar = ProgressBars.get(url);
39 if (bar != null) {
40 // 设置进度条按读取的length长度更新
41 bar.incrementProgressBy(length);
42 if (bar.getProgress() == bar.getMax()) {
43 Toast.makeText(MainActivity.this, "下载完毕。", 0).show();
44 // 下载完毕后清除进度条并将map中的数据清空
45 LinearLayout layout = (LinearLayout) bar.getParent();
46 layout.removeView(bar);
47 ProgressBars.remove(url);
48 downloaders.get(url).delete(url);
49 downloaders.get(url).reset();
50 downloaders.remove(url);
51
52 }
53 }
54 }
55 }
56 };
57 @Override
58 public void onCreate(Bundle savedInstanceState) {
59 super.onCreate(savedInstanceState);
60 setContentView(R.layout.main);
61 showListView();
62 }
63 // 显示listView,这里能够随便加入音乐
64 private void showListView() {
65 List<Map<String, String>> data = new ArrayList<Map<String, String>>();
66 Map<String, String> map = new HashMap<String, String>();
67 map.put("name", "mm.mp3");
68 data.add(map);
69 map = new HashMap<String, String>();
70 map.put("name", "pp.mp3");
71 data.add(map);
72 map = new HashMap<String, String>();
73 map.put("name", "tt.mp3");
74 data.add(map);
75 map = new HashMap<String, String>();
76 map.put("name", "You.mp3");
77 data.add(map);
78 SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.list_item, new String[] { "name" },
79 new int[] { R.id.tv_resouce_name });
80 setListAdapter(adapter);
81 }
82 /**
83 * 响应開始下载button的点击事件
84 */
85 public void startDownload(View v) {
86 // 得到textView的内容
87 LinearLayout layout = (LinearLayout) v.getParent();
88 String musicName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();
89 String urlstr = URL + musicName;
90 String localfile = SD_PATH + musicName;
91 //设置下载线程数为4。这里是我为了方便随便固定的
92 int threadcount = 4;
93 // 初始化一个downloader下载器
94 Downloader downloader = downloaders.get(urlstr);
95 if (downloader == null) {
96 downloader = new Downloader(urlstr, localfile, threadcount, this, mHandler);
97 downloaders.put(urlstr, downloader);
98 }
99 if (downloader.isdownloading())
100 return;
101 // 得到下载信息类的个数组成集合
102 LoadInfo loadInfo = downloader.getDownloaderInfors();
103 // 显示运行进度条
104 showProgress(loadInfo, urlstr, v);
105 // 调用方法開始下载
106 downloader.download();
107 }
108
109 /**
110 * 显示运行进度条
111 */
112 private void showProgress(LoadInfo loadInfo, String url, View v) {
113 ProgressBar bar = ProgressBars.get(url);
114 if (bar == null) {
115 bar = new ProgressBar(this, null, android.R.attr.progressBarStyleHorizontal);
116 bar.setMax(loadInfo.getFileSize());
117 bar.setProgress(loadInfo.getComplete());
118 ProgressBars.put(url, bar);
119 LinearLayout.LayoutParams params = new LayoutParams(LayoutParams.FILL_PARENT, 5);
120 ((LinearLayout) ((LinearLayout) v.getParent()).getParent()).addView(bar, params);
121 }
122 }
123 /**
124 * 响应暂停下载button的点击事件
125 */
126 public void pauseDownload(View v) {
127 LinearLayout layout = (LinearLayout) v.getParent();
128 String musicName = ((TextView) layout.findViewById(R.id.tv_resouce_name)).getText().toString();
129 String urlstr = URL + musicName;
130 downloaders.get(urlstr).pause();
131 }
132 }

最后我们要在清单文件里加入权限。一个是訪问网络的权限,一个是往SD卡写数据的权限。

代码例如以下:

 <uses-permission android:name="android.permission.INTERNET"/>
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

这样我们就实现了文件的断点续传下载功能。详细效果图例如以下:

Android该HTTP下载的更多相关文章

  1. Android Studio的下载和安装教程(从ADT到AS)

    之前一直使用的是Android development tools(简称ADT),后来说是google对ADT不再提供支持,然后一直在考虑是否把自己电脑换成Android Studio(简称AS),从 ...

  2. Android利用Http下载文件

    Android利用Http下载文件 一.场景 下载存文本文件和下载如mp3等大容量的文件 界面 二.代码编写 1.AndroidMainfest.xml中配置 主要是解决网络权限和写SDCard的权限 ...

  3. 驾照理论模拟考试系统Android源码下载

    ‍‍‍驾照理论模拟考试系统Android源码下载 <ignore_js_op> 9.png (55.77 KB, 下载次数: 0) <ignore_js_op> 10.png ...

  4. 【Android 应用开发】Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载

    19af543b068bdb7f27787c2bc69aba7f Additional Download (32-, 64-bit) Package r10 STL debug info androi ...

  5. Android版多线程下载器核心代码分享

    首先给大家分享多线程下载核心类: package com.example.urltest; import java.io.IOException; import java.io.InputStream ...

  6. Android中多线程下载列表的封装实现(含进度反馈)

    来源:http://blog.csdn.net/u011638883/article/details/17347015 实现了一下Android中的文件多线程下载模块,支持自定义线程数.断点续传.下载 ...

  7. android网络图片的下载

    android网络图片的下载 /** * Get image from newwork * * @param path * The path of image * @return byte[] * @ ...

  8. Android源码下载方法详解

    转自:http://www.cnblogs.com/anakin/archive/2011/12/20/2295276.html Android源码下载方法详解 相信很多下载过内核的人都对这个很熟悉 ...

  9. android 多线程断点续传下载

    今天跟大家一起分享下Android开发中比较难的一个环节,可能很多人看到这个标题就会感觉头很大,的确如果没有良好的编码能力和逻辑思维,这块是很难搞明白的,前面2次总结中已经为大家分享过有关技术的一些基 ...

  10. Android之断点续传下载

    今天学习了Android开发中比较难的一个环节,就是断点续传下载,很多人看到这个标题就感觉头大,的确,如果没有良好的逻辑思维,这块的确很难搞明白.下面我就将自己学到的知识和一些见解写下供那些在这个环节 ...

随机推荐

  1. org.springframework.core.Ordered接口

    关于Ordered接口,用过的人可能知道,这里我谈下自己的理解.也希望各位大神能给予指点. 源码如下: /**  * Interface that can be implemented by obje ...

  2. org.apache.jasper.JasperException: java.lang.ClassCastException

    异常信息: org.apache.jasper.JasperException: java.lang.ClassCastException:org.apache.catalina.util.Defau ...

  3. OpenLayers学习笔记5——使用jQuery UI实现查询并标注(UI篇)

    近期事情非常多,老板给的压力也非常大.经常出差,另外项目和个人研究还都要跟上,本月要交论文,还要写专利,仅仅能抽时间来学习其它的东西了. 关于OpenLayers的在博客中不会写太多详细的实现(网上有 ...

  4. 通过OpenSSL解码X509证书文件

    在Windows平台下.假设要解析一个X509证书文件,最直接的办法是使用微软的CryptoAPI. 可是在非Windows平台下,就仅仅能使用强大的开源跨平台库OpenSSL了.一个X509证书通过 ...

  5. Swift - 搜索条(UISearchBar)的用法

    1,搜索条Options属性还可设置如下功能样式: Shows Search Results Button:勾选后,搜索框右边显示一个圆形向下的按钮,单击会发送特殊事件. Shows Bookmark ...

  6. PHP中抽象类与接口的应用场景

    <?php /*** ====笔记部分==== 接口的具体语法: 0:以人类为, class Human 是人的草图 而接口 是零件 可以用多种零件组合出一种新特种来. 1: 如上,接口本身即是 ...

  7. 为什么Lisp语言如此先进?(译文) - 阮一峰的网络日志

      为什么Lisp语言如此先进?(译文) - 阮一峰的网络日志 为什么Lisp语言如此先进?(译文)

  8. html5实现拖拽文件上传

    以下是自学it网--中级班上课笔记 网址:www.zixue.it html文件 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict ...

  9. [SVN]创建本地的SVN仓库

    本地创建SVN仓库,就算是自己平时写代码也养成使用SVN的习惯. 环境: OS:Mac OS X10.9.1 SVN Version:1.7.10 创建本地SVN仓库: $svnadmin creat ...

  10. nginx+tomcat负载均衡策略

    測试环境均为本地,測试软件为: nginx-1.6.0,apache-tomcat-7.0.42-1.apache-tomcat-7.0.42-2.apache-tomcat-7.0.42-3 利用n ...