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)

Linux操作系统目录的作用

了解linux下操作系统目录的作用对学习linux操作系统会有很大帮助。
Linux各个目录其实就是文件,
以下是根目录低下的个个目录的作用总结:
1. 根文件系统(/ )
根文件系统中包含了几乎所有的文件目录。相当于中央系统。进入的最简单方法是:cd /
2. /usr文件系统
/usr文件系统中包含了命令库文件和在通常操作中不会修改的文件。安装程序默认就是安装在此文件内部某个子文件夹内。输入命令后系统默认执行/usr/bin下的程序。
3. /var文件系统
/var文件系统中包含一些经常改变的文件。例如假脱机(spool)目录文件日志目录?锁文件?临时文件和格式化后的手册文件。
4. /home文件系统
/home文件系统中保存了用户文件(用户自己的配置文件,定制文件,文档,数据等),root用户除外。
5. /proc文件系统
/proc文件系统中包含了全部虚拟文件。它们并不保存在磁盘中,也不占据磁盘空间(尽管命令ls -c会显示它们的大小)。当您查看它们时,您实际上看到的是内存里的信息,这些文件有助于我们了解系统内部信息。
根文件系统中主要包括以下目录:
/bin:普通用户可以使用的命令文件。
/sbin:一般为非普通用户使用的命令。有时普通用户也可能会用到。
/etc:系统的配置文件。
/root:系统管理员(root或超级用户)的主目录。
/dev:设备文件。在Linux中设备以文件形式出现,从而可以按照写文件的方式简便地对设备进行写操作。
/mnt:文件系统安装点。一般用于安装移动介质?其它文件系统(如DOS)的分区、网络共享文件系统或任何可安装文件系统。
/lib:根目录下的所有程序的共享库。
/boot:LILO使用的文件。Linux内核一般放在该目录下。当然您也可以设置LILO的配置文件,向LILO指明加载内核的其它路径。
/opt:可选择安装的大型应用程序。
/tmp:临时文件,该目录中的文件被系统自动清空。
/lost+found:在系统修复过程中恢复的文件,一般为空。
/usr文件系统中主要包括以下目录:
/usr/x11R6:X Window系统。
/usr/X11:等同于/usr/X11R6 (是到/usr/X11R6的符号链接)。
/usr/X11R6/bin:保存有大量的X Window小程序,或者是指向一些大应用程序的符号链接。
/usr/bin和/usr/sbin:相当于根文件系统下的对应目录,但在基本的系统自举过程中是不需要的(例如在紧急维护中)。
/usr/local:安装本地用户应用程序,例如,Netscape(每一个用户在一个单独的目录中)。
/usr/local/bin:可能是一些小的用户应用程序,也可能是一些指向/usr/local子目录中大应用程序的符号链接。

分布式缓存系统

概述
在数据驱动的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

hadoop职位要求

Hadoop的职位一般有:
1、hadoop运维工程师(负责维护hadoop平台,确保平台平稳运行,作业正常提交)
2、基于hadoop平台,在此基础上进行开发新功能。(多数是写些MapReduce程序)
3、Hadoop解决方案架构(Hadoop相关产品技术架构设计、实现、应用)
大家可以参考现有的hadoop职位要求,选择自己的技术路线。hadoop其实离我们并不远!
下面是几个典型的职位要求:
1、hadoop高级运维工程师(暴风影音)
岗位职责
负责Hadoop平台运维和优化工作;
保证Hadoop平台各核心服务运行的稳定、高效;
对Hadoop平台运维不断优化,提升数据产品的质量和响应速度;
开发各种Hadoop大数据自动化运维与监控工具。/
岗位要求
本科3年以上Linux系统管理工作经验;
1年以上Hadoop平台管理经验;
熟悉Apache Hadoop部署、性能调优,熟悉jetty,thrift;
精通Shell/Python/Java/Php语言的一种或多种;
熟悉nagios,cacti,ganglia,zabbix,zenoss优先;
对大数据和自动化运维开发有浓厚兴趣,熟悉hadoop、hbase、hive、scribe、flume、storm等分布式相关技术优先。
2、hadoop研发工程师(优酷土豆)
职责:
1.基于hadoop的海量数据分析系统研发
2.基于hadoop集群的MapReduce程序的开发、测试及优化
要求:
1.对Linux操作系统熟练掌握,熟悉shell等脚本编程
2.扎实的java基础,两年以上java实际开发经验
3.熟悉hadoop集群的搭建、管理及优化
4.熟悉hadoop及hive,有MapReduce分布式编程经验
5.熟练掌握MySQL数据库,熟练使用SQL
6.对海量数据的分析、挖掘有浓厚兴趣,有海量数据处理经验
7.对技术有激情,喜欢钻研,能快速接受和掌握新技术,有较强的独立、主动的学习能力
8.理解能力强,有较强的逻辑思维分析能力
9.有强烈的责任心及良好的团队合作精神
其他:
1.两年以上工作经验,本科以上学历
2.有过移动数据统计系统开发经验者优先
3、Hadoop解决方案架构师(北京云基地企业管理有限公司)
工作职责:
1.产品技术架构设计、实现、应用
2.Hadoop及大数据相关技术研究
3.客户需求分析及沟通
4.向客户提供Hadoop咨询和培训
职位要求:
1.计算机相关专业毕业,3年以上工作经验,至少1年MapReduce开发经验
2.熟悉Linux操作系统,熟悉Java语言和开发环境
3.熟悉Hadoop生态系统相关项目的功能、架构、实现
4.对计算机体系结构和分布式系统有深入了解
5.优秀的表达和沟通能力

童小军_HD录制的Hadoop视频下载

EasyHadoop创始人@童小军_HD 辛苦录制的Hadoop实战视频被无良卖家放到淘宝网上牟取私利,经和作者沟通,小军愿意无偿将全部视频资料分享给各位爱好者学习使用,因文件太大,需要服务器和带宽,求接受方慷慨相助,也算为行业贡献一己之力 @张栋_机器学习 @邓侃 @梁斌penny @vinWHadoop
视频已经上传到百度网盘,同时视频下载地址已经更新到 EasyHadoop技术大学 页面。希望大家怀着感恩、分享的心去学习,正如作者说的:去帮助别人就如同帮助过去的你
PS:好像原作者已经删除了部分视频,百度网盘已经无法分享这些视频了,我发现在“钱”面前,说的总比做的好听!如果需要可以在这个页面给我留下邮箱,我发给你们下载地址,仅供学习参考。
欢迎订阅博客:http://feed.feedsky.com/Hadoop_java  以后还会分享些有用的内容!
也可以加入Hadoop云计算群:300165122
PPS:大家不要把邮箱留在评论内容里,这样会被收集邮箱地址的发垃圾邮件软件抓取的,在填写内容的时候,会让你填邮件,我能看到的。我正在把这部分资源放到Dropbox上,没收到链接到同学请耐心等待。
下面是地址:http://university.easyhadoop.com/university.html

hadoop视频下载链接

hadoop视频下载链接


百度网盘下载地址:http://pan.baidu.com/share/link?shareid=492484&uk=1124363056#dir/path=%2FEasyHadoop%E6%8A%80%E6%9C%AF%E5%A4%A7%E5%AD%A6%20%E5%9F%B9%E8%AE%AD%E8%A7%86%E9%A2%91
童小军_HD微博:http://weibo.com/tongxiaojun
童小军_HD微博

童小军_HD微博

IT人不要一辈子靠技术生存

我现在是自己做,但我此前有多年在从事软件开发工作,当回过头来想一想自己,觉得特别想对那些初学JAVA/DOT。NET技术的朋友说点心里话,希望你们能从我们的体会中,多少受点启发(也许我说的不好,你不赞同但看在我真心的份上别扔砖头啊).
一。 在中国你千万不要因为学习技术就可以换来稳定的生活和高的薪水待遇,你千万更不要认为哪些从事 市场开发,跑腿的人,没有前途。
不知道你是不是知道,咱们中国有相当大的一部分软件公司,他们的软件开发团队都小的可怜,甚至只有1-3个人,连一个项目小组都算不上,而这样的团队却要承担一个软件公司所有的软件开发任务,在软件上线和开发的关键阶段需要团队的成员没日没夜的加班,还需要为测试出的BUG和不能按时提交的软件模块功能而心怀忐忑,有的时候如果你不幸加入现场开发的团队你则需要背井离乡告别你的女友,进行封闭开发,你平时除了编码之外就是吃饭和睡觉(有钱的公司甚至请个保姆为你做饭,以让你节省出更多的时间来投入到工作中,让你一直在那种累了就休息,不累就立即工作的状态)
更可怕的是,会让你接触的人际关系非常单一,除了有限的技术人员之外你几乎见不到做其他行业工作和职位的人,你的朋友圈子小且单一,甚至破坏你原有的爱情(想象一下,你在外地做现场开发2个月以上,却从没跟女友见过一面的话,你的女友是不是会对你呲牙裂嘴)。
也许你拿到了所谓的白领的工资,但你却从此失去享受生活的自由,如果你想做技术人员尤其是开发人员,我想你很快就会理解,你多么想在一个地方长期待一段时间,认识一些朋友,多一些生活时间的愿望。
比之于我们的生活和人际关系及工作,那些从事售前和市场开发的朋友,却有比我们多的多的工作之外的时间,甚至他们工作的时间有的时候是和生活的时间是可以兼顾的,他们可以通过市场开发,认识各个行业的人士,可以认识各种各样的朋友,他们比我们坦率说更有发财和发展的机会,只要他们跟我们一样勤奋。(有一种勤奋的普通人,如果给他换个地方,他马上会成为一个勤奋且出众的人。)
二。在学习技术的时候千万不要认为如果做到技术最强,就可以成为100%受尊重的人。
有一次一个人在面试项目经理的时候说了这么一段话:我只用最听话的人,按照我的要求做只要是听话就要,如果不听话不管他技术再好也不要。随后这个人得到了试用机会,如果没意外的话,他一定会是下一个项目经理的继任者。
朋友们你知道吗?不管你技术有多强,你也不可能自由的腾出时间象别人那样研究一下LINUX源码,甚至写一个LINUX样的杰作来表现你的才能。你需要做的就是按照要求写代码,写代码的含义就是都规定好,你按照规定写,你很快就会发现你昨天写的代码,跟今天写的代码有很多类似,等你写过一段时间的代码,你将领略:复制,拷贝,粘贴那样的技术对你来说是何等重要。(如果你没有做过1年以上的真正意义上的开发不要反驳我)。
如果你幸运的能够听到市场人员的谈话,或是领导们的谈话,你会隐约觉得他们都在把技术人员当作编码的机器来看,你的价值并没有你想象的那么重要。而在你所在的团队内部,你可能正在为一个技术问题的讨论再跟同事搞内耗,因为他不服你,你也不服他,你们都认为自己的对,其实你们两个都对,而争论的目的就是为了在关键场合证明一下自己比对方技术好,比对方强。(在一个项目开发中,没有人愿意长期听别人的,总想换个位置领导别人。)
三。你更不要认为,如果我技术够好,我就自己创业,自己有创业的资本,因为自己是搞技术的。
如果你那样认为,真的是大错特错了,你可以做个调查在非技术人群中,没有几个人知道C#与JAVA的,更谈不上来欣赏你的技术是好还是不好。一句话,技术仅仅是一个工具,善于运用这个工具为别人干活的人,却往往不太擅长用这个工具来为自己创业,因为这是两个概念,训练的技能也是完全不同的。
创业最开始的时候,你的人际关系,你处理人际关系的能力,你对社会潜规则的认识,还有你明白不明白别人的心,你会不会说让人喜欢的话,还有你对自己所提供的服务的策划和推销等等,也许有一万,一百万个值得我们重视的问题,但你会发现技术却很少有可能包含在这一万或一百万之内,如果你创业到了一个快成功的阶段,你会这样告诉自己:我干吗要亲自做技术,我聘一个人不就行了,这时候你才真正会理解技术的作用,和你以前做技术人员的作用。
[小结]
基于上面的讨论,我奉劝那些学习技术的朋友,千万不要拿科举考试样的心态去学习技术,对技术的学习几近的痴迷,想掌握所有所有的技术,以让自己成为技术领域的权威和专家,以在必要的时候或是心里不畅快的时候到网上对着菜鸟说自己是前辈。
技术仅仅是一个工具,是你在人生一个阶段生存的工具,你可以一辈子喜欢他,但最好不要一辈子靠它生存。
掌握技术的唯一目的就是拿它找工作(如果你不想把技术当作你第二生命的话),就是干活。所以你在学习的时候千万不要去做那些所谓的技术习题或是研究那些帽泡算法,最大数算法了,什么叫干活?
就是做一个东西让别人用,别人用了,可以提高他们的工作效率,想象吧,你做1万道技术习题有什么用?只会让人觉得酸腐,还是在学习的时候,多培养些自己务实的态度吧,比如研究一下当地市场目前有哪些软件公司用人,自己离他们的要求到底有多远,自己具体应该怎么做才可以达到他们的要求。等你分析完这些,你就会发现,找工作成功,技术的贡献率其实并没有你原来想象的那么高。
不管你是学习技术为了找工作还是创业,你都要对技术本身有个清醒的认识,在中国不会出现BILL GATES,因为,中国目前还不是十分的尊重技术人才,还仅仅的停留在把软件技术人才当作人才机器来用的尴尬境地。(如果你不理解,一种可能是你目前仅仅从事过技术工作,你的朋友圈子里技术类的朋友占了大多数,一种可能是你还没有工作,但喜欢读比尔。盖茨的传记)。

struts1.2和struts2区别

struts1.2和struts2区别
struts1.2和struts2最大的不同是,struts2集成了Webwork。
区别相当大,2.0改进很多,整合webwork,去掉了一些不常用得标签,
struts2.x是在webwork2的基础上构建的,集成了大量的东西,像什么拦截器,校验框架等,相当复杂,struts1.x相对来说就显得小得多了,东西就那么几个。
特性
Struts 1。2
Struts 2 .0
Action类
Struts 1要求Action类要扩展自一个抽象基类。Struts 1的一个共有的问题是面向抽象类编程而不是面向接口编程。
Struts 2的Action类实现了一个Action接口,连同其他接口一起来实现可选择和自定义的服务。Struts 2提供一个名叫ActionSupport的基类来实现一般使用的接口。虽然,Action接口不是必须的。任何使用execute方法的POJO对象可以被当作Struts 2的Action对象来使用。
线程模型
Struts 1 Action类是单例类,因为只有一个示例来控制所有的请求。单例类策略造成了一定的限制幷且给开发带来了额外的烦恼。Action资源必须是线程安全或者同步的。
Struts 2 Action对象为每一个请求都实例化对象,所以没有线程安全的问题。(实践中,servlet容器产生许多丢弃的对象对于每一个请求,多于一个的对象并不影响垃圾收集)
Servlet 依赖
Struts 1的Action类依赖于servlet API以为HttpServletRequest和HttpServletResponse作为参数传给execute方法当Action被调用时。
Struts 2的Action不和容器有关。Servlet上下文被表现为简单的Maps,允许Action被独立的测试。Struts 2的Action可以访问最初的请求和相应,如果需要的话。然而,其他的架构元素减少或者排除直接访问HttpServletRequest或者HttpServletResponse的需要。
易测性
测试Struts 1的主要障碍是execute方法暴露了Servlet API。第三方的扩展,Struts测试用例,提供Struts 1的集合对象。
Struts 2的Action可以通过实例化Action来测试,设置属性,然后调用方法。依赖注入的支持也是测试变得更简单。
接受输入
Struts 1使用ActionForm对象来捕获输入。象Action一样,所有的ActionForm必须扩展基类。因为其他的JavaBean不能作为ActionForm使用,开发者经常创建多余的类来捕获输入。DynaBeans可以被用来作为替代ActionForm的类来创建。但是开发者可以重新描述已经存在的JavaBean。
Struts 2 Action属性作为输入属性,排除第二个输入对象的需要。输入属性可能有丰富的对象类型这些类型有他们自己的属性。Action的属性可以通过标签库来访问。Struts 2也支持ActionForm形式。丰富的对象类型,包含业务或者域对象,可以被当作输入或者输出对象来使用。糢型驱动特性简化标签对POJO输入对象的引用。
表达式语言
Struts 1整和JSTL,所以它使用JSTL的表达式语言。表达式语言有基本的图形对象移动,但是相对很弱的集合和被索引的属性支持。
Struts 2使用JSTL,但是框架也支持更强大和更灵活的表达式,叫做“对象图形符号语言”(OGNL)。
将值绑定要视图上
Struts 1使用标準JSP机製来绑定对象到页面上下文。
Struts 2使用“ValueStack”技术为了标签库可以不用链接你的视图到对象的表现类型来访问值。ValueStack策略允许重用视图。
类型转换
Struts 1的ActionForm属性经常都是String的。Struts 1使用Commons-Beanutils来类型转换。转换每一个类,幷不是为每一个实例配置。
Struts 2使用OGNL来类型转换。框架包含转换器来为基本的和共同的对象类型和原始类型。
验证
Struts 1支持手动验证凭借ActionForm的validate方法,或者通过扩展的公用验证器。类可以有不同的验证上下文来未相同的类,但是不能不能包括验证子对象。
Struts 2支持手动验证凭藉validate方法和XWork验证框架。Xwork验证框架支持一连串的验证子属性使用的验证为了属性类的类型和严正上下文而定义。
Action执行的控制
Struts 1支持独立的请求处理器对于每一个模型,但是所有在模型中的Action必须共享同一个生命周期。
Struts 2支持在每一个Action基础上凭借拦截栈创建不同的生命周期。自定义栈可以被创建幷且使用不同的所需 的Action。

编程-学校不会教你的课程-Code.org宣传片

编程,学校不会教你的课程——Code.org 宣传片(中文版)
视频的明星有:Bill Gates(微软公司创始人,前世界首富)、 Mark Zuckberg(Facebook创始人,最年轻的亿万富翁之一)、 Chris Bosh(NBA全明星球员,曾效力多伦多猛龙队,目前迈阿密热火队的主力大前锋), I.Am.Will(超级R&B说唱乐队”黒眼豆豆”的创始人和主唱)。
其实,学编程并不仅仅是为了生存!

情人节html5玫瑰花源码

情人节html5玫瑰花源码:将代码复制成为html文件,用支持html5的浏览器(火狐)访问该页面就可以看到效果

</pre>
<iframe src="javascript:'<br /> <!doctype html>n<html>nt<head>ntt<title>JS1k, 1k demo submission [1022]</title>ntt<meta charset=&quot;utf-8&quot; />nt</head>nt<body>ntt<canvas id=&quot;c&quot;></canvas>ntt<script>ntttvar b =
document.body;ntttvar c = document.getElementsByTagName('canvas')[0];ntttvar a = c.getContext
('2d');ntttdocument.body.clientWidth; // fix bug in webkit: http://qfox.nl/weblog/218
ntt</script>ntt<script>n// start of submission //nwith(m=Math)
C=cos,S=sin,P=pow,R=random;c.width=c.height=f=500;h=-250;function p(a,b,c){if(c>60)return[S(a*7)*(13+5/(.2+P
(b*4,4)))-S(b)*50,b*f+50,625+C(a*7)*(13+5/(.2+P(b*4,4)))+b*400,a*1-b/2,a];A=a*2-1;B=b*2-1;if(A*A+B*B<1){if(c>37){n=
(j=c&1)%3F6:4;o=.5/(a+.01)+C(b*125)*3-a*300;w=b*h;return[o*C(n)+w*S(n)+j*610-390,o*S(n)-w*C(n)+550-j*350,1180+C
(B+A)*99-j*300,.4-a*.1+P(1-B*B,-h*6)*.15-a*b*.4+C(a+b)/5+P(C((o*(a+1)+(B>0%3Fw:-w))/25),30)*.1*(1-B*B),o/1e3+.7-
o*w*3e-6]}if(c>32){c=c*1.16-.15;o=a*45-20;w=b*b*h;z=o*S(c)+w*C(c)+620;return[o*C(c)-w*S(c),28+C(B*.5)*99-b*b*b*60-
z/2-h,z,(b*b*.3+P((1-(A*A)),7)*.15+.3)*b,b*.7]}o=A*(2-b)*(80-c*2);w=99-C(A)*120-C(b)*(-h-c*4.9)+C(P(1-b,7))
*50+c*2;z=o*S(c)+w*C(c)+700;return[o*C(c)-w*S(c),B*99-C(P(b, 7))*50-c/3-z/1.35+450,z,(1-b/1.2)*.9+a*.1, P((1-
b),20)/4+.05]}}setInterval('for(i=0;i<1e4;i++)if(s=p(R(),R(),i%2546/.74)){z=s[2];x=~~(s[0]*f/z-h);y=~~(s[1]*f/z- h);if(!m[q=y*f+x]|m[q]>z)m[q]=z,a.fillStyle=&quot;rgb(&quot;+~(s[3]*h)+&quot;,&quot;+~(s[4]*h)+&quot;,&quot;+~(s[3]
*s[3]*-80)+&quot;)&quot;,a.fillRect(x,y,1,1)}',0)n// end of submission //
ntt</script>nt</body>n</html>'" frameborder="0" scrolling="no" width="1200px" height="820px"></iframe>
<pre>

HTML5是用于取代1999年所制定的 HTML 4.01 和 XHTML 1.0 标准的 HTML 标准版本,现在仍处于发展阶段,但大部分浏览器已经支持某些 HTML5 技术。HTML 5有两大特点:首先,强化了 Web 网页的表现性能。其次,追加了本地数据库等 Web 应用的功能。广义论及HTML5时,实际指的是包括HTML、CSS和JavaScript在内的一套技术组合。它希望能够减少浏览器对于需要插件的丰富性网络应用服务(plug-in-based rich internet application,RIA),如Adobe Flash、Microsoft Silverlight,与Oracle JavaFX的需求,并且提供更多能有效增强网络应用的标准集。
请使用火狐、谷歌等支持html5的浏览器,点击查看效果:http://tianhailong.com/rose.html