分类 Java 下的文章

java实现的map排序

java实现的map排序,直接上代码:

import java.util.Arrays;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
public class TestSort {
	// HashMap里面的元素是无序的,要进行排序的话只能是用TreeMap和SortedMap,例如:
	public static void main(String[] args) throws Exception {
		Map<Integer, Integer> map = new TreeMap<Integer, Integer>();
		map.put(100, 131);
		map.put(0, 0);
		map.put(83, 49);
		map.put(137, 98);
		map.put(33, 651);
		map = mapSortByKey(map);
		System.out.println(map.toString());
	}
	private static SortedMap<Integer, Integer> mapSortByKey(
			Map<Integer, Integer> unsort_map) {
		TreeMap<Integer, Integer> result = new TreeMap<Integer, Integer>();
		Object[] unsort_key = unsort_map.keySet().toArray();
		Arrays.sort(unsort_key);
		for (int i = 0; i < unsort_key.length; i++) {
			System.out.println(unsort_map.get(unsort_key[i]));
			result.put(Integer.parseInt(unsort_key[i].toString()),
					unsort_map.get(unsort_key[i]));
		}
		return result.tailMap(result.firstKey());
	}
}

打印结果:

651
49
131
98
{0=0, 33=651, 83=49, 100=131, 137=98}

js小技巧-引号多层嵌套-自提示上下键选择

html中的超链接中比如有多层嵌套,就会导致字符串被截取,出现很多问题
引号嵌套两层时,可以使用转义或者单双引号交替的形式实现,当引号嵌套达到三四层的时候,问题就出现了,该怎么办?
举个例子:”javascript:fnabc(‘abcd(“123″)’)”
html的href=以上的字符串
那么即使加了转义字符,以上的字符串还是会被截取为”javascript:fnabc(‘abcd(”
解决的方法是使用&quot;代替引号
“javascript:fnabc(‘abcd(“123″)’)”
http://blog.csdn.net/panfang/article/details/7626032
监听回车、上、下键事件,实现自提示按上下键选择下拉项:

//监听回车、上、下键事件
			$("#queryWord").keydown(function(e) {
                var key = (e.keyCode) || (e.which) || (e.charCode);//兼容IE(e.keyCode)和Firefox(e.which)
                var index = 0;
                if (key == "38"){//向上
					 if($("#queryWord").val().length > 0){
					 	$("#autocomplete").show();
					 	$.each($("#autocomplete").children("li"),function(i,n){
//					  		alert(i);
	     					var $cr = $(n);
	     					if($cr.children("a").hasClass("current")){
	     						index = i - 1;
//	     						alert(index);
	     						$cr.children("a").removeClass("current");
	     					}
	      			 });
//					 alert(index);
	      			 $("#autocomplete").children("li").eq(index).children("a").addClass("current");
					 }
                }
                if (key == "40"){//向下
                	if($("#queryWord").val().length > 0){
					 $("#autocomplete").show();
					  	$.each($("#autocomplete").children("li"),function(i,n){
//					  		alert(i);
	     					var $cr = $(n);
	     					if($cr.children("a").hasClass("current")){
	     						index = 1 + i;
//	     						alert(index);
	     						$cr.children("a").removeClass("current");
	     					}
	      			 });
//					 alert(index);
	      			 $("#autocomplete").children("li").eq(index).children("a").addClass("current");
                	}
                }
                if(key == "13"){
                	var enterIndex = 0;
                	if($("#queryWord").val().length > 0){
					 $("#autocomplete").show();
					  	$.each($("#autocomplete").children("li"),function(i,n){
	     					var $cr = $(n);
	     					if($cr.children("a").hasClass("current")){
	     						enterIndex = i;
	     						$cr.children("a").removeClass("current");
	     					}
	      			 });
	      			 $("#autocomplete").children("li").eq(enterIndex).children("a").addClass("current");
	      			 query($("#autocomplete").children("li").eq(enterIndex).children("a").children(".title").html());
                	}
                }
            });

不用插件实现异步自动提示

不用插件实现自动提示实现思路:
1:focus事件执行清空原来的提示
2:keyup事件判断非空时查询显示提示框
3:blur事件隐藏显示框
优点:不用学习其他插件,自己可以精确控制
js部分:

$(function() {
			// 查询框获得焦点
			$("#queryWord").focus(function() {
						$("#queryWord").val("");
					});
			// 查询框有输入
			$("#queryWord").keyup(function() {
						if($("#queryWord").val().length > 0){
							getAnswer($("#queryWord").val());
						}
					});
			// 查询框失去焦点
			$("#queryWord").blur(function() {
				if ($("#queryWord").val().length == 0) {
					$("#queryWord").val("输入节目名称或视频的网址(URL)");
				}
				$("#autocomplete").hide();
			});
		});
// 自动提示
function getAnswer(queryWord) {
	$.ajax({
				type : "POST",
				url : "getPromptAnswer.action",
				cache : false,
				data : "word=" + $("#queryWord").val() + "&t=" + Math.random(),
				dataType : "json",
				async : true,
				success : function(json) {
					if ($.isEmptyObject(json)) {
						$("#autocomplete").hide();
					} else {
						$("#autocomplete").empty();
						$.each(json,function(i,n){
	     					$("#autocomplete").append('<li><a href="#"><span class="title">'+json[i].keyword+'</span><span class="type">'+json[i].typeStr+'</span></a></li>');
	      				});
						$("#autocomplete").show();
					}
				}
			});
}

html部分:

 <div class="indexnav_so">
        <div class="indexnav_tool">
        	<input type="text" class="" id="queryWord" value="输入节目名称或视频的网址(URL)" />
        	<button onclick="query(jQuery('#queryWord').val())">查询</button></div>
        <!--When focused input add class="search" to change input color-->
        <ul id="autocomplete" class="autocomplete" style="display:none;"></ul>
</div>

后台Java部分:返回json格式即可

[{"keyword":"第二十二条婚规","name":"d","typeStr":"电视剧"},{"keyword":"大唐女巡按","name":"d","typeStr":"电视剧"},{"keyword":"独生子女的婆婆妈妈","name":"d","typeStr":"电视剧"},{"keyword":"第八号当铺","name":"d","typeStr":"电视剧"},{"keyword":"大太监","name":"d","typeStr":"电视剧"},{"keyword":"毒女","name":"d","typeStr":"电影"},{"keyword":"大男当婚","name":"d","typeStr":"电视剧"},{"keyword":"读心神探","name":"d","typeStr":"电视剧"},{"keyword":"敌后便衣队传奇","name":"d","typeStr":"电视剧"},{"keyword":"大宅门 第一部","name":"d","typeStr":"电视剧"}]

基于jquery.autocomplete实现拼音中文自动提示

如何实现基于“jquery.autocomplete”实现拼音中文自动提示,直接上代码吧
其中三个参数:row:一行数据({}),i:第几行,max:总行数。这里返回自定义格式的数据。

基于“jquery.autocomplete”实现拼音中文自动提示

基于“jquery.autocomplete”实现拼音中文自动提示

<html xmlns="http://www.w3.org/1999/xhtml">
 <head runat="server">
     <title>自定义提示</title>
     <script type="text/javascript" src="jquery-1.4.3.js"></script>
     <script type="text/javascript" src="jquery.autocomplete.min.js"></script>
     <link rel="Stylesheet" href="jquery.autocomplete.css" />
     <script type="text/javascript">
         var emails = [
             { name: "datong dt", to: "大同" },
             { name: "beijing bj", to: "北京" },
             { name: "tianjin tj", to: "天津" },
             { name: "hefei hf", to: "合肥" },
             { name: "shanghai shh sh", to: "上海" }
         ];
             $(function() {
                 $('#keyword').autocomplete(emails, {
                     max: 12,    //列表里的条目数
                     minChars: 0,    //自动完成激活之前填入的最小字符
                     width: 400,     //提示的宽度,溢出隐藏
                     scrollHeight: 300,   //提示的高度,溢出显示滚动条
                     matchContains: true,    //包含匹配,就是data参数里的数据,是否只要包含文本框里的数据就显示
                     autoFill: false,    //自动填充
                     formatItem: function(row, i, max) {
                         //return i + '/' + max + ':"' + row.name + '"[' + row.to + ']';
						 return row.to;
                     },
                     formatMatch: function(row, i, max) {
                         return row.name + row.to;
                     },
                     formatResult: function(row) {
                         return row.to;
                     }
                 }).result(function(event, row, formatted) {
                     alert(row.to);
                 });
             });
     </script>
 </head>
 <body>
     <form id="form1" runat="server">
     <div>
         <input id="keyword" />
         <input id="getValue" value="GetValue" type="button" />
     </div>
     </form>
 </body>
 </html>

Java线程安全

线程安全,那么什么是线程不安全呢?
在单线程运行的情况下,如果 sum = 0,加1后,sum=1一定是对的,但在多线程的情况下,有两个线程同时对sum加1,那么结果可能有两种,一种是sum=1,一种是sum=2;原因就在于sum被定义为全局变量。
如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。
或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。
线程安全问题都是由全局变量及静态变量引起的。
若每个线程中对全局变量、静态变量只有读操作,而无写操作,一般来说,这个全局变量是线程安全的;若有多个线程同时执行写操作,一般都需要考虑线程同步,否则就可能影响线程安全。
这两篇文章总结的很到位:
http://www.iteye.com/topic/806990
http://www.iteye.com/topic/808550

261个Java基础问题

这是摘自《你必须知道的261个Java语言问题》的书目,大家可以对照着,排查下自己哪些还不熟悉,都是比较基础的问题
第1章 java基本概念及环境配置 .1
faq1.01 什么是面向对象程序设计? 1
faq1.02 面向对象程序设计的基本特征有哪些? 2
faq1.03 java语言是如何产生和发展的? 3
faq1.04 android与java语言有什么关系? 4
faq1.05 java se、java ee和java me有什么区别? 5
faq1.06 java语言的运行机制如何? 6
faq1.07 什么是jvm?有什么作用?工作机制如何? 8
faq1.08 什么是jre(或j2re)? 9
faq1.09 什么是jdk? 10
faq1.10 jdk、jre和jvm之间有什么区别? 11
faq1.11 什么是gc?gc的工作原理如何? 12
faq1.12 如何安装java基本开发环境jdk? 13
faq1.13 为何在jdk安装路径下存在两个jre? 16
faq1.14 jdk安装时设置path和classpath环境变量有何作用? 17
faq1.15 如何编译、运行java应用程序? 18
faq1.16 如何将程序中的文档注释提取出来生成说明文档? 20
faq1.17 怎样制作鼠标双击就可以运行的jar文件? 23
faq1.18 怎样给main(string[] args)方法的args指定参数值? 26
第2章 java编程基础 28
faq2.01 java中的标识符如何命名?可以用中文吗? 28
faq2.02 java中有哪些关键字? 29
faq2.03 用public、protected和private修饰方法有什么区别? 30
faq2.04 this关键字有什么含义?在哪些情况下应用? 31
faq2.05 super关键字有什么含义?在哪些情况下应用? 32
faq2.06 static关键字有什么含义?具体如何应用?能修饰构造方法吗? 34
faq2.07 final关键字有什么含义?具体如何应用? 36
faq2.08 instanceof关键字有什么含义?如何应用? 37
faq2.09 java中有哪些数据类型? 38
faq2.10 如何解决double和float精度不准的问题? 40
faq2.11 int和integer都可以作为整数类型,那么它们有什么区别? 43
faq2.12 float f=3.4语句是否正确? 44
faq2.13 成员变量和局部变量有什么区别? 45
faq2.14 变量之间传值时可分为值传递和引用传递,那么它们有何区别? 46
faq2.15 java中有哪些运算符?优先级如何? 48
faq2.16 在实现x和y相加时,x+=y和x=x+y两种实现方式有区别吗? 50
faq2.17 在执行与运算时,运算符&和&&有什么区别? 50
faq2.18 在实现x递增加1操作时,x++和++x有什么区别? 52
faq2.19 x?y:z格式的语句表示什么意思? 53
faq2.20 “+”操作符在java内部是如何实现字符串连接的? 54
faq2.21 ==和equals()都可用于比较两个操作数是否相等,它们有什么区别吗? 55
faq2.22 创建string对象时,使用string s=new string (“abc”)和string s=“abc”语句有什么区别? 56
faq2.23 break和continue语句有什么区别? 56
faq2.24 数组如何定义和初始化? 57
faq2.25 如何实现一维和二维数组的遍历? 59
faq2.26 如何实现数组的复制? 60
faq2.27 数组的排序算法有哪些?如何实现? 61
faq2.28 如何解决arrayindexoutofbounds exception异常? 64
第3章 java与面向对象 65
faq3.01 什么是类、对象、属性和方法? 65
faq3.02 什么是包?有什么好处? 67
faq3.03 什么是抽象类?有什么好处? 67
faq3.04 什么是接口?有什么好处? 69
faq3.05 什么是多态?有什么好处? 70
faq3.06 什么是内部类?有什么好处? 71
faq3.07 什么是匿名内部类?如何使用? 73
faq3.08 什么是封装类?有什么作用? 74
faq3.09 什么是继承?有什么好处? 75
faq3.10 使用new关键字创建对象时,为什么有时候提示找不到无参的构造方法? 76
faq3.11 抽象类和接口都可以包含抽象方法,那么它们有什么区别?使用时该如何选择? 76
faq3.12 什么是方法重写?为什么需要方法重写? 78
faq3.13 什么是方法重载?为什么需要方法重载? 78
faq3.14 构造方法是否可以被重写?能否被重载? 79
faq3.15 static修饰的方法能否在子类中重写? 80
faq3.16 在定义类时,何时需要重写object类中tostring()方法? 81
faq3.17 在定义类时,何时需要重写object类中equals()方法? 82
faq3.18 为什么在重写equals()方法时,一般都会重写hashcode()方法? 84
faq3.19 如何重写hashcode()方法? 85
faq3.20 java中动态绑定是什么意思? 87
faq3.21 java中是如何实现多态的?实现机制是什么? 88
faq3.22 创建类的对象时,类中各成员的执行顺序是什么样的? 89
faq3.23 什么是初始化块?有什么作用? 90
faq3.24 静态初始化块与非静态初始化块有什么区别? 92
faq3.25 如何调用内部类中的方法? 93
faq3.26 当内部类和外部类的成员名称相同时,如何在内部类中调用外部类的成员? 94
faq3.27 匿名内部类如何访问外部方法的局部变量或参数? 95
faq3.28 java异常处理机制是什么样的? 96
faq3.29 常见的runtimeexception异常有哪些? 97
faq3.30 java中异常处理的方式有哪些? 98
faq3.31 try-catch-finally语句块各部分的执行顺序如何? 100
faq3.32 为什么使用自定义异常?自定义异常如何使用? 101
第4章 java流和文件操作 103
faq4.01 如何获取文件的属性信息? 103
faq4.02 如何判断文件是否为空? 105
faq4.03 如何实现文件的创建、删除和移动? 105
faq4.04 如何创建和删除文件夹? 107
faq4.05 如何遍历目录中所有的文件? 109
faq4.06 如何获取文件夹大小? 110
faq4.07 什么是流?如何分类?具体包含哪些类? 111
faq4.08 如何实现字节流和字符流之间的转化? 113
faq4.09 如何判断要读的文件是否到达末尾? 116
faq4.10 如何读文件、写文件? 117
faq4.11 如何以追加的方式写文件? 118
faq4.12 如何实现文件和文件夹的复制? 119
faq4.13 如何在文件的任意位置进行读写? 121
faq4.14 使用buffered缓冲流写文件,为什么内容没有写入? 122
faq4.15 如何实现文件的分割与合并? 123
faq4.16 什么是nio?与i/o有什么区别和联系? 125
faq4.17 如何使用nio读写文件? 127
faq4.18 什么是字符编码和解码? 129
faq4.19 读写文件时为什么中文字符经常产生乱码? 130
faq4.20 如何解决filereader读文件乱码的问题? 131
faq4.21 为什么datainputstream和dataoutputstream读写文件时乱码? 132
faq4.22 如何实现文件锁定功能? 134
faq4.23 如何实现对文件和字符串加密、解密? 135
faq4.24 如何实现对文件和目录的压缩、解压缩? 139
faq4.25 如何读写properties文件? 143
faq4.26 如何读写xml文件? 146
faq4.27 如何读写xml文件中的元素属性? 151
faq4.28 如何读写csv格式的文件? 152
faq4.29 如何为图片文件生成缩略图? 154
faq4.30 如何操作excel文件? 156
faq4.31 如何操作word文件? 161
第5章 java gui编程 164
faq5.01 什么是java gui?swing与awt有什么关系? 164
faq5.02 什么是布局管理器?常用的布局管理器有哪些? 165
faq5.03 如何在窗体中显示一张图片? 170
faq5.04 如何为容器添加滚动条功能? 171
faq5.05 如何实现一个打开文件或者是存储文件的对话框? 173
faq5.06 如何实现弹出消息框的功能? 175
faq5.07 如何使用dialog对话框? 177
faq5.08 如何为按钮添加单击事件? ..178
faq5.09 如何为窗体添加关闭事件? 181
faq5.10 如何实现窗体菜单功能? 183
faq5.11 如何处理键盘输入事件? 185
faq5.12 如何处理鼠标单击事件?如何区分是左键还是右键? 186
faq5.13 如何实现鼠标右键弹出菜单的功能? 189
faq5.14 如何使用表格组件? 191
faq5.15 如何实现记事本功能? 193
faq5.16 如何实现贪吃蛇游戏? 198
第6章 java线程和序列化 208
faq6.01 线程、进程和程序有何区别和联系? 208
faq6.02 如何创建和启动一个线程? 209
faq6.03 线程的基本状态有哪些?它们之间有何关系? 211
faq6.04 什么是线程优先级?线程依据什么原则调度执行? 212
faq6.05 什么是后台线程?如何创建一个后台线程? 214
faq6.06 如何使正在运行的线程在指定时间内休眠? 216
faq6.07 如何终止一个正在运行的线程? 218
faq6.08 为何stop()和suspend()方法不推荐使用? 219
faq6.09 如何控制线程的暂停和启动? 220
faq6.10 如何实现多个线程同步? 225
faq6.11 什么是对象序列化和对象反序列化? 233
faq6.12 实现对象序列化的方法有哪些? 234
faq6.13 如何实现对象在磁盘中的存取操作? 236
faq6.14 使用objectinputstream读取对象时为什么会发生streamcorruptedexception异常? 238
faq6.15 对象中的成员哪些参与序列化?哪些不参与序列化? 241
faq6.16 如何自定义序列化和反序列化过程? 243
faq6.17 如何使用externalizable接口定制序列化过程? 247
faq6.18 在序列化类中添加serialversionuid属性有什么作用? 250
faq6.19 当序列化遭遇继承时,如何正确处理对象序列化过程? 251
第7章 java网络编程 256
faq7.01 什么是tcp/ip?什么是ip? 256
faq7.02 tcp和udp有什么区别? 258
faq7.03 什么是http?http的工作原理如何? 259
faq7.04 在socket通信时如何获取主机和客户机的ip地址? 261
faq7.05 如何利用socket实现基于tcp的通信? 264
faq7.06 如何利用socket传输中文字符? 265
faq7.07 如何在socket读取数据时使用超时设置? 267
faq7.08 如何利用socket传递对象信息? 268
faq7.09 如何利用socket实现文件传输? 271
faq7.10 如何基于socket实现聊天系统? 274
faq7.11 如何利用socket实现基于udp的通信? 278
faq7.12 如何利用udp socket技术实现ip多点传送? 280
faq7.13 如何获取internet资源的大小? 285
faq7.14 如何实现internet资源的单线程下载? 286
faq7.15 url如何通过proxy代理访问internet资源? 287
faq7.16 如何实现internet资源下载的断点续传? 288
faq7.17 如何实现internet资源的多线程下载? 290
faq7.18 如何解析internet网页内容? 293
第8章 java常用功能 296
faq8.01 如何使字符串中包含“””字符 296
faq8.02 如何实现字符串和整数之间的转化? 297
faq8.03 如何替换字符串中的字符或子字符串? 298
faq8.04 如何过滤字符串前后以及中间出现的空格? 299
faq8.05 如何对字符串中的子字符或子字符串进行截取? 301
faq8.06 如何判断一个字符串是否符合数值格式? 302
faq8.07 如何实现字符串的切割和查找? 303
faq8.08 如何实现十进制和二进制之间的相互转化? 306
faq8.09 如何将字节流转换为指定编码的字符串? 307
faq8.10 如何实现日期格式和字符串之间的转化? 308
faq8.11 string、stringbuffer和stringbuilder有什么区别? 310
faq8.12 如何获得一个随机数? 311
faq8.13 list、set和map是否继承自collection接口?有什么区别? 312
faq8.14 arraylist与linkedlist、vector的区别是什么? 313
faq8.15 hashmap和hashtable有什么区别? 314
faq8.16 如何遍历map和vector集合? 315
faq8.17 如何获取系统当前时间? 317
faq8.18 如何获得系统属性? 318
faq8.19 什么是反射机制?有什么作用? 319
faq8.20 如何读取键盘输入的信息? 322
faq8.21 如何获取当前工程目录? 323
faq8.22 如何使用java调用系统的exe文件? 324
faq8.23 如何使用java执行cmd命令? 325
faq8.24 如何使用java程序打开一个word文档? 326
faq8.25 如何使用md5和sha算法加密信息? 327
第9章 java数据库操作 329
faq9.01 什么是jdbc?有什么作用? 329
faq9.02 java与数据库的连接方式有哪些? 330
faq9.03 如何连接各种类型的数据库? 331
faq9.04 如何实现对数据库数据的查询? 335
faq9.05 如何实现对数据库数据的增加、删除和修改? 336
faq9.06 如何使用preparestatement对数据库操作? 339
faq9.07 statement和preparestatement有什么区别? 340
faq9.08 如何调用数据库中的存储过程? 341
faq9.09 如何通过jdbc-odbc桥访问access数据库? 344
faq9.10 连接oracle数据库时thin和oci方式有什么区别? 346
faq9.11 如何判断resultset结果集为空? 347
faq9.12 如何获取resultset中含有的记录数量? 348
faq9.13 如何获取resultset中n~m位置区间的记录? 350
faq9.14 如何利用resultset更新数据库数据? 351
faq9.15 如何使用like关键字实现模糊查询? 352
faq9.16 如何实现查询的分组统计和排序? 354
faq9.17 如何实现多表联合查询? 355
faq9.18 如何使用jdbc的批处理操作? 357
faq9.19 如何实现oracle字段值递增的功能? 358
faq9.20 如何处理数据表中date类型的字段? 360
faq9.21 如何向表中插入含有特殊字符的信息? 360
faq9.22 如何使用blob类型的字段存取图片? 361
faq9.23 如何使用clob类型的字段存取字符文件? 363
faq9.24 如何通过程序创建和删除数据表? 365
faq9.25 如何获取数据表的结构信息? 367
faq9.26 如何获取数据库中所有表名? 369
faq9.27 如何用程序备份和恢复数据库? 370
faq9.28 什么是事务?如何使用jdbc事务控制? 372
faq9.29 什么是jta?jta事务与jdbc事务有什么区别? 373
faq9.30 如何使用jta实现分布式事务控制? 374
faq9.31 什么是数据库连接池?工作原理如何? 376
faq9.32 如何提升sql语句的查询性能? 377
faq9.33 如何解决mysql数据库插入乱码的问题? 379
第10章 java web程序设计 381
faq10.01 什么是jsp?jsp的工作原理如何? 381
faq10.02 jsp、java和javascript有什么区别和联系? 383
faq10.03 jsp程序开发和运行环境是什么?如何搭建? 383
faq10.04 如何开发一款jsp程序? 387
faq10.05 在jsp中有哪些注释格式?有什么作用? 390
faq10.06 jsp中有哪些内建对象?分别有什么作用? 391
faq10.07 page、request、session和application有什么区别? 395
faq10.08 如何解决request.getparameter()取值乱码问题? 396
faq10.09 jsp中forward和redirect有什么区别? 397
faq10.10 如何在多个jsp页面之间传递信息? 399
faq10.11 如何解决url传递中文时出现乱码的问题? 400
faq10.12 动态include与静态include有什么区别? 401
faq10.13 什么是javabean?如何使用javabean? 402
faq10.14 什么是session?如何使用session? 403
faq10.15 如何在关闭页面时自动清除session? 405
faq10.16 什么是cookie?如何使用cookie? 406
faq10.17 如何在禁用cookie的情况下使用session? 408
faq10.18 如何在jsp中避免表单的重复提交? 409
faq10.19 如何实现jsp数据和javascript数据的交互使用? 411
faq10.20 什么是servlet?servlet与jsp有什么区别? 412
faq10.21 servlet容器的工作原理如何? 413
faq10.22 如何在servlet中使用session和application? 414
faq10.23 如何编写多线程安全的servlet程序? 415
faq10.24 如何在servlet和jsp中获取工程文件的绝对路径? 417
faq10.25 如何获取客户端浏览器和操作系统信息? 417
faq10.26 如何在web程序中实现定时运行的功能? 418
faq10.27 如何实现网站登录记忆跳转的功能? 421
faq10.28 如何将jsp动态页面转换为html静态页面? 423
faq10.29 如何实现数据分页显示的功能? 424
faq10.30 如何将jsp内容以excel或word格式输出? 431
faq10.31 如何在jsp中实现打印功能? 432
faq10.32 如何实现图片验证码功能? 433
faq10.33 如何实现饼状图、柱状图和曲线图? 436
faq10.34 如何实现进度条显示功能? 443
faq10.35 如何实现网站计数器功能? 447
faq10.36 如何发送html格式和带附件的邮件? 448
faq10.37 如何实现文件的上传和下载? 453
faq10.38 如何禁止浏览器缓存页面内容? 457
faq10.39 如何在网页中在线播放音乐和视频? 458
faq10.40 如何处理jsp页面的错误? 460
faq10.41 如何利用过滤器实现权限验证功能? 462
faq10.42 如何实现jsp防盗链功能? …464

cookie是什么

Cookie(复数形态Cookies),中文名称为小型文本文件或小甜饼,指某些网站为了辨别用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。定义于RFC2109。为网景公司的前雇员Lou Montulli在1993年3月所发明。
Cookie总是保存在客户端中,按在客户端中的存储位置,可分为内存Cookie和硬盘Cookie。
内存Cookie由浏览器维护,保存在内存中,浏览器关闭后就消失了,其存在时间是短暂的。硬盘Cookie保存在硬盘里,有一个过期时间,除非用户手工清理或到了过期时间,硬盘Cookie不会被删除,其存在时间是长期的。所以,按存在时间,可分为非持久Cookie和持久Cookie。
因为HTTP协议是无状态的,即服务器不知道用户上一次做了什么,这严重阻碍了交互式Web应用程序的实现。在典型的网上购物场景中,用户浏览了几个页面,买了一盒饼干和两瓶饮料。最后结帐时,由于HTTP的无状态性,不通过额外的手段,服务器并不知道用户到底买了什么。 所以Cookie就是用来绕开HTTP的无状态性的“额外手段”之一。服务器可以设置或读取Cookies中包含信息,借此维护用户跟服务器会话中的状态。
在刚才的购物场景中,当用户选购了第一项商品,服务器在向用户发送网页的同时,还发送了一段Cookie,记录着那项商品的信息。当用户访问另一个页面,浏览器会把Cookie发送给服务器,于是服务器知道他之前选购了什么。用户继续选购饮料,服务器就在原来那段Cookie里追加新的商品信息。结帐时,服务器读取发送来的Cookie就行了。
Cookie另一个典型的应用是当登录一个网站时,网站往往会请求用户输入用户名和密码,并且用户可以勾选“下次自动登录”。如果勾选了,那么下次访问同一网站时,用户会发现没输入用户名和密码就已经登录了。这正是因为前一次登录时,服务器发送了包含登录凭据(用户名加密码的某种加密形式)的Cookie到用户的硬盘上。第二次登录时,(如果该Cookie尚未到期)浏览器会发送该Cookie,服务器验证凭据,于是不必输入用户名和密码就让用户登录了。
cookie会被附加在每个HTTP请求中,所以无形中增加了流量。
由于在HTTP请求中的cookie是明文传递的,所以安全性成问题。(除非用HTTPS)
Cookie的大小限制在4KB左右。对于复杂的存储需求来说是不够用的。
虽然cookies没有中电脑病毒那么危险,但它仍包含了一些敏感信息:用户名,电脑名,使用的浏览器和曾经访问的网站。用户不希望这些内容泄漏出去,尤其是当其中还包含有私人信息的时候。
这并非危言耸听,跨站点脚本(Cross site scripting)可以达到此目的。在受到跨站点脚本攻击时,cookie盗贼和cookie毒药将窃取内容。一旦cookie落入攻击者手中,它将会重现其价值。
Cookie盗贼:搜集用户cookie并发给攻击者的黑客。攻击者将利用cookie信息通过合法手段进入用户帐户。
Cookie投毒:一般认为,Cookie在储存和传回服务器期间没有被修改过,而攻击者会在cookie送回服务器之前对其进行修改,达到自己的目的。例如,在一个购物网站的cookie中包含了顾客应付的款项,攻击者将该值改小,达到少付款的目的。这就是cookie投毒。
网络信标(web beacon),又称网页臭虫(web bug),是可以暗藏在任何网页元素或邮件内的1像素大小的透明GIF或PNG图片,常用来收集目标电脑用户的上网习惯等数据,并将这些数据写入Cookie。网络信标在邮件跟踪和垃圾邮件中较为常用。

Java编写的类QQ聊天系统

这是我09年写的第一个Java程序,一个类QQ聊天软件,当时是为了练习,现在把源码拿出来,当时水平有限,现在也没动力去优化了,希望能对Java初学者有一些帮助!说老实话,好多东西都忘了,但是仍有好多人找我,说要“交作业”和“毕业设计写论文”的,请大家先学好java基础,课本上的基础知识是有的,但是课本上却没告诉我们怎么把这些知识组合起来成为一个软件,这才是做作业、写论文的最大的价值所在,这才也是中国教育目前最大的悲哀。
实现思路:
首先每登录一个用户都会先到主持人这边登记,会记录每个用户的联系方式(这些都是只有主持人知道),然后主持人会通知已经登记的用户又有新用户加入;
李四想和张三说话,就把想说的话告诉主持人,由主持人帮你传话给张三,李四是不知道怎么才能联系到张三,但是主持人有每个用户的联系方式;
私聊是一对一聊,如果群里只有一个两个人,那这个群聊也就是私聊;
一共包含六个类:
Client.java
Clientframe.java
ClientUtil.java
Message.java
Server.java
Usermessage.java
Client.java:

import java.awt.Color;
import java.awt.FileDialog;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.*;
import java.net.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JList;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
/**
 *
 * @author tian QQ客户端
 */
public class Client extends Clientframe {
	Message receivemsg; // 在线用户之间的聊天信息
	Usermessage usermsg; // 用户信息
	Socket s;
	ObjectOutputStream oos;
	String ipaddress; // 服务器IP
	ArrayList al = new ArrayList();
	String cmd;
	boolean flag = false;
	/**
	 * 构造方法
	 */
	public Client() {
		usermsg = new Usermessage();
		try {
			usermsg.ip = InetAddress.getLocalHost().getHostAddress();
		} catch (UnknownHostException e3) {
			e3.printStackTrace();
		}
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		//上线时触发,发送用户信息(usermsg)给服务器
		jb1.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				String ipaddress = jtfname2.getText(); // 得到服务器IP
					try {
						if (flag == false) {
						s = new Socket(ipaddress, 9999);
						oos = new ObjectOutputStream(s.getOutputStream());
						flag = true;
						}
					} catch (UnknownHostException e2) {
						e2.printStackTrace();
					} catch (IOException e2) {
						e2.printStackTrace();
					}
					try {
						usermsg.username = jtfname.getText();
						usermsg.password = jtfpwd.getText();
						usermsg.flag1 = true; // 登陆是设为true
						oos.writeObject(usermsg);
						oos.reset();
					} catch (UnknownHostException e1) {
						e1.printStackTrace();
					} catch (IOException e1) {
						e1.printStackTrace();
					}
					ClientThread ct = new ClientThread();
					ct.start();
				}
		});
//		  监听用户下线信息
		jfb.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				Usermessage usermsg1 = new Usermessage();
				usermsg1.flag1 = false; // 表明用户下线
				usermsg1.username = usermsg.username;
				usermsg1.password = usermsg.password;
				try {
					usermsg1.ip = InetAddress.getLocalHost().getHostAddress();
				} catch (UnknownHostException e2) {
					e2.printStackTrace();
				}
				// 将用户信息发给服务器说明该客户要下线
				try {
					oos.writeObject(usermsg1);
					System.exit(0);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		});
//		  监听双击在线用户列表事件
		jli.addMouseListener(new MouseListener() {
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					JList source = (JList) e.getSource();
					Object[] selection = source.getSelectedValues();
					cmd = (String) selection[0];
					String[] ss = cmd.split("\s+");
					jfaa.setTitle("与" + ss[0] + "聊天");
					jfaa.setVisible(true);
				}
			}
			public void mouseEntered(MouseEvent e) {
			}
			public void mouseExited(MouseEvent e) {
			}
			public void mousePressed(MouseEvent e) {
			}
			public void mouseReleased(MouseEvent e) {
			}
		});
		//监听私聊send按钮
		jbaa.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				ClientUtil cu = new ClientUtil();
				Message m = new Message();
				m.fromname = usermsg.username;
				m.msg = jtabb.getText();
				String[] ss = cmd.split("\s+");
				m.toname = ss[0];
				m.flag = true;
				try {
					oos.writeObject(m);
				} catch (IOException e1) {
					e1.printStackTrace();
				}
				jtabb.setText("");
//				 调用ClientUtil中的dealmessage()方法对信息进行处理
				ArrayList msglist = ClientUtil.dealmessage(m.msg);
				// 调用ClientUtil中的printmsg()将信息显示到面板上
				cu.printmsg(msglist, jtaaa,m);
			}
		});
		 // 监听群聊send按钮
		jba.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				Message m = new Message();
				m.fromname = usermsg.username;
				m.msg = textPane1.getText();
				m.toname = "alluser";
				try {
					oos.writeObject(m);
				} catch (IOException e1) {
					// e1.printStackTrace();
				}
				textPane1.setText("");
			}
		});
		// 监听Transportfile按钮,实现文件传输,只能传输小文件
		jbbc.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				FileDialog f = new FileDialog(jfaa, "文件传送", FileDialog.LOAD);
				f.setVisible(true);
				String filename = f.getDirectory() + f.getFile();
				File file = new File(filename);
				FileInputStream fis;
				try {
					fis = new FileInputStream(file);
					int len = (int) file.length();
					byte[] data = new byte[len];
					fis.read(data);
					Message m = new Message();
					m.data = new byte[len];
					m.fromname = usermsg.username;
					String[] ss = cmd.split("\s+");
					m.toname = ss[0];
					m.flag = false;
					for (int i = 0; i < data.length; i++) {
						m.data[i] = data[i];
					}
					oos.writeObject(m);
				} catch (FileNotFoundException e1) {
					e1.printStackTrace();
				} catch (IOException e2) {
					e2.printStackTrace();
				}
			}
		});
		// 监听"群聊"按钮
		jb.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				jfa.setVisible(true);
			}
		});
	}
	 //显示在线用户列表(由服务器传入)
	class ClientThread extends Thread {
		ObjectInputStream ois;
		public void run() {
			ClientUtil cu = new ClientUtil();
			try {
				ois = new ObjectInputStream(s.getInputStream());
				while (true) {
					Object[] o = (Object[]) ois.readObject();
					// 处理“用户名重名”信息
					if (o[0] instanceof String) {
						String s1 = (String) o[0];
						if (s1.equals("用户名重复请重新填写")) {
							jtfname3.setText(s1);
						} else {
							jfb.setTitle(jtfname.getText());
							jfb.setVisible(true);
							jf.setVisible(false);
						}
					}
					// 处理用户信息
					if (o[0] instanceof Usermessage) {
						Usermessage u = (Usermessage) o[0];
						// 处理用户上线信息
						if (u.flag1) {
							dlm.clear();
							for (int i = 0; i < o.length; i++) {
								dlm.addElement(o[i].toString());
							}
						} else {
							// 处理用户下线信息
							for (int i = 0; i < dlm.size(); i++) {
								String s = dlm.get(i).toString();
								String[] ss = s.split("\s+");
								if (ss[0].equals(u.username)) {
									dlm.remove(i);
									break;
								}
							}
						}
					}
					// 处理聊天信息
					if (o[0] instanceof Message) {
						Message u = (Message) o[0];
						// 处理群聊信息
						if (u.toname.equals("alluser")) {
							// 调用ClientUtil中的dealmessage()方法对信息进行处理
							ArrayList msglist = ClientUtil.dealmessage(u.msg);
							// 调用ClientUtil中的printmsg()将信息显示到面板上
							cu.printmsg(msglist, textPane,u);
						}
						// 处理私聊信息
						if (u.toname.equals(usermsg.username)) {
							if (u.flag) {
								jfaa.setVisible(true);
								jfaa.setTitle("与" + u.fromname + "聊天");
//								 调用ClientUtil中的dealmessage()方法对信息进行处理
								ArrayList msglist = ClientUtil.dealmessage(u.msg);
								// 调用ClientUtil中的printmsg()将信息显示到面板上
								cu.printmsg(msglist, jtaaa,u);
								cmd = u.fromname;
							} else {
//								处理接收文件
								FileDialog f = new FileDialog(jfaa,
										"文件接收", FileDialog.SAVE);
								f.setVisible(true);
								String filename = f.getDirectory()
										+ f.getFile();
								FileOutputStream fos = new FileOutputStream(
										filename);
								byte[] buf = u.data;
								fos.write(buf);
								fos.close();
							}
						}
					}
				}
			} catch (IOException e) {
				 e.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}
	public static void main(String[] args) {
		Client c = new Client();
	}
}

Clientframe.java:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.File;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import sun.awt.image.ToolkitImage;
import sun.reflect.generics.scope.Scope;
/**
 *
 * @author tian
 *
 */
public class Clientframe {
	//	登陆窗口
	JFrame jf;
	JPanel jp1;
	JPanel jp2;
	JLabel jl1;
	JLabel jl2;
	JLabel jl3;
	JLabel jl4;
	JLabel jl5;
	JLabel jl6;
	JLabel jl7;
	Checkbox cb;
	Checkbox cb2;
	Choice ci ;
	ImageIcon im;
	JLabel jl8;
	JTextField jtfname;
	JPasswordField jtfpwd;
	JTextField jtfname2;
	JTextField jtfname3;
	JButton jb1;
	JButton jb2;
//	  群聊窗口
	JFrame jfa;
	JPanel jpa;
	JPanel jp;
	JPanel jpl;
	TextArea jtaa;
	TextArea jtab;
	JButton jba;
	JButton jbb;
	JButton jbc;
	JTextPane textPane;
	JTextPane textPane1;
	ImageIcon iic;
//	  私聊窗口
	JFrame jfaa;
	JPanel jpaa;
	JPanel jpp;
	JPanel jpll;
	JTextPane jtaaa;
	JTextPane jtabb;
	JButton jbaa;
	JButton jbbb;
	JButton jbbc;
	ImageIcon iic2;
//	  上线用户列表
	JFrame jfb;
	JPanel jpan;
	JPanel jpan1;
	DefaultListModel dlm;
	JList jli;
	JButton jb;
	ImageIcon ii;
	ImageIcon iii;
	JLabel jl;
//	群聊表情窗口
	JFrame jfc;
	JPanel jpbq;
	/**
	 *
	 */
	public Clientframe(){
//		初始化群聊表情窗口
		jfc = new JFrame("表情");
		jpbq = new JPanel();
		jfc.add(jpbq, BorderLayout.CENTER);
		jpbq.setLayout(new GridLayout(5,5));
		jfc.add(jpbq);
		URL qqurl = this.getClass().getClassLoader().getResource("Image/qq.jpg");
		jfc.setIconImage(Toolkit.getDefaultToolkit().createImage(qqurl));
		ArrayList al = new ArrayList();
		for (int i = 10; i < 35; i++) {
			URL url = this.getClass().getClassLoader().getResource( "Image/"+i+".gif");
			ImageIcon ii=new ImageIcon(url);
			JLabel jl = new JLabel(ii);
			al.add(jl);
		}
		for (int j = 0; j < al.size(); j++) { 			JLabel jl = (JLabel) al.get(j); 			jl.addMouseListener(new MouseListener(){ 				public void mouseClicked(MouseEvent e) { 					StyledDocument doc = textPane1.getStyledDocument(); 					SimpleAttributeSet attr = new SimpleAttributeSet(); 					StyleConstants.setForeground(attr, Color.red); 					String s = e.getSource().toString(); 					Pattern p = Pattern.compile(".gif"); 					Matcher m = p.matcher(s); 					while(m.find()){ 							int start = m.start(); 							int end = m.end(); 							String subs = s.substring(start-2,end); 							String path = "d:\"+subs; 							textPane1.setCaretPosition(doc.getLength()); // 设置插入位置 							File file = new File(path); 							Icon image = new ImageIcon(file.getAbsoluteFile().toString()); 							textPane1.insertIcon(image); 							try { 								doc.insertString(doc.getLength(), file.getName(), attr); 							} catch (BadLocationException e1) { 								 								e1.printStackTrace(); 							} 						} 				} 				public void mouseEntered(MouseEvent e) { 					 				} 			 				public void mouseExited(MouseEvent e) { 					 				} 				public void mousePressed(MouseEvent e) { 					 				} 				public void mouseReleased(MouseEvent e) { 					 				} 			}); 			jpbq.add(jl); 		} 		 		jfc.setVisible(false); 		jfc.setSize(250,250); 		 //		初始化登陆窗口 		 		jf = new JFrame("QQ用户登陆"); 		jp1 = new JPanel(); 		jp2 = new JPanel(); 		jtfname = new JTextField("",15); 		jtfpwd = new JPasswordField("",15); 		jtfname2 = new JTextField("",15); 		jl1 = new JLabel("QQ账号:"); 		jl2 = new JLabel("QQ密码:"); 		jl3 = new JLabel("ServerIP:"); 		jl4 = new JLabel("申请账号"); 	    jl5 = new JLabel("忘了密码"); 		jl6 = new JLabel("QQ状态:"); 		jl7=new JLabel("动感地带 "); 		cb = new Checkbox("自动登录"); 	    cb2 = new Checkbox("记住密码"); 		ci = new Choice(); 		jb1 = new JButton("登录");         jb2 = new JButton("退出");         URL jmurl =this.getClass().getClassLoader().getResource("Image/jm.jpg");         im = new ImageIcon(jmurl);         jl8=new JLabel(im); 		jf.add(jp1,BorderLayout.CENTER); 		jf.add(jp2,BorderLayout.SOUTH); 		jp1.add(jl8); 		jp1.add(jl1); 		jp1.add(jtfname); 		jp1.add(jl4); 		jp1.add(jl2); 		jp1.add(jtfpwd); 		jp1.add(jl5); 		jp1.add(jl3); 		jp1.add(jtfname2); 		jp1.add(jl7); 		jp1.add(jl6); 		jp1.add(ci); 		jp1.add(cb2); 		jp1.add(cb); 		jp2.add(jb1); 		jp2.add(jb2); 		jf.setBackground(new Color(100, 253, 98)); 		jp1.setBackground(new Color(176, 224, 230 )); 		jp2.setBackground(new Color(127, 255, 212 )); 		ci.add("在线"); 		ci.add("Q我吧"); 		ci.add("忙碌"); 		ci.add("离开"); 		ci.add("静音"); 		ci.add("隐身"); 		jl1.setForeground(Color.BLUE); 		jl2.setForeground(Color.BLUE); 		jl3.setForeground(Color.BLUE); 		jl4.setForeground(Color.BLUE); 		jl5.setForeground(Color.BLUE); 		jl7.setForeground(Color.BLUE); 		jb1.setSize(20, 10); 		jb2.setSize(20, 10);         jf.setSize(333, 250); 		jf.setIconImage(Toolkit.getDefaultToolkit().createImage(qqurl)); 		jf.setLocation(500, 250); 		jf.setResizable(false); 		jf.setVisible(true); 		 		jb2.addActionListener(new ActionListener(){ 			public void actionPerformed(ActionEvent e) { 				System.exit(1); 				 			} 			 		}); 		 //		初始化群聊窗口 		jfa = new JFrame("QQ聊天室"); 		jpa = new JPanel(); 		jp = new JPanel(); 		jpl = new JPanel(); 		dlm = new DefaultListModel(); 		URL iicurl =this.getClass().getClassLoader().getResource("Image/12.gif"); 		iic=new ImageIcon(iicurl); 		textPane = new JTextPane(); 		textPane1 = new JTextPane(); 		textPane.setPreferredSize(new Dimension(360, 200)); 		textPane1.setPreferredSize(new Dimension(360, 100)); 		textPane.setFont(new Font("Serif",Font.BOLD,14)); 		textPane1.setFont(new Font("Serif",Font.BOLD,14)); 		JScrollPane scrollPane = new JScrollPane(textPane); 		JScrollPane scrollPane1 = new JScrollPane(textPane1); 		textPane1.setForeground(Color.red); 		jba = new JButton("发送"); 		jbb = new JButton("清空"); 		jbc = new JButton("表情",iic); 		jbc.setMnemonic(KeyEvent.VK_F);//给“表情”按钮设置快捷键 		jba.setForeground(Color.BLUE); 		jbb.setForeground(Color.BLUE); 		jbc.setForeground(Color.BLUE); 		jfa.add(jpa, BorderLayout.NORTH); 		jfa.add(jp, BorderLayout.CENTER); 		jfa.add(jpl, BorderLayout.SOUTH); 		jfa.setIconImage(Toolkit.getDefaultToolkit().createImage(qqurl)); 		jpa.add(scrollPane); 		jp.add(scrollPane1); 		jpl.add(jba); 		jpl.add(jbc); 		jpl.add(jbb); 		jpa.setBackground(new Color(100, 253, 98)); 		jp.setBackground(new Color(100, 253, 98)); 		jpl.setBackground(new Color(100, 253, 98)); 		jfa.setSize(380, 400); 		jfa.setLocation(500, 150); 		jfa.setResizable(false); 		jfa.setVisible(false); 		jbb.addActionListener(new ActionListener() { 			public void actionPerformed(ActionEvent e) { 				textPane1.setText(""); 			} 		}); 		 		 //		 监听群聊表情按钮 		jbc.addActionListener(new ActionListener() { 			public void actionPerformed(ActionEvent e) { 				jfc.setVisible(true); 				jfc.setLocation(500, 150); 			} 		}); 		 //		初始化私聊窗口 		jfaa = new JFrame("私聊");			 		jpaa = new JPanel();			 		jpp = new JPanel(); 		jpll =new JPanel(); 		URL transcurl =this.getClass().getClassLoader().getResource("Image/trans.gif"); 		iic2 =new ImageIcon(transcurl); 		jtaaa = new JTextPane();	 		jtabb = new JTextPane(); 		jtaaa.setPreferredSize(new Dimension(360, 200)); 		jtabb.setPreferredSize(new Dimension(360, 100)); 		JScrollPane scrollPanea = new JScrollPane(jtaaa); 		JScrollPane scrollPaneb = new JScrollPane(jtabb); 		jtabb.setForeground(Color.red); 		jbaa = new JButton("发送");		 		jbbb = new JButton("清空");		 		jbbc = new JButton("",iic2); 		jbc.setMnemonic(KeyEvent.VK_F); 		jtaaa.setFont(new Font("Serif",Font.BOLD,14)); 		jtabb.setFont(new Font("Serif",Font.BOLD,14)); 	    jbaa.setForeground(Color.BLACK); 		jbbb.setForeground(Color.BLACK); 		jbbc.setForeground(Color.BLACK); 		jfaa.add(jpaa,BorderLayout.NORTH); 		jfaa.add(jpp,BorderLayout.CENTER); 		jfaa.add(jpll,BorderLayout.SOUTH); 		jfaa.setIconImage(Toolkit.getDefaultToolkit().createImage(qqurl)); 		jpaa.add(scrollPanea); 		jpp.add(scrollPaneb); 		jpll.add(jbaa); 		jpll.add(jbbc); 		jpll.add(jbbb); 		jf.setBackground(new Color(100, 253, 98)); 		jpaa.setBackground(new Color(100, 253, 98));		 		jpp.setBackground(new Color(100, 253, 98));		  		jpll.setBackground(new Color(100, 253, 98));		  		jfaa.setSize(380, 400); 		jfaa.setLocation(500, 150); 		jfaa.setResizable(false); 		jfaa.setVisible(false);	 		 	    		jbbb.addActionListener(new ActionListener(){ 			public void actionPerformed(ActionEvent e) { 				jtabb.setText(""); 			} 			 		}); 		 //		初始化上线用户列表 		jfb = new JFrame(); 		jpan = new JPanel(); 		dlm = new DefaultListModel(); 		jli = new JList(dlm); 		jb = new JButton(">>>群聊模式");
		jli.setForeground(Color.BLUE);
		jb.setSize(15, 20);
		jb.setForeground(Color.BLUE);
		jfb.add(jpan);
		jpan.setLayout(new BorderLayout());
		jpan.add(jli, BorderLayout.CENTER);
		jpan.add(jb, BorderLayout.SOUTH);
		jpan.add(jli);
		jfb.setIconImage(Toolkit.getDefaultToolkit().createImage(qqurl));
		jfb.setResizable(false);
		jfb.setLocation(500, 200);
		jfb.setSize(200, 450);
		jfb.setVisible(false);
	}
}

ClientUtil.java:

import java.awt.Color;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JTextPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.SimpleAttributeSet;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
public class ClientUtil {
	/**
	 * 处理已接收信息,将表情与字符分开
	 */
	public static ArrayList dealmessage(String message) {
		String msg = message;
		// 处理字符串
		ArrayList list = new ArrayList();
		ArrayList substrlist = new ArrayList();
		list.add(0);
		Pattern p = Pattern.compile(".gif");
		Matcher m = p.matcher(msg);
		while (m.find()) {
			int start = m.start() - 2;
			list.add(start);
			start = start + 6;
			if (start > msg.length()) {
				break;
			}
			list.add(start);
		}
		for (int i = 0; i < list.size(); i++) {
			if (i < list.size()-1) {
				int begin = Integer.parseInt(list.get(i).toString());
				int over = Integer.parseInt(list.get(i + 1).toString());
				String subs = msg.substring(begin, over);
				substrlist.add(subs);
			}else{
				String subs = msg.substring(Integer.parseInt(list.get(i).toString()));
				substrlist.add(subs);
			}
		}
		return substrlist;
	}
	/**
	 * 将处理过的信息显示在聊天面板上
	 */
	public void printmsg(ArrayList list,JTextPane tPane,Message u){
		Icon image = null;
		JTextPane textPane = tPane;
		StyledDocument doc = textPane.getStyledDocument();
		SimpleAttributeSet attr = new SimpleAttributeSet();
		StyleConstants.setForeground(attr, Color.red);
		ArrayList msglist = list;
		Pattern p = Pattern.compile(".gif");
		try {
			doc.insertString(doc.getLength(), u.toString() ,
					attr);
		} catch (BadLocationException e1) {
			e1.printStackTrace();
		}
		for (int i = 0; i < msglist.size(); i++) {
			String sub = msglist.get(i).toString();
			Matcher m = p.matcher(sub);
			if(m.find()){
				URL url = this.getClass().getClassLoader().getResource("Image/" + sub);
				textPane.setCaretPosition(doc.getLength()); // 设置插入位置
				image = new ImageIcon(url);
				textPane.insertIcon(image);
			}else{
				try {
					doc.insertString(doc.getLength(), sub ,
							attr);
				} catch (BadLocationException e) {
					e.printStackTrace();
				}
			}
		}
		try {
			doc.insertString(doc.getLength(), "n" ,
					attr);
		} catch (BadLocationException e) {
			e.printStackTrace();
		}
	}
}

Message.java:

import java.io.Serializable;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;
/**
 *
 * @author tian
 *	在线用户之间的聊天信息
 */
public class Message implements Serializable{
	public String fromname;
	public String toname;
	public String msg;
	public boolean flag;
	byte[] data = null;//用于传送文件
	int len;   //信息会随着文件的长度而变化
	public Message(){
	}
	public int getLen() {
		return len;
	}
	public void setLen(int len) {
		this.len = len;
	}
	public String toString() {
		Date today = new Date();
		Locale cnLocale = new Locale("zh", "CN");
		DateFormat df = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, cnLocale);
		return fromname+" 于"+df.format(today)+"说:"+"n";
	}
}

Server.java:

import java.awt.BorderLayout;
import java.awt.FlowLayout;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.DefaultListModel;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
/**
 *
 * @author tian	QQ服务器端
 *
 */
public class Server {
	JFrame jf = new JFrame("QQ服务器");
	JPanel jp = new JPanel();
	JPanel jp1 = new JPanel();
	JTextArea jta = new JTextArea();
	JTextArea jta1 = new JTextArea();
	JScrollPane jsp = new JScrollPane(jta1);
	JLabel jl = new JLabel("QQ在线列表");
	protected ServerSocket ss;
	DefaultListModel dlm = new DefaultListModel();
	JList jli = new JList(dlm);
	ArrayList uml = new ArrayList();
	HashMap mp = new HashMap();		//存储socket对应的oos
	HashMap mp1 = new HashMap();	//存储用户所对应的socket
//	 初始化服务器
	public Server() {
		jf.add(jp, BorderLayout.NORTH);
		jp.setLayout(new FlowLayout(FlowLayout.LEFT));
		jp.add(jl);
		jf.add(jli, BorderLayout.CENTER);
		jf.add(jsp, BorderLayout.SOUTH);
		jta1.setSize(250, 300);
		jsp.setSize(250, 300);
		jf.setSize(250, 500);
		jf.setLocation(500, 150);
		jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		jf.setVisible(true);
		try {
			ss = new ServerSocket(9999);
			Thread t = new ServerThread();
			t.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	/**
	 *
	 * 监听线程
	 *
	 */
	class ServerThread extends Thread {
		public void run() {
			try {
				while (true) {
					Socket sc = ss.accept();
					ObjectOutputStream oos = new ObjectOutputStream(sc
							.getOutputStream());
					mp.put(sc, oos);
					SocketThread st = new SocketThread(sc);
					st.start();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 *
	 * 读线程
	 *
	 */
	class SocketThread extends Thread {
		Socket sc;
		public SocketThread(Socket sc) {
			this.sc = sc;
		}
		public void run() {
			try {
				ObjectInputStream ois = new ObjectInputStream(sc
						.getInputStream());
				while (true) {
					Object m = ois.readObject();
					// 处理用户信息
					if (m instanceof Usermessage) {
						Usermessage u = (Usermessage) m;
						// 如果flag1为true,则是登陆信息
						if (u.flag1 && Server.checkuser(u,uml,mp)) {
							mp1.put(u.username, sc);
							dlm.addElement(sc.getRemoteSocketAddress() + "n");
							uml.add(u);
							Object[] o = uml.toArray();
							Iterator i = mp.keySet().iterator();
							while (i.hasNext()) {
								Socket sc = (Socket) i.next();
								((ObjectOutputStream) mp.get(sc))
										.writeObject(o);
							}
						} else if(!u.flag1){
							ois.close();
							ObjectOutputStream oos = (ObjectOutputStream) mp
									.get(sc);
							oos.close();
							sc.close();
							mp.remove(sc);
							for (int i = 0; i < uml.size(); i++) { // 通过for循环可以遍历ArrayList
								Usermessage um = (Usermessage) uml.get(i); // 通过下标输出ArrayList里面的值
								if (um.username.equals(u.username)) {
									uml.remove(i);
									break;
								}
							}
							Object[] o = new Object[1];
							o[0] = u;
							Iterator i = mp.keySet().iterator();
							while (i.hasNext()) {
								Socket sc = (Socket) i.next();
								((ObjectOutputStream) mp.get(sc))
										.writeObject(o);
							}
						}
					}
					// 处理聊天信息
					if (m instanceof Message) {
						Message u = (Message) m;
						//处理群聊
						if (u.toname.equals("alluser")) {
							ArrayList al = new ArrayList();
							al.add(u);
							Object[] o1 = al.toArray();
							Iterator i = mp.keySet().iterator();
							while (i.hasNext()) {
								Socket sc = (Socket) i.next();
								((ObjectOutputStream) mp.get(sc))
										.writeObject(o1);
							}
						}else{
							//处理私聊和文件传送
							ArrayList al = new ArrayList();
							al.add(u);
							Object[] o1 = al.toArray();
							((ObjectOutputStream) mp.get(mp1.get(u.toname))).writeObject(o1);
						}
					}
				}
			} catch (IOException e1) {
//				e1.printStackTrace();
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
	}
	//检测用户名是否重复
	public static boolean checkuser(Usermessage u,ArrayList uml,HashMap mp){
		ArrayList uml1 = uml;
		int i;
		for (i = 0; i < uml1.size(); i++) { // 通过for循环可以遍历ArrayList 			Usermessage um = (Usermessage) uml1.get(i); // 通过下标输出ArrayList里面的值 			if (um.username.equals(u.username)) { 				String s = "用户名重复请重新填写"; 				Object[] o = new Object[1]; 				o[0] = s; 				Iterator it = mp.keySet().iterator(); 				while (it.hasNext()) { 					try { 						Socket sc = (Socket) it.next(); 						((ObjectOutputStream) mp.get(sc)) 								.writeObject(o); 					} catch (IOException e) { 						e.printStackTrace(); 					} 				} 			break;	 			} 		} 		if(i>=uml1.size()){
		String s = "success";
		Object[] o = new Object[1];
		o[0] = s;
		Iterator it = mp.keySet().iterator();
		while (it.hasNext()) {
			try {
				Socket sc = (Socket) it.next();
				((ObjectOutputStream) mp.get(sc))
						.writeObject(o);
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return true;
		}else{
			return false;
		}
	}
	public static void main(String[] args) {
		Server s = new Server();
	}
}

Usermessage.java:

import java.io.Serializable;
import java.net.ServerSocket;
import java.net.Socket;
/**
 *
 * @author tian
 *	用于传递用户信息
 */
public class Usermessage implements Serializable{
	public String username;		//用户名称
	public String password;		//用户密码
	public String ip;			//用户IP
	public boolean flag1;		//标志用户上线还是下线,为true表示为登陆
	public String ipaddress;	//服务器IP
	public Usermessage(){
	}
	public boolean equals(Usermessage user) {
		boolean flag= false;
		if(ip.equals(user.ip)){
			flag = true;
		}
		return flag;
	}
	public String toString() {
		return username + "  "+ ip;
	}
}

打包好的程序和图片资源下载地址:
http://download.csdn.net/detail/xionglong/1638561
效果:



表情窗口

jsp页面编译后的java文件的位置

开发的时候碰到了个bug,从下面的异常情况来看是说空指针异常,而且空指针的位置是发生在-org.apache.jsp.show_jsp:966
这个文件应该是jsp编译后生成的java代码的966行。那么这个java代码在哪里能找到呢?答案是:apache-tomcat-6.0.18workCatalinalocalhost_orgapachejspshow_jsp.java(这是tomcat缓存下的路径)找到966行,发现
Listlist = (List)getServletContext().getAttribute(“indexPDFList”);
for(int i=0; i可能是list为空造成的。

jsp页面编译后的java文件的位置

jsp页面编译后的java文件的位置

严重: Servlet.service() for servlet jsp threw exception
java.lang.NullPointerException
	at org.apache.jsp.show_jsp._jspService(org.apache.jsp.show_jsp:966)
	at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:97)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:322)
	at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:314)
	at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:264)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:88)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:630)
	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
	at org.apache.struts2.dispatcher.ServletDispatcherResult.doExecute(ServletDispatcherResult.java:157)
	at org.apache.struts2.dispatcher.StrutsResultSupport.execute(StrutsResultSupport.java:186)
	at com.opensymphony.xwork2.DefaultActionInvocation.executeResult(DefaultActionInvocation.java:374)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:278)
	at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:176)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
	at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:211)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:211)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:190)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:75)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:90)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:243)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:176)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:192)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:187)
	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:249)
	at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
	at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:510)
	at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
	at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:630)
	at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:436)
	at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:374)
	at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:302)
	at org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:213)
	at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:171)
	at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
	at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
	at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:381)
	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:286)
	at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:845)
	at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
	at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:447)
	at java.lang.Thread.run(Thread.java:619)

分布式缓存系统

概述
在数据驱动的Web开发中,经常要重复从数据库中取出相同的数据,这种重复极大的增加了数据库负载。缓存是解决这个问题的好办法。
种类
比较流行的有Memcached、Ehcache、OSCache,还有JSC、Jmemcached、Tcache等。
Memcached
1、定义:是高性能的分布式的内存对象缓存系统。
2、原理:通过在内存里维护一个统一的巨大的Hash表来存储各种格式的数据,包括图像、视频、文件以及数据库检索的数据等。
3、特点:是一种分布式的缓存系统,可以允许不同主机上的不同用户同时访问这个系统,从而解决了共享内存只能是单机的弊端,同时也减轻了数据库检索的压力。
4、优点:提高了访问获取数据的速度,也可用于加速Web应用。
5、缺点:没有特殊的安全机制,需要自己控制安全。
6、适用场景:缓存对性能影响较大的数据、缓存变动不是很频繁的数据。
7、语言:支持多重语言开发,包括:Perl/PHP/JAVA/C/Python/Ruby/C#。
8、延伸:也可以使用到分布式数据库、分布式计算等领域。
参考网址:http://phpe.net/2010/09/getting-started-with-memcached-distributed-memory-caching/
Ehcache
1、定义:是一个纯 Java 的进程内缓存框架。
2、应用举例:是 Hibernate 中默认的CacheProvide。
3、特点:快速;简单;多种缓存策略;多级缓存;数据缓存会在虚拟机重启的过程中写入缓存;通过RMI、可插入API等方式进行分布式缓存;
具有缓存和缓存管理器的侦听接口;支持多缓存管理器实例,以及一个实例的多缓存区域;提供Hibernate的缓存实现。
4、缺点:由于是进程中的缓存,在集群环境中,每个节点各自维护各自的缓存数据,当某个节点对缓存数据进行更新,这些更新数据无法在别的节点中共享,
从而会降低节点的运行效率,还会导致数据不同步情况的发生。所以需要使用集群解决方案。
5、集群解决方案:从V1.7开始,支持5种集群解决方案,分别是:Terracotta、RMI、JMS、JGroups、Ehcache Server,常用的是RMI、JGroups以及EhCache Server。
6、语言:EhCache Server集群方式基于HTTP协议,支持多语言开发;RMI、JGroups应该仅支持Java。
参考网址:http://www.ibm.com/developerworks/cn/java/j-lo-ehcache/index.html
OSCache
1、定义:是一个被广泛应用的J2EE缓存框架,还能应用于任何Java应用程序的普通的缓存解决方案。
2、特点:能缓存任何对象;拥有全面的API;永久缓存;支持集群;可以控制缓存过期时间。
3、适用场景:适用于对象缓存、Filter缓存、JSP或部分JSP缓存。
4、缺点:并发量较高时,会出现线程阻塞和数据错误(内部缺陷导致)。
参考网址:http://baike.baidu.com/view/1835163.html?fromTaglist
指标参数
缓存数据类型、分布式(集群)支持、API及使用、缓存过期控制、开发语言支持、缓存策略、伸缩性、缓存监控管理、数据一致性、稳定性
其他
各种缓存框架的简单比较:http://news.newhua.com/news1/program_language/2010/326/10326142152I7GCJ98DFI81BDHJ08J94FB386GJHHH5IJ2I28ECJ9K67.html
http://jackyrong.iteye.com/blog/239206