diff --git a/web/WEB-INF/classes/com/demo/action/HelloAction.java b/web/WEB-INF/classes/com/demo/action/HelloAction.java new file mode 100644 index 0000000..2e805f8 --- /dev/null +++ b/web/WEB-INF/classes/com/demo/action/HelloAction.java @@ -0,0 +1,34 @@ +package com.demo.action; + +import com.opensymphony.xwork2.ActionSupport; + +/** + * Hello World 示例 Action + * 展示 Struts2 最基础的 Action 写法 + * + * ActionSupport 提供了: + * - validate() 方法用于表单验证 + * - getText() 方法用于国际化 + * - addActionError()/addFieldError() 用于错误消息 + */ +public class HelloAction extends ActionSupport { + + private String name; + private String message; + + @Override + public String execute() throws Exception { + // 业务逻辑 + if (name == null || name.trim().isEmpty()) { + name = "World"; + } + message = "Hello, " + name + "! 欢迎学习 Struts2!"; + return SUCCESS; + } + + // Getter/Setter (Struts2 需要这些来获取/设置参数) + public String getName() { return name; } + public void setName(String name) { this.name = name; } + public String getMessage() { return message; } + public void setMessage(String message) { this.message = message; } +} \ No newline at end of file diff --git a/web/WEB-INF/classes/com/demo/action/LoginAction.java b/web/WEB-INF/classes/com/demo/action/LoginAction.java new file mode 100644 index 0000000..4822b92 --- /dev/null +++ b/web/WEB-INF/classes/com/demo/action/LoginAction.java @@ -0,0 +1,47 @@ +package com.demo.action; + +import com.opensymphony.xwork2.ActionSupport; + +/** + * 用户登录 Action + * 展示: + * - 表单参数接收 + * - 数据验证 + * - Session 使用 + * - 返回不同结果 + */ +public class LoginAction extends ActionSupport { + + private String username; + private String password; + + @Override + public String execute() throws Exception { + // 模拟登录验证 + if ("admin".equals(username) && "123456".equals(password)) { + // 登录成功,设置 session + return SUCCESS; + } else if (username != null && !username.isEmpty()) { + // 登录失败 + addActionError("用户名或密码错误!"); + return INPUT; + } + return INPUT; + } + + // 表单验证 + @Override + public void validate() { + if (username == null || username.trim().length() < 3) { + addFieldError("username", "用户名至少3个字符"); + } + if (password == null || password.length() < 6) { + addFieldError("password", "密码至少6个字符"); + } + } + + 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; } +} \ No newline at end of file diff --git a/web/WEB-INF/classes/com/demo/model/User.java b/web/WEB-INF/classes/com/demo/model/User.java new file mode 100644 index 0000000..1d30de2 --- /dev/null +++ b/web/WEB-INF/classes/com/demo/model/User.java @@ -0,0 +1,30 @@ +package com.demo.model; + +/** + * 用户模型 + * 展示 Struts2 的 ModelDriven 和 Bean 封装 + */ +public class User { + private Long id; + private String username; + private String email; + private String phone; + + public User() {} + + public User(Long id, String username, String email) { + this.id = id; + this.username = username; + this.email = email; + } + + // Getters and Setters + 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 getEmail() { return email; } + public void setEmail(String email) { this.email = email; } + public String getPhone() { return phone; } + public void setPhone(String phone) { this.phone = phone; } +} \ No newline at end of file diff --git a/web/WEB-INF/classes/struts.xml b/web/WEB-INF/classes/struts.xml new file mode 100644 index 0000000..d64c786 --- /dev/null +++ b/web/WEB-INF/classes/struts.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + /index.jsp + + + + + /hello.jsp + + + + + /user/success.jsp + /user/login.jsp + + + + + /user/success.jsp + /user/form.jsp + + + + + /upload/success.jsp + /upload/index.jsp + + + + + + + + + + /validation/success.jsp + /validation/form.jsp + + + + + + + + + + + + \ No newline at end of file diff --git a/web/WEB-INF/web.xml b/web/WEB-INF/web.xml index 17f74e2..958916e 100644 --- a/web/WEB-INF/web.xml +++ b/web/WEB-INF/web.xml @@ -1,11 +1,34 @@ - + + + Struts2 学习 Demo + + struts2 org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter + struts2 /* - + + + index.jsp + + + + + 404 + /error/404.jsp + + + 500 + /error/500.jsp + + \ No newline at end of file diff --git a/web/demo/ajax/index.jsp b/web/demo/ajax/index.jsp new file mode 100644 index 0000000..ef9a9d8 --- /dev/null +++ b/web/demo/ajax/index.jsp @@ -0,0 +1,101 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + AJAX + JSON - Struts2 学习 + + + +
+ +
+

⚡ AJAX + JSON

+ +

1. JSON 结果类型

+
+

使用 struts2-json-plugin 实现 AJAX 返回 JSON

+
// struts.xml 配置
+<action name="getUser" class="com.demo.UserAction">
+    <result type="json">
+        <!-- 可选: 只包含指定属性 -->
+        <param name="includeProperties">user\..*,success</param>
+    </result>
+</action>
+
+ +

2. Action 示例

+
+
public class UserAction extends ActionSupport {
+    
+    private User user;
+    private boolean success;
+    private String message;
+    
+    // getter 是必须的,JSON 插件只序列化有 getter 的属性
+    public User getUser() { return user; }
+    public boolean isSuccess() { return success; }
+    public String getMessage() { return message; }
+    
+    public String getData() {
+        user = new User("张三", "zhangsan@email.com");
+        success = true;
+        message = "获取成功";
+        return SUCCESS;
+    }
+}
+
+ +

3. 前端 AJAX 调用

+
+
// 原生 fetch
+fetch('/getUser')
+    .then(r => r.json())
+    .then(data => {
+        console.log(data.user);
+        console.log(data.success);
+    });
+
+// jQuery
+$.getJSON('/getUser', function(data) {
+    $('#username').text(data.user.username);
+});
+
+ +

4. 完整示例:实时搜索

+
+
// HTML
+<input type="text" id="keyword" onkeyup="search(this.value)"/>
+<div id="results"></div>
+
+// JS
+function search(keyword) {
+    $.getJSON('/search', {keyword: keyword}, function(data) {
+        $('#results').empty();
+        data.results.forEach(function(item) {
+            $('#results').append('<div>' + item.name + '</div>');
+        });
+    });
+}
+
+ + 下一节:拦截器 → +
+
+ + \ No newline at end of file diff --git a/web/demo/hello/index.jsp b/web/demo/hello/index.jsp new file mode 100644 index 0000000..966aa76 --- /dev/null +++ b/web/demo/hello/index.jsp @@ -0,0 +1,168 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + + Hello World - Struts2 学习 + + + +
+ + +
+

👋 Hello World - 第一个 Struts2 应用

+ +
+ 📝 本节要点: 创建最简单的 Struts2 应用,掌握 Action 编写和 struts.xml 配置 +
+ +

1. 项目结构

+
+webapp/
+├── WEB-INF/
+│   ├── web.xml
+│   └── lib/
+│       └── struts2-core.jar
+├── struts.xml          ← Action 配置
+├── index.jsp
+└── hello.jsp           ← 结果页面
+ +

2. web.xml 配置

+
+
<?xml version="1.0" encoding="UTF-8"?>
+<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee">
+    
+    <!-- Struts2 核心过滤器 -->
+    <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>
+    
+</web-app>
+
+ +

3. struts.xml 配置

+
+
<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE struts PUBLIC
+    "-//Apache Software Foundation//DTD Struts Configuration 2.5//EN"
+    "http://struts.apache.org/dtds/struts-2.5.dtd">
+
+<struts>
+    <!-- 开发模式 -->
+    <constant name="struts.devMode" value="true"/>
+    
+    <!-- 定义包 -->
+    <package name="default" namespace="/" extends="struts-default">
+        
+        <!-- Action 配置 -->
+        <action name="hello" class="com.demo.HelloAction">
+            <result>/hello.jsp</result>
+        </action>
+        
+    </package>
+</struts>
+
+ +

4. HelloAction.java

+
+
package com.demo;
+
+import com.opensymphony.xwork2.ActionSupport;
+
+/**
+ * 第一个 Struts2 Action
+ * 继承 ActionSupport 可以获得验证、国际化的能力
+ */
+public class HelloAction extends ActionSupport {
+    
+    // 接收参数
+    private String name;
+    
+    // 返回给页面的数据
+    private String message;
+    
+    /**
+     * 执行方法,默认调用
+     */
+    @Override
+    public String execute() throws Exception {
+        if (name == null || name.trim().isEmpty()) {
+            name = "Struts2 学习者";
+        }
+        message = "你好, " + name + "! 欢迎学习 Struts2!";
+        return SUCCESS;  // 返回 "success"
+    }
+    
+    // Getter/Setter 必须提供,Struts2 通过反射注入参数
+    public String getName() { return name; }
+    public void setName(String name) { this.name = name; }
+    
+    public String getMessage() { return message; }
+    public void setMessage(String message) { this.message = message; }
+}
+
+ +

5. hello.jsp 结果页面

+
+
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
+<%@ taglib prefix="s" uri="/struts-tags" %>
+<!DOCTYPE html>
+<html>
+<body>
+    <!-- 使用 Struts2 标签获取 Action 返回的值 -->
+    <h1><s:property value="message"/></h1>
+</body>
+</html>
+
+ +

6. 访问方式

+
+

启动应用后,访问:

+ http://localhost:8080/hello - 默认执行
+ http://localhost:8080/hello?name=张三 - 传递参数 +
+ +

执行流程图

+
+
+浏览器请求 → Struts2 Filter → ActionProxy → HelloAction.execute()
+    → 返回 "success" → 配置的 result → hello.jsp → 浏览器
+
+ +
+ 下一节:表单验证 → + ← 返回首页 +
+
+
+ + \ No newline at end of file diff --git a/web/demo/model/index.jsp b/web/demo/model/index.jsp new file mode 100644 index 0000000..ebb30eb --- /dev/null +++ b/web/demo/model/index.jsp @@ -0,0 +1,173 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + + 数据封装 - Struts2 学习 + + + +
+ + +
+

📦 数据封装 - 属性驱动 vs 模型驱动

+ +
+ 📝 本节要点: 掌握 Struts2 两种数据封装方式,将请求参数封装到 Java 对象 +
+ +

1. 两种封装方式对比

+
+ + + + + + + + + + + + + + + + +
方式实现适用场景
属性驱动Action 中定义属性 + getter/setter简单场景,属性较少
模型驱动实现 ModelDriven 接口复杂对象,表单字段多
+
+ +

2. 方式一:属性驱动 (Property Driven)

+ +

2.1 基本属性封装

+
+
/**
+ * 直接在 Action 中定义属性
+ * 表单: <input name="username"> 会自动调用 setUsername()
+ */
+public class UserAction extends ActionSupport {
+    
+    // Struts2 自动调用 setter 注入参数
+    private String username;
+    private String email;
+    private Integer age;
+    
+    @Override
+    public String execute() {
+        System.out.println(username + " - " + email + " - " + age);
+        return SUCCESS;
+    }
+    
+    // 必须提供 setter 和 getter
+    public String getUsername() { return username; }
+    public void setUsername(String username) { this.username = username; }
+    
+    public String getEmail() { return email; }
+    public void setEmail(String email) { this.email = email; }
+    
+    public Integer getAge() { return age; }
+    public void setAge(Integer age) { this.age = age; }
+}
+
+ +

2.2 复杂属性 (嵌套对象)

+
+

表单中的 user.username 会自动调用 setUser(用户对象).setUsername()

+
// Action
+private User user;  // 包含 username, email 属性的对象
+
+// 表单
+<input name="user.username"/>
+<input name="user.email"/>
+
+ +

3. 方式二:模型驱动 (ModelDriven)

+
+ 💡 推荐: 对于复杂表单,使用模型驱动更清晰,Action 和 Model 分离 +
+ +
+
import com.opensymphony.xwork2.ModelDriven;
+
+/**
+ * 实现 ModelDriven 接口
+ * 需要:
+ * 1. 实现 getModel() 方法
+ * 2. 泛型指定模型类型
+ */
+public class UserAction extends ActionSupport implements ModelDriven<User> {
+    
+    // 模型对象
+    private User user = new User();
+    
+    /**
+     * 返回模型对象
+     * Struts2 会把参数注入到返回的对象中
+     */
+    @Override
+    public User getModel() {
+        return user;
+    }
+    
+    @Override
+    public String execute() {
+        // 直接使用 user 对象
+        System.out.println(user.getUsername());
+        return SUCCESS;
+    }
+}
+
+ +

4. List/Map 属性封装

+
+
// Action - 接收 List
+private List<User> users;
+public void setUsers(List<User> users) { this.users = users; }
+public List<User> getUsers() { return users; }
+
+// 页面表单 - users[0].username, users[1].username
+<input name="users[0].username" value="张三"/>
+<input name="users[1].username" value="李四"/>
+
+// Action - 接收 Map
+private Map<String, User> userMap;
+<input name="userMap['one'].username"/>
+
+ +

5. 封装流程图

+
+
+请求参数 → Action  setter 方法 → 属性赋值
+                ↓
+      实现 ModelDriven → getModel() → 模型对象赋值
+                ↓
+             值栈 (Value Stack)
+
+ +
+ 下一节:文件上传 → + ← 返回首页 +
+
+
+ + \ No newline at end of file diff --git a/web/demo/upload/index.jsp b/web/demo/upload/index.jsp new file mode 100644 index 0000000..a32e483 --- /dev/null +++ b/web/demo/upload/index.jsp @@ -0,0 +1,102 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + 文件上传 - Struts2 学习 + + + +
+ +
+

📁 文件上传

+ +

1. 单文件上传

+
+
// Action
+public class UploadAction extends ActionSupport {
+    
+    // 文件对象
+    private File upload;
+    
+    // 文件名 (格式: 属性名FileName)
+    private String uploadFileName;
+    
+    // 文件类型 (格式: 属性名ContentType)
+    private String uploadContentType;
+    
+    @Override
+    public String execute() throws Exception {
+        // 保存文件
+        String path = ServletActionContext.getServletContext()
+            .getRealPath("/upload");
+        new File(path, uploadFileName).createNewFile();
+        
+        // 复制文件
+        FileUtils.copyFile(upload, new File(path, uploadFileName));
+        
+        return SUCCESS;
+    }
+    
+    // getter/setter
+    public File getUpload() { return upload; }
+    public void setUpload(File upload) { this.upload = upload; }
+    public String getUploadFileName() { return uploadFileName; }
+    public void setUploadFileName(String uploadFileName) { this.uploadFileName = uploadFileName; }
+    public String getUploadContentType() { return uploadContentType; }
+    public void setUploadContentType(String uploadContentType) { this.uploadContentType = uploadContentType; }
+}
+
+ +

2. JSP 表单

+
+
<%@ taglib prefix="s" uri="/struts-tags" %>
+<s:form action="upload" method="post" enctype="multipart/form-data">
+    <s:file name="upload" label="选择文件"/>
+    <s:submit value="上传"/>
+</s:form>
+
+ +

3. 多文件上传

+
+
// 使用 List 接收多文件
+private List<File> uploads;
+private List<String> uploadsFileName;
+
+// 表单
+<s:file name="uploads" multiple="multiple"/>
+
+ +

4. 限制文件大小和类型

+
+
// struts.xml 配置
+<action name="upload" class="com.demo.UploadAction">
+    <interceptor-ref name="fileUpload">
+        <param name="maximumSize">10485760</param><!-- 10MB -->
+        <param name="allowedTypes">image/png,image/jpeg</param>
+    </interceptor-ref>
+    <result>/upload/success.jsp</result>
+</action>
+
+ + 下一节:AJAX → +
+
+ + \ No newline at end of file diff --git a/web/demo/validation/index.jsp b/web/demo/validation/index.jsp new file mode 100644 index 0000000..283e7a4 --- /dev/null +++ b/web/demo/validation/index.jsp @@ -0,0 +1,227 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + + 表单验证 - Struts2 学习 + + + +
+ + +
+

✅ 表单验证

+ +
+ 📝 本节要点: 掌握 Struts2 的两种验证方式:编程式验证和声明式验证 +
+ +

1. 验证方式概览

+
+ + + + + + + + + + + + + + + + + + + + + +
方式实现方式适用场景
编程式重写 validate() 方法简单验证,逻辑复杂
声明式 - 方法级validateXxx() 方法特定方法的验证
声明式 - XMLXxxAction-validation.xml可复用,团队协作
+
+ +

2. 方式一:编程式验证 (validate)

+
+
public class LoginAction extends ActionSupport {
+    
+    private String username;
+    private String password;
+    
+    @Override
+    public String execute() {
+        // 登录逻辑...
+        return SUCCESS;
+    }
+    
+    /**
+     * 验证方法 - 对所有 execute 方法都生效
+     */
+    @Override
+    public void validate() {
+        // 用户名验证
+        if (username == null || username.trim().length() < 3) {
+            addFieldError("username", "用户名至少3个字符");
+        }
+        
+        // 密码验证
+        if (password == null || password.length() < 6) {
+            addFieldError("password", "密码至少6个字符");
+        }
+    }
+    
+    // getter/setter...
+}
+
+ +

3. 方式二:方法级验证 (validateXxx)

+
+
/**
+ * 只验证 register 方法,不验证 login 方法
+ */
+public void validateRegister() {
+    if (email == null || !email.contains("@")) {
+        addFieldError("email", "邮箱格式不正确");
+    }
+}
+
+ +

4. 方式三:XML 声明式验证

+
+ 优点: 验证规则与代码分离,团队协作更清晰,可复用 +
+ +

4.1 创建验证文件

+
+

文件名格式:ActionName-validation.xml

+

位置:WEB-INF/classes/com/demo/action/

+
<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE validators PUBLIC
+    "-//OpenSymphony Group//XWork Validator 1.0.3//EN"
+    "http://www.opensymphony.com/xwork/xwork-validator-1.0.3.dtd">
+
+<validators>
+    <!-- 字段验证 -->
+    <field name="username">
+        <field-validator type="requiredstring">
+            <message>用户名不能为空</message>
+        </field-validator>
+        <field-validator type="stringlength">
+            <param name="minLength">3</param>
+            <param name="maxLength">20</param>
+            <message>用户名长度3-20字符</message>
+        </field-validator>
+    </field>
+    
+    <!-- 字段验证:email -->
+    <field name="email">
+        <field-validator type="email">
+            <message>邮箱格式不正确</message>
+        </field-validator>
+    </field>
+    
+    <!-- 非字段验证 -->
+    <validator type="expression">
+        <param name="expression">password==confirmPassword</param>
+        <message>两次密码不一致</message>
+    </validator>
+</validators>
+
+ +

5. 常用验证器类型

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
验证器说明示例
required必填username 不能为空
requiredstring字符串必填不能为空字符串
stringlength字符串长度minLength, maxLength
email邮箱格式xxx@xxx.com
regex正则表达式手机号、身份证等
int整数范围min, max
urlURL 格式http://xxx.com
date日期范围min, max
+
+ +

6. 在 JSP 中显示错误

+
+
<%@ taglib prefix="s" uri="/struts-tags" %>
+
+<!-- 显示特定字段的错误 -->
+<s:fielderror fieldName="username"/>
+
+<!-- 显示所有字段错误 -->
+<s:fielderror/>
+
+<!-- 显示 Action 级别错误 -->
+<s:actionerror/>
+
+<!-- 显示 Action 级别消息 -->
+<s:actionmessage/>
+
+ +
+ 下一节:数据封装 → + ← 返回首页 +
+
+
+ + \ No newline at end of file diff --git a/web/error/404.jsp b/web/error/404.jsp new file mode 100644 index 0000000..bd3cf2d --- /dev/null +++ b/web/error/404.jsp @@ -0,0 +1,21 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + 404 - 页面未找到 + + + +
+

404

+

页面未找到

+

返回首页

+
+ + \ No newline at end of file diff --git a/web/hello.jsp b/web/hello.jsp new file mode 100644 index 0000000..50f4681 --- /dev/null +++ b/web/hello.jsp @@ -0,0 +1,47 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + Hello - Struts2 Demo + + + +
+

+

Struts2 Action 执行成功!

+ 返回首页 +
+ + \ No newline at end of file diff --git a/web/index.jsp b/web/index.jsp new file mode 100644 index 0000000..a0ac5a6 --- /dev/null +++ b/web/index.jsp @@ -0,0 +1,552 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + + + Struts2 全栈学习平台 + + + +
+
+ + +
+
+ +
+
+

从零掌握 Struts2 框架

+

完整的 Struts2 学习路径 | 视频教程 | 代码示例 | 实战项目

+
+ + +
+

📈 学习路径

+
+
+

第一阶段

+ 环境搭建 + 基础 +
+
+

第二阶段

+ 核心组件 +
+
+

第三阶段

+ 数据处理 +
+
+

第四阶段

+ 企业应用 +
+
+
+ + +
+ + +
+
+
👋
+

1. Hello World

+
+

Struts2 入门最简单的示例,掌握基本的 Action 配置和参数传递。

+
    +
  • Action 编写
  • +
  • struts.xml 配置
  • +
  • 结果视图映射
  • +
+ 入门 + 开始学习 +
+ + +
+
+
+

2. 表单与验证

+
+

深入理解 Struts2 的两种验证方式:编程式验证和声明式验证。

+
    +
  • validate() 方法
  • +
  • XML 验证文件
  • +
  • 字段级验证
  • +
+ 入门 + 开始学习 +
+ + +
+
+
📦
+

3. 数据封装

+
+

掌握 Struts2 的数据封装机制,包括属性驱动和模型驱动。

+
    +
  • 属性驱动
  • +
  • 模型驱动 (ModelDriven)
  • +
  • 复杂对象封装
  • +
+ 进阶 + 开始学习 +
+ + +
+
+
📁
+

4. 文件上传

+
+

Struts2 文件上传功能,支持单文件和多文件上传。

+
    +
  • File 对象接收
  • +
  • 文件类型验证
  • +
  • 多文件上传
  • +
+ 进阶 + 开始学习 +
+ + +
+
+
🔄
+

5. 类型转换器

+
+

自定义类型转换器,处理特殊数据类型和复杂对象。

+
    +
  • TypeConverter
  • +
  • StrutsTypeConverter
  • +
  • 局部/全局转换器
  • +
+ 进阶 + 开始学习 +
+ + +
+
+
+

6. AJAX + JSON

+
+

使用 Struts2 JSON 插件实现异步数据交互。

+
    +
  • JSON 结果类型
  • +
  • AJAX 表单提交
  • +
  • 局部页面刷新
  • +
+ 进阶 + 开始学习 +
+ + +
+
+
🛡️
+

7. 拦截器

+
+

理解拦截器机制,这是 Struts2 框架的核心灵魂。

+
    +
  • 自定义拦截器
  • +
  • 拦截器栈
  • +
  • 方法过滤拦截器
  • +
+ 进阶 + 开始学习 +
+ + +
+
+
📊
+

8. OGNL 表达式

+
+

掌握 Struts2 的表达式语言,操作对象图和集合。

+
    +
  • 基础语法
  • +
  • 集合操作
  • +
  • 上下文对象
  • +
+ 进阶 + 开始学习 +
+ + +
+
+
🔐
+

9. 作用域对象

+
+

掌握 ActionContext 和值栈的操作。

+
    +
  • Session 管理
  • +
  • Request/Response
  • +
  • 值栈操作
  • +
+ 进阶 + 开始学习 +
+ + +
+
+
🌐
+

10. RESTful

+
+

使用 Struts2 实现 RESTful 风格的 API 设计。

+
    +
  • REST 插件
  • +
  • URL 参数映射
  • +
  • 内容协商
  • +
+ 专家 + 开始学习 +
+ + +
+
+
🌍
+

11. 国际化 (i18n)

+
+

实现多语言支持的应用程序。

+
    +
  • 资源文件配置
  • +
  • getText() 使用
  • +
  • 动态语言切换
  • +
+ 进阶 + 开始学习 +
+ + +
+
+
🔍
+

12. 源码解析

+
+

深入理解 Struts2 框架的内部实现原理。

+
    +
  • 请求处理流程
  • +
  • 拦截器链源码
  • +
  • OGNL 原理
  • +
+ 专家 + 开始学习 +
+ +
+ + +
+

⚙️ 配置文件示例

+
+
+

struts.xml 基础配置

+
+<?xml version="1.0"?> +<struts> + <!-- 开发模式 --> + <constant name="struts.devMode" value="true"/> + + <!-- 包定义 --> + <package name="default" namespace="/" extends="struts-default"> + + <action name="hello" class="com.demo.HelloAction"> + <result>/hello.jsp</result> + </action> + + </package> +</struts> +
+
+
+

Action 基础写法

+
+public class HelloAction extends ActionSupport { + + private String name; + + @Override + public String execute() { + return SUCCESS; + } + + // getter/setter + public String getName() { return name; } + public void setName(String name) { this.name = name; } +} +
+
+
+
+ + +
+

💼 实战项目

+
+
+

📝 博客系统

+

完整的博客系统,包含文章管理、评论、分类等功能。

+ 入门 + 查看详情 +
+
+

📋 待办事项

+

Todo 列表应用,练习 CRUD 操作和 AJAX。

+ 入门 + 查看详情 +
+
+

🛒 商城购物车

+

购物车功能,练习 Session 和订单管理。

+ 进阶 + 查看详情 +
+
+
+ +
+ + + + \ No newline at end of file diff --git a/web/upload/index.jsp b/web/upload/index.jsp new file mode 100644 index 0000000..1133b85 --- /dev/null +++ b/web/upload/index.jsp @@ -0,0 +1,87 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + + 文件上传 - Struts2 Demo + + + +
+
+

📁 文件上传

+ +
+ Struts2 文件上传原理: +
    +
  • 使用 File 类型接收文件
  • +
  • 使用 String fileName 获取原始文件名
  • +
  • 使用 String contentType 获取文件类型
  • +
  • 底层使用 commons-fileupload
  • +
+
+ + +
+ + +
+ +
+ + +
+ + +
+ +

+ ← 返回首页 +

+
+
+ + \ No newline at end of file diff --git a/web/upload/success.jsp b/web/upload/success.jsp new file mode 100644 index 0000000..90eb272 --- /dev/null +++ b/web/upload/success.jsp @@ -0,0 +1,39 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> + + + + 操作成功 + + + +
+

✅ 操作成功!

+ 返回首页 +
+ + \ No newline at end of file diff --git a/web/user/form.jsp b/web/user/form.jsp new file mode 100644 index 0000000..bb5bfc8 --- /dev/null +++ b/web/user/form.jsp @@ -0,0 +1,58 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + 用户表单 - Struts2 Demo + + + +
+
+

👤 用户信息提交

+ +
+ + +
+
+ + +
+
+ + +
+ +
+
+
+ + \ No newline at end of file diff --git a/web/user/login.jsp b/web/user/login.jsp new file mode 100644 index 0000000..1e223aa --- /dev/null +++ b/web/user/login.jsp @@ -0,0 +1,94 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + + 用户登录 - Struts2 Demo + + + +
+

🔐 用户登录

+ +
+ 测试账号: admin / 123456 +
+ + + +
+ + + +
+ +
+ + + +
+ + + + + +
+ +

+ ← 返回首页 +

+
+ + \ No newline at end of file diff --git a/web/user/success.jsp b/web/user/success.jsp new file mode 100644 index 0000000..b3e4065 --- /dev/null +++ b/web/user/success.jsp @@ -0,0 +1,44 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + 登录成功 - Struts2 Demo + + + +
+

✅ 登录成功!

+

欢迎回来,

+ 返回首页 +
+ + \ No newline at end of file diff --git a/web/validation/form.jsp b/web/validation/form.jsp new file mode 100644 index 0000000..f54ad01 --- /dev/null +++ b/web/validation/form.jsp @@ -0,0 +1,103 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + + 表单验证 - Struts2 Demo + + + +
+
+

📝 表单验证示例

+ +
+ 验证方式: +
    +
  • 在 Action 中重写 validate() 方法
  • +
  • 使用 XML 验证文件 (ActionName-validation.xml)
  • +
  • 使用注解验证 (@Required, @IntRange 等)
  • +
+
+ + +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ + +
+ + + +
+
+
+ + \ No newline at end of file diff --git a/web/validation/success.jsp b/web/validation/success.jsp new file mode 100644 index 0000000..82c544e --- /dev/null +++ b/web/validation/success.jsp @@ -0,0 +1,54 @@ +<%@ page contentType="text/html;charset=UTF-8" language="java" %> +<%@ taglib prefix="s" uri="/struts-tags" %> + + + + 验证成功 - Struts2 Demo + + + +
+

✅ 验证通过!

+
+

用户名:

+

邮箱:

+

年龄:

+

简介:

+
+ 继续测试 +
+ + \ No newline at end of file