자바 기반 Socket 채 팅 프로그램-서버(데모 첨부)

앞 에 쓰기:
어제 블 로그 에 자신 이 시간 을 내 서 쓴Socket 채 팅 프로그램의 초기 디자인 을 기록 했다.그것 은 이 프로그램의 전체적인 디자인 이다.완전 성 을 위해 오늘 서버 의 디자인 을 세분 화하 여 기록 하고 첫 페이지 에 Socket 채 팅 프로그램의 서버 대체 설계 도 를 붙 였 다.다음 과 같다.

기능 설명:
서버 는 주로 두 가지 조작 이 있 습 니 다.하 나 는 클 라 이언 트 를 받 는 socket 을 막 고 응답 처 리 를 하 는 것 입 니 다.다른 하 나 는 클 라 이언 트 의 심장 박동 을 검사 하 는 것 입 니 다.클 라 이언 트 가 한 동안 심장 박동 을 보 내지 않 으 면 이 클 라 이언 트 를 제거 하고 Server 에서 ServerSocket 을 만 든 다음 에 두 개의 스 레 드 풀 을 시작 하여 이 두 가지 일 을 처리 합 니 다(new Fixed ThreadPool,new Scheduled ThreadPool).대응 하 는 처리 클래스 는 각각 SocketDispatcher,SocketSchedule 이다.그 중에서 SocketDispatcher 는 socket 의 서로 다른 요청 에 따라 서로 다른 SocketHandler 에 게 나 누 어 처리 하고 SocketWrapper 는 socket 에 케이스 포장 을 한 층 더 해서 lastAliveTime 으로 socket 의 최신 상호작용 시간 을 기록 하고 SocketHolder 는 현재 서버 와 상호작용 하 는 socket 집합 을 저장한다.
구체 적 인 실현:
[Server.java]
서버 는 서버 의 입구 입 니 다.서버 의 start()방법 으로 ServerSocket 을 시작 한 다음 에 클 라 이언 트 의 요청 을 차단 하고 SocketDispatcher 에 게 전달 합 니 다.SocketDispatcher 는 new Fixed Thread 형식의 스 레 드 풀 에서 시작 합 니 다.연결 수가 최대 데 이 터 를 초과 할 때 정렬 처 리 됩 니 다.scheduleAtFixed Rate 를 사용 하여 Socket Schedule 을 시작 하여 클 라 이언 트 의 심장 박동 패 키 지 를 정기 적 으로 순환 하여 감청 합 니 다.이 두 가지 유형 은 모두 Runnable 인 터 페 이 스 를 실 현 했 습 니 다.다음은 서버 의 코드 를 드 립 니 다.

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;

/**
 *    
 * @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]
서버 는 서버 의 입구 일 뿐 이 고 지휘 센터 입 니 다.SocketDispatcher 야 말로 서버 의 지휘 센터 입 니 다.클 라 이언 트 의 서로 다른 메시지 유형 에 대한 요 구 를 배포 하고 서로 다른 SocketHandler 로 하여 금 대응 하 는 메시지 요 구 를 처리 하 게 합 니 다.여기 서 서버 와 클 라 이언 트 의 메시지 상호작용 은 모두 JSON 데이터 로 모든 메시지 류 는 BaseMessage 를 계승 합 니 다.따라서 수신 한 데 이 터 를 BaseMessage 형식 으로 변환 하고 그 유형 을 판단 합 니 다.(데이터 형식 모듈 은 common 모듈 에 속 합 니 다)메시지 형식 이 파일 형식 일 때 수면 설정 이 실 행 된 간격 을 두 어야 FileHandler 가 지정 한 클 라 이언 트 에 파일 흐름 을 읽 고 다시 보 낼 수 있 습 니 다.다음 순환 에서 메시지 유형 에 대한 판단 에 바로 들 어가 지 않 습 니 다.

/**
 * 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]
서버 와 직접적인 관 계 를 가 진 또 다른 클래스(구성 요소)는 SocketSchedule 입 니 다.SocketSchedule 은 클 라 이언 트 의 최신 서버 와 의 상호작용 시간 이 시스템 설정 이 허용 하 는 최대 시간 을 초과 하 는 지 확인 합 니 다.초과 하면 이 클 라 이언 트 socket 을 서비스 에서 제거 합 니 다.그렇지 않 으 면 클 라 이언 트 의 최신 서버 와 의 상호작용 시간 을 업데이트 합 니 다.다음은 구체 적 인 실현 이다.

/**
 * 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()은 시간 에 대한 간단 한 판단 일 뿐 정말 의미 있 는 것 은 SocketHolder 와 SocketWrapper 이 고 SocketWrapper 는 socket 에 케이스 포장 을 한 층 더 했 습 니 다.SocketHolder 는 현재 유효 시간 동안 서버 와 상호작용 을 하 는 모든 클 라 이언 트 를 저장 합 니 다.SocketHolder 는 클 라 이언 트 의 유일한 표지(여기 서 사용자 이름 사용)로 KEY 로 클 라 이언 트 가 있 는 socket 을 VALUE 의 키 쌍 으로 저장 합 니 다.그 중에서 SocketHolder\#flushClient Status()의 처리 논 리 는 다른 클 라 이언 트 에 게 현재 클 라 이언 트 의 온라인/오프라인 상 태 를 알 리 는 데 사 용 됩 니 다.다음은 이 두 가지 구체 적 인 실현 을 보 여 줍 니 다.

/**
 * 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;
  }
}


/**
 * 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 로 하여 금 대응 하 는 메시지 요청 을 처리 하 게 합 니 다.SocketHandler 의 디자인 은 사실은 간단 한 공장 구성 요소 입 니 다.

다음은 이 코드 를 드 리 고 편폭 을 줄 이기 위해 모든 Handler 가 구현 한 코드 를 걷 습 니 다.

/**
 * SocketHandler
 * @author yaolin
 */
public interface SocketHandler {
  /**
   * Handle Client Socket
   */
  public Object handle(Socket client,Object data);
}

/**
 * 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
  }
}


/**
 * 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;
  }

}


/**
 * 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;
  }
}


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;
  }
}


/**
 * 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;
  }

}


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;
  }

}


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;
  }

}

 


/**
 * 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;
  }

}

 사용자 업무:
서버 는 socket 을 제외 하고 약간의 구체 적 인 업무 가 있 습 니 다.그것 이 바로 사용자 의 등록,로그 인 등 입 니 다.여 기 는 Usr 와 UsrService 라 는 두 가지 유형 을 간단하게 보 여 줍 니 다.이런 업 무 는 아직 실현 되 지 않 았 습 니 다.저 는 이 프로그램 에 ORM 프레임 워 크 를 도입 할 생각 이 없 기 때문에 스스로 DBUtil(개선 해 야 함)을 작성 하고 여기에 도 함께 붙 입 니 다.

DB 에 영구적 으로 저장 되 지 않 은 간단 한 검사 만 진행 되 었 습 니 다.다음은 Usr 와 UsrService 입 니 다.

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;
  }
}


/**
 * // 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 도구 입 니 다.

 /**
 * DBUtils // TODO     &  !!
 * @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);
  }
}


/**
 * PreparedStatementSetter
 * @author yaolin
 */
public interface PreparedStatementSetter {
  public void setter(PreparedStatement ps);
}


/**
 * ResultSetMapper
 * @author yaolin
 */
public interface ResultSetMapper {
  public Object mapper(ResultSet rs);
}
원본 다운로드:demo
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기