本範例示範一個極簡聊天室,功能包含:
架構:Servlet (TalkServlet) → Service Bean (TalkBean) → DBUtil (JDBC 封裝) → MySQL;前端透過 Pushlet JavaScript 客戶端訂閱 /message/world 事件。
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
亮點:executeSql 內建命名參數轉換(:userName → ?),使用 Pattern 解析 SQL,極大提升可讀性。
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); }
}
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; }
}
public class TalkBean {
public Map getUserInfo(String userName, String password) {
List
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);
}
}
}
<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>
test,執行 create table user (id int primary key auto_increment, user_name varchar(50), password varchar(50));DBUtil 連線參數(URL、帳密)webapps,確保 pushlet.jar、mysql-connector-java.jar、commons-* 等依賴在 WEB-INF/libhttps://localhost:8080/專案/talkService.srv此範例雖簡單,但涵蓋了 Java Web 經典分層架構、JDBC 封裝、反射路由、Comet 推播整合等核心技能。適合初學者理解「請求-回應」與「伺服器主動推送」兩種互動模式的差異與協作方式。