Struts2LoginDemoWEB-INF/libStruts2LoginDemo
├── src
│ └── com.example.struts2
│ ├── action
│ │ └── LoginAction.java
│ └── model
│ └── User.java
├── WebRoot
│ ├── WEB-INF
│ │ ├── lib/ # Struts2 依賴 JAR
│ │ ├── struts.xml # 核心配置
│ │ └── web.xml # Filter 配置
│ ├── login.jsp # 登錄頁
│ ├── success.jsp # 成功頁
│ └── error.jsp # 失敗頁
└── build/ # 編譯輸出
package com.example.struts2.model;
public class User {
private String username;
private String password;
// Getter/Setter
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; }
}
package com.example.struts2.action;
import com.example.struts2.model.User;
import com.opensymphony.xwork2.ActionSupport;
public class LoginAction extends ActionSupport {
private User user = new User(); // 模型驅動或屬性驅動
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
@Override
public String execute() throws Exception {
String u = user.getUsername();
String p = user.getPassword();
// 模擬業務驗證 (實際調用 Service/DAO)
if ("admin".equals(u) && "123456".equals(p)) {
return SUCCESS; // 返回 "success" 字符串
} else {
addFieldError("user.username", "用戶名或密碼錯誤");
return ERROR; // 返回 "error" 字符串
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
"https://struts.apache.org/dtds/struts-2.5.dtd">
<struts>
<!-- 常量配置 -->
<constant name="struts.devMode" value="true"/>
<constant name="struts.ui.theme" value="simple"/>
<constant name="struts.i18n.encoding" value="UTF-8"/>
<package name="default" namespace="/" extends="struts-default">
<action name="login" class="com.example.struts2.action.LoginAction">
<result name="success">/success.jsp</result>
<result name="error">/login.jsp</result> <!-- 失敗返回登錄頁 -->
<result name="input">/login.jsp</result> <!-- 驗證失敗返回登錄頁 -->
</action>
</package>
</struts>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://xmlns.jcp.org/xml/ns/javaee" version="3.1">
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</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>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<title>用戶登錄 - Struts2 Demo</title>
<style>
body { font-family: Arial; background: #f5f5f5; display: flex; justify-content: center; padding-top: 100px; margin: 0; }
.login-box { background: white; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); width: 320px; }
h2 { text-align: center; color: #333; margin-bottom: 20px; }
.form-group { margin-bottom: 15px; }
label { display: block; margin-bottom: 5px; color: #666; }
input[type="text"], input[type="password"] { width: 100%; padding: 10px; border: 1px solid #ddd; border-radius: 4px; box-sizing: border-box; }
button { width: 100%; padding: 12px; background: #007bff; color: white; border: none; border-radius: 4px; font-size: 16px; cursor: pointer; }
button:hover { background: #0056b3; }
.error { color: #dc3545; font-size: 14px; margin-top: 10px; text-align: center; }
.field-error { color: #dc3545; font-size: 12px; margin-top: 3px; }
</style>
</head>
<body>
<div class="login-box">
<h2>用戶登錄</h2>
<s:form action="login" method="post" theme="simple">
<div class="form-group">
<label>用戶名</label>
<s:textfield name="user.username" label="用戶名" cssClass="form-control"/>
<s:fielderror fieldName="user.username" cssClass="field-error"/>
</div>
<div class="form-group">
<label>密碼</label>
<s:password name="user.password" label="密碼" cssClass="form-control"/>
</div>
<button type="submit">登錄</button>
</s:form>
<s:if test="hasActionErrors()">
<div class="error"><s:actionerror/></div>
</s:if>
</div>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head><title>登錄成功</title></head>
<body style="text-align:center; padding-top:100px; font-family:Arial;">
<h1 style="color:#28a745;">登錄成功!</h1>
<p>歡迎,<s:property value="user.username"/>!</p>
<p><a href="login.jsp">返回登錄頁</a></p>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" %>
<!DOCTYPE html>
<html><head><title>登錄失敗</title></head>
<body style="text-align:center; padding-top:100px;">
<h1 style="color:#dc3545;">登錄失敗</h1>
<p>用戶名或密碼不正確</p>
<a href="login.jsp">重新登錄</a>
</body>
</html>
https://localhost:8080/Struts2LoginDemo/admin,密碼 123456 → 顯示成功頁public class LoginAction extends ActionSupport implements ModelDriven<User> {
private User user = new User();
@Override public User getModel() { return user; }
// JSP 中直接用 name="username" 而非 name="user.username"
}
<!-- LoginAction-validation.xml -->
<!DOCTYPE validators PUBLIC "-//OpenSymphony Group//XWork Validator 1.0.2//EN"
"https://www.opensymphony.com/xwork/xwork-validator-1.0.2.dtd">
<validators>
<field name="user.username">
<field-validator type="requiredstring">
<message>用戶名不能為空</message>
</field-validator>
</field>
<field name="user.password">
<field-validator type="requiredstring">
<message>密碼不能為空</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">6</param>
<message>密碼長度至少 6 位</message>
</field-validator>
</field>
</validators>
# global.properties
login.title=用戶登錄
username.label=用戶名
password.label=密碼
login.button=登錄
error.invalid=用戶名或密碼錯誤
# global_en_US.properties
login.title=User Login
username.label=Username
password.label=Password
login.button=Login
error.invalid=Invalid username or password
<!-- JSP 使用 -->
<s:text name="login.title"/>
<s:textfield name="user.username" key="username.label"/>
<package name="default" namespace="/" extends="struts-default">
<interceptors>
<interceptor-stack name="myStack">
<interceptor-ref name="defaultStack">
<param name="validation.excludeMethods">input,back,cancel,browse</param>
</interceptor-ref>
</interceptor-stack>
</interceptors>
<default-interceptor-ref name="myStack"/>
<action ...>...</action>
</package>
<!-- applicationContext.xml -->
<bean id="loginAction" class="com.example.struts2.action.LoginAction" scope="prototype">
<property name="userService" ref="userService"/>
</bean>
<!-- struts.xml -->
<constant name="struts.objectFactory" value="spring"/>
<action name="login" class="loginAction">...</action>
| 現象 | 原因 | 解決 |
|---|---|---|
| 404: /login.action | struts.xml 未加載、namespace/action 名不匹配、Filter 未攔截 | 檢查 web.xml filter-mapping、struts.xml package namespace、action name |
| ClassNotFound: StrutsPrepareAndExecuteFilter | struts2-core JAR 缺失或版本衝突 | MyEclipse Add Capabilities 重新添加、檢查 WEB-INF/lib |
| OGNL 表達式報錯 | 屬性名不匹配、Getter/Setter 缺失、類型轉換失敗 | 檢查 Action 屬性名、JSP name 屬性、添加類型轉換器 |
| 驗證不生效 | validation.xml 命名不規範、未繼承 defaultStack、devMode=false | 文件名 ActionClass-validation.xml、確保攔截器棧包含 validation |
| 中文亂碼 | 編碼未統一 | struts.i18n.encoding=UTF-8、JSP pageEncoding、Tomcat URIEncoding |
Struts2 基於「Filter + 攔截器鏈 + Action + Result」架構,通過 OGNL 表達式實現數據綁定、類型轉換、驗證。本教程展示了從項目創建、核心配置、Action 開發、頁面實現到運行驗證的完整流程,並提供了模型驅動、驗證、國際化、Spring 整合等進階方向。掌握 Struts2 核心流程與配置細節,是維護老項目、理解 MVC 演進歷史的重要基礎。