基于Android的简单聊天工具-服务器端
1、数据库用的mysql,一共有3张表,一张用户表user、一张朋友列表friend和一张消息表message。
1 User table 用户表 uid 主键自动生成 userName 昵称 userPwd 密码 userSex 性别 userPho 用户头像,有默认头像 2 Friend table 好友列表 fid 主键自动生成 uid --> fk 用户id,外键 fuid --> 朋友的id fName 好友名称 3 Messages table 消息表 mid 消息id,主键自动生成 fromid --> fk from id 发送者id tofid --> fk to id 接收者id msg 消息内容 mtime 发送时间
2、服务器端架构
3、model包解析
public class User{//1 用户类 private String userName;//用户名 private String userPwd;//用户密码 private String userSex;//用户性别 private String userPho;//用户照片 ... public class Friend {//2 朋友类 private int uid;//用户id private int fuid;//friend id private String fName;//用户的朋友名字 ... public class FriendList extends ArrayList<Friend>{//3 朋友列表类 /** * */ private static final long serialVersionUID = 1L; private FriendList friendlist; public FriendList() { friendlist = null; } }
public class Messages{//4 消息类 private int fromId; private int toId; private String msg; private String mtime; public Messages() { }
4、db包解析
主要作用是加载类,获取mysql数据库的连接
public class DBConnection { public static final String DBURL = "jdbc:mysql://localhost:3306/qq"; public static final String DBUSER = "root"; public static final String DBPASS = "root"; public static final String DBDRIVER = "com.mysql.jdbc.Driver"; static { try { Class.forName(DBDRIVER);//加载类 } catch (ClassNotFoundException e) { e.printStackTrace(); } } //返回Connection public Connection getConnect() throws SQLException{ return DriverManager.getConnection(DBURL,DBUSER,DBPASS); } //关闭资源 public void close(Connection con, Statement sta, ResultSet rs) { try { rs.close(); if(con != null) { con.close(); } if(sta != null) { sta.close(); } } catch (SQLException e) { e.printStackTrace(); } } }
5、util包解析
第一个类Packager
public class Packager { //用于登录数据包的分析 public String loginPackager(String operate,String friends,String result) { StringBuffer mes = new StringBuffer(""); mes.append("operate:" + operate + "\n"); mes.append("content:" + friends); mes.append("result:" + result + "\n"); return mes.toString(); } //用于发送数据包的分析 public String sendPackager(String operate,String msg,String result) { StringBuffer mes = new StringBuffer(""); mes.append("operate:" + operate + "\n"); mes.append("content:" + "\n"); mes.append("result:" + result + "\n"); return mes.toString(); } }
第二个类Parser
public class Parser { //解析类 //用于解析获取的请求类型是什么,比如登录、发送消息 public String getOperate(String request) { String[] message = request.split("\n"); String operate = message[0].substring(8,message[0].length()); return operate; } //获取内容 public String getContent(String request) { String[] message = request.split("\n"); String content = message[1].substring(8,message[1].length()); return content; } //获取发送的消息 public Messages parseMessages(String content) { String[] mes = content.split("#"); int toId = Integer.parseInt(mes[0]); String message = mes[1]; Messages msg = new Messages(); msg.setToId(toId); msg.setMsg(message); return msg; } //将字符串解析为用户类,返回用户类 public User parseUser(String content) { //分隔符为# String[] mes = content.split("#"); //第一个是用户名,第二个是密码 String userName = mes[0]; String userPwd = mes[1]; User user = new User(); user.setUserName(userName); user.setUserPwd(userPwd); return user; } }
6、controll包解析
controller类解析
//控制器 public class Controller { //无参构造函数 public Controller() { } //相应请求 public String doResponse(String request,String ip) { Parser parser = new Parser(); String operate = parser.getOperate(request);//用于解析用户的请求操作是什么 String content = parser.getContent(request);//获取请求的内容 String response = null;//相应字符串 String friends = null;//朋友 if("login".equals(operate)) {//判断是否是登录请求 int uid = login(content);//返回该用户的id,如果没有该用户返回0 String result = null; if(uid != 0) { //将该用户的主键和ip地址加入管理客户端类中 ManageClients.addIps(new Integer(uid), ip); result = "success";//如果登陆成功,那么获得该用户的所有朋友列表 friends = getFriends(uid); }else{ result = "fail";//登录失败 } Packager packager = new Packager(); response = packager.loginPackager(operate,friends,result); }else if("sendMessage".equals(operate)) {//如果是发送消息 Messages msg = parser.parseMessages(content); int toId = msg.getToId();//找到要接受者的id String ipaddress = ManageClients.ips.get(new Integer(toId)).toString();//通过id 获得ip地址 ServerThread sendto = (ServerThread)ManageClients.clients.get(ipaddress);//通过ip地址获取接受者的线程 sendto.send(msg.getMsg());//向发送端发送信息 Packager packager = new Packager(); String result = "success"; response = packager.sendPackager(operate,null,result); } return response; } public String getFriends(int uid) { String sql = "select fid,uid,fuid,fName from friend where uid=" + uid; DBConnection dbc = new DBConnection(); Connection con = null; Statement sta = null; ResultSet rs = null; StringBuilder sb = new StringBuilder(""); try { con = dbc.getConnect(); con = dbc.getConnect(); sta = con.createStatement(); rs = sta.executeQuery(sql); while(rs.next()) { sb.append(rs.getInt(1)+"#" + rs.getInt(2) + "#" + rs.getInt(3) + "#" + rs.getString(4) + "\n"); } } catch (SQLException e) { e.printStackTrace(); } return sb.toString(); } public int login(String content) {//登录操作,登陆成功,返回朋友列表,否则返回错误原因 Parser parser = new Parser(); User user = parser.parseUser(content);//获取用户类 //然后去数据库中查询是否有该用户,如果有该用户,那么返回该用户的主键id String sql = "select uid,userPwd from user where userName='" + user.getUserName() +"'"; DBConnection dbc = new DBConnection(); Connection con = null; Statement sta = null; ResultSet rs = null; String dbpwd = null; int uid = 0; try { con = dbc.getConnect(); sta = con.createStatement(); rs = sta.executeQuery(sql); while(rs.next()) { uid = rs.getInt(1); dbpwd = rs.getString(2); } } catch (SQLException e) { e.printStackTrace(); }finally{ dbc.close(con, sta, rs); } if(dbpwd != null && dbpwd.equals(user.getUserPwd()) && uid != 0) { return uid; }else{ uid = 0; return uid; } }
7、server包解析
7.1 Server类 开启监听端口,不断监听请求的用户
public class Server { public static void main(String[] args) { new Server(); } public Server() { ServerSocket serversocket = null; Socket socket = null; try { serversocket = new ServerSocket(5000); System.out.println("服务器已经启动,正在监听5000端口"); while(true) { socket = serversocket.accept(); String ip = socket.getLocalAddress().getHostAddress(); ServerThread st = new ServerThread(socket,ip);//服务器端线程 st.start(); ManageClients.addClients(ip, st);//将该线程添加到ManageClients类中 int port = socket.getPort(); System.out.println("连接上的客户端ip:" + ip + ",端口号:" + port); } } catch (IOException e) { e.printStackTrace(); } } }
7.2 ServerThread类 ,用于转发消息
public class ServerThread extends Thread{ private Socket socket; private String ip; private InputStream in; private OutputStream out; private static final int SIZE = 1024; public Socket getSocket(){ return socket; } public ServerThread(Socket socket,String ip) { this.socket = socket; this.ip = ip; try { in = socket.getInputStream(); out = socket.getOutputStream(); } catch (IOException e) { e.printStackTrace(); } } public void send(String mes) { try { out.write(mes.getBytes()); out.flush(); } catch (IOException e) { e.printStackTrace(); } } public void close() { try { if(in != null){ in.close(); in = null; } if(out != null) { out.close(); out = null; } if(socket != null) { socket.close(); socket = null; } } catch (IOException e) { e.printStackTrace(); } } public void run() { while(true) { try { byte[] buffer = new byte[SIZE]; int index = in.read(buffer); String message = new String(buffer,0,index);//获取客户端发送过来的请求 Parser parser = new Parser(); String operate = parser.getOperate(message); Controller controller = new Controller(); if(operate.equals("exit")) { break; } String response = controller.doResponse(message,ip);//服务器处理发送过来的消息,如果不是收获 //的操作不是exit if(response != null) send(response);//向客户端发送请求操作的结果 } catch (IOException e) { e.printStackTrace(); }finally{ close(); } } }
7.3 ManageClients
public class ManageClients { //管理客户端 ,用HashMap存储用户ip和线程的键值对 public static HashMap<String,ServerThread> clients = new HashMap<String,ServerThread>();//string sender //用于用户主键 和ip之间的键值对 public static HashMap<Integer,String> ips = new HashMap<Integer,String>(); public static void addClients(String senderip, ServerThread st) { clients.put(senderip, st); } public static void addIps(Integer i, String ip) { ips.put(i, ip); } }
服务器端结束 ,启动Server中的main 函数,监听是否有客户端请求