一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|編程技術(shù)|正則表達(dá)式|

服務(wù)器之家 - 編程語言 - JAVA教程 - 詳解基于java的Socket聊天程序——服務(wù)端(附demo)

詳解基于java的Socket聊天程序——服務(wù)端(附demo)

2020-07-12 15:30jAVA-yaolin JAVA教程

這篇文章主要介紹了詳解基于java的Socket聊天程序——服務(wù)端(附demo),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。

 寫在前面:

昨天在博客記錄自己抽空寫的一個(gè)Socket聊天程序的初始設(shè)計(jì),那是這個(gè)程序的整體設(shè)計(jì),為了完整性,今天把服務(wù)端的設(shè)計(jì)細(xì)化記錄一下,首頁貼出Socket聊天程序的服務(wù)端大體設(shè)計(jì)圖,如下圖:

詳解基于java的Socket聊天程序——服務(wù)端(附demo)

功能說明:

服務(wù)端主要有兩個(gè)操作,一是阻塞接收客戶端的socket并做響應(yīng)處理,二是檢測(cè)客戶端的心跳,如果客戶端一段時(shí)間內(nèi)沒有發(fā)送心跳則移除該客戶端,由Server創(chuàng)建ServerSocket,然后啟動(dòng)兩個(gè)線程池去處理這兩件事(newFixedThreadPool,newScheduledThreadPool),對(duì)應(yīng)的處理類分別是SocketDispatcher、SocketSchedule,其中SocketDispatcher根據(jù)socket不同的請(qǐng)求分發(fā)給不同SocketHandler去處理,而SocketWrapper則是對(duì)socket加了一層外殼包裝,用lastAliveTime記錄socket最新的交互時(shí)間,SocketHolder存儲(chǔ)當(dāng)前跟服務(wù)端交互的socket集合。

具體實(shí)現(xiàn):

[Server.java]

Server是服務(wù)端的入口,由Server的start()方法啟動(dòng)ServerSocket,然后阻塞接收客戶端的請(qǐng)求,交由SocketDispatcher去分發(fā),SocketDispatcher由newFixedThread類型的線程池啟動(dòng),當(dāng)連接數(shù)超過最大數(shù)據(jù)時(shí)將被隊(duì)列處理,使用scheduleAtFixedRate啟動(dòng)SocketSchedule定時(shí)循環(huán)去監(jiān)聽客戶端的心跳包,這兩個(gè)類型都實(shí)現(xiàn)了Runnable接口,下面給出服務(wù)端的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
package yaolin.chat.server;
 
import java.io.IOException;
import java.net.ServerSocket;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
 
import yaolin.chat.common.ConstantValue;
import yaolin.chat.util.LoggerUtil;
 
/**
 * 服務(wù)器
 * @author yaolin
 */
public class Server {
 
  private final ServerSocket server;
  private final ExecutorService pool;
  
  public Server() throws IOException {
    server = new ServerSocket(ConstantValue.SERVER_PORT);
    pool = Executors.newFixedThreadPool(ConstantValue.MAX_POOL_SIZE);
  }
 
  public void start() {
    try {
      ScheduledExecutorService schedule = Executors.newScheduledThreadPool(1);
      // Watch dog. Exception??
      schedule.scheduleAtFixedRate(new SocketSchedule(), 10, ConstantValue.TIME_OUT, TimeUnit.SECONDS);
 
      while (true) {
        pool.execute(new SocketDispatcher(server.accept()));
        LoggerUtil.info("ACCEPT A CLIENT AT " + new Date());
      }
    } catch (IOException e) {
      pool.shutdown();
    }
  }
  
  
  public static void main(String[] args) {
    try {
      new Server().start();
    } catch (IOException e) {
      LoggerUtil.error("Server start failed! -> " + e.getMessage(), e);
    }
  }
}

[SocketDispatcher.java]

Server只是服務(wù)端的入口,并指揮中心,SocketDispatcher才是服務(wù)端的指揮中心,對(duì)客戶端不同的消息類型請(qǐng)求進(jìn)行分發(fā),讓不同的SocketHandler去處理對(duì)應(yīng)的消息請(qǐng)求,這里服務(wù)端和客戶端的消息交互都是用JSON數(shù)據(jù),所有消息類都繼承BaseMessage,所以將接收到數(shù)據(jù)轉(zhuǎn)換成BaseMessage類型,再判斷其類型,(數(shù)據(jù)類型模塊屬于common模塊),這里需要提一下的是當(dāng)消息類型是文件類型的時(shí)候會(huì)睡眠配置執(zhí)行的間隔時(shí)間,這樣FileHandler才能有時(shí)間對(duì)文件流進(jìn)行讀取和重新發(fā)送給指定的客戶端,而不會(huì)立即進(jìn)入下一次循環(huán)對(duì)消息類型的判斷(可能這里設(shè)計(jì)有點(diǎn)問題,不過暫時(shí)先這樣做),下面給出SocketDispatcher的代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
 * SocketDispatcher
 *
 * @author yaolin
 */
public class SocketDispatcher implements Runnable {
 
  private final Socket socket;
 
  public SocketDispatcher(Socket socket) {
    this.socket = socket;
  }
 
  @Override
  public void run() {
    if (socket != null) {
      while (!socket.isClosed()) {
        try {
          InputStream is = socket.getInputStream();
          String line = null;
          StringBuffer sb = null;
          
          if (is.available() > 0) {
            
            BufferedReader bufr = new BufferedReader(new InputStreamReader(is));
            sb = new StringBuffer();
            while (is.available() > 0 && (line = bufr.readLine()) != null) {
              sb.append(line);
            }
            LoggerUtil.trach("RECEIVE [" + sb.toString() + "] AT " + new Date());
            
            BaseMessage message = JSON.parseObject(sb.toString(), BaseMessage.class);
            
            switch (message.getType()) {
            case MessageType.ALIVE:
              HandlerFactory.getHandler(MessageType.ALIVE).handle(socket, sb.toString());
              break;
            case MessageType.CHAT:
              HandlerFactory.getHandler(MessageType.CHAT).handle(socket, sb.toString());
              break;
            case MessageType.FILE:
              HandlerFactory.getHandler(MessageType.FILE).handle(socket, sb.toString());
              LoggerUtil.trach("SEVER:PAUSE TO RECEIVE FILE");
              Thread.sleep(ConstantValue.MESSAGE_PERIOD);
              break;
            case MessageType.LOGIN:
              HandlerFactory.getHandler(MessageType.LOGIN).handle(socket, sb.toString());
              break;
            case MessageType.LOGOUT:
              break;
            case MessageType.REGISTER:
              HandlerFactory.getHandler(MessageType.REGISTER).handle(socket, sb.toString());
              break;
            }
          } else {
            Thread.sleep(ConstantValue.MESSAGE_PERIOD);
          }
        } catch (Exception e) { // catch all handler exception
          LoggerUtil.error("SocketDispatcher Error!" + e.getMessage(), e);
        }
      }
    }
  }
}

[SocketSchedule.java]

跟Server有直接關(guān)系的另一個(gè)類(組件)是SocketSchedule,SocketSchedule主要負(fù)責(zé)檢測(cè)客戶端的最新一次跟服務(wù)端的交互時(shí)間是否超過系統(tǒng)配置允許最大的時(shí)間,如果超過了,則將該客戶端socket從服務(wù)端移除,否則更新客戶端的最新一次跟服務(wù)端的交互時(shí)間。下面是具體的實(shí)現(xiàn):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * Remove socket from SocketHolder if lastAliveTime > TIME_OUT
 * @author yaolin
 *
 */
public class SocketSchedule implements Runnable {
 
  @Override
  public void run() {
    for (String key : SocketHolder.keySet()) {
      SocketWrapper wrapper = SocketHolder.get(key);
      if (wrapper != null && wrapper.getLastAliveTime() != null) {
        if (((new Date().getTime() - wrapper.getLastAliveTime().getTime()) / 1000) > ConstantValue.TIME_OUT) {
          // remove socket if timeout
          SocketHolder.remove(key);
        }
      }
    }
  }
}

[SocketHolder.java、SocketWrapper.java]

從上面的代碼可以看出,SocketSchedule#run()只是簡(jiǎn)單的對(duì)時(shí)間進(jìn)行一次判斷,真正有意義的其實(shí)是SocketHolder和SocketWrapper,SocketWrapper則是對(duì)socket加了一層外殼包裝,SocketHolder的存儲(chǔ)了當(dāng)前有效時(shí)間內(nèi)所有跟服務(wù)端有交互的客戶端,SocketHolder以客戶端的唯一標(biāo)識(shí)(這里使用用戶名),作為KEY,客戶端所在的socket作為VALUE的鍵值對(duì)形式存儲(chǔ),其中SocketHolder#flushClientStatus()的處理邏輯是用于通知其他客戶端當(dāng)前客戶端的上線/離線狀態(tài),下面給出這兩個(gè)類的具體實(shí)現(xiàn):

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
 * Wrap Socket, SocketSchedule remove socket if lastAliveTime > TIME_OUT
 * @author yaolin
 *
 */
public class SocketWrapper {
 
  private Socket socket;
  private Date lastAliveTime;
  
  // full constructor
  public SocketWrapper(Socket socket, Date lastAliveTime) {
    this.socket = socket;
    this.lastAliveTime = lastAliveTime;
  }
  public Socket getSocket() {
    return socket;
  }
  public void setSocket(Socket socket) {
    this.socket = socket;
  }
  public Date getLastAliveTime() {
    return lastAliveTime;
  }
  public void setLastAliveTime(Date lastAliveTime) {
    this.lastAliveTime = lastAliveTime;
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
 * SocketHolder
 * @author yaolin
 */
public class SocketHolder {
 
  private static ConcurrentMap<String, SocketWrapper> listSocketWrap = new ConcurrentHashMap<String, SocketWrapper>();
  
  public static Set<String> keySet() {
    return listSocketWrap.keySet();
  }
  
  public static SocketWrapper get(String key) {
    return listSocketWrap.get(key);
  }
  
  public static void put(String key, SocketWrapper value) {
    listSocketWrap.put(key, value);
    flushClientStatus(key, true);
  }
  
  public static SocketWrapper remove(String key) {
    flushClientStatus(key, false);
    return listSocketWrap.remove(key);
  }
  
  public static void clear() {
    listSocketWrap.clear();
  }
  
  /**
   * <pre>content:{username:"",flag:false}</pre>
   * @param flag true:put,false:remove;
   */
  private static void flushClientStatus(String key, boolean flag) {
    ClientNotifyDTO dto = new ClientNotifyDTO(flag, key);
    ReturnMessage rm = new ReturnMessage().setKey(Key.NOTIFY).setSuccess(true).setContent(dto);
    rm.setFrom(ConstantValue.SERVER_NAME);
    for (String toKey : listSocketWrap.keySet()) {
      if (!toKey.equals(key)) { // not send to self
        rm.setTo(toKey);
        SocketWrapper wrap = listSocketWrap.get(toKey);
        if (wrap != null) {
          SendHelper.send(wrap.getSocket(), rm);
        }
      }
    }
  }
}

[SocketHandler.java、HandlerFactory.java、OtherHandlerImpl.java]

SocketDispatcher讓不同的SocketHandler去處理對(duì)應(yīng)的消息請(qǐng)求,SocketHandler的設(shè)計(jì)其實(shí)就是一套簡(jiǎn)單的工廠組件吧(其中ReturnHandler暫時(shí)由SendHelper實(shí)現(xiàn)信息傳送,暫時(shí)沒有用到,已經(jīng)@Deprecated ,這里還是給出),完整類圖如下:

詳解基于java的Socket聊天程序——服務(wù)端(附demo)

下面給出這一塊的代碼,為了縮小篇幅,將所有Handler實(shí)現(xiàn)的代碼收起來。

?
1
2
3
4
5
6
7
8
9
10
/**
 * SocketHandler
 * @author yaolin
 */
public interface SocketHandler {
  /**
   * Handle Client Socket
   */
  public Object handle(Socket client,Object data);
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
 * SocketHandlerFactory
 * @author yaolin
 */
public class HandlerFactory {
 
  // can not create instance
  private HandlerFactory(){}
 
  public static SocketHandler getHandler(int type) {
    switch (type) {
    case MessageType.ALIVE: // usually use
      return new AliveHandler();
    case MessageType.CHAT:
      return new ChatHandler();
    case MessageType.LOGIN:
      return new LoginHandler();
//    case MessageType.RETURN:
//      return new ReturnHandler();
    case MessageType.LOGOUT:
      return new LogoutHandler();
    case MessageType.REGISTER:
      return new RegisterHandler();
    case MessageType.FILE:
      return new FileHandler();
    }
    return null; // NullPointException
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
 * AliveSocketHandler
 * @author yaolin
 */
public class AliveHandler implements SocketHandler {
 
  /**
   * @return null
   */
  @Override
  public Object handle(Socket client, Object data) {
    if (data != null) {
      BaseMessage message = JSON.parseObject(data.toString(), BaseMessage.class);
      if (StringUtil.isNotEmpty(message.getFrom())) {
        SocketWrapper wrapper = SocketHolder.get(message.getFrom());
        if (wrapper != null) {
          wrapper.setLastAliveTime(new Date()); // KEEP SOCKET ...
          SocketHolder.put(message.getFrom(), wrapper);
        }
      }
    }
    return null;
  }
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/**
 * ChatHandler
 *
 * @author yaolin
 */
public class ChatHandler implements SocketHandler {
 
  @Override
  public Object handle(Socket client, Object data) {
    if (data != null) {
      ChatMessage message = JSON.parseObject(data.toString(), ChatMessage.class);
 
      if (StringUtil.isNotEmpty(message.getFrom()) && StringUtil.isNotEmpty(message.getTo())) {
        // exist & send
        if (SocketHolder.keySet().contains(message.getFrom())) {
          String owner = message.getFrom();
          message.setOwner(owner); // owner will be display
          if (ConstantValue.TO_ALL.equals(message.getTo())) { // one-to-all
            // TO_ALL TAB will be select;
            message.setFrom(ConstantValue.TO_ALL);
            for (String key : SocketHolder.keySet()) {
              // also send to self
              SocketWrapper wrapper = SocketHolder.get(key);
              if (wrapper != null) {
                SendHelper.send(wrapper.getSocket(), message);
              }
            }
          } else {// one-to-one
            SocketWrapper wrapper = SocketHolder.get(message.getTo());
            if (wrapper != null) {
              // owner = from
              SendHelper.send(wrapper.getSocket(), message);
              // also send to self
              // TO TAB will be select;
              message.setFrom(message.getTo()).setTo(owner);
              SendHelper.send(client, message);
            }
          }
        }
      }
    }
    return null;
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class FileHandler implements SocketHandler {
 
  @Override
  public Object handle(Socket client, Object data) {
    if (client != null) {
      FileMessage message = JSON.parseObject(data.toString(), FileMessage.class);
      if (StringUtil.isNotEmpty(message.getFrom()) && StringUtil.isNotEmpty(message.getTo())) {
        // exist & send
        if (SocketHolder.keySet().contains(message.getFrom())) {
          if (!ConstantValue.TO_ALL.equals(message.getTo())) { // one-to-all
            SocketWrapper wrapper = SocketHolder.get(message.getTo());
            if (wrapper != null) {
              SendHelper.send(wrapper.getSocket(), message);
              try {
                if (client != null && wrapper.getSocket() != null && message.getSize() > 0) {
                  InputStream is = client.getInputStream();
                  OutputStream os = wrapper.getSocket().getOutputStream();
                  int total = 0;
                  while (!client.isClosed() && !wrapper.getSocket().isClosed()) {
                    if (is.available() > 0) {
                      byte[] buff = new byte[ConstantValue.BUFF_SIZE];
                      int len = -1;
                      while (is.available() > 0 && (len = is.read(buff)) != -1) {
                        os.write(buff, 0, len);
                        total += len;
                        LoggerUtil.debug("SEND BUFF [" + len + "]");
                      }
                      os.flush();
                      if (total >= message.getSize()) {
                        LoggerUtil.info("SEND BUFF [OK]");
                        break;
                      }
                    }
                  }
                  // AFTER SEND FILE
                  // SEND SUCCESSFULLY
                  ReturnMessage result = new ReturnMessage().setKey(Key.TIP)
                      .setSuccess(true)
                      .setContent(I18N.INFO_FILE_SEND_SUCCESSFULLY);
                  result.setFrom(message.getTo()).setTo(message.getFrom())
                      .setOwner(ConstantValue.SERVER_NAME);
                  SendHelper.send(client, result);
                  // RECEIVE SUCCESSFULLY
                  result.setContent(I18N.INFO_FILE_RECEIVE_SUCCESSFULLY)
                      .setFrom(message.getFrom())
                      .setTo(message.getTo());
                  SendHelper.send(wrapper.getSocket(), result);
                }
              } catch (Exception e) {
                LoggerUtil.error("Handle file failed !" + e.getMessage(), e);
              }
            }
          }
        }
      }
    }
    return null;
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
 * LoginHandler
 *
 * @author yaolin
 *
 */
public class LoginHandler implements SocketHandler {
 
  private UsrService usrService = new UsrService();
 
  @Override
  public Object handle(Socket client, Object data) {
    ReturnMessage result = new ReturnMessage();
    result.setSuccess(false);
    if (data != null) {
      LoginMessage message = JSON.parseObject(data.toString(), LoginMessage.class);
      if (StringUtil.isNotEmpty(message.getUsername()) && StringUtil.isNotEmpty(message.getPassword())) {
        if (usrService.login(message.getUsername(), message.getPassword()) != null) {
          result.setSuccess(true);
        } else {
          result.setMessage(I18N.INFO_LOGIN_ERROR_DATA);
        }
        result.setFrom(ConstantValue.SERVER_NAME).setTo(message.getUsername());
      } else {
        result.setMessage(I18N.INFO_LOGIN_EMPTY_DATA);
      }
      // AFTER LOGIN
      result.setKey(Key.LOGIN);
      if (result.isSuccess()) { // HOLD SOCKET
        SocketHolder.put(result.getTo(), new SocketWrapper(client, new Date()));
      }
      SendHelper.send(client, result);
      if (result.isSuccess()) { // SEND LIST USER
        ClientListUserDTO dto = new ClientListUserDTO();
        dto.setListUser(SocketHolder.keySet());
        result.setContent(dto).setKey(Key.LISTUSER);
        SendHelper.send(client, result);
      }
    }
    return null;
  }
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class LogoutHandler implements SocketHandler {
 
  @Override
  public Object handle(Socket client, Object data) {
    if (data != null) {
      LogoutMessage message = JSON.parseObject(data.toString(), LogoutMessage.class);
      if (message != null && StringUtil.isNotEmpty(message.getFrom())) {
        SocketWrapper wrapper = SocketHolder.get(message.getFrom());
        Socket socket = wrapper.getSocket();
        if (socket != null) {
          try {
            socket.close();
            socket = null;
          } catch (Exception ignore) {
          }
        }
        SocketHolder.remove(message.getFrom());
      }
    }
    return null;
  }
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class RegisterHandler implements SocketHandler {
 
  private UsrService usrService = new UsrService();
  
  @Override
  public Object handle(Socket client, Object data) {
    ReturnMessage result = new ReturnMessage();
    result.setSuccess(false).setFrom(ConstantValue.SERVER_NAME);
    if (data != null) {
      RegisterMessage message = JSON.parseObject(data.toString(), RegisterMessage.class);
      if (StringUtil.isNotEmpty(message.getUsername()) && StringUtil.isNotEmpty(message.getPassword())) {
        if (usrService.register(message.getUsername(), message.getPassword()) != null) {
          result.setSuccess(true).setContent(I18N.INFO_REGISTER_OK);
        } else {
          result.setMessage(I18N.INFO_REGISTER_CLIENT_EXIST);
        }
      } else {
        result.setMessage(I18N.INFO_REGISTER_EMPTY_DATA);
      }
       
      if (StringUtil.isNotEmpty(message.getUsername())) {
        result.setTo(message.getUsername());
      }
      // AFTER REGISTER
      result.setKey(Key.REGISTER);
      SendHelper.send(client, result);
    }
    return null;
  }
 
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/**
 * Use SendHelper to send ReturnMessage,
 * @see yaolin.chat.server.SocketDispatcher#run()
 * @author yaolin
 */
@Deprecated
public class ReturnHandler implements SocketHandler {
 
  /**
   * @param data ReturnMessage
   */
  @Override
  public Object handle(Socket client, Object data) {
    if (data != null) {
      ReturnMessage message = (ReturnMessage) data;
      if(StringUtil.isNotEmpty(message.getFrom()) && StringUtil.isNotEmpty(message.getTo())) {
        SocketWrapper wrap = SocketHolder.get(message.getTo());
        if (wrap != null) {
          SendHelper.send(wrap.getSocket(), message);
        }
      }
    }
    return null;
  }
 
}

 用戶業(yè)務(wù):

服務(wù)端除了socket之外,還有一點(diǎn)點(diǎn)具體的業(yè)務(wù),那就是用戶的注冊(cè)、登陸等,這里簡(jiǎn)單的列出Usr和UsrService這兩個(gè)類,這些業(yè)務(wù)暫時(shí)沒有怎么實(shí)現(xiàn),我并不打算在這個(gè)程序中引入ORM框架,所以自己寫一套DBUtil(待改善),在這里也一并貼出來。

詳解基于java的Socket聊天程序——服務(wù)端(附demo)

這里只進(jìn)行了簡(jiǎn)單的校驗(yàn),沒有持久化存儲(chǔ)到DB中,下面是Usr和UsrService:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Usr {
 
  private long id;
  private String username;
  private String password;
  public long getId() {
    return id;
  }
  public void setId(long id) {
    this.id = id;
  }
  public String getUsername() {
    return username;
  }
  public void setUsername(String username) {
    this.username = username;
  }
  public String getPassword() {
    return password;
  }
  public void setPassword(String password) {
    this.password = password;
  }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/**
 * // TODO
 * @see yaolin.chat.server.usr.repository.UsrRepository
 * @author yaolin
 *
 */
public class UsrService {
  // TODO db
  private static Map<String,Usr> db = new HashMap<String,Usr>();
  
  public Usr register(String username, String password) {
    if (StringUtil.isEmpty(username) || StringUtil.isEmpty(password)) {
      return null;
    }
    if (db.containsKey(username)) {
      return null; // exist;
    }
    Usr usr = new Usr();
    usr.setUsername(username);
    usr.setPassword(MD5Util.getMD5Code(password));
    db.put(username, usr);
    return usr;
  }
  
  public Usr login(String username, String password) {
    if (StringUtil.isEmpty(username) || StringUtil.isEmpty(password)) {
      return null;
    }
    if (db.containsKey(username)) {
      Usr usr = db.get(username);
      if (MD5Util.getMD5Code(password).equals(usr.getPassword())) {
        return usr;
      }
    }
    return null;
  }
}

 下面是DBUtil工具:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
/**
 * DBUtils // TODO 有待調(diào)整&優(yōu)化!!
 * @author yaolin
 */
public class DBUtil {
  // make connection used repeatedly
  private static final List<Connection> cache = new LinkedList<Connection>();
  private static String url;
  private static String driver;
  private static String user;
  private static String password;
  private static Boolean debug;
 
  static {
    InputStream is = DBUtil.class.getResourceAsStream("/db.properties");
    try {
      Properties p = new Properties();
      p.load(is);
      url = p.getProperty("url");
      driver = p.getProperty("driver");
      user = p.getProperty("user");
      password = p.getProperty("password");
      // just for debug
      try {
        debug = Boolean.valueOf(p.getProperty("debug"));
      } catch (Exception ignore) {
        debug = false;
      }
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      if (is != null) {
        try {
          is.close();
          is = null;
        } catch (Exception ignore) {
        }
      }
    }
  }
 
  public synchronized static Connection getConnection() {
    if (cache.isEmpty()) {
      cache.add(makeConnection());
    }
    Connection conn = null;
    int i = 0;
    try {
      do {
        conn = cache.remove(i);
      } while (conn != null && conn.isClosed() && i < cache.size());
    } catch (Exception ignore) {
    }
 
    try {
      if (conn == null || conn.isClosed()) {
        cache.add(makeConnection());
        conn = cache.remove(0);
      }
      return conn;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
 
  public synchronized static void close(Connection connection) {
    try {
      if (connection != null && !connection.isClosed()) {
        if (debug)
          debug("release connection!");
        cache.add(connection);
      }
    } catch (SQLException ignore) {
    }
  }
 
  public static Object query(String sql, ResultSetMapper mapper, Object... args) {
    if (debug)
      debug(sql);
    Connection conn = getConnection();
    PreparedStatement ps = null;
    ResultSet rs = null;
    Object result = null;
    try {
      ps = conn.prepareStatement(sql);
      int i = 1;
      for (Object object : args) {
        ps.setObject(i++, object);
      }
      rs = ps.executeQuery();
      result = mapper.mapper(rs);
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      try {
        if (rs != null) {
          rs.close();
          rs = null;
        }
        if (ps != null) {
          ps.close();
          ps = null;
        }
      } catch (Exception ignore) {
      }
    }
    close(conn);
    return result;
  }
 
  public static int modify(String sql, Object... args) {
    if (debug)
      debug(sql);
    Connection conn = getConnection();
    PreparedStatement ps = null;
    int row = 0;
    try {
      ps = conn.prepareStatement(sql);
      int i = 1;
      for (Object object : args) {
        ps.setObject(i++, object);
      }
      row = ps.executeUpdate();
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      try {
        if (ps != null) {
          ps.close();
          ps = null;
        }
      } catch (Exception ignore) {
      }
    }
    close(conn);
    return row;
  }
 
  public static int[] batch(List<String> sqls) {
    if (debug)
      debug(sqls.toString());
    Connection conn = getConnection();
    Statement stmt = null;
    int[] row;
    try {
      stmt = conn.createStatement();
      for (String sql : sqls) {
        stmt.addBatch(sql);
      }
      row = stmt.executeBatch();
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      try {
        if (stmt != null) {
          stmt.close();
          stmt = null;
        }
      } catch (Exception ignore) {
      }
    }
    close(conn);
    return row;
  }
 
  public static int[] batch(String sql, PreparedStatementSetter setter) {
    if (debug)
      debug(sql);
    Connection conn = getConnection();
    PreparedStatement ps = null;
    int[] row;
    try {
      ps = conn.prepareStatement(sql);
      setter.setter(ps);
      row = ps.executeBatch();
    } catch (Exception e) {
      throw new RuntimeException(e);
    } finally {
      try {
        if (ps != null) {
          ps.close();
          ps = null;
        }
      } catch (Exception ignore) {
      }
    }
    close(conn);
    return row;
  }
 
  private static Connection makeConnection() {
    try {
      Class.forName(driver).newInstance();
      Connection conn = DriverManager.getConnection(url, user, password);
      if (debug)
        debug("create connection!");
      return conn;
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }
 
  private static void debug(String sqls) {
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    System.out.println(sdf.format(new Date())
        + " DEBUG " + Thread.currentThread().getId()
        + " --- [" + Thread.currentThread().getName() + "] " + "excute sqls : " + sqls);
  }
}
?
1
2
3
4
5
6
7
/**
 * PreparedStatementSetter
 * @author yaolin
 */
public interface PreparedStatementSetter {
  public void setter(PreparedStatement ps);
}
?
1
2
3
4
5
6
7
/**
 * ResultSetMapper
 * @author yaolin
 */
public interface ResultSetMapper {
  public Object mapper(ResultSet rs);
}

源碼下載:demo

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。

原文鏈接:http://www.cnblogs.com/niloay/p/socket-chatserver.html

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 黄片毛片| 91九色麻豆 | 婷综合| 9久热这里只有精品免费 | 手机能看的黄色网站 | 精新精新国产自在现拍 | 日韩毛片在线影视 | 爱福利视频一区 | 青青青国产精品国产精品美女 | 韩国男女做性全过程视频 | 视频久久 | tube4欧美4| 98色花堂永久地址国产精品 | 日本三级在线观看免费 | 男生操女生漫画 | 四色6677最新永久网站 | 亚洲欧美韩国日产综合在线 | 好男人天堂网 | 调教女高中生第3部分 | 香蕉 在线播放 | 久久五月综合婷婷中文云霸高清 | 青久草视频| 久久国产精品人妻中文 | 人与善xuanwen在线400 | 国产精品吹潮香蕉在线观看 | 2019理论韩国理论中文 | 欧美8x8x| japaneseles女同专区 | 1024免费永久福利视频 | ass性强迫rape| 欧美国产日本精品一区二区三区 | 色欲麻豆国产福利精品 | 免费在线看 | 无人在线高清免费看 | 亚洲精品乱码久久久久久蜜桃 | 久久精品AV一区二区无码 | 国产免费资源高清小视频在线观看 | japanhd粗暴video | 奇米久草| 高中生放荡日记高h娜娜 | 国产伦精品一区二区 |