亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > Java > 正文

Java GUI編程實現在線聊天室

2024-07-14 08:41:46
字體:
來源:轉載
供稿:網友

引言

綜合應用Java的GUI編程和網絡編程,實現一個能夠支持多組用戶同時使用的聊天室軟件。該聊天室具有比較友好的GUI界面,并使用C/S模式,支持多個用戶同時使用,用戶可以自己選擇加入或者創建房間,和房間內的其他用戶互發信息(文字和圖片)

主要功能

客戶端的功能主要包括如下的功能:

  • 選擇連上服務端
  • 顯示當前房間列表(包括房間號和房間名稱)
  • 選擇房間進入
  • 多個用戶在線群聊
  • 可以發送表情(用本地的,實際上發送只發送表情的代碼)
  • 退出房間
  • 選擇創建房間
  • 房間里沒人(房主退出),導致房間解散
  • 顯示系統提示消息
  • 顯示用戶消息
  • 構造標準的消息結構發送
  • 維護GUI所需的數據模型

服務端的功能主要包括:

  • 維護用戶信息和房間信息
  • 處理用戶發送來的消息選擇轉發或者回復處理結果
  • 構造標準的消息結構發送

架構

整個程序采用C/S設計架構,分為一個服務端和多個客戶端。服務端開放一個端口給所有開客戶端,客戶端連接該端口并收發信息,服務端在內部維護客戶端的組,并對每一個客戶端都用一個子線程來收發信息

基本類的設計

User類

package User;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;/** *  * @author lannooo * */public class User { private String name; private long id; private long roomId; private Socket socket; private BufferedReader br; private PrintWriter pw; /**  *   * @param name: 設置user的姓名  * @param id:設置user的id  * @param socket:保存用戶連接的socket  * @throws IOException  */ public User(String name, long id, final Socket socket) throws IOException {  this.name=name;  this.id=id;  this.socket=socket;  this.br=new BufferedReader(new InputStreamReader(    socket.getInputStream()));  this.pw=new PrintWriter(socket.getOutputStream()); } /**  * 獲得該用戶的id  * @return id  */ public long getId() {  return id; } /**  * 設置該用戶的id  * @param id 新的id  */ public void setId(long id) {  this.id = id; } /**  * 獲得用戶當前所在的房間號  * @return roomId  */ public long getRoomId() {  return roomId; } /**  * 設置當前用戶的所在的房間號  * @param roomId  */ public void setRoomId(long roomId) {  this.roomId = roomId; } /**  * 設置當前用戶在聊天室中的昵稱  * @param name  */ public void setName(String name) {  this.name = name; } /**  * 返回當前用戶在房間中的昵稱  * @return  */ public String getName() {  return name; } /**  * 返回當前用戶連接的socket實例  * @return  */ public Socket getSocket() {  return socket; } /**  * 設置當前用戶連接的socket  * @param socket  */ public void setSocket(Socket socket) {  this.socket = socket; } /**  * 獲得該用戶的消息讀取輔助類BufferedReader實例  * @return  */ public BufferedReader getBr() {  return br; } /**  * 設置 用戶的消息讀取輔助類  * @param br  */ public void setBr(BufferedReader br) {  this.br = br; } /**  * 獲得消息寫入類實例  * @return  */ public PrintWriter getPw() {  return pw; } /**  * 設置消息寫入類實例  * @param pw  */ public void setPw(PrintWriter pw) {  this.pw = pw; } /**  * 重寫了用戶類打印的函數  */ @Override public String toString() {  return "#User"+id+"#"+name+"[#Room"+roomId+"#]<socket:"+socket+">"; }}

Room類

package Room;import java.util.ArrayList;import java.util.List;import User.User;/** *  * @author lannooo * */public class Room { private String name; private long roomId; private ArrayList<User> list; private int totalUsers; /**  * 獲得房間的名字  * @return name  */ public String getName() {  return name; } /**  * 設置房間的新名字  * @param name  */ public void setName(String name) {  this.name = name; } /**  * 獲得房間的id號  * @return  */ public long getRoomId() {  return roomId; } /**  * 設置房間的id  * @param roomId  */ public void setRoomId(long roomId) {  this.roomId = roomId; } /**  * 向房間中加入一個新用戶  * @param user  */ public void addUser(User user) {  if(!list.contains(user)){   list.add(user);   totalUsers++;  }else{   System.out.println("User is already in Room<"+name+">:"+user);  } } /**  * 從房間中刪除一個用戶  * @param user  * @return 目前該房間中的總用戶數目  */ public int delUser(User user){  if(list.contains(user)){   list.remove(user);   return --totalUsers;  }else{   System.out.println("User is not in Room<"+name+">:"+user);   return totalUsers;  } } /**  * 獲得當前房間的用戶列表  * @return  */ public ArrayList<User> getUsers(){  return list; } /**  * 獲得當前房間的用戶昵稱的列表  * @return  */ public String[] getUserNames(){  String[] userList = new String[list.size()];  int i=0;  for(User each: list){   userList[i++]=each.getName();  }  return userList; } /**  * 使用房間的名稱和id來new一個房間  * @param name  * @param roomId  */ public Room(String name, long roomId) {  this.name=name;  this.roomId=roomId;  this.totalUsers=0;  list = new ArrayList<>(); }}

RoomList類

package Room;import java.awt.image.DirectColorModel;import java.util.HashMap;import java.util.Iterator;import java.util.Map;import java.util.Map.Entry;import java.util.Set;import User.User;/** *  * @author lannooo * */public class RoomList { private HashMap<Long, Room> map; private long unusedRoomId; public static long MAX_ROOMS = 9999; private int totalRooms; /**  * 未使用的roomid從1算起,起始的房間總數為0  */ public RoomList(){  map = new HashMap<>();  unusedRoomId = 1;  totalRooms = 0; } /**  * 創建一個新的房間,使用未使用的房間號進行創建,如果沒有可以使用的則就創建失敗  * @param name: 房間的名字  * @return 創建的房間的id  */ public long createRoom(String name){  if(totalRooms<MAX_ROOMS){   if(name.length()==0){    name = ""+unusedRoomId;   }   Room room = new Room(name, unusedRoomId);   map.put(unusedRoomId, room);   totalRooms++;   return unusedRoomId++;  }else{   return -1;  } } /**  * 用戶加入一個房間  * @param user  * @param roomID  * @return  */ public boolean join(User user, long roomID){  if(map.containsKey(roomID)){   map.get(roomID).addUser(user);   return true;  }else{   return false;  } } /**  * 用戶退出他的房間  * @param user  * @param roomID  * @return  */ public int esc(User user, long roomID){  if(map.containsKey(roomID)){   int number = map.get(roomID).delUser(user);   /*如果這個房間剩下的人數為0,那么刪除該房間*/   if(number==0){    map.remove(roomID);    totalRooms--;    return 0;   }   return 1;  }else{   return -1;  } } /**  * 列出所有房間的列表,返回一個二維數組,strings[i][0]放房間的id,string[i][1]放房間的name  * @return  */ public String[][] listRooms(){  String[][] strings = new String[totalRooms][2];  int i=0;  /*將map轉化為set并使用迭代器來遍歷*/  Set<Entry<Long, Room>> set = map.entrySet();  Iterator<Entry<Long, Room>> iterator = set.iterator();  while(iterator.hasNext()){   Map.Entry<Long, Room> entry = iterator.next();   long key = entry.getKey();   Room value = entry.getValue();   strings[i][0]=""+key;   strings[i][1]=value.getName();  }  return strings; } /**  * 通過roomID來獲得房間  * @param roomID  * @return  */ public Room getRoom(long roomID){  if(map.containsKey(roomID)){   return map.get(roomID);  }  else    return null; }}

服務端

Server

package Server;import java.net.ServerSocket;import java.net.Socket;import java.util.ArrayList;import java.util.HashMap;import java.util.Map;import org.json.*;import Room.Room;import Room.RoomList;import User.User;/** *  * @author lannooo * */public class Server { private ArrayList<User> allUsers; private RoomList rooms; private int port; private ServerSocket ss; private long unusedUserID; public final long MAX_USERS = 999999; /**  * 通過port號來構造服務器端對象  * 維護一個總的用戶列表和一個房間列表  * @param port  * @throws Exception  */ public Server(int port) throws Exception {  allUsers = new ArrayList<>();  rooms = new RoomList();  this.port=port;  unusedUserID=1;  ss = new ServerSocket(port);  System.out.println("Server is builded!"); } /**  * 獲得下一個可用的用戶id  * @return  */ private long getNextUserID(){  if(unusedUserID < MAX_USERS)   return unusedUserID++;  else   return -1; } /**  * 開始監聽,當接受到新的用戶連接,就創建一個新的用戶,并添加到用戶列表中  * 然后創建一個新的服務線程用于收發該用戶的消息  * @throws Exception  */ public void startListen() throws Exception{  while(true){   Socket socket = ss.accept();   long id = getNextUserID();   if(id != -1){    User user = new User("User"+id, id, socket);    System.out.println(user.getName() + " is login...");    allUsers.add(user);    ServerThread thread = new ServerThread(user, allUsers, rooms);    thread.start();   }else{    System.out.println("Server is full!");    socket.close();   }  } } /**  * 測試用main方法,設置偵聽端口為9999,并開始監聽  * @param args  */ public static void main(String[] args) {  try {   Server server = new Server(9999);   server.startListen();  } catch (Exception e) {   e.printStackTrace();  } }}

ServerThread

package Server;import java.io.IOException;import java.io.PrintWriter;import java.net.SocketException;import java.util.ArrayList;import java.util.regex.Matcher;import java.util.regex.Pattern;import Room.Room;import Room.RoomList;import User.User;/** *  * @author lannooo * */public class ServerThread extends Thread { private User user; private ArrayList<User> userList;/*保存用戶列表*/ private RoomList map;   /*保存房間列表*/ private long roomId; private PrintWriter pw; /**  * 通過用戶的對象實例、全局的用戶列表、房間列表進行構造  * @param user  * @param userList  * @param map  */ public ServerThread(User user,    ArrayList<User> userList, RoomList map){  this.user=user;  this.userList=userList;  this.map=map;  pw=null;  roomId = -1; } /**  * 線程運行部分,持續讀取用戶socket發送來的數據,并解析  */ public void run(){  try{   while (true) {    String msg=user.getBr().readLine();    System.out.println(msg); /*解析用戶的數據格式*/    parseMsg(msg);   }  }catch (SocketException se) { /*處理用戶斷開的異常*/   System.out.println("user "+user.getName()+" logout.");  }catch (Exception e) { /*處理其他異常*/   e.printStackTrace();  }finally {   try {    /*     * 用戶斷開或者退出,需要把該用戶移除     * 并關閉socket     */    remove(user);    user.getBr().close();    user.getSocket().close();   } catch (IOException ioe) {    ioe.printStackTrace();   }  } } /**  * 用正則表達式匹配數據的格式,根據不同的指令類型,來調用相應的方法處理  * @param msg  */ private void parseMsg(String msg){  String code = null;  String message=null;  if(msg.length()>0){   /*匹配指令類型部分的字符串*/   Pattern pattern = Pattern.compile("<code>(.*)</code>");   Matcher matcher = pattern.matcher(msg);   if(matcher.find()){    code = matcher.group(1);   }   /*匹配消息部分的字符串*/   pattern = Pattern.compile("<msg>(.*)</msg>");   matcher = pattern.matcher(msg);   if(matcher.find()){    message = matcher.group(1);   }   switch (code) {   case "join":    // add to the room    // code = 1, 直接顯示在textArea中    // code = 11, 在list中加入    // code = 21, 把當前房間里的所有用戶返回給client    if(roomId == -1){     roomId = Long.parseLong(message);     map.join(user, roomId);     sendRoomMsgExceptSelf(buildCodeWithMsg("<name>"+user.getName()+"</name><id>"+user.getId()+"</id>", 11));     // 這個消息需要加入房間里已有用戶的列表     returnMsg(buildCodeWithMsg("你加入了房間:" + map.getRoom(roomId).getName(), 1));     returnMsg(buildCodeWithMsg(getMembersInRoom(), 21));    }else{     map.esc(user, roomId);     sendRoomMsg(buildCodeWithMsg(""+user.getId(), 12));     long oldRoomId = roomId;     roomId = Long.parseLong(message);     map.join(user, roomId);     sendRoomMsgExceptSelf(buildCodeWithMsg("<name>"+user.getName()+"</name><id>"+user.getId()+"</id>", 11));     returnMsg(buildCodeWithMsg("你退出房間:" + map.getRoom(oldRoomId).getName() + ",并加入了房間:" + roomId,1));     returnMsg(buildCodeWithMsg(getMembersInRoom(), 21));    }    break;   case "esc":    // delete from room list    // code = 2, 彈窗提示    // code = 12, 對所有該房間的其他用戶發送該用戶退出房間的信息,從list中刪除    if(roomId!=-1){     int flag=map.esc(user, roomId);     sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getId(), 12));     long oldRoomId=roomId;     roomId = -1;     returnMsg(buildCodeWithMsg("你已經成功退出房間,不會收到消息", 2));     if(flag==0){      sendMsg(buildCodeWithMsg(""+oldRoomId, 13));     }    }else{     returnMsg(buildCodeWithMsg("你尚未加入任何房間", 2));    }    break;   case "list":    // list all the rooms    // code = 3, 在客戶端解析rooms,并填充roomlist    returnMsg(buildCodeWithMsg(getRoomsList(), 3));    break;   case "message":    // send message    // code = 4, 自己收到的話,打印的是‘你說:....'否則打印user id對應的name    sendRoomMsg(buildCodeWithMsg("<from>"+user.getId()+"</from><smsg>"+message+"</smsg>", 4));    break;   case "create":    // create a room     // code=5,提示用戶進入了房間    // code=15,需要在其他所有用戶的room列表中更新    roomId = map.createRoom(message);    map.join(user, roomId);    sendMsg(buildCodeWithMsg("<rid>"+roomId+"</rid><rname>"+message+"</rname>", 15));    returnMsg(buildCodeWithMsg("你進入了創建的房間:"+map.getRoom(roomId).getName(), 5));    returnMsg(buildCodeWithMsg(getMembersInRoom(), 21));    break;   case "setname":    // set name for user    // code=16,告訴房間里的其他人,你改了昵稱    user.setName(message);    sendRoomMsg(buildCodeWithMsg("<id>"+user.getId()+"</id><name>"+message+"</name>", 16));    break;   default:    // returnMsg("something unknown");    System.out.println("not valid message from user"+user.getId());    break;   }  }  } /**  * 獲得該用戶房間中的所有用戶列表,并構造成一定格式的消息返回  * @return  */ private String getMembersInRoom(){  /*先從room列表獲得該用戶的room*/  Room room = map.getRoom(roomId);  StringBuffer stringBuffer = new StringBuffer();  if(room != null){   /*獲得房間中所有的用戶的列表,然后構造成一定的格式發送回去*/   ArrayList<User> users = room.getUsers();   for(User each: users){    stringBuffer.append("<member><name>"+each.getName()+        "</name><id>"+each.getId()+"</id></member>");   }  }  return stringBuffer.toString(); } /**  * 獲得所有房間的列表,并構造成一定的格式  * @return  */ private String getRoomsList(){  String[][] strings = map.listRooms();  StringBuffer sb = new StringBuffer();  for(int i=0; i<strings.length; i++){   sb.append("<room><rname>"+strings[i][1]+      "</rname><rid>"+strings[i][0]+"</rid></room>");  }  return sb.toString(); } /**  * 構造成一個統一的消息格式  * @param msg  * @param code  * @return  */ private String buildCodeWithMsg(String msg, int code){  return "<code>"+code+"</code><msg>"+msg+"</msg>/n"; } /**  * 這個是群發消息:全體用戶,code>10  * @param msg  */ private void sendMsg(String msg) {//  System.out.println("In sendMsg()");  /*取出用戶列表中的每一個用戶來發送消息*/  for(User each:userList){   try {    pw=each.getPw();    pw.println(msg);    pw.flush();    System.out.println(msg);   } catch (Exception e) {    System.out.println("exception in sendMsg()");   }  } } /**  * 只對同一房間的用戶發:code>10  * @param msg  */ private void sendRoomMsg(String msg){  /*先獲得該用戶的房間號,然后往該房間發送消息*/  Room room = map.getRoom(roomId);  if(room != null){   ArrayList<User> users = room.getUsers();   for(User each: users){    pw = each.getPw();    pw.println(msg);    pw.flush();   }  } } /**  * 向房間中除了該用戶自己,發送消息  * @param msg  */ private void sendRoomMsgExceptSelf(String msg){  Room room = map.getRoom(roomId);  if(room != null){   ArrayList<User> users = room.getUsers();   for(User each: users){    if(each.getId()!=user.getId()){     pw = each.getPw();     pw.println(msg);     pw.flush();    }   }  } } /**  * 對于client的來信,返回一個結果,code<10  * @param msg  */ private void returnMsg(String msg){  try{   pw = user.getPw();   pw.println(msg);   pw.flush();  }catch (Exception e) {   System.out.println("exception in returnMsg()");  } } /**  * 移除該用戶,并向房間中其他用戶發送該用戶已經退出的消息  * 如果房間中沒人了,那么就更新房間列表給所有用戶  * @param user  */ private void remove(User user){  if(roomId!=-1){   int flag=map.esc(user, roomId);   sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getId(), 12));   long oldRoomId=roomId;   roomId = -1;   if(flag==0){    sendMsg(buildCodeWithMsg(""+oldRoomId, 13));   }  }  userList.remove(user); }}

客戶端

Client

package Client;import java.awt.BorderLayout;import java.awt.Color;import java.awt.Dimension;import java.awt.FlowLayout;import java.awt.Font;import java.awt.GridBagConstraints;import java.awt.GridBagLayout;import java.awt.Insets;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;import java.util.HashMap;import java.util.Iterator;import java.util.Set;import java.util.regex.Matcher;import java.util.regex.Pattern;import javax.swing.DefaultListModel;import javax.swing.Icon;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JFrame;import javax.swing.JLabel;import javax.swing.JList;import javax.swing.JOptionPane;import javax.swing.JPanel;import javax.swing.JScrollBar;import javax.swing.JScrollPane;import javax.swing.JTextField;import javax.swing.JTextPane;import javax.swing.UIManager;import javax.swing.UnsupportedLookAndFeelException;import javax.swing.text.BadLocationException;import javax.swing.text.SimpleAttributeSet;import javax.swing.text.Style;import javax.swing.text.StyleConstants;import javax.swing.text.StyledDocument;/** *  * @author lannooo * */public class Client implements ActionListener{ private JFrame frame; private Socket socket; private BufferedReader br; private PrintWriter pw; private String name; private HashMap<String, Integer> rooms_map; private HashMap<String, Integer> users_map; private JTextField host_textfield; private JTextField port_textfield; private JTextField text_field; private JTextField name_textfiled; private JLabel rooms_label; private JLabel users_label; private JList<String> roomlist; private JList<String> userlist; private JTextPane msgArea; private JScrollPane textScrollPane; private JScrollBar vertical; DefaultListModel<String> rooms_model; DefaultListModel<String> users_model; /*  * 構造函數  * 該客戶端對象維護兩個map,房間的hashmap和房間中用戶的hashmap  * 作為列表組件的數據模型  */ public Client(){  rooms_map = new HashMap<>();  users_map = new HashMap<>();  initialize(); } /**  * 連接服務端,指定host和port  * @param host  * @param port  * @return  */ public boolean connect(String host, int port){  try {   socket = new Socket(host, port);   System.out.println("Connected to server!"+socket.getRemoteSocketAddress());   br=new BufferedReader(new InputStreamReader(System.in));   pw=new PrintWriter(socket.getOutputStream());   /*    * 創建一個接受和解析服務器消息的線程    * 傳入當前客戶端對象的指針,作為句柄調用相應的處理函數    */   ClientThread thread = new ClientThread(socket, this);   thread.start();   return true;  } catch (IOException e) {   System.out.println("Server error");   JOptionPane.showMessageDialog(frame, "服務器無法連接!");   return false;  } } /*當前進程作為只發送消息的線程,從命令行中獲取輸入*/// public void sendMsg(){//  String msg;//  try {//   while(true){//    msg = br.readLine();//    pw.println(msg);//    pw.flush();//   }//  } catch (IOException e) {//   System.out.println("error when read msg and to send.");//  }// } /**  * 發給服務器的消息,先經過一定的格式構造再發送  * @param msg  * @param code  */ public void sendMsg(String msg, String code){  try {   pw.println("<code>"+code+"</code><msg>"+msg+"</msg>");   pw.flush();  } catch (Exception e) {   //一般是沒有連接的問題   System.out.println("error in sendMsg()");   JOptionPane.showMessageDialog(frame, "請先連接服務器!");  } } /**  * 窗口初始化  */ private void initialize() {  /*設置窗口的UI風格和字體*/  setUIStyle();  setUIFont();  JFrame frame = new JFrame("ChatOnline");  JPanel panel = new JPanel();  /*主要的panel,上層放置連接區,下層放置消息區,             中間是消息面板,左邊是room列表,右邊是當前room的用戶列表*/  JPanel headpanel = new JPanel(); /*上層panel,用于放置連接區域相關的組件*/  JPanel footpanel = new JPanel(); /*下層panel,用于放置發送信息區域的組件*/  JPanel leftpanel = new JPanel(); /*左邊panel,用于放置房間列表和加入按鈕*/  JPanel rightpanel = new JPanel(); /*右邊panel,用于放置房間內人的列表*/  /*最上層的布局,分中間,東南西北五個部分*/  BorderLayout layout = new BorderLayout();  /*格子布局,主要用來設置西、東、南三個部分的布局*/  GridBagLayout gridBagLayout = new GridBagLayout();  /*主要設置北部的布局*/  FlowLayout flowLayout = new FlowLayout();  /*設置初始窗口的一些性質*/  frame.setBounds(100, 100, 800, 600);  frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  frame.setContentPane(panel);  frame.setLayout(layout);  /*設置各個部分的panel的布局和大小*/  headpanel.setLayout(flowLayout);  footpanel.setLayout(gridBagLayout);  leftpanel.setLayout(gridBagLayout);  rightpanel.setLayout(gridBagLayout);  leftpanel.setPreferredSize(new Dimension(130, 0));  rightpanel.setPreferredSize(new Dimension(130, 0));  /*以下均是headpanel中的組件*/  host_textfield = new JTextField("127.0.0.1");  port_textfield = new JTextField("9999");  name_textfiled = new JTextField("匿名");  host_textfield.setPreferredSize(new Dimension(100, 25));  port_textfield.setPreferredSize(new Dimension(70, 25));  name_textfiled.setPreferredSize(new Dimension(150, 25));  JLabel host_label = new JLabel("服務器IP");  JLabel port_label = new JLabel("端口");  JLabel name_label = new JLabel("昵稱");  JButton head_connect = new JButton("連接");//  JButton head_change = new JButton("確認更改");  JButton head_create = new JButton("創建房間");  headpanel.add(host_label);  headpanel.add(host_textfield);  headpanel.add(port_label);  headpanel.add(port_textfield);  headpanel.add(head_connect);  headpanel.add(name_label);  headpanel.add(name_textfiled);//  headpanel.add(head_change);  headpanel.add(head_create);  /*以下均是footpanel中的組件*/  JButton foot_emoji = new JButton("表情");  JButton foot_send = new JButton("發送");  text_field = new JTextField();  footpanel.add(text_field, new GridBagConstraints(0, 0, 1, 1, 100, 100,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  footpanel.add(foot_emoji, new GridBagConstraints(1, 0, 1, 1, 1.0, 1.0,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  footpanel.add(foot_send, new GridBagConstraints(2, 0, 1, 1, 1.0, 1.0,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  /*兩邊的格子中的組件*/  rooms_label = new JLabel("當前房間數:0");  users_label = new JLabel("房間內人數:0");  JButton join_button = new JButton("加入房間");  JButton esc_button = new JButton("退出房間");  rooms_model = new DefaultListModel<>();  users_model = new DefaultListModel<>();//  rooms_model.addElement("房間1");//  rooms_model.addElement("房間2");//  rooms_model.addElement("房間3");//  String fangjian = "房間1";//  rooms_map.put(fangjian, 1);  roomlist = new JList<>(rooms_model);  userlist = new JList<>(users_model);  JScrollPane roomListPane = new JScrollPane(roomlist);  JScrollPane userListPane = new JScrollPane(userlist);  leftpanel.add(rooms_label, new GridBagConstraints(0, 0, 1, 1, 1, 1,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  leftpanel.add(join_button, new GridBagConstraints(0, 1, 1, 1, 1, 1,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  leftpanel.add(esc_button, new GridBagConstraints(0, 2, 1, 1, 1, 1,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  leftpanel.add(roomListPane, new GridBagConstraints(0, 3, 1, 1, 100, 100,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  rightpanel.add(users_label, new GridBagConstraints(0, 0, 1, 1, 1, 1,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  rightpanel.add(userListPane,new GridBagConstraints(0, 1, 1, 1, 100, 100,     GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));  /*中間的文本區組件*/  msgArea = new JTextPane();  msgArea.setEditable(false);  textScrollPane = new JScrollPane();  textScrollPane.setViewportView(msgArea);  vertical = new JScrollBar(JScrollBar.VERTICAL);  vertical.setAutoscrolls(true);  textScrollPane.setVerticalScrollBar(vertical);  /*設置頂層布局*/  panel.add(headpanel, "North");  panel.add(footpanel, "South");  panel.add(leftpanel, "West");  panel.add(rightpanel, "East");  panel.add(textScrollPane, "Center");  /*注冊各種事件*/  /*連接服務器*/  head_connect.addActionListener(this);  /*發送消息,如果沒有連接則會彈窗提示*/  foot_send.addActionListener(this);  /*改名字*///  head_change.addActionListener(this);  /*創建房間*/  head_create.addActionListener(this);  /*發送表情*/  foot_emoji.addActionListener(this);  /*加入room*/  join_button.addActionListener(this);  /*退出房間*/  esc_button.addActionListener(this);  /*最終顯示*/  frame.setVisible(true); } /**  * 事件監聽處理  */ @Override public void actionPerformed(ActionEvent e) {  String cmd = e.getActionCommand();  switch (cmd) {  case "連接": /*點擊連接按鈕*/   String strhost = host_textfield.getText();   String strport = port_textfield.getText();   connect(strhost, Integer.parseInt(strport));   String nameSeted = JOptionPane.showInputDialog("請輸入你的昵稱:"); /*提示輸入昵稱*/   name_textfiled.setText(nameSeted);   name_textfiled.setEditable(false);   port_textfield.setEditable(false);   host_textfield.setEditable(false);   /*發送設置姓名的消息和列出用戶列表的消息*/   sendMsg(nameSeted, "setname");   sendMsg("", "list");   break;//  case "確認更改"://   String strname = name_textfiled.getText();//   name = strname;//   sendMsg(strname, "setname");//   break;  case "加入房間": /*選擇房間后,點擊加入房間按鈕*/   String selected = roomlist.getSelectedValue();   if(rooms_map.containsKey(selected)){    sendMsg(""+rooms_map.get(selected), "join");   }   break;  case "退出房間": /*點擊退出房間的按鈕*/   sendMsg("", "esc");   break;  case "發送":  /*點擊發送消息的按鈕*/   String text = text_field.getText();   text_field.setText("");   sendMsg(text, "message");   break;  case "表情":  /*發送表情,新建一個表情窗口,并直接在表情窗口中處理消息發送*/   IconDialog dialog = new IconDialog(frame, this);   break;  case "創建房間": /*點擊創建房間的按鈕,彈出提示框數據房間名稱*/   String string = JOptionPane.showInputDialog("請輸入你的房間名稱");   if(string==null || string.equals("")){    string = name+(int)(Math.random()*10000)+"的房間";   }   sendMsg(string, "create");   break;  default:   break;  } } /*很多輔助和clientThread互動的*/ /**  * 加入用戶,通過正則表達式,匹配消息內容中的用戶信息  * @param content  */ public void addUser(String content){  if(content.length()>0){   Pattern pattern = Pattern.compile("<name>(.*)</name><id>(.*)</id>");   Matcher matcher = pattern.matcher(content);   if(matcher.find()){    /*     * 獲得用戶的name和id     * 加入用戶列表     * 在消息區顯示系統提示     */    String name = matcher.group(1);    String id = matcher.group(2);    insertUser(Integer.parseInt(id), name);    insertMessage(textScrollPane, msgArea, null, "系統:", name+"加入了聊天室");   }  }  users_label.setText("房間內人數:"+users_map.size()); /*更新房間內的人數*/ } /**  * 刪除用戶  * @param content  */ public void delUser(String content){  if(content.length()>0){   int id = Integer.parseInt(content);   /*    * 從維護的用戶map中取得所有的用戶名字,然后去遍歷匹配的用戶    * 匹配到的用戶名字從相應的數據模型中移除    * 并從map中移除,并在消息框中提示系統消息    */   Set<String> set = users_map.keySet();   Iterator<String> iter = set.iterator();   String name=null;   while(iter.hasNext()){    name = iter.next();    if(users_map.get(name)==id){     users_model.removeElement(name);     break;    }   }   users_map.remove(name);   insertMessage(textScrollPane, msgArea, null, "系統:", name+"退出了聊天室");  }  users_label.setText("房間內人數:"+users_map.size()); } /**  * 更新用戶信息  * @param content  */ public void updateUser(String content){  if(content.length()>0){   Pattern pattern = Pattern.compile("<id>(.*)</id><name>(.*)</name>");   Matcher matcher = pattern.matcher(content);   if(matcher.find()){    String id = matcher.group(1);    String name = matcher.group(2);    insertUser(Integer.parseInt(id), name);   }  } } /**  * 列出所有用戶  * @param content  */ public void listUsers(String content){  String name = null;  String id=null;  Pattern rough_pattern=null;  Matcher rough_matcher=null;  Pattern detail_pattern=null;  /*   * 先用正則表達式匹配用戶信息   * 然后插入數據模型中   * 并更新用戶數據模型中的條目   */  if(content.length()>0){   rough_pattern = Pattern.compile("<member>(.*?)</member>");   rough_matcher = rough_pattern.matcher(content);   while(rough_matcher.find()){    String detail = rough_matcher.group(1);    detail_pattern = Pattern.compile("<name>(.*)</name><id>(.*)</id>");    Matcher detail_matcher = detail_pattern.matcher(detail);    if(detail_matcher.find()){     name = detail_matcher.group(1);     id = detail_matcher.group(2);     insertUser(Integer.parseInt(id), name);    }   }  }  users_label.setText("房間內人數:"+users_map.size()); } /**  * 直接在textarea中顯示消息  * @param content  */ public void updateTextArea(String content){  insertMessage(textScrollPane, msgArea, null, "系統:", content); } /**  * 在textarea中顯示其他用戶的消息  * 先用正則匹配,再顯示消息  * 其中還需要匹配emoji表情的編號  * @param content  */ public void updateTextAreaFromUser(String content){  if(content.length()>0){   Pattern pattern = Pattern.compile("<from>(.*)</from><smsg>(.*)</smsg>");   Matcher matcher = pattern.matcher(content);   if(matcher.find()){    String from = matcher.group(1);    String smsg = matcher.group(2);    String fromName = getUserName(from);    if(fromName.equals(name))     fromName = "你";    if(smsg.startsWith("<emoji>")){     String emojiCode = smsg.substring(7, smsg.length()-8);//     System.out.println(emojiCode);     insertMessage(textScrollPane, msgArea, emojiCode, fromName+"說:", null);     return ;    }    insertMessage(textScrollPane, msgArea, null, fromName+"說:", smsg);   }  } } /**  * 顯示退出的結果  * @param content  */ public void showEscDialog(String content){  JOptionPane.showMessageDialog(frame, content);  /*清除消息區內容,清除用戶數據模型內容和用戶map內容,更新房間內人數*/  msgArea.setText("");  users_model.clear();  users_map.clear();  users_label.setText("房間內人數:0"); } /**  * 新增一個room  * @param content  */ public void addRoom(String content){  if(content.length()>0){   Pattern pattern = Pattern.compile("<rid>(.*)</rid><rname>(.*)</rname>");   Matcher matcher = pattern.matcher(content);   if(matcher.find()){    String rid = matcher.group(1);    String rname = matcher.group(2);    insertRoom(Integer.parseInt(rid), rname);   }  }  rooms_label.setText("當前房間數:"+rooms_map.size()); } /**  * 刪除一個room  * @param content  */ public void delRoom(String content){  if(content.length()>0){   int delRoomId = Integer.parseInt(content);   Set<String> set = rooms_map.keySet();   Iterator<String> iter = set.iterator();   String rname=null;   while(iter.hasNext()){    rname = iter.next();    if(rooms_map.get(rname)==delRoomId){     rooms_model.removeElement(rname);     break;    }   }   rooms_map.remove(rname);  }  rooms_label.setText("當前房間數:"+rooms_map.size()); } /**  * 列出目前所有的rooms  * @param content  */ public void listRooms(String content){  String rname = null;  String rid=null;  Pattern rough_pattern=null;  Matcher rough_matcher=null;  Pattern detail_pattern=null;  if(content.length()>0){   rough_pattern = Pattern.compile("<room>(.*?)</room>");   rough_matcher = rough_pattern.matcher(content);   while(rough_matcher.find()){    String detail = rough_matcher.group(1);    detail_pattern = Pattern.compile("<rname>(.*)</rname><rid>(.*)</rid>");    Matcher detail_matcher = detail_pattern.matcher(detail);    if(detail_matcher.find()){     rname = detail_matcher.group(1);     rid = detail_matcher.group(2);     insertRoom(Integer.parseInt(rid), rname);    }   }  }  rooms_label.setText("當前房間數:"+rooms_map.size()); } /**  * 插入一個room  * @param rid  * @param rname  */ private void insertRoom(Integer rid, String rname){  if(!rooms_map.containsKey(rname)){   rooms_map.put(rname, rid);   rooms_model.addElement(rname);  }else{   rooms_map.remove(rname);   rooms_model.removeElement(rname);   rooms_map.put(rname, rid);   rooms_model.addElement(rname);  }  rooms_label.setText("當前房間數:"+rooms_map.size()); } /**  * 插入一個user  * @param id  * @param name  */ private void insertUser(Integer id, String name){  if(!users_map.containsKey(name)){   users_map.put(name, id);   users_model.addElement(name);  }else{   users_map.remove(name);   users_model.removeElement(name);   users_map.put(name, id);   users_model.addElement(name);  }  users_label.setText("房間內人數:"+users_map.size()); } /**  * 獲得用戶的姓名  * @param strId  * @return  */ private String getUserName(String strId){  int uid = Integer.parseInt(strId);  Set<String> set = users_map.keySet();  Iterator<String> iterator = set.iterator();  String cur=null;  while(iterator.hasNext()){   cur = iterator.next();   if(users_map.get(cur)==uid){    return cur;   }  }  return ""; } /**  * 獲得用戶所在房間的名稱  * @param strId  * @return  */ private String getRoomName(String strId){  int rid = Integer.parseInt(strId);  Set<String> set = rooms_map.keySet();  Iterator<String> iterator = set.iterator();  String cur = null;  while(iterator.hasNext()){   cur = iterator.next();   if(rooms_map.get(cur)==rid){    return cur;   }  }  return ""; } /**  * 打印一條消息,如果有圖片就打印圖片,否則打印content  * @param scrollPane  * @param textPane  * @param icon_code  * @param title  * @param content  */ private void insertMessage(JScrollPane scrollPane, JTextPane textPane,   String icon_code, String title, String content){  StyledDocument document = textPane.getStyledDocument();  /*獲取textpane中的文本*/  /*設置標題的屬性*/  SimpleAttributeSet title_attr = new SimpleAttributeSet();  StyleConstants.setBold(title_attr, true);  StyleConstants.setForeground(title_attr, Color.BLUE);  /*設置正文的屬性*/  SimpleAttributeSet content_attr = new SimpleAttributeSet();   StyleConstants.setBold(content_attr, false);   StyleConstants.setForeground(content_attr, Color.BLACK);  Style style = null;  if(icon_code!=null){   Icon icon = new ImageIcon("icon/"+icon_code+".png");   style = document.addStyle("icon", null);    StyleConstants.setIcon(style, icon);  }  try {    document.insertString(document.getLength(), title+"/n", title_attr);   if(style!=null)    document.insertString(document.getLength(), "/n", style);   else    document.insertString(document.getLength(), " "+content+"/n", content_attr);  } catch (BadLocationException ex) {    System.out.println("Bad location exception");  }  /*設置滑動條到最后*/  vertical.setValue(vertical.getMaximum()); } /**  * 設置需要美化字體的組件  */ public static void setUIFont() {  Font f = new Font("微軟雅黑", Font.PLAIN, 14);  String names[]={ "Label", "CheckBox", "PopupMenu","MenuItem", "CheckBoxMenuItem",    "JRadioButtonMenuItem","ComboBox", "Button", "Tree", "ScrollPane",    "TabbedPane", "EditorPane", "TitledBorder", "Menu", "TextArea","TextPane",    "OptionPane", "MenuBar", "ToolBar", "ToggleButton", "ToolTip",    "ProgressBar", "TableHeader", "Panel", "List", "ColorChooser",    "PasswordField","TextField", "Table", "Label", "Viewport",    "RadioButtonMenuItem","RadioButton", "DesktopPane", "InternalFrame"  };   for (String item : names) {    UIManager.put(item+ ".font",f);   } } /**  * 設置UI風格為當前系統的風格  */ public static void setUIStyle(){  String lookAndFeel =UIManager.getSystemLookAndFeelClassName();  try {   UIManager.setLookAndFeel(lookAndFeel);  } catch (ClassNotFoundException e) {   // TODO Auto-generated catch block   e.printStackTrace();  } catch (InstantiationException e) {   // TODO Auto-generated catch block   e.printStackTrace();  } catch (IllegalAccessException e) {   // TODO Auto-generated catch block   e.printStackTrace();  } catch (UnsupportedLookAndFeelException e) {   // TODO Auto-generated catch block   e.printStackTrace();  } } /**  * 測試用的main函數  * @param args  */ public static void main(String[] args) {  Client client = new Client(); }}

ClientThread

package Client;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStreamReader;import java.io.PrintWriter;import java.net.Socket;import java.util.regex.Matcher;import java.util.regex.Pattern;/** *  * @author lannooo * */public class ClientThread extends Thread{ private Socket socket; private Client client; private BufferedReader br; private PrintWriter pw; /**  * 從過主線程傳入的socket和client對象來構造  * @param socket  * @param client  */ public ClientThread(Socket socket, Client client){  this.client = client;  this.socket = socket;  try {   br=new BufferedReader(new InputStreamReader(socket.getInputStream()));  } catch (IOException e) {   System.out.println("cannot get inputstream from socket.");  } } /**  * 不斷的讀數據并處理  * 調用主線程的方法來處理:client.method();  */ public void run() {  try{   br=new BufferedReader(new InputStreamReader(socket.getInputStream()));   while(true){    String msg = br.readLine();    parseMessage(msg);   }  }catch (Exception e) {   e.printStackTrace();  } } /**  * 處理從服務器收到的消息  * @param message  */ public void parseMessage(String message){  String code = null;  String msg=null;  /*   * 先用正則表達式匹配code碼和msg內容    */  if(message.length()>0){   Pattern pattern = Pattern.compile("<code>(.*)</code>");   Matcher matcher = pattern.matcher(message);   if(matcher.find()){    code = matcher.group(1);   }   pattern = Pattern.compile("<msg>(.*)</msg>");   matcher = pattern.matcher(message);   if(matcher.find()){    msg = matcher.group(1);   }   System.out.println(code+":"+msg);   switch(code){   case "1": /*一個普通消息處理*/    client.updateTextArea(msg);    break;   case "2": /*退出消息*/    client.showEscDialog(msg);    break;   case "3": /*列出房間*/    client.listRooms(msg);    break;   case "4": /*其他用戶的消息*/    client.updateTextAreaFromUser(msg);    break;   case "5": /*普通消息處理*/    client.updateTextArea(msg);    break;   case "11": /*添加用戶*/    client.addUser(msg);    break;   case "12": /*刪除用戶*/    client.delUser(msg);    break;   case "13": /*刪除房間*/    client.delRoom(msg);    break;   case "15": /*添加房間*/    client.addRoom(msg);    break;   case "16": /*更新用戶名稱*/    client.updateUser(msg);    break;   case "21": /*列出用戶列表*/    client.listUsers(msg);    break;   }  } }}

IconDialog(選擇表情界面)

package Client;import java.awt.Container;import java.awt.Dialog;import java.awt.FlowLayout;import java.awt.GridLayout;import java.awt.Image;import java.awt.event.ActionEvent;import java.awt.event.ActionListener;import javax.swing.ImageIcon;import javax.swing.JButton;import javax.swing.JDialog;import javax.swing.JFrame;/** *  * @author lannooo * */public class IconDialog implements ActionListener { private JDialog dialog; private Client client; /**  * 通過frame和客戶端對象來構造  * @param frame  * @param client  */ public IconDialog(JFrame frame, Client client) {  this.client = client;  dialog = new JDialog(frame, "請選擇表情", true);  /*16個表情*/  JButton[] icon_button = new JButton[16];  ImageIcon[] icons = new ImageIcon[16];  /*獲得彈出窗口的容器,設置布局*/  Container dialogPane = dialog.getContentPane();  dialogPane.setLayout(new GridLayout(0, 4));  /*加入表情*/  for(int i=1; i<=15; i++){   icons[i] = new ImageIcon("icon/"+i+".png");   icons[i].setImage(icons[i].getImage().getScaledInstance(50, 50, Image.SCALE_DEFAULT));   icon_button[i] = new JButton(""+i, icons[i]);   icon_button[i].addActionListener(this);   dialogPane.add(icon_button[i]);  }  dialog.setBounds(200,266,266,280);  dialog.show(); } @Override public void actionPerformed(ActionEvent e) {  /*構造emoji結構的消息發送*/  String cmd = e.getActionCommand();  System.out.println(cmd);  dialog.dispose();  client.sendMsg("<emoji>"+cmd+"</emoji>", "message"); }}

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持VeVb武林網。


注:相關教程知識閱讀請移步到JAVA教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
超碰日本道色综合久久综合| 91网站在线看| 欧美日韩性生活视频| 国产精品高潮呻吟久久av无限| 久久久久久久久久久免费精品| 国产91精品久久久久| 亚洲深夜福利网站| 欧美视频二区36p| 97av视频在线| 奇米影视亚洲狠狠色| 欧美精品激情视频| 欧美日韩性生活视频| 国产精品h在线观看| 少妇av一区二区三区| 自拍视频国产精品| 亚洲女同性videos| 成人免费视频xnxx.com| 日韩在线高清视频| 亚洲乱码一区av黑人高潮| 亚洲一区二区三区四区在线播放| 日韩中文字幕视频| 国产精品大片wwwwww| 国产成+人+综合+亚洲欧洲| 在线亚洲欧美视频| 成人亚洲欧美一区二区三区| 亚洲黄色www| 欧美精品成人91久久久久久久| 中文字幕日本精品| 欧美视频精品一区| 久久成人一区二区| 久久理论片午夜琪琪电影网| 欧美视频二区36p| 国产不卡av在线| 亚洲精品日韩在线| 欧美超级免费视 在线| 2018国产精品视频| 国产精品aaaa| 精品网站999www| 全亚洲最色的网站在线观看| 国产在线精品播放| 97色在线观看| 青青在线视频一区二区三区| 国产亚洲视频在线观看| 欧美精品videosex极品1| 亚洲国产美女精品久久久久∴| 欧美大奶子在线| 亚洲精品福利资源站| 欧美午夜精品久久久久久人妖| 日韩高清免费在线| 日韩av一区在线观看| 国产成+人+综合+亚洲欧洲| 日韩精品极品在线观看| 国产精品嫩草影院一区二区| 国产精品吹潮在线观看| 成人春色激情网| 另类图片亚洲另类| 精品视频9999| 91久久精品日日躁夜夜躁国产| 国产精品久久久久久久久久99| 国产精品久久久久国产a级| 爱福利视频一区| 亚洲欧美三级伦理| www.国产精品一二区| 不用播放器成人网| 国内免费久久久久久久久久久| 欧美专区福利在线| 在线电影欧美日韩一区二区私密| 成人在线视频福利| 国产91在线视频| 欧美日韩一二三四五区| 欧美乱大交做爰xxxⅹ性3| 日韩精品极品在线观看| 欧美视频在线观看免费| 一区二区三区四区精品| 日韩中文字幕免费视频| 国产精欧美一区二区三区| 亚洲精品国产拍免费91在线| …久久精品99久久香蕉国产| 成人激情黄色网| 久久久www成人免费精品| 久久久av电影| 中文字幕日韩在线观看| 亚洲乱码国产乱码精品精天堂| 国产97免费视| 一区二区中文字幕| 亚洲精品美女久久久久| 日韩高清电影免费观看完整| 精品成人69xx.xyz| 国模私拍视频一区| 色综合色综合网色综合| 亚洲第一精品久久忘忧草社区| 国产精品免费一区| 亚洲欧美国产一区二区三区| 美日韩精品视频免费看| 日本国产欧美一区二区三区| 亚洲桃花岛网站| 91久热免费在线视频| 亚洲人成77777在线观看网| 欧美在线视频一二三| 97精品一区二区三区| 亚洲精品福利在线观看| 欧美性开放视频| 亚洲免费福利视频| 欧美电影在线播放| 亚洲人a成www在线影院| 亚洲欧美日韩一区二区在线| 欧美高清理论片| 欧美日韩爱爱视频| 久久久久久久久久久成人| 久久久女女女女999久久| 日韩大片在线观看视频| 久久久久久久久久久久av| 国产亚洲欧美一区| 91po在线观看91精品国产性色| 中文字幕日韩精品在线观看| 国产精品视频999| 91欧美激情另类亚洲| 国产乱肥老妇国产一区二| 一本色道久久综合狠狠躁篇怎么玩| 国内精品免费午夜毛片| 日韩精品免费电影| 久久人91精品久久久久久不卡| 亚洲偷熟乱区亚洲香蕉av| 伊人av综合网| 国产亚洲精品成人av久久ww| 国产在线999| 亚洲精品视频久久| 欧美日韩免费在线| 亚洲第一区中文字幕| 久久青草精品视频免费观看| 久久综合免费视频影院| 亚洲女人天堂色在线7777| 日韩美女福利视频| 色婷婷亚洲mv天堂mv在影片| 97精品国产97久久久久久| 日韩hd视频在线观看| 夜夜嗨av色综合久久久综合网| 日韩欧美在线第一页| 亚洲自拍欧美色图| xvideos国产精品| 欧美午夜无遮挡| 日韩亚洲精品电影| 亚洲黄色在线看| 国产精品久久久亚洲| 欧美日韩国产在线看| 国产香蕉一区二区三区在线视频| 国产日韩中文字幕| 91国自产精品中文字幕亚洲| 国产精品亚洲美女av网站| 日韩极品精品视频免费观看| 欧美成人性色生活仑片| 国产精品7m视频| 久久久久久久久国产| 久久精品国产精品| 18性欧美xxxⅹ性满足| 日韩在线播放一区| 欧美日韩午夜视频在线观看| 成人在线精品视频| 久久手机精品视频| 亚洲精品成a人在线观看| 亚洲码在线观看| 51午夜精品视频| 日韩亚洲欧美中文在线| 亚洲国产欧美在线成人app|