本教學將示範如何使用 Struts 2.0 與 Hibernate 3.2 搭建一個完整的用戶註冊與登入系統。開發環境採用 MyEclipse 6.0、Tomcat 5.5、JDK 1.5 以及 MySQL 5.0。文章將從專案結構規劃、配置檔編寫、實體類設計、DAO 層實作、Action 處理、前端頁面到驗證碼元件,逐步講解完整開發流程。
開發完成後的套件與類別關係圖如下:

在 MyEclipse 中建立名為 LoginSystem 的 Web Project,將 Struts 2.0 和 Hibernate 3.2 所需的所有 Jar 包放入 WebRoot/WEB-INF/lib 目錄下。
在 src 目錄下建立 hibernate.cfg.xml,配置資料庫連線資訊與映射檔:
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"https://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.username">root</property>
<property name="connection.url">jdbc:mysql://localhost:3306/LoginSystem</property>
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.password">root</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="show_sql">true</property>
<!-- POJO 類映射配置 -->
<mapping resource="com/rong/ORM/User.hbm.xml" />
</session-factory>
</hibernate-configuration>
在 com.rong.ORM 套件下建立 User.java 與 User.hbm.xml。
package com.rong.ORM;
public class User {
private int id;
private String name;
private String pwd;
// Getter/Setter 方法
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getPwd() { return pwd; }
public void setPwd(String pwd) { this.pwd = pwd; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
}
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"https://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.rong.ORM.User" table="tb_user">
<id name="id">
<generator class="native"/>
</id>
<property name="name" type="java.lang.String" length="20"/>
<property name="pwd" type="java.lang.String" length="20"/>
</class>
</hibernate-mapping>
利用 Hibernate 的 SchemaExport 自動建立資料表,前提是 MySQL 中已建立 LoginSystem 資料庫。
package tool;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
public class ExportDB {
public static void main(String[] args){
Configuration cfg = new Configuration().configure();
SchemaExport export = new SchemaExport(cfg);
export.create(true, true);
}
}
採用單例模式確保 SessionFactory 僅初始化一次,提供開啟與關閉 Session 的方法。
package com.rong.hibernate;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static String configFile = "/hibernate.cfg.xml";
private static Configuration configuration = new Configuration();
private static SessionFactory sessionFactory = null;
static {
try {
configuration.configure(configFile);
sessionFactory = configuration.buildSessionFactory();
System.out.println("[標記]初始化SessionFactory");
} catch (Exception e) {
System.out.println("[異常]創建SessionFactory時發生異常");
e.printStackTrace();
}
}
public Session getSession() {
Session session = null;
try { session = sessionFactory.openSession(); }
catch (Exception e) { e.printStackTrace(); }
return session;
}
public void closeSession(Session session) {
try { if (session != null) session.close(); }
catch (Exception e) { e.printStackTrace(); }
}
}
定義介面 UserDao 與實作類 UserDaoImpl,封裝新增用戶與登入驗證邏輯。
package com.rong.DAO;
import com.rong.ORM.User;
public interface UserDao {
void add(User user);
int isExist(String name, String password); // -1:用戶不存在 -2:密碼錯誤 >0:登入成功返回ID
}
package com.rong.DAO;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.rong.ORM.User;
import com.rong.hibernate.HibernateUtil;
public class UserDaoImpl implements UserDao {
HibernateUtil util = new HibernateUtil();
public void add(User user) {
Session session = util.getSession();
Transaction ts = null;
try {
ts = session.beginTransaction();
session.save(user);
ts.commit();
} catch (Exception e) { e.printStackTrace(); }
finally { util.closeSession(session); }
}
public int isExist(String name, String password) {
Session session = util.getSession();
try {
Query query = session.createQuery("from User u where u.name = ?");
query.setString(0, name);
List list = query.list();
if (list == null || list.size() == 0) return -1;
Query query2 = session.createQuery("from User u where u.name = ? and u.pwd = ?");
query2.setString(0, name);
query2.setString(1, password);
List list2 = query2.list();
if (list2 == null || list2.size() == 0) return -2;
Iterator it = list.iterator();
User user = (User) it.next();
return user.getId();
} catch (Exception e) { e.printStackTrace(); return 0; }
finally { util.closeSession(session); }
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="https://java.sun.com/xml/ns/javaee"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_2.5.xsd">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>login.jsp</welcome-file>
</welcome-file-list>
</web-app>
使用 Struts 標籤庫,包含帳號、密碼、驗證碼輸入欄位。
<%@ page language="java" pageEncoding="gbk"%>
<%@ taglib prefix="s" uri="/struts-tags" %>
<html><head><title>Login Page</title></head><body>
<p><a href="register.jsp">用戶註冊</a> | 用戶登入 </p>
<s:form action="loginAction" theme="simple">
<table>
<tr><td>帳號</td><td><s:textfield name="name" label="帳號" /></td></tr>
<tr><td>密碼</td><td><s:password name="pwd" label="密碼" /></td></tr>
<tr><td>驗證碼</td><td><s:textfield name="inputCertCode" cssStyle="width:100px"/>
<img src="other/makeCertPic.jsp"></td></tr>
<tr><td><s:submit value="登入" /></td>
<td><s:reset value="取消"/></td></tr>
</table>
</s:form>
<s:fielderror cssStyle="color:red"/>
</body></html>
包含帳號、密碼、確認密碼、驗證碼欄位,表單提交至 registerAction。
<%@ page language="java" pageEncoding="gbk"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html><head><title>Register Page</title></head><body>
<p><a href="login.jsp">用戶登入</a> | 用戶註冊 </p>
<s:form action="registerAction" theme="simple">
<table>
<tr><td>請輸入帳號</td><td><s:textfield name="user.name" label="帳號" /></td></tr>
<tr><td>請輸入密碼</td><td><s:password name="user.pwd" label="密碼" /></td></tr>
<tr><td>請再次輸入密碼</td><td><s:password name="repwd" label="重複密碼" /></td></tr>
<tr><td>請輸入驗證碼</td><td><s:textfield name="inputCertCode" cssStyle="width:100px"/>
<img src="other/makeCertPic.jsp"></td></tr>
<tr><td><s:submit value="註冊" /></td><td><s:reset value="取消"/></td></tr>
</table>
</s:form>
<s:fielderror cssStyle="color:red"/>
</body></html>
將 makeCertPic.jsp 放置於 WebRoot/other 目錄,調用 com.rong.other.makeCertPic Bean 生成圖片並將驗證碼存入 Session。
<%@page contentType="image/jpeg" pageEncoding="gbk"%>
<jsp:useBean id="image" scope="page" class="com.rong.other.makeCertPic" />
<%
String str = image.getCertPic(0,0,response.getOutputStream());
session.setAttribute("certCode", str);
%>
核心類 makeCertPic.java 使用 Java 2D API 繪製干擾線與隨機字元:
package com.rong.other;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.OutputStream;
import java.util.Random;
import javax.imageio.ImageIO;
public class makeCertPic {
private char mapTable[] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m',
'n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9' };
public String getCertPic(int width, int height, OutputStream os) {
if (width <= 0) width = 60;
if (height <= 0) height = 20;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
g.setColor(new Color(0xDCDCDC));
g.fillRect(0, 0, width, height);
g.setColor(Color.black);
g.drawRect(0, 0, width-1, height-1);
String strEnsure = "";
for (int i = 0; i < 4; ++i) {
strEnsure += mapTable[(int)(mapTable.length * Math.random())];
}
g.setFont(new Font("Atlantic Inline", Font.PLAIN, 18));
g.drawString(strEnsure.substring(0,1), 8, 17);
g.drawString(strEnsure.substring(1,2), 20, 15);
g.drawString(strEnsure.substring(2,3), 35, 18);
g.drawString(strEnsure.substring(3,4), 45, 15);
Random rand = new Random();
for (int i = 0; i < 10; i++) {
g.drawOval(rand.nextInt(width), rand.nextInt(height), 1, 1);
}
g.dispose();
try { ImageIO.write(image, "JPEG", os); }
catch (Exception e) { return ""; }
return strEnsure;
}
}
定義登入與註冊 Action 的結果導向。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"https://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="com.rong.action" extends="struts-default">
<action name="loginAction" class="com.rong.action.LoginAction">
<result name="success" type="redirect">/back/index.jsp</result>
<result name="input">/login.jsp</result>
</action>
<action name="registerAction" class="com.rong.action.RegisterAction">
<result name="success" type="redirect">/login.jsp</result>
<result name="input">/register.jsp</result>
</action>
</package>
</struts>
處理登入邏輯與驗證碼校驗,繼承 ActionSupport 並實作 validate() 方法。
package com.rong.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.rong.DAO.UserDao;
import com.rong.DAO.UserDaoImpl;
import com.rong.ORM.User;
public class LoginAction extends ActionSupport {
private UserDao userDao = new UserDaoImpl();
private String name, pwd, inputCertCode;
private int id;
// Getter/Setter 略
@Override
public String execute() throws Exception {
int state = userDao.isExist(name, pwd);
if (state == -1) { addFieldError("name", "用戶名不正確,請先註冊!"); return INPUT; }
else if (state == -2) { addFieldError("pwd", "密碼不正確,請重新輸入!"); return INPUT; }
else if (state > 0) { this.id = state; return SUCCESS; }
else { addFieldError("name", "登入失敗,請聯繫管理員!"); return INPUT; }
}
public void validate() {
if (inputCertCode == null || "".equals(inputCertCode)) {
addFieldError("inputCertCode", "驗證碼不能為空!");
} else {
Map session = ActionContext.getContext().getSession();
String certCode = session.get("certCode").toString();
if (!certCode.equals(inputCertCode)) addFieldError("inputCertCode", "驗證碼不正確!");
}
}
}
處理用戶註冊與表單驗證。
package com.rong.action;
import java.util.Map;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import com.rong.DAO.UserDao;
import com.rong.DAO.UserDaoImpl;
import com.rong.ORM.User;
public class RegisterAction extends ActionSupport {
private UserDao userDao = new UserDaoImpl();
private User user;
private String repwd, inputCertCode;
// Getter/Setter 略
@Override
public String execute() throws Exception {
userDao.add(user);
return SUCCESS;
}
@Override
public void validate() {
// 驗證碼校驗邏輯同 LoginAction
if (inputCertCode == null || "".equals(inputCertCode)) {
addFieldError("inputCertCode", "驗證碼不能為空!");
} else {
Map session = ActionContext.getContext().getSession();
String certCode = session.get("certCode").toString();
if (!certCode.equals(inputCertCode)) addFieldError("inputCertCode", "驗證碼不正確!");
}
}
}
在 Action 同目錄下建立 LoginAction-validation.xml 與 RegisterAction-validation.xml,使用 Struts 內建驗證器進行必填、正則與欄位比對驗證。
<!-- LoginAction-validation.xml 片段 -->
<validators>
<field name="name">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>用戶名不能為空!</message>
</field-validator>
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,8})]]></param>
<message>帳號必須是長度 4-8 的數字或字母!</message>
</field-validator>
</field>
<field name="pwd">
<field-validator type="requiredstring">
<param name="trim">true</param>
<message>密碼不能為空!</message>
</field-validator>
<field-validator type="regex">
<param name="expression"><![CDATA[(\w{4,8})]]></param>
<message>密碼必須長度 4-8 的數字或字母!</message>
</field-validator>
</field>
</validators>
<!-- RegisterAction-validation.xml 片段 -->
<validators>
<field name="user.name"> ... </field>
<field name="user.pwd"> ... </field>
<field name="repwd">
<field-validator type="requiredstring" short-circuit="true">
<message>重複密碼不能為空!</message>
</field-validator>
<field-validator type="fieldexpression">
<param name="expression"><![CDATA[repwd==user.pwd]]></param>
<message>兩次輸入的密碼要一致!</message>
</field-validator>
</field>
</validators>
至此,基於 Struts 2.0 + Hibernate 3.2 的註冊登入系統已開發完成。專案涵蓋了從資料庫配置、實體映射、DAO 封裝、Action 處理、前端表單到驗證碼與驗證框架的完整流程。開發者可依此架構擴展更複雜的業務功能。