Java GUI編程實(shí)現(xiàn)在線聊天室
引言
綜合應(yīng)用Java的GUI編程和網(wǎng)絡(luò)編程,實(shí)現(xiàn)一個(gè)能夠支持多組用戶同時(shí)使用的聊天室軟件。該聊天室具有比較友好的GUI界面,并使用C/S模式,支持多個(gè)用戶同時(shí)使用,用戶可以自己選擇加入或者創(chuàng)建房間,和房間內(nèi)的其他用戶互發(fā)信息(文字和圖片)
主要功能
客戶端的功能主要包括如下的功能:
- 選擇連上服務(wù)端
- 顯示當(dāng)前房間列表(包括房間號(hào)和房間名稱)
- 選擇房間進(jìn)入
- 多個(gè)用戶在線群聊
- 可以發(fā)送表情(用本地的,實(shí)際上發(fā)送只發(fā)送表情的代碼)
- 退出房間
- 選擇創(chuàng)建房間
- 房間里沒人(房主退出),導(dǎo)致房間解散
- 顯示系統(tǒng)提示消息
- 顯示用戶消息
- 構(gòu)造標(biāo)準(zhǔn)的消息結(jié)構(gòu)發(fā)送
- 維護(hù)GUI所需的數(shù)據(jù)模型
服務(wù)端的功能主要包括:
- 維護(hù)用戶信息和房間信息
- 處理用戶發(fā)送來(lái)的消息選擇轉(zhuǎn)發(fā)或者回復(fù)處理結(jié)果
- 構(gòu)造標(biāo)準(zhǔn)的消息結(jié)構(gòu)發(fā)送
架構(gòu)
整個(gè)程序采用C/S設(shè)計(jì)架構(gòu),分為一個(gè)服務(wù)端和多個(gè)客戶端。服務(wù)端開放一個(gè)端口給所有開客戶端,客戶端連接該端口并收發(fā)信息,服務(wù)端在內(nèi)部維護(hù)客戶端的組,并對(duì)每一個(gè)客戶端都用一個(gè)子線程來(lái)收發(fā)信息
基本類的設(shè)計(jì)
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: 設(shè)置user的姓名
* @param id:設(shè)置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;
}
/**
* 設(shè)置該用戶的id
* @param id 新的id
*/
public void setId(long id) {
this.id = id;
}
/**
* 獲得用戶當(dāng)前所在的房間號(hào)
* @return roomId
*/
public long getRoomId() {
return roomId;
}
/**
* 設(shè)置當(dāng)前用戶的所在的房間號(hào)
* @param roomId
*/
public void setRoomId(long roomId) {
this.roomId = roomId;
}
/**
* 設(shè)置當(dāng)前用戶在聊天室中的昵稱
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 返回當(dāng)前用戶在房間中的昵稱
* @return
*/
public String getName() {
return name;
}
/**
* 返回當(dāng)前用戶連接的socket實(shí)例
* @return
*/
public Socket getSocket() {
return socket;
}
/**
* 設(shè)置當(dāng)前用戶連接的socket
* @param socket
*/
public void setSocket(Socket socket) {
this.socket = socket;
}
/**
* 獲得該用戶的消息讀取輔助類BufferedReader實(shí)例
* @return
*/
public BufferedReader getBr() {
return br;
}
/**
* 設(shè)置 用戶的消息讀取輔助類
* @param br
*/
public void setBr(BufferedReader br) {
this.br = br;
}
/**
* 獲得消息寫入類實(shí)例
* @return
*/
public PrintWriter getPw() {
return pw;
}
/**
* 設(shè)置消息寫入類實(shí)例
* @param pw
*/
public void setPw(PrintWriter pw) {
this.pw = pw;
}
/**
* 重寫了用戶類打印的函數(shù)
*/
@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;
}
/**
* 設(shè)置房間的新名字
* @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 獲得房間的id號(hào)
* @return
*/
public long getRoomId() {
return roomId;
}
/**
* 設(shè)置房間的id
* @param roomId
*/
public void setRoomId(long roomId) {
this.roomId = roomId;
}
/**
* 向房間中加入一個(gè)新用戶
* @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);
}
}
/**
* 從房間中刪除一個(gè)用戶
* @param user
* @return 目前該房間中的總用戶數(shù)目
*/
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;
}
}
/**
* 獲得當(dāng)前房間的用戶列表
* @return
*/
public ArrayList<User> getUsers(){
return list;
}
/**
* 獲得當(dāng)前房間的用戶昵稱的列表
* @return
*/
public String[] getUserNames(){
String[] userList = new String[list.size()];
int i=0;
for(User each: list){
userList[i++]=each.getName();
}
return userList;
}
/**
* 使用房間的名稱和id來(lái)new一個(gè)房間
* @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算起,起始的房間總數(shù)為0
*/
public RoomList(){
map = new HashMap<>();
unusedRoomId = 1;
totalRooms = 0;
}
/**
* 創(chuàng)建一個(gè)新的房間,使用未使用的房間號(hào)進(jìn)行創(chuàng)建,如果沒有可以使用的則就創(chuàng)建失敗
* @param name: 房間的名字
* @return 創(chuàng)建的房間的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;
}
}
/**
* 用戶加入一個(gè)房間
* @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);
/*如果這個(gè)房間剩下的人數(shù)為0,那么刪除該房間*/
if(number==0){
map.remove(roomID);
totalRooms--;
return 0;
}
return 1;
}else{
return -1;
}
}
/**
* 列出所有房間的列表,返回一個(gè)二維數(shù)組,strings[i][0]放房間的id,string[i][1]放房間的name
* @return
*/
public String[][] listRooms(){
String[][] strings = new String[totalRooms][2];
int i=0;
/*將map轉(zhuǎn)化為set并使用迭代器來(lái)遍歷*/
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;
}
/**
* 通過(guò)roomID來(lái)獲得房間
* @param roomID
* @return
*/
public Room getRoom(long roomID){
if(map.containsKey(roomID)){
return map.get(roomID);
}
else
return null;
}
}
服務(wù)端
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;
/**
* 通過(guò)port號(hào)來(lái)構(gòu)造服務(wù)器端對(duì)象
* 維護(hù)一個(gè)總的用戶列表和一個(gè)房間列表
* @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!");
}
/**
* 獲得下一個(gè)可用的用戶id
* @return
*/
private long getNextUserID(){
if(unusedUserID < MAX_USERS)
return unusedUserID++;
else
return -1;
}
/**
* 開始監(jiān)聽,當(dāng)接受到新的用戶連接,就創(chuàng)建一個(gè)新的用戶,并添加到用戶列表中
* 然后創(chuàng)建一個(gè)新的服務(wù)線程用于收發(fā)該用戶的消息
* @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();
}
}
}
/**
* 測(cè)試用main方法,設(shè)置偵聽端口為9999,并開始監(jiān)聽
* @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;
/**
* 通過(guò)用戶的對(duì)象實(shí)例、全局的用戶列表、房間列表進(jìn)行構(gòu)造
* @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;
}
/**
* 線程運(yùn)行部分,持續(xù)讀取用戶socket發(fā)送來(lái)的數(shù)據(jù),并解析
*/
public void run(){
try{
while (true) {
String msg=user.getBr().readLine();
System.out.println(msg); /*解析用戶的數(shù)據(jù)格式*/
parseMsg(msg);
}
}catch (SocketException se) { /*處理用戶斷開的異常*/
System.out.println("user "+user.getName()+" logout.");
}catch (Exception e) { /*處理其他異常*/
e.printStackTrace();
}finally {
try {
/*
* 用戶斷開或者退出,需要把該用戶移除
* 并關(guān)閉socket
*/
remove(user);
user.getBr().close();
user.getSocket().close();
} catch (IOException ioe) {
ioe.printStackTrace();
}
}
}
/**
* 用正則表達(dá)式匹配數(shù)據(jù)的格式,根據(jù)不同的指令類型,來(lái)調(diào)用相應(yīng)的方法處理
* @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, 把當(dāng)前房間里的所有用戶返回給client
if(roomId == -1){
roomId = Long.parseLong(message);
map.join(user, roomId);
sendRoomMsgExceptSelf(buildCodeWithMsg("<name>"+user.getName()+"</name><id>"+user.getId()+"</id>", 11));
// 這個(gè)消息需要加入房間里已有用戶的列表
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, 對(duì)所有該房間的其他用戶發(fā)送該用戶退出房間的信息,從list中刪除
if(roomId!=-1){
int flag=map.esc(user, roomId);
sendRoomMsgExceptSelf(buildCodeWithMsg(""+user.getId(), 12));
long oldRoomId=roomId;
roomId = -1;
returnMsg(buildCodeWithMsg("你已經(jīng)成功退出房間,不會(huì)收到消息", 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, 自己收到的話,打印的是‘你說(shuō):....'否則打印user id對(duì)應(yīng)的name
sendRoomMsg(buildCodeWithMsg("<from>"+user.getId()+"</from><smsg>"+message+"</smsg>", 4));
break;
case "create":
// create a room
// code=5,提示用戶進(jìn)入了房間
// code=15,需要在其他所有用戶的room列表中更新
roomId = map.createRoom(message);
map.join(user, roomId);
sendMsg(buildCodeWithMsg("<rid>"+roomId+"</rid><rname>"+message+"</rname>", 15));
returnMsg(buildCodeWithMsg("你進(jìn)入了創(chuàng)建的房間:"+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;
}
}
}
/**
* 獲得該用戶房間中的所有用戶列表,并構(gòu)造成一定格式的消息返回
* @return
*/
private String getMembersInRoom(){
/*先從room列表獲得該用戶的room*/
Room room = map.getRoom(roomId);
StringBuffer stringBuffer = new StringBuffer();
if(room != null){
/*獲得房間中所有的用戶的列表,然后構(gòu)造成一定的格式發(fā)送回去*/
ArrayList<User> users = room.getUsers();
for(User each: users){
stringBuffer.append("<member><name>"+each.getName()+
"</name><id>"+each.getId()+"</id></member>");
}
}
return stringBuffer.toString();
}
/**
* 獲得所有房間的列表,并構(gòu)造成一定的格式
* @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();
}
/**
* 構(gòu)造成一個(gè)統(tǒng)一的消息格式
* @param msg
* @param code
* @return
*/
private String buildCodeWithMsg(String msg, int code){
return "<code>"+code+"</code><msg>"+msg+"</msg>\n";
}
/**
* 這個(gè)是群發(fā)消息:全體用戶,code>10
* @param msg
*/
private void sendMsg(String msg) {
// System.out.println("In sendMsg()");
/*取出用戶列表中的每一個(gè)用戶來(lái)發(fā)送消息*/
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()");
}
}
}
/**
* 只對(duì)同一房間的用戶發(fā):code>10
* @param msg
*/
private void sendRoomMsg(String msg){
/*先獲得該用戶的房間號(hào),然后往該房間發(fā)送消息*/
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();
}
}
}
/**
* 向房間中除了該用戶自己,發(fā)送消息
* @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();
}
}
}
}
/**
* 對(duì)于client的來(lái)信,返回一個(gè)結(jié)果,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()");
}
}
/**
* 移除該用戶,并向房間中其他用戶發(fā)送該用戶已經(jīng)退出的消息
* 如果房間中沒人了,那么就更新房間列表給所有用戶
* @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;
/*
* 構(gòu)造函數(shù)
* 該客戶端對(duì)象維護(hù)兩個(gè)map,房間的hashmap和房間中用戶的hashmap
* 作為列表組件的數(shù)據(jù)模型
*/
public Client(){
rooms_map = new HashMap<>();
users_map = new HashMap<>();
initialize();
}
/**
* 連接服務(wù)端,指定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());
/*
* 創(chuàng)建一個(gè)接受和解析服務(wù)器消息的線程
* 傳入當(dāng)前客戶端對(duì)象的指針,作為句柄調(diào)用相應(yīng)的處理函數(shù)
*/
ClientThread thread = new ClientThread(socket, this);
thread.start();
return true;
} catch (IOException e) {
System.out.println("Server error");
JOptionPane.showMessageDialog(frame, "服務(wù)器無(wú)法連接!");
return false;
}
}
/*當(dāng)前進(jìn)程作為只發(fā)送消息的線程,從命令行中獲取輸入*/
// 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.");
// }
// }
/**
* 發(fā)給服務(wù)器的消息,先經(jīng)過(guò)一定的格式構(gòu)造再發(fā)送
* @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, "請(qǐng)先連接服務(wù)器!");
}
}
/**
* 窗口初始化
*/
private void initialize() {
/*設(shè)置窗口的UI風(fēng)格和字體*/
setUIStyle();
setUIFont();
JFrame frame = new JFrame("ChatOnline");
JPanel panel = new JPanel(); /*主要的panel,上層放置連接區(qū),下層放置消息區(qū),
中間是消息面板,左邊是room列表,右邊是當(dāng)前room的用戶列表*/
JPanel headpanel = new JPanel(); /*上層panel,用于放置連接區(qū)域相關(guān)的組件*/
JPanel footpanel = new JPanel(); /*下層panel,用于放置發(fā)送信息區(qū)域的組件*/
JPanel leftpanel = new JPanel(); /*左邊panel,用于放置房間列表和加入按鈕*/
JPanel rightpanel = new JPanel(); /*右邊panel,用于放置房間內(nèi)人的列表*/
/*最上層的布局,分中間,東南西北五個(gè)部分*/
BorderLayout layout = new BorderLayout();
/*格子布局,主要用來(lái)設(shè)置西、東、南三個(gè)部分的布局*/
GridBagLayout gridBagLayout = new GridBagLayout();
/*主要設(shè)置北部的布局*/
FlowLayout flowLayout = new FlowLayout();
/*設(shè)置初始窗口的一些性質(zhì)*/
frame.setBounds(100, 100, 800, 600);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.setLayout(layout);
/*設(shè)置各個(gè)部分的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("服務(wù)器IP");
JLabel port_label = new JLabel("端口");
JLabel name_label = new JLabel("昵稱");
JButton head_connect = new JButton("連接");
// JButton head_change = new JButton("確認(rèn)更改");
JButton head_create = new JButton("創(chuàng)建房間");
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("發(fā)送");
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("當(dāng)前房間數(shù):0");
users_label = new JLabel("房間內(nèi)人數(shù):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));
/*中間的文本區(qū)組件*/
msgArea = new JTextPane();
msgArea.setEditable(false);
textScrollPane = new JScrollPane();
textScrollPane.setViewportView(msgArea);
vertical = new JScrollBar(JScrollBar.VERTICAL);
vertical.setAutoscrolls(true);
textScrollPane.setVerticalScrollBar(vertical);
/*設(shè)置頂層布局*/
panel.add(headpanel, "North");
panel.add(footpanel, "South");
panel.add(leftpanel, "West");
panel.add(rightpanel, "East");
panel.add(textScrollPane, "Center");
/*注冊(cè)各種事件*/
/*連接服務(wù)器*/
head_connect.addActionListener(this);
/*發(fā)送消息,如果沒有連接則會(huì)彈窗提示*/
foot_send.addActionListener(this);
/*改名字*/
// head_change.addActionListener(this);
/*創(chuàng)建房間*/
head_create.addActionListener(this);
/*發(fā)送表情*/
foot_emoji.addActionListener(this);
/*加入room*/
join_button.addActionListener(this);
/*退出房間*/
esc_button.addActionListener(this);
/*最終顯示*/
frame.setVisible(true);
}
/**
* 事件監(jiān)聽處理
*/
@Override
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
switch (cmd) {
case "連接": /*點(diǎn)擊連接按鈕*/
String strhost = host_textfield.getText();
String strport = port_textfield.getText();
connect(strhost, Integer.parseInt(strport));
String nameSeted = JOptionPane.showInputDialog("請(qǐng)輸入你的昵稱:"); /*提示輸入昵稱*/
name_textfiled.setText(nameSeted);
name_textfiled.setEditable(false);
port_textfield.setEditable(false);
host_textfield.setEditable(false);
/*發(fā)送設(shè)置姓名的消息和列出用戶列表的消息*/
sendMsg(nameSeted, "setname");
sendMsg("", "list");
break;
// case "確認(rèn)更改":
// String strname = name_textfiled.getText();
// name = strname;
// sendMsg(strname, "setname");
// break;
case "加入房間": /*選擇房間后,點(diǎn)擊加入房間按鈕*/
String selected = roomlist.getSelectedValue();
if(rooms_map.containsKey(selected)){
sendMsg(""+rooms_map.get(selected), "join");
}
break;
case "退出房間": /*點(diǎn)擊退出房間的按鈕*/
sendMsg("", "esc");
break;
case "發(fā)送": /*點(diǎn)擊發(fā)送消息的按鈕*/
String text = text_field.getText();
text_field.setText("");
sendMsg(text, "message");
break;
case "表情": /*發(fā)送表情,新建一個(gè)表情窗口,并直接在表情窗口中處理消息發(fā)送*/
IconDialog dialog = new IconDialog(frame, this);
break;
case "創(chuàng)建房間": /*點(diǎn)擊創(chuàng)建房間的按鈕,彈出提示框數(shù)據(jù)房間名稱*/
String string = JOptionPane.showInputDialog("請(qǐng)輸入你的房間名稱");
if(string==null || string.equals("")){
string = name+(int)(Math.random()*10000)+"的房間";
}
sendMsg(string, "create");
break;
default:
break;
}
}
/*很多輔助和clientThread互動(dòng)的*/
/**
* 加入用戶,通過(guò)正則表達(dá)式,匹配消息內(nèi)容中的用戶信息
* @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
* 加入用戶列表
* 在消息區(qū)顯示系統(tǒng)提示
*/
String name = matcher.group(1);
String id = matcher.group(2);
insertUser(Integer.parseInt(id), name);
insertMessage(textScrollPane, msgArea, null, "系統(tǒng):", name+"加入了聊天室");
}
}
users_label.setText("房間內(nèi)人數(shù):"+users_map.size()); /*更新房間內(nèi)的人數(shù)*/
}
/**
* 刪除用戶
* @param content
*/
public void delUser(String content){
if(content.length()>0){
int id = Integer.parseInt(content);
/*
* 從維護(hù)的用戶map中取得所有的用戶名字,然后去遍歷匹配的用戶
* 匹配到的用戶名字從相應(yīng)的數(shù)據(jù)模型中移除
* 并從map中移除,并在消息框中提示系統(tǒng)消息
*/
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, "系統(tǒng):", name+"退出了聊天室");
}
users_label.setText("房間內(nèi)人數(shù):"+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;
/*
* 先用正則表達(dá)式匹配用戶信息
* 然后插入數(shù)據(jù)模型中
* 并更新用戶數(shù)據(jù)模型中的條目
*/
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("房間內(nèi)人數(shù):"+users_map.size());
}
/**
* 直接在textarea中顯示消息
* @param content
*/
public void updateTextArea(String content){
insertMessage(textScrollPane, msgArea, null, "系統(tǒng):", content);
}
/**
* 在textarea中顯示其他用戶的消息
* 先用正則匹配,再顯示消息
* 其中還需要匹配emoji表情的編號(hào)
* @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+"說(shuō):", null);
return ;
}
insertMessage(textScrollPane, msgArea, null, fromName+"說(shuō):", smsg);
}
}
}
/**
* 顯示退出的結(jié)果
* @param content
*/
public void showEscDialog(String content){
JOptionPane.showMessageDialog(frame, content);
/*清除消息區(qū)內(nèi)容,清除用戶數(shù)據(jù)模型內(nèi)容和用戶map內(nèi)容,更新房間內(nèi)人數(shù)*/
msgArea.setText("");
users_model.clear();
users_map.clear();
users_label.setText("房間內(nèi)人數(shù):0");
}
/**
* 新增一個(gè)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("當(dāng)前房間數(shù):"+rooms_map.size());
}
/**
* 刪除一個(gè)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("當(dāng)前房間數(shù):"+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("當(dāng)前房間數(shù):"+rooms_map.size());
}
/**
* 插入一個(gè)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("當(dāng)前房間數(shù):"+rooms_map.size());
}
/**
* 插入一個(gè)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("房間內(nèi)人數(shù):"+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中的文本*/
/*設(shè)置標(biāo)題的屬性*/
SimpleAttributeSet title_attr = new SimpleAttributeSet();
StyleConstants.setBold(title_attr, true);
StyleConstants.setForeground(title_attr, Color.BLUE);
/*設(shè)置正文的屬性*/
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");
}
/*設(shè)置滑動(dòng)條到最后*/
vertical.setValue(vertical.getMaximum());
}
/**
* 設(shè)置需要美化字體的組件
*/
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);
}
}
/**
* 設(shè)置UI風(fēng)格為當(dāng)前系統(tǒng)的風(fēng)格
*/
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();
}
}
/**
* 測(cè)試用的main函數(shù)
* @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;
/**
* 從過(guò)主線程傳入的socket和client對(duì)象來(lái)構(gòu)造
* @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.");
}
}
/**
* 不斷的讀數(shù)據(jù)并處理
* 調(diào)用主線程的方法來(lái)處理: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();
}
}
/**
* 處理從服務(wù)器收到的消息
* @param message
*/
public void parseMessage(String message){
String code = null;
String msg=null;
/*
* 先用正則表達(dá)式匹配code碼和msg內(nèi)容
*/
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": /*一個(gè)普通消息處理*/
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;
/**
* 通過(guò)frame和客戶端對(duì)象來(lái)構(gòu)造
* @param frame
* @param client
*/
public IconDialog(JFrame frame, Client client) {
this.client = client;
dialog = new JDialog(frame, "請(qǐng)選擇表情", true);
/*16個(gè)表情*/
JButton[] icon_button = new JButton[16];
ImageIcon[] icons = new ImageIcon[16];
/*獲得彈出窗口的容器,設(shè)置布局*/
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) {
/*構(gòu)造emoji結(jié)構(gòu)的消息發(fā)送*/
String cmd = e.getActionCommand();
System.out.println(cmd);
dialog.dispose();
client.sendMsg("<emoji>"+cmd+"</emoji>", "message");
}
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- java實(shí)現(xiàn)在線聊天系統(tǒng)
- Java實(shí)現(xiàn)在線聊天室(層層遞進(jìn))
- Java實(shí)現(xiàn)在線聊天功能
- Java網(wǎng)絡(luò)編程UDP實(shí)現(xiàn)多線程在線聊天
- Java網(wǎng)絡(luò)編程實(shí)例——簡(jiǎn)單模擬在線聊天
- Java使用TCP實(shí)現(xiàn)在線聊天的示例代碼
- Java中使用websocket實(shí)現(xiàn)在線聊天功能
- java Socket實(shí)現(xiàn)網(wǎng)頁(yè)版在線聊天
- 基于Java Socket實(shí)現(xiàn)一個(gè)簡(jiǎn)易在線聊天功能(一)
- java基于UDP實(shí)現(xiàn)在線聊天功能
相關(guān)文章
Java?Rabbitmq中四種集群架構(gòu)的區(qū)別詳解
這篇文章主要為大家詳細(xì)介紹了Java?Rabbitmq中四種集群架構(gòu)的區(qū)別,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-02-02
springboot引入遠(yuǎn)程nacos配置文件錯(cuò)誤的解決方案
本文為解決Spring Cloud Alibaba中配置導(dǎo)入問題,提供了詳細(xì)的步驟說(shuō)明,包括引入依賴、配置nacos、創(chuàng)建bootstrap.yml文件以及測(cè)試配置導(dǎo)入是否成功的方法,幫助開發(fā)者快速解決相關(guān)問題2024-09-09
spring cloud gateway全局過(guò)濾器實(shí)現(xiàn)向request header中放數(shù)據(jù)
這篇文章主要介紹了spring cloud gateway全局過(guò)濾器實(shí)現(xiàn)向request header中放數(shù)據(jù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07
java如何把逗號(hào)分隔的String字符串轉(zhuǎn)int集合
這篇文章主要介紹了java實(shí)現(xiàn)把逗號(hào)分隔的String字符串轉(zhuǎn)int集合,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-06-06
MyBatis中操作類對(duì)象的實(shí)現(xiàn)
在MyBatis框架中,操作類對(duì)象是用于執(zhí)行數(shù)據(jù)庫(kù)操作的核心對(duì)象,本文主要介紹了MyBatis中操作類對(duì)象的實(shí)現(xiàn),具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
利用Java工具類Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn)功能
這篇文章主要介紹了利用Java工具類Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn)功能,利用Hutool實(shí)現(xiàn)驗(yàn)證碼校驗(yàn),校驗(yàn)的Servlet與今天的第一篇是一樣的,唯一就是驗(yàn)證碼的生成是不一樣的,利用Hutool生成驗(yàn)證碼更快捷.需要的朋友可以參考下2022-10-10

