首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java + Pushlet + Bootstrap 實作簡易聊天室:從資料庫到即時推播的完整範例

     編輯:Java 相關知識

專案概覽

本範例示範一個極簡聊天室,功能包含:

  1. 使用者註冊 / 登入(資料庫帳密驗證,密碼 MD5 儲存)
  2. 即時訊息廣播(基於 Pushlet Comet 長連線技術)
  3. 前端採 Bootstrap 快速構建響應式介面

架構:Servlet (TalkServlet) → Service Bean (TalkBean) → DBUtil (JDBC 封裝) → MySQL;前端透過 Pushlet JavaScript 客戶端訂閱 /message/world 事件。

核心模組程式碼

1. DBUtil:JDBC 通用封裝(支援命名參數、自動資源關閉)

public class DBUtil {
    private static DataSource dataSource;

    static {
        MysqlDataSource mds = new MysqlDataSource();
        mds.setURL("jdbc:mysql://localhost:3306/test");
        mds.setUser("test");
        mds.setPassword("123456");
        mds.setCharacterEncoding("utf8");
        dataSource = mds;
    }

    public static Connection getConnection() throws SQLException {
        return dataSource.getConnection();
    }

    public static void close(Connection c, Statement s, ResultSet rs) { ... }

    // 通用 SQL 執行,支援 ? 與 :param 兩種參數風格
    public static Object executeSql(Object sql, Object... params) throws SQLException { ... }

    // 便利方法
    public static List> select(Object sql, Object... params) throws SQLException { ... }
    public static int update(Object sql, Object... params) throws SQLException { ... }
    public static int insert(Object sql, Object... params) throws SQLException { return update(sql, params); }
    public static int delete(Object sql, Object... params) throws SQLException { return update(sql, params); }
}

亮點:executeSql 內建命名參數轉換(:userName → ?),使用 Pattern 解析 SQL,極大提升可讀性。

2. WebServlet:基礎控制器(路由、編碼、視圖轉發、參數綁定)

public class WebServlet extends HttpServlet {
    protected HttpServletRequest request;
    protected HttpServletResponse response;
    protected Map cfgParams = new HashMap<>();

    @Override public void init(ServletConfig config) { ... }  // 注入 Bean、讀取初始化參數
    @Override public void service(HttpServletRequest req, HttpServletResponse resp) {
        this.request = req; this.response = resp;
        // 設定編碼、路由到 action 方法(透過反射 invoke)
        String action = get(routeParam, "initPage");
        getClass().getMethod(action).invoke(this);
    }
    protected void show(String jsp) { ... }      // RequestDispatcher forward
    protected void print(String str) { ... }     // 直接輸出回應
    protected String get(String name, String def) { ... }  // 取參數含預設值
    protected void put(String name, Object value) { request.setAttribute(name, value); }
}

3. Sql 枚舉:SQL 语句集中管理

public enum Sql {
    GET_USERINFO("select id,user_name,password from user where user_name=:userName and password=md5(:password)"),
    SAVE_USER("insert into user(user_name,password) values(:userName,md5(:password))");
    private final String value;
    Sql(String v) { this.value = v; }
    public String getValue() { return value; }
    @Override public String toString() { return value; }
}

4. TalkBean:業務邏輯層

public class TalkBean {
    public Map getUserInfo(String userName, String password) {
        List> list = DBUtil.select(Sql.GET_USERINFO, 
            new HashMap<>() {{ put("userName", userName); put("password", password); }});
        return (list != null && list.size() == 1) ? list.get(0) : null;
    }
    public boolean saveUser(String userName, String password) {
        return DBUtil.insert(Sql.SAVE_USER, 
            new HashMap<>() {{ put("userName", userName); put("password", password); }}) == 1;
    }
}

5. TalkServlet:聊天室核心控制器

public class TalkServlet extends WebServlet {
    public TalkBean talkBean;  // 由 WebServlet.init() 透過反射注入

    @Override public void initPage() {
        if (request.getSession().getAttribute("userInfo") != null) talkPage();
        else loginPage();
    }
    public void loginPage() { show("login.jsp"); }
    public void regPage() { show("reg.jsp"); }

    public void login() throws IOException {
        String u = get("userName",""), p = get("password","");
        if (!u.isEmpty() && !p.isEmpty()) {
            Map info = talkBean.getUserInfo(u, p);
            if (info != null) {
                request.getSession().setAttribute("userInfo", info);
                response.sendRedirect("./talkService.srv?action=talkPage");
                return;
            }
        }
        show("login.jsp");
    }

    public void reg() throws IOException {
        String u = get("userName",""), p = get("password",""), pc = get("passConfirm","");
        if (!u.isEmpty() && !p.isEmpty() && p.equals(pc) && talkBean.saveUser(u, p)) {
            response.sendRedirect("./talkService.srv?action=loginPage");
            return;
        }
        show("reg.jsp");
    }

    public void talkPage() {
        Map info = (Map) request.getSession().getAttribute("userInfo");
        if (info != null) { put("userName", info.get("user_name")); show("talk.jsp"); }
        else show("login.jsp");
    }

    // 發送訊息:透過 Pushlet Dispatcher 多播事件
    public void sendMsg() throws UnsupportedEncodingException {
        String msg = get("message","");
        if (!msg.isEmpty()) {
            Event event = Event.createDataEvent("/message/world");
            Map info = (Map) request.getSession().getAttribute("userInfo");
            if (info != null) 
                event.setField("userName", new String(info.get("user_name").toString().getBytes("utf-8"), "iso-8859-1"));
            event.setField("message", new String(msg.getBytes("utf-8"), "iso-8859-1"));
            Dispatcher.getInstance().multicast(event);
        }
    }
}

前端關鍵點(talk.jsp 片段)

<script src="pushlet.js"></script>
<script>
  PL._init();
  PL.joinListen('/message/world');  // 訂閱頻道
  PL.onData = function(event) {
    var msg = event.get('message');
    var user = event.get('userName');
    $('#msgList').append('<div><strong>' + user + '</strong>: ' + msg + '</div>');
  };
  function send() {
    var txt = $('#msgInput').val();
    if (txt) $.post('talkService.srv?action=sendMsg', {message: txt});
  }
</script>

部署與執行步驟

  1. 建立 MySQL 資料庫 test,執行 create table user (id int primary key auto_increment, user_name varchar(50), password varchar(50));
  2. 修改 DBUtil 連線參數(URL、帳密)
  3. 專案結構放入 Tomcat webapps,確保 pushlet.jar、mysql-connector-java.jar、commons-* 等依賴在 WEB-INF/lib
  4. 啟動 Tomcat,瀏覽 https://localhost:8080/專案/talkService.srv

擴充方向建議

  • 引入 BCrypt/Argon2 取代 MD5 加密密碼
  • 加入 Session 活躍檢測、線上用戶列表
  • 前端改用 WebSocket (JSR-356 / Spring WebSocket) 取代 Pushlet,支援雙向通訊與更佳相容性
  • 訊息持久化、離線推播、群組/私聊功能

結語

此範例雖簡單,但涵蓋了 Java Web 經典分層架構、JDBC 封裝、反射路由、Comet 推播整合等核心技能。適合初學者理解「請求-回應」與「伺服器主動推送」兩種互動模式的差異與協作方式。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved