Update: struts config, new actions and views

This commit is contained in:
likingcode
2026-03-18 15:18:32 +08:00
parent e0afbdc002
commit 077f054e2c
87 changed files with 7883 additions and 0 deletions

36
pom.xml Normal file
View File

@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>struts2-scaffold</artifactId>
<version>1.0.0</version>
<packaging>war</packaging>
<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>6.4.0</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>3.4.0</version>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,325 @@
package com.example.struts2;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import com.google.gson.Gson;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.*;
/**
* Action生命周期可视化Action - 展示请求处理完整流程
*
* 学习点:
* - Action的完整生命周期
* - 拦截器链的执行过程
* - 结果渲染流程
*/
public class ActionLifecycleAction extends ActionSupport {
private static final Gson gson = new Gson();
private static List<String> lifecycleLog = new ArrayList<>();
/**
* 显示生命周期可视化页面
*/
public String execute() {
return SUCCESS;
}
/**
* 获取Action生命周期流程AJAX
*/
public String getLifecycle() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> stages = new ArrayList<>();
// 阶段1: 请求接收
Map<String, Object> stage1 = new LinkedHashMap<>();
stage1.put("id", 1);
stage1.put("name", "请求接收");
stage1.put("icon", "📨");
stage1.put("description", "客户端发送HTTP请求被Servlet容器接收");
stage1.put("components", Arrays.asList("HttpServletRequest", "HttpServletResponse"));
stage1.put("details", "请求URL、参数、Header等信息被封装到请求对象中");
stages.add(stage1);
// 阶段2: Filter处理
Map<String, Object> stage2 = new LinkedHashMap<>();
stage2.put("id", 2);
stage2.put("name", "Filter处理");
stage2.put("icon", "🛡️");
stage2.put("description", "StrutsPrepareAndExecuteFilter接管请求");
stage2.put("components", Arrays.asList("StrutsPrepareAndExecuteFilter", "ActionContextCleanUp"));
stage2.put("details", "过滤器准备ActionContext设置值栈创建ActionProxy");
stages.add(stage2);
// 阶段3: ActionProxy创建
Map<String, Object> stage3 = new LinkedHashMap<>();
stage3.put("id", 3);
stage3.put("name", "ActionProxy创建");
stage3.put("icon", "🔧");
stage3.put("description", "根据URL映射创建ActionProxy和ActionInvocation");
stage3.put("components", Arrays.asList("ActionProxy", "ActionInvocation", "Configuration"));
stage3.put("details", "从struts.xml查找Action配置确定拦截器栈和结果映射");
stages.add(stage3);
// 阶段4: 拦截器前置处理
Map<String, Object> stage4 = new LinkedHashMap<>();
stage4.put("id", 4);
stage4.put("name", "拦截器前置处理");
stage4.put("icon", "⛓️");
stage4.put("description", "按顺序执行拦截器的intercept方法");
stage4.put("components", Arrays.asList("Interceptor", "InterceptorStack"));
stage4.put("details", "执行日志、权限、校验等前置处理,可中断请求流程");
stages.add(stage4);
// 阶段5: Action执行
Map<String, Object> stage5 = new LinkedHashMap<>();
stage5.put("id", 5);
stage5.put("name", "Action执行");
stage5.put("icon", "");
stage5.put("description", "调用Action的execute或其他指定方法");
stage5.put("components", Arrays.asList("Action", "ActionSupport", "ModelDriven"));
stage5.put("details", "执行业务逻辑,操作数据库,返回结果字符串");
stages.add(stage5);
// 阶段6: 拦截器后置处理
Map<String, Object> stage6 = new LinkedHashMap<>();
stage6.put("id", 6);
stage6.put("name", "拦截器后置处理");
stage6.put("icon", "↩️");
stage6.put("description", "拦截器链返回,执行后置处理");
stage6.put("components", Arrays.asList("Interceptor", "Result"));
stage6.put("details", "记录执行时间,处理结果,进行资源清理");
stages.add(stage6);
// 阶段7: 结果渲染
Map<String, Object> stage7 = new LinkedHashMap<>();
stage7.put("id", 7);
stage7.put("name", "结果渲染");
stage7.put("icon", "🎨");
stage7.put("description", "根据返回的结果字符串查找并执行Result");
stage7.put("components", Arrays.asList("Result", "ServletDispatcherResult", "JSP"));
stage7.put("details", "转发或重定向到视图页面,渲染响应内容");
stages.add(stage7);
// 阶段8: 响应返回
Map<String, Object> stage8 = new LinkedHashMap<>();
stage8.put("id", 8);
stage8.put("name", "响应返回");
stage8.put("icon", "📤");
stage8.put("description", "将渲染后的响应返回给客户端");
stage8.put("components", Arrays.asList("HttpServletResponse", "OutputStream"));
stage8.put("details", "清理ActionContext释放资源完成请求处理");
stages.add(stage8);
result.put("stages", stages);
result.put("totalStages", stages.size());
writeJsonResponse(result);
return NONE;
}
/**
* 获取拦截器链执行流程AJAX
*/
public String getInterceptorChain() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> interceptors = new ArrayList<>();
// 框架级拦截器
Map<String, Object> i1 = new LinkedHashMap<>();
i1.put("name", "TimerInterceptor");
i1.put("type", "framework");
i1.put("description", "记录Action执行时间");
i1.put("phase", "前后");
interceptors.add(i1);
Map<String, Object> i2 = new LinkedHashMap<>();
i2.put("name", "LoggerInterceptor");
i2.put("type", "framework");
i2.put("description", "记录请求日志");
i2.put("phase", "前置");
interceptors.add(i2);
Map<String, Object> i3 = new LinkedHashMap<>();
i3.put("name", "ParametersInterceptor");
i3.put("type", "framework");
i3.put("description", "将请求参数设置到Action");
i3.put("phase", "前置");
interceptors.add(i3);
Map<String, Object> i4 = new LinkedHashMap<>();
i4.put("name", "ValidationInterceptor");
i4.put("type", "framework");
i4.put("description", "执行数据验证");
i4.put("phase", "前置");
interceptors.add(i4);
Map<String, Object> i5 = new LinkedHashMap<>();
i5.put("name", "WorkflowInterceptor");
i5.put("type", "framework");
i5.put("description", "处理验证错误返回input结果");
i5.put("phase", "前置");
interceptors.add(i5);
// 自定义拦截器
Map<String, Object> i6 = new LinkedHashMap<>();
i6.put("name", "LoggingInterceptor");
i6.put("type", "custom");
i6.put("description", "自定义日志拦截器");
i6.put("phase", "前后");
interceptors.add(i6);
Map<String, Object> i7 = new LinkedHashMap<>();
i7.put("name", "TimingInterceptor");
i7.put("type", "custom");
i7.put("description", "自定义计时拦截器");
i7.put("phase", "前后");
interceptors.add(i7);
Map<String, Object> i8 = new LinkedHashMap<>();
i8.put("name", "RateLimitInterceptor");
i8.put("type", "custom");
i8.put("description", "限流拦截器");
i8.put("phase", "前置");
interceptors.add(i8);
result.put("interceptors", interceptors);
result.put("chainPattern", "责任链模式");
result.put("executionOrder", "先入后出(递归调用)");
writeJsonResponse(result);
return NONE;
}
/**
* 模拟请求执行过程AJAX
*/
public String simulateRequest() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> logs = new ArrayList<>();
long startTime = System.currentTimeMillis();
// 模拟每个阶段的执行
String[] stages = {
"接收请求: GET /user/list",
"Filter: StrutsPrepareAndExecuteFilter.doFilter()",
"创建ActionProxy: UserFormAction.list()",
"创建ActionInvocation",
"▶️ 开始拦截器链",
" → TimerInterceptor.before()",
" → LoggerInterceptor.before()",
" → ParametersInterceptor.before()",
" → ValidationInterceptor.before()",
" → LoggingInterceptor.before()",
" → TimingInterceptor.before()",
"▶️ 执行Action: UserFormAction.list()",
" → 查询用户列表",
" → 设置userList到值栈",
" → 返回结果: SUCCESS",
"↩️ 拦截器链返回",
" → TimingInterceptor.after()",
" → LoggingInterceptor.after()",
" → ValidationInterceptor.after()",
" → ParametersInterceptor.after()",
" → LoggerInterceptor.after()",
" → TimerInterceptor.after()",
"▶️ 结果渲染: /user-list.jsp",
" → OGNL解析值栈数据",
" → 渲染JSP页面",
" → 返回响应",
"✅ 请求完成"
};
for (int i = 0; i < stages.length; i++) {
Map<String, Object> log = new LinkedHashMap<>();
log.put("step", i + 1);
log.put("message", stages[i]);
log.put("timestamp", startTime + i * 10);
log.put("indent", stages[i].startsWith(" ") ? 2 : (stages[i].startsWith("") ? 1 : 0));
logs.add(log);
}
result.put("logs", logs);
result.put("totalTime", stages.length * 10);
result.put("interceptorCount", 6);
result.put("actionTime", 10);
result.put("renderTime", 20);
writeJsonResponse(result);
return NONE;
}
/**
* 获取值栈信息AJAX
*/
public String getValueStack() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> stack = new ArrayList<>();
Map<String, Object> root = new LinkedHashMap<>();
root.put("name", "CompoundRoot");
root.put("type", "root");
root.put("description", "值栈的根对象列表");
root.put("objects", Arrays.asList(
mapOf("name", "当前Action", "type", "UserFormAction", "properties", "userList, user, id"),
mapOf("name", "模型对象", "type", "User", "properties", "id, name, email, age")
));
stack.add(root);
Map<String, Object> context = new LinkedHashMap<>();
context.put("name", "ActionContext");
context.put("type", "context");
context.put("description", "Action上下文");
context.put("objects", Arrays.asList(
mapOf("name", "request", "type", "HttpServletRequest", "properties", "参数、Header、Attribute"),
mapOf("name", "session", "type", "HttpSession", "properties", "会话数据"),
mapOf("name", "application", "type", "ServletContext", "properties", "应用级数据"),
mapOf("name", "parameters", "type", "Map", "properties", "请求参数"),
mapOf("name", "attr", "type", "Map", "properties", "属性查找")
));
stack.add(context);
result.put("stack", stack);
result.put("ognl", "OGNL表达式用于访问值栈中的数据");
result.put("examples", Arrays.asList(
"user.name - 访问Action的user对象的name属性",
"#session.user - 访问session中的user",
"#request.ip - 访问request中的ip属性",
"userList.size() - 调用userList的size方法"
));
writeJsonResponse(result);
return NONE;
}
/**
* 辅助方法创建Map
*/
private Map<String, String> mapOf(String... pairs) {
Map<String, String> map = new LinkedHashMap<>();
for (int i = 0; i < pairs.length; i += 2) {
map.put(pairs[i], pairs[i + 1]);
}
return map;
}
/**
* 辅助方法写入JSON响应
*/
private void writeJsonResponse(Map<String, Object> data) {
try {
ServletActionContext.getResponse().setContentType("application/json;charset=UTF-8");
PrintWriter out = ServletActionContext.getResponse().getWriter();
out.print(gson.toJson(data));
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,126 @@
package com.example.struts2;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import com.google.gson.Gson;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
/**
* AJAX演示Action - 展示Struts2处理异步请求
*
* 学习点:
* - 返回JSON数据
* - 处理AJAX请求
* - 前后端分离交互
*/
public class AjaxDemoAction extends ActionSupport {
private String username;
private String email;
private Integer age;
private Long userId;
// Gson用于JSON序列化
private static final Gson gson = new Gson();
/**
* 检查用户名是否可用AJAX验证
*/
public String checkUsername() {
Map<String, Object> result = new HashMap<>();
// 模拟数据库检查
boolean available = !"admin".equals(username) && !"root".equals(username);
result.put("available", available);
result.put("message", available ? "用户名可用" : "用户名已被占用");
result.put("username", username);
writeJsonResponse(result);
return NONE;
}
/**
* 获取用户统计信息
*/
public String getStats() {
Map<String, Object> stats = new HashMap<>();
stats.put("totalUsers", 156);
stats.put("activeUsers", 89);
stats.put("newUsersToday", 12);
stats.put("timestamp", System.currentTimeMillis());
writeJsonResponse(stats);
return NONE;
}
/**
* 模拟保存用户AJAX提交
*/
public String saveUser() {
Map<String, Object> result = new HashMap<>();
// 模拟验证
if (username == null || username.trim().isEmpty()) {
result.put("success", false);
result.put("error", "用户名不能为空");
} else if (email == null || !email.contains("@")) {
result.put("success", false);
result.put("error", "邮箱格式不正确");
} else {
// 模拟保存成功
result.put("success", true);
result.put("message", "用户保存成功");
result.put("userId", System.currentTimeMillis());
result.put("username", username);
}
writeJsonResponse(result);
return NONE;
}
/**
* 获取实时数据(模拟)
*/
public String getRealtimeData() {
Map<String, Object> data = new HashMap<>();
data.put("serverTime", new java.util.Date().toString());
data.put("requestsPerSecond", Math.random() * 100);
data.put("memoryUsage", Runtime.getRuntime().totalMemory() / 1024 / 1024);
data.put("activeSessions", (int)(Math.random() * 50) + 10);
writeJsonResponse(data);
return NONE;
}
/**
* 辅助方法写入JSON响应
*/
private void writeJsonResponse(Map<String, Object> data) {
try {
ServletActionContext.getResponse().setContentType("application/json;charset=UTF-8");
PrintWriter out = ServletActionContext.getResponse().getWriter();
out.print(gson.toJson(data));
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Getters and Setters
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; }
public Long getUserId() { return userId; }
public void setUserId(Long userId) { this.userId = userId; }
}

View File

@@ -0,0 +1,319 @@
package com.example.struts2;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import com.google.gson.Gson;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.*;
/**
* 类加载可视化Action - 展示JVM类加载机制
*
* 学习点:
* - 类加载器层次结构Bootstrap -> Extension -> Application
* - 类的加载过程
* - 双亲委派模型
*/
public class ClassLoaderAction extends ActionSupport {
private static final Gson gson = new Gson();
private Map<String, Object> classLoaderInfo;
private List<Map<String, Object>> loadedClasses;
/**
* 显示类加载可视化页面
*/
public String execute() {
return SUCCESS;
}
/**
* 获取类加载器层次结构信息AJAX
*/
public String getClassLoaderHierarchy() {
Map<String, Object> result = new LinkedHashMap<>();
// 获取当前类的类加载器
ClassLoader appLoader = this.getClass().getClassLoader();
ClassLoader extLoader = appLoader.getParent();
ClassLoader bootstrapLoader = extLoader != null ? extLoader.getParent() : null;
List<Map<String, Object>> hierarchy = new ArrayList<>();
// Bootstrap ClassLoader
Map<String, Object> bootstrap = new LinkedHashMap<>();
bootstrap.put("name", "Bootstrap ClassLoader");
bootstrap.put("type", "bootstrap");
bootstrap.put("description", "启动类加载器 - 加载核心Java类rt.jar");
bootstrap.put("loadedClasses", getBootstrapClasses());
bootstrap.put("parent", null);
hierarchy.add(bootstrap);
// Extension ClassLoader
if (extLoader != null) {
Map<String, Object> extension = new LinkedHashMap<>();
extension.put("name", "Extension ClassLoader");
extension.put("type", "extension");
extension.put("description", "扩展类加载器 - 加载扩展类ext目录");
extension.put("className", extLoader.getClass().getName());
extension.put("loadedClasses", countLoadedClasses(extLoader));
extension.put("parent", "Bootstrap ClassLoader");
hierarchy.add(extension);
}
// Application ClassLoader
Map<String, Object> application = new LinkedHashMap<>();
application.put("name", "Application ClassLoader");
application.put("type", "application");
application.put("description", "应用类加载器 - 加载classpath下的类");
application.put("className", appLoader.getClass().getName());
application.put("loadedClasses", countLoadedClasses(appLoader));
application.put("parent", extLoader != null ? "Extension ClassLoader" : "Bootstrap ClassLoader");
hierarchy.add(application);
// 当前Web应用的类加载器如果是Web应用
ClassLoader threadLoader = Thread.currentThread().getContextClassLoader();
if (threadLoader != appLoader) {
Map<String, Object> web = new LinkedHashMap<>();
web.put("name", "WebApp ClassLoader");
web.put("type", "webapp");
web.put("description", "Web应用类加载器 - 加载WEB-INF/classes和lib下的类");
web.put("className", threadLoader.getClass().getName());
web.put("loadedClasses", "动态加载");
web.put("parent", "Application ClassLoader");
hierarchy.add(web);
}
result.put("hierarchy", hierarchy);
result.put("currentClassLoader", this.getClass().getClassLoader().getClass().getName());
writeJsonResponse(result);
return NONE;
}
/**
* 获取已加载的类列表AJAX
*/
public String getLoadedClasses() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> classes = new ArrayList<>();
// 获取一些重要的Struts2相关类
String[] classNames = {
"com.opensymphony.xwork2.ActionSupport",
"org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter",
"com.opensymphony.xwork2.interceptor.AbstractInterceptor",
"org.apache.struts2.components.Component",
"com.opensymphony.xwork2.util.ValueStack",
"ognl.Ognl",
"com.example.struts2.HelloAction",
"com.example.struts2.CalculatorAction"
};
for (String className : classNames) {
try {
Class<?> clazz = Class.forName(className);
Map<String, Object> classInfo = new LinkedHashMap<>();
classInfo.put("name", className);
classInfo.put("simpleName", clazz.getSimpleName());
classInfo.put("classLoader", clazz.getClassLoader() != null ?
clazz.getClassLoader().getClass().getSimpleName() : "Bootstrap");
classInfo.put("package", clazz.getPackage().getName());
classInfo.put("superclass", clazz.getSuperclass() != null ?
clazz.getSuperclass().getSimpleName() : "None");
classInfo.put("interfaces", getInterfacesNames(clazz));
classInfo.put("loadedTime", "运行时已加载");
classes.add(classInfo);
} catch (ClassNotFoundException e) {
// 类未找到,跳过
}
}
result.put("classes", classes);
result.put("totalCount", classes.size());
writeJsonResponse(result);
return NONE;
}
/**
* 模拟类加载过程AJAX
*/
public String simulateClassLoading() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> steps = new ArrayList<>();
// 步骤1: 加载
Map<String, Object> step1 = new LinkedHashMap<>();
step1.put("step", 1);
step1.put("name", "加载 (Loading)");
step1.put("description", "通过类的全限定名获取二进制字节流,将静态存储结构转化为方法区的运行时数据结构");
step1.put("action", "查找.class文件 -> 读取字节码 -> 创建Class对象");
step1.put("icon", "📂");
steps.add(step1);
// 步骤2: 验证
Map<String, Object> step2 = new LinkedHashMap<>();
step2.put("step", 2);
step2.put("name", "验证 (Verification)");
step2.put("description", "确保字节码符合JVM规范不会危害虚拟机安全");
step2.put("action", "文件格式验证 -> 元数据验证 -> 字节码验证 -> 符号引用验证");
step2.put("icon", "");
steps.add(step2);
// 步骤3: 准备
Map<String, Object> step3 = new LinkedHashMap<>();
step3.put("step", 3);
step3.put("name", "准备 (Preparation)");
step3.put("description", "为类的静态变量分配内存并设置默认初始值");
step3.put("action", "分配静态变量内存 -> 设置默认值(int=0, boolean=false, reference=null)");
step3.put("icon", "📝");
steps.add(step3);
// 步骤4: 解析
Map<String, Object> step4 = new LinkedHashMap<>();
step4.put("step", 4);
step4.put("name", "解析 (Resolution)");
step4.put("description", "将常量池内的符号引用替换为直接引用");
step4.put("action", "类/接口解析 -> 字段解析 -> 方法解析 -> 接口方法解析");
step4.put("icon", "🔗");
steps.add(step4);
// 步骤5: 初始化
Map<String, Object> step5 = new LinkedHashMap<>();
step5.put("step", 5);
step5.put("name", "初始化 (Initialization)");
step5.put("description", "执行类构造器<clinit>()方法,为静态变量赋予正确的初始值");
step5.put("action", "执行静态代码块 -> 初始化静态变量 -> 类完全可用");
step5.put("icon", "🚀");
steps.add(step5);
result.put("steps", steps);
result.put("totalSteps", steps.size());
writeJsonResponse(result);
return NONE;
}
/**
* 获取Struts2框架核心类的加载信息
*/
public String getStrutsClassesInfo() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> modules = new ArrayList<>();
// Action模块
Map<String, Object> actionModule = new LinkedHashMap<>();
actionModule.put("name", "Action模块");
actionModule.put("description", "处理用户请求的核心组件");
actionModule.put("classes", Arrays.asList(
createClassInfo("ActionSupport", "提供了Action的基础实现", "com.opensymphony.xwork2"),
createClassInfo("ActionContext", "Action的上下文环境", "com.opensymphony.xwork2"),
createClassInfo("ServletActionContext", "与Servlet集成的上下文", "org.apache.struts2"),
createClassInfo("ActionInvocation", "Action调用链", "com.opensymphony.xwork2")
));
modules.add(actionModule);
// 拦截器模块
Map<String, Object> interceptorModule = new LinkedHashMap<>();
interceptorModule.put("name", "拦截器模块");
interceptorModule.put("description", "在Action执行前后进行增强处理");
interceptorModule.put("classes", Arrays.asList(
createClassInfo("AbstractInterceptor", "拦截器基类", "com.opensymphony.xwork2.interceptor"),
createClassInfo("Interceptor", "拦截器接口", "com.opensymphony.xwork2.interceptor"),
createClassInfo("ActionInvocation", "拦截器链调用", "com.opensymphony.xwork2"),
createClassInfo("DefaultActionInvocation", "默认实现", "com.opensymphony.xwork2")
));
modules.add(interceptorModule);
// OGNL模块
Map<String, Object> ognlModule = new LinkedHashMap<>();
ognlModule.put("name", "OGNL模块");
ognlModule.put("description", "对象图导航语言,用于数据绑定");
ognlModule.put("classes", Arrays.asList(
createClassInfo("Ognl", "OGNL核心类", "ognl"),
createClassInfo("OgnlContext", "OGNL上下文", "ognl"),
createClassInfo("ValueStack", "值栈", "com.opensymphony.xwork2.util"),
createClassInfo("CompoundRoot", "复合根对象", "com.opensymphony.xwork2.util")
));
modules.add(ognlModule);
// 结果处理模块
Map<String, Object> resultModule = new LinkedHashMap<>();
resultModule.put("name", "结果处理模块");
resultModule.put("description", "处理Action执行结果");
resultModule.put("classes", Arrays.asList(
createClassInfo("Result", "结果接口", "com.opensymphony.xwork2"),
createClassInfo("ServletDispatcherResult", "Servlet转发结果", "org.apache.struts2.dispatcher"),
createClassInfo("ServletRedirectResult", "重定向结果", "org.apache.struts2.dispatcher"),
createClassInfo("StreamResult", "流结果", "org.apache.struts2.dispatcher")
));
modules.add(resultModule);
result.put("modules", modules);
writeJsonResponse(result);
return NONE;
}
/**
* 辅助方法:创建类信息
*/
private Map<String, String> createClassInfo(String name, String desc, String pkg) {
Map<String, String> info = new LinkedHashMap<>();
info.put("name", name);
info.put("description", desc);
info.put("package", pkg);
return info;
}
/**
* 辅助方法:获取接口名称列表
*/
private List<String> getInterfacesNames(Class<?> clazz) {
List<String> interfaces = new ArrayList<>();
for (Class<?> iface : clazz.getInterfaces()) {
interfaces.add(iface.getSimpleName());
}
return interfaces;
}
/**
* 辅助方法:统计已加载的类数量
*/
private String countLoadedClasses(ClassLoader loader) {
// 实际项目中可以使用Instrumentation API获取准确数字
return "动态加载";
}
/**
* 辅助方法获取Bootstrap加载的核心类
*/
private List<String> getBootstrapClasses() {
return Arrays.asList("java.lang.Object", "java.lang.String", "java.lang.System",
"java.util.ArrayList", "java.util.HashMap", "java.io.File");
}
/**
* 辅助方法写入JSON响应
*/
private void writeJsonResponse(Map<String, Object> data) {
try {
ServletActionContext.getResponse().setContentType("application/json;charset=UTF-8");
PrintWriter out = ServletActionContext.getResponse().getWriter();
out.print(gson.toJson(data));
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Getters and Setters
public Map<String, Object> getClassLoaderInfo() { return classLoaderInfo; }
public void setClassLoaderInfo(Map<String, Object> classLoaderInfo) { this.classLoaderInfo = classLoaderInfo; }
public List<Map<String, Object>> getLoadedClasses() { return loadedClasses; }
public void setLoadedClasses(List<Map<String, Object>> loadedClasses) { this.loadedClasses = loadedClasses; }
}

View File

@@ -0,0 +1,216 @@
package com.example.struts2;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
/**
* 文件上传Action - 演示Struts2文件上传功能
*
* 学习点:
* - 文件上传配置
* - 多文件上传
* - 文件类型和大小限制
*/
public class FileUploadAction extends ActionSupport {
// 单文件上传字段
private File upload;
private String uploadFileName;
private String uploadContentType;
private String description;
// 多文件上传字段
private File[] uploads;
private String[] uploadsFileName;
private String[] uploadsContentType;
// 上传结果
private Map<String, Object> uploadResult;
private String uploadedFilePath;
// 上传目录
private static final String UPLOAD_DIR = "/tmp/struts2-uploads/";
/**
* 显示上传页面
*/
public String execute() {
return SUCCESS;
}
/**
* 处理单文件上传
*/
public String uploadSingle() {
uploadResult = new HashMap<>();
if (upload == null) {
uploadResult.put("success", false);
uploadResult.put("error", "请选择要上传的文件");
return SUCCESS;
}
try {
// 创建上传目录
File dir = new File(UPLOAD_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
// 生成唯一文件名
String uniqueFileName = UUID.randomUUID().toString() + "_" + uploadFileName;
File destFile = new File(dir, uniqueFileName);
// 保存文件
copyFile(upload, destFile);
uploadedFilePath = destFile.getAbsolutePath();
uploadResult.put("success", true);
uploadResult.put("message", "文件上传成功");
uploadResult.put("originalName", uploadFileName);
uploadResult.put("savedName", uniqueFileName);
uploadResult.put("fileSize", upload.length());
uploadResult.put("contentType", uploadContentType);
uploadResult.put("filePath", uploadedFilePath);
uploadResult.put("description", description);
} catch (Exception e) {
uploadResult.put("success", false);
uploadResult.put("error", "上传失败: " + e.getMessage());
}
return SUCCESS;
}
/**
* 处理多文件上传
*/
public String uploadMultiple() {
uploadResult = new HashMap<>();
if (uploads == null || uploads.length == 0) {
uploadResult.put("success", false);
uploadResult.put("error", "请选择要上传的文件");
return SUCCESS;
}
Map<String, Object>[] files = new HashMap[uploads.length];
int successCount = 0;
try {
File dir = new File(UPLOAD_DIR);
if (!dir.exists()) {
dir.mkdirs();
}
for (int i = 0; i < uploads.length; i++) {
Map<String, Object> fileInfo = new HashMap<>();
if (uploads[i] != null) {
String uniqueFileName = UUID.randomUUID().toString() + "_" + uploadsFileName[i];
File destFile = new File(dir, uniqueFileName);
copyFile(uploads[i], destFile);
fileInfo.put("originalName", uploadsFileName[i]);
fileInfo.put("savedName", uniqueFileName);
fileInfo.put("fileSize", uploads[i].length());
fileInfo.put("contentType", uploadsContentType[i]);
fileInfo.put("success", true);
successCount++;
} else {
fileInfo.put("success", false);
fileInfo.put("error", "文件为空");
}
files[i] = fileInfo;
}
uploadResult.put("success", true);
uploadResult.put("message", "成功上传 " + successCount + " 个文件");
uploadResult.put("totalFiles", uploads.length);
uploadResult.put("successCount", successCount);
uploadResult.put("files", files);
} catch (Exception e) {
uploadResult.put("success", false);
uploadResult.put("error", "上传失败: " + e.getMessage());
}
return SUCCESS;
}
/**
* 文件复制辅助方法
*/
private void copyFile(File src, File dest) throws IOException {
try (FileInputStream fis = new FileInputStream(src);
FileOutputStream fos = new FileOutputStream(dest)) {
byte[] buffer = new byte[1024];
int length;
while ((length = fis.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
}
}
@Override
public void validate() {
// 可以在这里添加文件大小和类型的验证
if (upload != null) {
// 限制文件大小为10MB
if (upload.length() > 10 * 1024 * 1024) {
addFieldError("upload", "文件大小不能超过10MB");
}
// 限制文件类型
String[] allowedTypes = {"image/jpeg", "image/png", "image/gif", "application/pdf", "text/plain"};
boolean allowed = false;
for (String type : allowedTypes) {
if (type.equals(uploadContentType)) {
allowed = true;
break;
}
}
if (!allowed) {
addFieldError("upload", "不支持的文件类型: " + uploadContentType);
}
}
}
// Getters and Setters
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; }
public String getDescription() { return description; }
public void setDescription(String description) { this.description = description; }
public File[] getUploads() { return uploads; }
public void setUploads(File[] uploads) { this.uploads = uploads; }
public String[] getUploadsFileName() { return uploadsFileName; }
public void setUploadsFileName(String[] uploadsFileName) { this.uploadsFileName = uploadsFileName; }
public String[] getUploadsContentType() { return uploadsContentType; }
public void setUploadsContentType(String[] uploadsContentType) { this.uploadsContentType = uploadsContentType; }
public Map<String, Object> getUploadResult() { return uploadResult; }
public void setUploadResult(Map<String, Object> uploadResult) { this.uploadResult = uploadResult; }
public String getUploadedFilePath() { return uploadedFilePath; }
public void setUploadedFilePath(String uploadedFilePath) { this.uploadedFilePath = uploadedFilePath; }
}

View File

@@ -0,0 +1,299 @@
package com.example.struts2;
import com.opensymphony.xwork2.ActionSupport;
import org.apache.struts2.ServletActionContext;
import com.google.gson.Gson;
import ognl.Ognl;
import ognl.OgnlContext;
import ognl.OgnlException;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.*;
/**
* OGNL可视化Action - 交互式学习OGNL表达式
*
* 学习点:
* - OGNL语法和表达式
* - 值栈访问机制
* - 集合操作和投影
*/
public class OgnlVisualAction extends ActionSupport {
private static final Gson gson = new Gson();
private String expression;
private Object result;
private String error;
// 测试数据
private User user;
private List<User> users;
private Map<String, Object> context;
public OgnlVisualAction() {
// 初始化测试数据
user = new User(1L, "张三", "zhangsan@example.com", 25,
new Address("北京", "朝阳区", "100000"));
users = Arrays.asList(
new User(1L, "张三", "zhangsan@example.com", 25, new Address("北京", "朝阳区", "100000")),
new User(2L, "李四", "lisi@example.com", 30, new Address("上海", "浦东新区", "200000")),
new User(3L, "王五", "wangwu@example.com", 28, new Address("广州", "天河区", "510000")),
new User(4L, "赵六", "zhaoliu@example.com", 35, new Address("深圳", "南山区", "518000"))
);
context = new HashMap<>();
context.put("sessionUser", user);
context.put("appName", "Struts2学习平台");
context.put("version", "1.0.0");
}
/**
* 显示OGNL可视化页面
*/
public String execute() {
return SUCCESS;
}
/**
* 执行OGNL表达式AJAX
*/
public String executeExpression() {
Map<String, Object> response = new LinkedHashMap<>();
try {
// 创建OGNL上下文
OgnlContext ognlContext = new OgnlContext();
ognlContext.setRoot(user);
ognlContext.putAll(context);
// 解析并执行表达式
Object expr = Ognl.parseExpression(expression);
Object value = Ognl.getValue(expr, ognlContext, user);
response.put("success", true);
response.put("expression", expression);
response.put("result", value);
response.put("resultType", value != null ? value.getClass().getSimpleName() : "null");
} catch (OgnlException e) {
response.put("success", false);
response.put("expression", expression);
response.put("error", e.getMessage());
}
writeJsonResponse(response);
return NONE;
}
/**
* 获取OGNL示例AJAX
*/
public String getExamples() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> examples = new ArrayList<>();
// 基础表达式
addExample(examples, "基础属性访问", "user.name",
"访问user对象的name属性", "张三");
addExample(examples, "链式属性访问", "user.address.city",
"访问嵌套对象的属性", "北京");
addExample(examples, "方法调用", "user.getName()",
"调用getter方法", "张三");
addExample(examples, "静态方法", "@java.lang.Math@random()",
"调用静态方法", "随机数");
// 集合操作
addExample(examples, "集合大小", "users.size()",
"获取集合大小", "4");
addExample(examples, "集合过滤", "users.{? #this.age > 25}",
"过滤年龄大于25的用户", "[李四, 王五, 赵六]");
addExample(examples, "集合投影", "users.{name}",
"提取所有用户的姓名", "[张三, 李四, 王五, 赵六]");
addExample(examples, "集合选择", "users.{^ #this.age > 25}",
"选择第一个符合条件的元素", "李四");
addExample(examples, "集合选择", "users.{$ #this.age > 25}",
"选择最后一个符合条件的元素", "赵六");
// 上下文访问
addExample(examples, "上下文变量", "#sessionUser.name",
"访问上下文中的sessionUser", "张三");
addExample(examples, "根对象", "#root",
"访问根对象", "User对象");
addExample(examples, "this引用", "users.{#this.name}",
"在投影中使用this引用", "[张三, 李四, 王五, 赵六]");
// 高级操作
addExample(examples, "创建集合", "{1, 2, 3, 4, 5}",
"创建List集合", "[1, 2, 3, 4, 5]");
addExample(examples, "创建Map", "#{'name':'张三', 'age':25}",
"创建Map对象", "{name=张三, age=25}");
addExample(examples, "投影+过滤", "users.{? #this.age > 25}.{name}",
"先过滤再投影", "[李四, 王五, 赵六]");
addExample(examples, "Lambda表达式", "users.stream().filter(u -> u.age > 25).count()",
"使用Stream API", "3");
result.put("examples", examples);
result.put("totalExamples", examples.size());
writeJsonResponse(result);
return NONE;
}
/**
* 获取测试数据AJAX
*/
public String getTestData() {
Map<String, Object> result = new LinkedHashMap<>();
result.put("user", user);
result.put("users", users);
result.put("context", context);
writeJsonResponse(result);
return NONE;
}
/**
* 获取OGNL语法树AJAX
*/
public String getSyntaxTree() {
Map<String, Object> result = new LinkedHashMap<>();
List<Map<String, Object>> nodes = new ArrayList<>();
// 根节点
Map<String, Object> root = new LinkedHashMap<>();
root.put("id", "root");
root.put("name", "OGNL表达式");
root.put("type", "root");
root.put("children", Arrays.asList(
createNode("property", "属性访问", "user.name, user.age"),
createNode("method", "方法调用", "user.getName(), users.size()"),
createNode("collection", "集合操作", "users.{name}, users.{? #this.age > 25}"),
createNode("context", "上下文访问", "#sessionUser, #root"),
createNode("static", "静态访问", "@java.lang.Math@PI"),
createNode("constructor", "构造创建", "new com.example.User(), {1,2,3}")
));
nodes.add(root);
result.put("nodes", nodes);
result.put("description", "OGNL表达式语法树结构");
writeJsonResponse(result);
return NONE;
}
/**
* 辅助方法:创建节点
*/
private Map<String, Object> createNode(String id, String name, String example) {
Map<String, Object> node = new LinkedHashMap<>();
node.put("id", id);
node.put("name", name);
node.put("example", example);
return node;
}
/**
* 辅助方法:添加示例
*/
private void addExample(List<Map<String, Object>> examples, String category,
String expression, String description, String result) {
Map<String, Object> example = new LinkedHashMap<>();
example.put("category", category);
example.put("expression", expression);
example.put("description", description);
example.put("expectedResult", result);
examples.add(example);
}
/**
* 辅助方法写入JSON响应
*/
private void writeJsonResponse(Map<String, Object> data) {
try {
ServletActionContext.getResponse().setContentType("application/json;charset=UTF-8");
PrintWriter out = ServletActionContext.getResponse().getWriter();
out.print(gson.toJson(data));
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
// Getters and Setters
public String getExpression() { return expression; }
public void setExpression(String expression) { this.expression = expression; }
public Object getResult() { return result; }
public void setResult(Object result) { this.result = result; }
public String getError() { return error; }
public void setError(String error) { this.error = error; }
public User getUser() { return user; }
public void setUser(User user) { this.user = user; }
public List<User> getUsers() { return users; }
public void setUsers(List<User> users) { this.users = users; }
public Map<String, Object> getContext() { return context; }
public void setContext(Map<String, Object> context) { this.context = context; }
/**
* 内部类:用户实体
*/
public static class User {
private Long id;
private String name;
private String email;
private Integer age;
private Address address;
public User() {}
public User(Long id, String name, String email, Integer age, Address address) {
this.id = id;
this.name = name;
this.email = email;
this.age = age;
this.address = address;
}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
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; }
public Address getAddress() { return address; }
public void setAddress(Address address) { this.address = address; }
}
/**
* 内部类:地址实体
*/
public static class Address {
private String city;
private String district;
private String zipCode;
public Address() {}
public Address(String city, String district, String zipCode) {
this.city = city;
this.district = district;
this.zipCode = zipCode;
}
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
public String getDistrict() { return district; }
public void setDistrict(String district) { this.district = district; }
public String getZipCode() { return zipCode; }
public void setZipCode(String zipCode) { this.zipCode = zipCode; }
}
}

View File

@@ -122,5 +122,83 @@
<result type="redirectAction">user</result> <result type="redirectAction">user</result>
</action> </action>
<!-- AJAX演示 -->
<action name="ajax" class="com.example.struts2.AjaxDemoAction">
<result>/ajax-demo.jsp</result>
</action>
<action name="ajax_checkUsername" class="com.example.struts2.AjaxDemoAction" method="checkUsername">
<result type="json"/>
</action>
<action name="ajax_getStats" class="com.example.struts2.AjaxDemoAction" method="getStats">
<result type="json"/>
</action>
<action name="ajax_saveUser" class="com.example.struts2.AjaxDemoAction" method="saveUser">
<result type="json"/>
</action>
<action name="ajax_getRealtimeData" class="com.example.struts2.AjaxDemoAction" method="getRealtimeData">
<result type="json"/>
</action>
<!-- 文件上传 -->
<action name="upload" class="com.example.struts2.FileUploadAction">
<result>/file-upload.jsp</result>
</action>
<action name="uploadSingle" class="com.example.struts2.FileUploadAction" method="uploadSingle">
<result>/file-upload.jsp</result>
<result name="input">/file-upload.jsp</result>
</action>
<action name="uploadMultiple" class="com.example.struts2.FileUploadAction" method="uploadMultiple">
<result>/file-upload.jsp</result>
<result name="input">/file-upload.jsp</result>
</action>
<!-- 类加载可视化 -->
<action name="classloader" class="com.example.struts2.ClassLoaderAction">
<result>/classloader-visual.jsp</result>
</action>
<action name="classloader_getHierarchy" class="com.example.struts2.ClassLoaderAction" method="getClassLoaderHierarchy">
<result type="json"/>
</action>
<action name="classloader_getLoadedClasses" class="com.example.struts2.ClassLoaderAction" method="getLoadedClasses">
<result type="json"/>
</action>
<action name="classloader_simulate" class="com.example.struts2.ClassLoaderAction" method="simulateClassLoading">
<result type="json"/>
</action>
<action name="classloader_getStrutsClasses" class="com.example.struts2.ClassLoaderAction" method="getStrutsClassesInfo">
<result type="json"/>
</action>
<!-- Action生命周期可视化 -->
<action name="lifecycle" class="com.example.struts2.ActionLifecycleAction">
<result>/lifecycle-visual.jsp</result>
</action>
<action name="lifecycle_getLifecycle" class="com.example.struts2.ActionLifecycleAction" method="getLifecycle">
<result type="json"/>
</action>
<action name="lifecycle_getInterceptorChain" class="com.example.struts2.ActionLifecycleAction" method="getInterceptorChain">
<result type="json"/>
</action>
<action name="lifecycle_simulate" class="com.example.struts2.ActionLifecycleAction" method="simulateRequest">
<result type="json"/>
</action>
<action name="lifecycle_getValueStack" class="com.example.struts2.ActionLifecycleAction" method="getValueStack">
<result type="json"/>
</action>
</package> </package>
</struts> </struts>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Struts2 Scaffold</display-name>
<!-- 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>
<!-- 欢迎页 -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

View File

@@ -0,0 +1,321 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>AJAX演示 - Struts2异步交互</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f7fa; padding: 20px; }
.container { max-width: 1200px; margin: 0 auto; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 15px; margin-bottom: 30px; text-align: center; }
.header h1 { font-size: 2em; margin-bottom: 10px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(350px, 1fr)); gap: 20px; margin-bottom: 30px; }
.card { background: white; border-radius: 12px; padding: 25px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); }
.card h3 { color: #333; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.form-group { margin-bottom: 15px; }
.form-group label { display: block; margin-bottom: 5px; color: #555; font-weight: 500; }
.form-group input { width: 100%; padding: 10px 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; transition: border-color 0.3s; }
.form-group input:focus { outline: none; border-color: #667eea; }
.btn { padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: all 0.3s; }
.btn-primary { background: #667eea; color: white; }
.btn-primary:hover { background: #5a6fd6; }
.btn-success { background: #27ae60; color: white; }
.btn-success:hover { background: #219a52; }
.btn-info { background: #3498db; color: white; }
.btn-info:hover { background: #2980b9; }
.result { background: #1e1e1e; color: #d4d4d4; padding: 15px; border-radius: 8px; margin-top: 15px; font-family: 'Monaco', 'Menlo', monospace; font-size: 13px; overflow-x: auto; max-height: 300px; overflow-y: auto; display: none; }
.result.show { display: block; }
.result.success { border-left: 4px solid #27ae60; }
.result.error { border-left: 4px solid #e74c3c; }
.status { padding: 10px 15px; border-radius: 6px; margin-top: 10px; font-size: 14px; display: none; }
.status.show { display: block; }
.status.success { background: #d4edda; color: #155724; }
.status.error { background: #f8d7da; color: #721c24; }
.status.loading { background: #d1ecf1; color: #0c5460; }
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; margin-top: 15px; }
.stat-item { background: #f8f9fa; padding: 15px; border-radius: 8px; text-align: center; }
.stat-item .value { font-size: 24px; font-weight: bold; color: #667eea; }
.stat-item .label { font-size: 12px; color: #666; margin-top: 5px; }
.realtime-data { background: #f8f9fa; padding: 15px; border-radius: 8px; margin-top: 15px; }
.realtime-data .item { display: flex; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid #e0e0e0; }
.realtime-data .item:last-child { border-bottom: none; }
.realtime-data .label { color: #666; }
.realtime-data .value { font-weight: 500; color: #333; }
.lab { background: #fff7e6; border-left: 4px solid #fa8c16; padding: 15px; border-radius: 8px; margin-bottom: 20px; }
.lab strong { color: #874d00; }
code { background: #f0f0f0; padding: 2px 6px; border-radius: 4px; font-size: 13px; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.nav a:hover { background: #667eea; color: white; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🚀 AJAX演示 - Struts2异步交互</h1>
<p>学习Struts2如何处理AJAX请求并返回JSON数据</p>
</div>
<div class="nav">
<a href="index.jsp">← 返回首页</a>
<a href="learn">学习中心</a>
<a href="user">用户管理</a>
</div>
<div class="lab">
<strong>🧪 实验任务</strong>
<ul>
<li>在"用户名检查"中输入"admin"或"root"观察AJAX实时验证</li>
<li>点击"获取统计数据"查看后端返回的JSON数据</li>
<li>使用"AJAX表单提交",体验无刷新表单提交</li>
<li>观察"实时数据"面板,了解如何定时获取服务器数据</li>
</ul>
</div>
<div class="grid">
<!-- 用户名实时检查 -->
<div class="card">
<h3>👤 用户名实时检查</h3>
<div class="form-group">
<label>输入用户名(试试 admin 或 root:</label>
<input type="text" id="checkUsername" placeholder="输入用户名" onblur="checkUsername()">
</div>
<div id="usernameStatus" class="status"></div>
<div id="usernameResult" class="result"></div>
</div>
<!-- 获取统计数据 -->
<div class="card">
<h3>📊 获取统计数据</h3>
<button class="btn btn-info" onclick="getStats()">获取统计数据</button>
<div id="statsContainer" style="margin-top: 15px;"></div>
<div id="statsResult" class="result"></div>
</div>
<!-- AJAX表单提交 -->
<div class="card">
<h3>📝 AJAX表单提交</h3>
<div class="form-group">
<label>用户名:</label>
<input type="text" id="ajaxUsername" placeholder="请输入用户名">
</div>
<div class="form-group">
<label>邮箱:</label>
<input type="email" id="ajaxEmail" placeholder="请输入邮箱">
</div>
<div class="form-group">
<label>年龄:</label>
<input type="number" id="ajaxAge" placeholder="请输入年龄">
</div>
<button class="btn btn-success" onclick="submitAjaxForm()">AJAX提交</button>
<div id="ajaxFormStatus" class="status"></div>
<div id="ajaxFormResult" class="result"></div>
</div>
<!-- 实时数据 -->
<div class="card">
<h3>⏱️ 实时数据监控</h3>
<button class="btn btn-primary" onclick="startRealtime()">开始监控</button>
<button class="btn" onclick="stopRealtime()" style="margin-left: 10px; background: #95a5a6; color: white;">停止监控</button>
<div id="realtimeContainer" class="realtime-data" style="display: none;">
<div class="item">
<span class="label">服务器时间:</span>
<span class="value" id="serverTime">--</span>
</div>
<div class="item">
<span class="label">每秒请求数:</span>
<span class="value" id="requestsPerSecond">--</span>
</div>
<div class="item">
<span class="label">内存使用:</span>
<span class="value" id="memoryUsage">--</span>
</div>
<div class="item">
<span class="label">活跃会话:</span>
<span class="value" id="activeSessions">--</span>
</div>
</div>
<div id="realtimeResult" class="result"></div>
</div>
</div>
<div class="card">
<h3>📚 学习要点</h3>
<ul>
<li><strong>返回JSON:</strong> Action中通过 <code>ServletActionContext.getResponse().getWriter()</code> 直接输出JSON</li>
<li><strong>不返回result:</strong> AJAX Action返回 <code>NONE</code>,不经过视图层</li>
<li><strong>异步验证:</strong> 使用 <code>onblur</code> 事件触发AJAX验证提升用户体验</li>
<li><strong>定时刷新:</strong> 使用 <code>setInterval</code> 实现实时数据监控</li>
<li><strong>Fetch API:</strong> 现代浏览器推荐使用 <code>fetch</code> 替代 <code>XMLHttpRequest</code></li>
</ul>
</div>
</div>
<script>
let realtimeInterval = null;
// 显示状态
function showStatus(elementId, message, type) {
const statusEl = document.getElementById(elementId);
statusEl.textContent = message;
statusEl.className = 'status show ' + type;
}
// 显示结果
function showResult(elementId, data, isSuccess) {
const resultEl = document.getElementById(elementId);
resultEl.textContent = JSON.stringify(data, null, 2);
resultEl.className = 'result show ' + (isSuccess ? 'success' : 'error');
}
// 检查用户名
async function checkUsername() {
const username = document.getElementById('checkUsername').value.trim();
if (!username) return;
showStatus('usernameStatus', '检查中...', 'loading');
try {
const response = await fetch('ajax_checkUsername?username=' + encodeURIComponent(username));
const data = await response.json();
showResult('usernameResult', data, data.available);
if (data.available) {
showStatus('usernameStatus', '✓ ' + data.message, 'success');
} else {
showStatus('usernameStatus', '✗ ' + data.message, 'error');
}
} catch (error) {
showStatus('usernameStatus', '请求失败: ' + error.message, 'error');
}
}
// 获取统计数据
async function getStats() {
showStatus('statsContainer', '加载中...', 'loading');
try {
const response = await fetch('ajax_getStats');
const data = await response.json();
// 显示统计卡片
const statsHtml = `
<div class="stats-grid">
<div class="stat-item">
<div class="value">${data.totalUsers}</div>
<div class="label">总用户数</div>
</div>
<div class="stat-item">
<div class="value">${data.activeUsers}</div>
<div class="label">活跃用户</div>
</div>
<div class="stat-item">
<div class="value">${data.newUsersToday}</div>
<div class="label">今日新增</div>
</div>
</div>
`;
document.getElementById('statsContainer').innerHTML = statsHtml;
showResult('statsResult', data, true);
} catch (error) {
showStatus('statsContainer', '请求失败: ' + error.message, 'error');
}
}
// AJAX表单提交
async function submitAjaxForm() {
const username = document.getElementById('ajaxUsername').value.trim();
const email = document.getElementById('ajaxEmail').value.trim();
const age = document.getElementById('ajaxAge').value;
if (!username || !email) {
showStatus('ajaxFormStatus', '请填写完整信息', 'error');
return;
}
showStatus('ajaxFormStatus', '提交中...', 'loading');
try {
const params = new URLSearchParams();
params.append('username', username);
params.append('email', email);
if (age) params.append('age', age);
const response = await fetch('ajax_saveUser', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: params.toString()
});
const data = await response.json();
showResult('ajaxFormResult', data, data.success);
if (data.success) {
showStatus('ajaxFormStatus', '✓ ' + data.message, 'success');
// 清空表单
document.getElementById('ajaxUsername').value = '';
document.getElementById('ajaxEmail').value = '';
document.getElementById('ajaxAge').value = '';
} else {
showStatus('ajaxFormStatus', '✗ ' + (data.error || '保存失败'), 'error');
}
} catch (error) {
showStatus('ajaxFormStatus', '请求失败: ' + error.message, 'error');
}
}
// 开始实时监控
async function startRealtime() {
if (realtimeInterval) return;
document.getElementById('realtimeContainer').style.display = 'block';
async function fetchRealtime() {
try {
const response = await fetch('ajax_getRealtimeData');
const data = await response.json();
document.getElementById('serverTime').textContent = data.serverTime;
document.getElementById('requestsPerSecond').textContent = data.requestsPerSecond.toFixed(2);
document.getElementById('memoryUsage').textContent = data.memoryUsage.toFixed(2) + ' MB';
document.getElementById('activeSessions').textContent = data.activeSessions;
showResult('realtimeResult', data, true);
} catch (error) {
console.error('获取实时数据失败:', error);
}
}
fetchRealtime(); // 立即执行一次
realtimeInterval = setInterval(fetchRealtime, 3000); // 每3秒刷新
}
// 停止实时监控
function stopRealtime() {
if (realtimeInterval) {
clearInterval(realtimeInterval);
realtimeInterval = null;
}
document.getElementById('realtimeContainer').style.display = 'none';
}
</script>
</body>
</html>

View File

@@ -0,0 +1,406 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>类加载可视化 - JVM类加载机制</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f7fa; padding: 20px; }
.container { max-width: 1400px; margin: 0 auto; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 15px; margin-bottom: 30px; text-align: center; }
.header h1 { font-size: 2em; margin-bottom: 10px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(400px, 1fr)); gap: 20px; margin-bottom: 30px; }
.card { background: white; border-radius: 12px; padding: 25px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); }
.card h3 { color: #333; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
/* 类加载器层次结构 */
.classloader-hierarchy { display: flex; flex-direction: column; gap: 15px; }
.classloader-item {
background: linear-gradient(135deg, #f5f7fa 0%, #e4e7f1 100%);
border-radius: 10px;
padding: 20px;
border-left: 5px solid #667eea;
position: relative;
transition: all 0.3s;
}
.classloader-item:hover { transform: translateX(5px); box-shadow: 0 4px 15px rgba(102, 126, 234, 0.2); }
.classloader-item.bootstrap { border-left-color: #e74c3c; }
.classloader-item.extension { border-left-color: #f39c12; }
.classloader-item.application { border-left-color: #27ae60; }
.classloader-item.webapp { border-left-color: #3498db; }
.classloader-item::after {
content: '▼';
position: absolute;
bottom: -20px;
left: 50%;
transform: translateX(-50%);
color: #999;
font-size: 12px;
}
.classloader-item:last-child::after { display: none; }
.classloader-name { font-weight: bold; font-size: 16px; color: #333; margin-bottom: 5px; }
.classloader-type { display: inline-block; padding: 3px 10px; border-radius: 15px; font-size: 11px; margin-bottom: 8px; }
.classloader-type.bootstrap { background: #ffeaea; color: #c0392b; }
.classloader-type.extension { background: #fef5e7; color: #d68910; }
.classloader-type.application { background: #eafaf1; color: #27ae60; }
.classloader-type.webapp { background: #ebf5fb; color: #2980b9; }
.classloader-desc { font-size: 13px; color: #666; margin-bottom: 8px; }
.classloader-info { font-size: 12px; color: #999; }
/* 类加载步骤 */
.loading-steps { display: flex; flex-direction: column; gap: 10px; }
.step-item {
display: flex;
align-items: center;
padding: 15px;
background: #f8f9fa;
border-radius: 8px;
cursor: pointer;
transition: all 0.3s;
border: 2px solid transparent;
}
.step-item:hover { background: #e8f4f8; border-color: #3498db; }
.step-item.active { background: #d4edda; border-color: #27ae60; }
.step-number {
width: 40px;
height: 40px;
border-radius: 50%;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
display: flex;
align-items: center;
justify-content: center;
font-weight: bold;
margin-right: 15px;
font-size: 18px;
}
.step-item.active .step-number { background: linear-gradient(135deg, #27ae60 0%, #2ecc71 100%); }
.step-content { flex: 1; }
.step-name { font-weight: bold; color: #333; margin-bottom: 3px; }
.step-desc { font-size: 12px; color: #666; }
.step-detail {
display: none;
margin-top: 10px;
padding: 15px;
background: white;
border-radius: 8px;
border-left: 4px solid #3498db;
}
.step-detail.show { display: block; }
/* 类列表 */
.class-list { max-height: 400px; overflow-y: auto; }
.class-item {
padding: 12px;
background: #f8f9fa;
border-radius: 8px;
margin-bottom: 8px;
cursor: pointer;
transition: all 0.3s;
}
.class-item:hover { background: #e8f4f8; transform: translateX(5px); }
.class-name { font-weight: bold; color: #333; margin-bottom: 3px; }
.class-package { font-size: 11px; color: #999; }
.class-loader { font-size: 11px; color: #667eea; margin-top: 5px; }
/* Struts2模块 */
.module-item {
background: #f8f9fa;
border-radius: 10px;
padding: 15px;
margin-bottom: 15px;
border-left: 4px solid #667eea;
}
.module-name { font-weight: bold; color: #333; margin-bottom: 5px; }
.module-desc { font-size: 12px; color: #666; margin-bottom: 10px; }
.module-classes { display: flex; flex-wrap: wrap; gap: 8px; }
.module-class {
background: white;
padding: 5px 10px;
border-radius: 15px;
font-size: 11px;
border: 1px solid #ddd;
cursor: pointer;
transition: all 0.3s;
}
.module-class:hover { background: #667eea; color: white; border-color: #667eea; }
/* 动画 */
@keyframes pulse {
0%, 100% { transform: scale(1); }
50% { transform: scale(1.05); }
}
.loading { animation: pulse 1.5s infinite; }
@keyframes slideIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
.animate-in { animation: slideIn 0.5s ease-out; }
.btn { padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: all 0.3s; }
.btn-primary { background: #667eea; color: white; }
.btn-primary:hover { background: #5a6fd6; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.nav a:hover { background: #667eea; color: white; }
.lab { background: #fff7e6; border-left: 4px solid #fa8c16; padding: 15px; border-radius: 8px; margin-bottom: 20px; }
.lab strong { color: #874d00; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🔍 类加载可视化</h1>
<p>深入理解JVM类加载机制和Struts2框架的类加载过程</p>
</div>
<div class="nav">
<a href="index.jsp">← 返回首页</a>
<a href="learn">学习中心</a>
<a href="ajax-demo">AJAX演示</a>
</div>
<div class="lab">
<strong>🧪 实验任务</strong>
<ul>
<li>观察<strong>类加载器层次结构</strong>,理解双亲委派模型</li>
<li>点击<strong>类加载步骤</strong>,查看每个阶段的详细说明</li>
<li>查看<strong>已加载的类</strong>了解Struts2核心类的加载信息</li>
<li>探索<strong>Struts2模块</strong>,理解框架的模块化设计</li>
</ul>
</div>
<div class="grid">
<!-- 类加载器层次结构 -->
<div class="card">
<h3>🏗️ 类加载器层次结构</h3>
<div id="classloaderHierarchy" class="classloader-hierarchy">
<div style="text-align: center; padding: 20px; color: #999;">
加载中...
</div>
</div>
</div>
<!-- 类加载步骤 -->
<div class="card">
<h3>📋 类加载步骤(点击展开)</h3>
<div id="loadingSteps" class="loading-steps">
<div style="text-align: center; padding: 20px; color: #999;">
加载中...
</div>
</div>
</div>
<!-- 已加载的类 -->
<div class="card">
<h3>📦 已加载的核心类</h3>
<div id="loadedClasses" class="class-list">
<div style="text-align: center; padding: 20px; color: #999;">
加载中...
</div>
</div>
</div>
<!-- Struts2模块 -->
<div class="card">
<h3>🎯 Struts2核心模块</h3>
<div id="strutsModules">
<div style="text-align: center; padding: 20px; color: #999;">
加载中...
</div>
</div>
</div>
</div>
<div class="card">
<h3>📚 学习要点</h3>
<ul>
<li><strong>类加载器层次:</strong> Bootstrap → Extension → Application → WebApp形成双亲委派模型</li>
<li><strong>双亲委派:</strong> 类加载时先委托父加载器,父加载器无法加载时才自己加载</li>
<li><strong>加载过程:</strong> 加载 → 验证 → 准备 → 解析 → 初始化,五个阶段确保类正确加载</li>
<li><strong>Struts2类加载:</strong> 框架类由Application加载器加载应用类由WebApp加载器加载</li>
<li><strong>热部署:</strong> WebApp类加载器可以重新加载修改后的类实现热部署</li>
</ul>
</div>
</div>
<script>
// 加载类加载器层次结构
async function loadClassLoaderHierarchy() {
try {
const response = await fetch('classloader_getHierarchy');
const data = await response.json();
const container = document.getElementById('classloaderHierarchy');
container.innerHTML = '';
data.hierarchy.forEach((item, index) => {
const div = document.createElement('div');
div.className = `classloader-item ${item.type} animate-in`;
div.style.animationDelay = `${index * 0.1}s`;
div.innerHTML = `
<div class="classloader-type ${item.type}">${item.type.toUpperCase()}</div>
<div class="classloader-name">${item.name}</div>
<div class="classloader-desc">${item.description}</div>
<div class="classloader-info">
${item.className ? `类: ${item.className}<br>` : ''}
${item.loadedClasses ? `加载类: ${item.loadedClasses}<br>` : ''}
${item.parent ? `父加载器: ${item.parent}` : '父加载器: 无(顶层)'}
</div>
`;
container.appendChild(div);
});
} catch (error) {
document.getElementById('classloaderHierarchy').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 加载类加载步骤
async function loadLoadingSteps() {
try {
const response = await fetch('classloader_simulate');
const data = await response.json();
const container = document.getElementById('loadingSteps');
container.innerHTML = '';
data.steps.forEach((step, index) => {
const div = document.createElement('div');
div.className = 'step-item animate-in';
div.style.animationDelay = `${index * 0.1}s`;
div.onclick = () => toggleStepDetail(div, step);
div.innerHTML = `
<div class="step-number">${step.icon || step.step}</div>
<div class="step-content">
<div class="step-name">${step.name}</div>
<div class="step-desc">${step.description}</div>
</div>
<div class="step-detail" id="step-detail-${step.step}">
<strong>执行动作:</strong><br>
${step.action}<br><br>
<strong>详细说明:</strong><br>
${step.description}
</div>
`;
container.appendChild(div);
});
} catch (error) {
document.getElementById('loadingSteps').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 切换步骤详情
function toggleStepDetail(element, step) {
// 移除其他active状态
document.querySelectorAll('.step-item').forEach(item => {
item.classList.remove('active');
});
document.querySelectorAll('.step-detail').forEach(detail => {
detail.classList.remove('show');
});
// 添加当前active状态
element.classList.add('active');
const detail = element.querySelector('.step-detail');
detail.classList.add('show');
}
// 加载已加载的类
async function loadLoadedClasses() {
try {
const response = await fetch('classloader_getLoadedClasses');
const data = await response.json();
const container = document.getElementById('loadedClasses');
container.innerHTML = '';
data.classes.forEach((cls, index) => {
const div = document.createElement('div');
div.className = 'class-item animate-in';
div.style.animationDelay = `${index * 0.05}s`;
div.innerHTML = `
<div class="class-name">${cls.simpleName}</div>
<div class="class-package">${cls.package}</div>
<div class="class-loader">
加载器: ${cls.classLoader} |
父类: ${cls.superclass} |
接口: ${cls.interfaces.join(', ') || '无'}
</div>
`;
div.onclick = () => {
alert(`类名: ${cls.name}\n包: ${cls.package}\n加载器: ${cls.classLoader}\n父类: ${cls.superclass}\n接口: ${cls.interfaces.join(', ') || '无'}`);
};
container.appendChild(div);
});
} catch (error) {
document.getElementById('loadedClasses').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 加载Struts2模块
async function loadStrutsModules() {
try {
const response = await fetch('classloader_getStrutsClasses');
const data = await response.json();
const container = document.getElementById('strutsModules');
container.innerHTML = '';
data.modules.forEach((module, index) => {
const div = document.createElement('div');
div.className = 'module-item animate-in';
div.style.animationDelay = `${index * 0.1}s`;
const classesHtml = module.classes.map(cls =>
`<span class="module-class" title="${cls.package}.${cls.name}">${cls.name}</span>`
).join('');
div.innerHTML = `
<div class="module-name">${module.name}</div>
<div class="module-desc">${module.description}</div>
<div class="module-classes">${classesHtml}</div>
`;
container.appendChild(div);
});
} catch (error) {
document.getElementById('strutsModules').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 页面加载时初始化
window.onload = function() {
loadClassLoaderHierarchy();
loadLoadingSteps();
loadLoadedClasses();
loadStrutsModules();
};
</script>
</body>
</html>

View File

@@ -0,0 +1,217 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>文件上传 - Struts2</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f7fa; padding: 20px; }
.container { max-width: 1000px; margin: 0 auto; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 15px; margin-bottom: 30px; text-align: center; }
.header h1 { font-size: 2em; margin-bottom: 10px; }
.card { background: white; border-radius: 12px; padding: 25px; margin-bottom: 20px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); }
.card h3 { color: #333; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
.form-group { margin-bottom: 20px; }
.form-group label { display: block; margin-bottom: 8px; color: #555; font-weight: 500; }
.form-group input[type="text"] { width: 100%; padding: 10px 12px; border: 1px solid #ddd; border-radius: 6px; font-size: 14px; }
.form-group input[type="file"] { padding: 10px; border: 2px dashed #ddd; border-radius: 6px; width: 100%; cursor: pointer; }
.form-group input[type="file"]:hover { border-color: #667eea; }
.file-list { margin-top: 10px; }
.file-item { background: #f8f9fa; padding: 10px; border-radius: 6px; margin-bottom: 8px; display: flex; align-items: center; }
.file-item .name { flex: 1; }
.file-item .size { color: #666; font-size: 12px; }
.file-item .remove { color: #e74c3c; cursor: pointer; margin-left: 10px; }
.btn { padding: 12px 24px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: all 0.3s; }
.btn-primary { background: #667eea; color: white; }
.btn-primary:hover { background: #5a6fd6; }
.btn-success { background: #27ae60; color: white; }
.btn-success:hover { background: #219a52; }
.result { background: #d4edda; color: #155724; padding: 15px; border-radius: 8px; margin-top: 15px; }
.result.error { background: #f8d7da; color: #721c24; }
.file-info { background: #f8f9fa; padding: 15px; border-radius: 8px; margin-top: 15px; }
.file-info .item { display: flex; margin-bottom: 8px; }
.file-info .label { width: 120px; color: #666; }
.file-info .value { flex: 1; font-weight: 500; }
.progress { width: 100%; height: 20px; background: #e0e0e0; border-radius: 10px; overflow: hidden; margin-top: 10px; }
.progress-bar { height: 100%; background: linear-gradient(90deg, #667eea, #764ba2); width: 0%; transition: width 0.3s; }
.lab { background: #fff7e6; border-left: 4px solid #fa8c16; padding: 15px; border-radius: 8px; margin-bottom: 20px; }
.lab strong { color: #874d00; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.nav a:hover { background: #667eea; color: white; }
.tips { background: #e8f4f8; padding: 15px; border-radius: 8px; margin-top: 15px; }
.tips ul { margin-left: 20px; }
.tips li { margin-bottom: 5px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>📁 文件上传演示</h1>
<p>学习Struts2如何处理文件上传包括单文件、多文件上传和文件验证</p>
</div>
<div class="nav">
<a href="index.jsp">← 返回首页</a>
<a href="learn">学习中心</a>
<a href="ajax-demo">AJAX演示</a>
</div>
<div class="lab">
<strong>🧪 实验任务</strong>
<ul>
<li>使用"单文件上传"上传一个图片或文档,观察上传结果</li>
<li>使用"多文件上传"一次性选择多个文件</li>
<li>尝试上传超过10MB的文件观察验证错误</li>
<li>尝试上传不支持的文件类型(如.exe观察类型验证</li>
</ul>
</div>
<!-- 单文件上传 -->
<div class="card">
<h3>📄 单文件上传</h3>
<s:form action="uploadSingle" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>选择文件支持图片、PDF、文本文件最大10MB:</label>
<s:file name="upload" accept="image/*,.pdf,.txt" />
<s:fielderror fieldName="upload" cssStyle="color: #e74c3c; font-size: 12px;" />
</div>
<div class="form-group">
<label>文件描述:</label>
<s:textfield name="description" placeholder="请输入文件描述" />
</div>
<s:submit value="上传文件" cssClass="btn btn-primary" />
</s:form>
<s:if test="uploadResult != null">
<s:if test="uploadResult.success">
<div class="result">
<strong>✓ 上传成功</strong>
</div>
<div class="file-info">
<div class="item">
<span class="label">原始文件名:</span>
<span class="value"><s:property value="uploadResult.originalName"/></span>
</div>
<div class="item">
<span class="label">保存文件名:</span>
<span class="value"><s:property value="uploadResult.savedName"/></span>
</div>
<div class="item">
<span class="label">文件大小:</span>
<span class="value"><s:property value="uploadResult.fileSize"/> 字节</span>
</div>
<div class="item">
<span class="label">文件类型:</span>
<span class="value"><s:property value="uploadResult.contentType"/></span>
</div>
<div class="item">
<span class="label">描述:</span>
<span class="value"><s:property value="uploadResult.description"/></span>
</div>
<div class="item">
<span class="label">保存路径:</span>
<span class="value"><s:property value="uploadResult.filePath"/></span>
</div>
</div>
</s:if>
<s:else>
<div class="result error">
<strong>✗ 上传失败:</strong> <s:property value="uploadResult.error"/>
</div>
</s:else>
</s:if>
</div>
<!-- 多文件上传 -->
<div class="card">
<h3>📁 多文件上传</h3>
<s:form action="uploadMultiple" method="post" enctype="multipart/form-data">
<div class="form-group">
<label>选择多个文件按住Ctrl或Cmd键多选:</label>
<s:file name="uploads" multiple="true" accept="image/*,.pdf,.txt" />
</div>
<s:submit value="上传多个文件" cssClass="btn btn-success" />
</s:form>
<s:if test="uploadResult != null && uploadResult.files != null">
<s:if test="uploadResult.success">
<div class="result">
<strong>✓ <s:property value="uploadResult.message"/></strong>
</div>
<div style="margin-top: 15px;">
<h4>上传的文件列表:</h4>
<table style="width: 100%; border-collapse: collapse; margin-top: 10px;">
<tr style="background: #3498db; color: white;">
<th style="padding: 10px; text-align: left;">文件名</th>
<th style="padding: 10px; text-align: left;">大小</th>
<th style="padding: 10px; text-align: left;">类型</th>
<th style="padding: 10px; text-align: left;">状态</th>
</tr>
<s:iterator value="uploadResult.files" var="file">
<tr style="border-bottom: 1px solid #ddd;">
<td style="padding: 10px;"><s:property value="#file.originalName"/></td>
<td style="padding: 10px;"><s:property value="#file.fileSize"/> 字节</td>
<td style="padding: 10px;"><s:property value="#file.contentType"/></td>
<td style="padding: 10px;">
<s:if test="#file.success">
<span style="color: #27ae60;">✓ 成功</span>
</s:if>
<s:else>
<span style="color: #e74c3c;">✗ <s:property value="#file.error"/></span>
</s:else>
</td>
</tr>
</s:iterator>
</table>
</div>
</s:if>
<s:else>
<div class="result error">
<strong>✗ 上传失败:</strong> <s:property value="uploadResult.error"/>
</div>
</s:else>
</s:if>
</div>
<!-- 学习要点 -->
<div class="card">
<h3>📚 学习要点</h3>
<ul>
<li><strong>文件字段命名:</strong> 表单中的文件字段名必须与Action中的属性名一致如 <code>upload</code></li>
<li><strong>三个属性:</strong> Action需要提供 <code>File upload</code>、<code>String uploadFileName</code>、<code>String uploadContentType</code></li>
<li><strong>多文件上传:</strong> 使用数组形式 <code>File[] uploads</code>、<code>String[] uploadsFileName</code> 等</li>
<li><strong>表单enctype:</strong> 必须设置 <code>enctype="multipart/form-data"</code></li>
<li><strong>文件验证:</strong> 可以在 <code>validate()</code> 方法中检查文件大小和类型</li>
<li><strong>文件保存:</strong> 使用 <code>FileUtils.copyFile()</code> 或手动流操作保存文件</li>
</ul>
<div class="tips">
<strong>💡 提示</strong>
<ul>
<li>上传的文件默认保存在临时目录,需要手动移动到目标位置</li>
<li>建议生成唯一文件名避免冲突如使用UUID</li>
<li>生产环境应该限制上传目录的访问权限</li>
<li>大文件上传需要考虑分片上传和进度显示</li>
</ul>
</div>
</div>
</div>
</body>
</html>

View File

@@ -71,6 +71,16 @@
<p>通过错误示例/正确示例切换直观看到字段错误、input 返回和成功路径的区别。</p> <p>通过错误示例/正确示例切换直观看到字段错误、input 返回和成功路径的区别。</p>
<a href="validation" class="btn">进入实验室</a> <a href="validation" class="btn">进入实验室</a>
</div> </div>
<div class="card">
<h3>🚀 AJAX 异步交互</h3>
<p>学习Struts2如何处理AJAX请求返回JSON数据实现前后端分离交互。</p>
<a href="ajax" class="btn purple">AJAX演示</a>
</div>
<div class="card">
<h3>📁 文件上传</h3>
<p>演示单文件、多文件上传,文件类型和大小验证,以及文件处理流程。</p>
<a href="upload" class="btn green">文件上传</a>
</div>
</div> </div>
<div class="timeline"> <div class="timeline">

View File

@@ -72,6 +72,16 @@
<p>学习为什么校验失败不会直接 500而是回到 input 页面并显示字段级错误。</p> <p>学习为什么校验失败不会直接 500而是回到 input 页面并显示字段级错误。</p>
<a class="btn" href="validation">打开验证实验室</a> <a class="btn" href="validation">打开验证实验室</a>
</div> </div>
<div class="card">
<h3>🚀 AJAX 异步交互</h3>
<p>学习Struts2如何处理AJAX请求返回JSON数据实现无刷新交互和实时数据更新。</p>
<a class="btn purple" href="ajax">打开AJAX演示</a>
</div>
<div class="card">
<h3>📁 文件上传</h3>
<p>演示单文件和多文件上传,学习文件类型验证、大小限制和文件处理流程。</p>
<a class="btn green" href="upload">打开文件上传</a>
</div>
</div> </div>
<h2>📚 学习路径</h2> <h2>📚 学习路径</h2>

View File

@@ -0,0 +1,457 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Action生命周期可视化 - Struts2请求处理流程</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f7fa; padding: 20px; }
.container { max-width: 1400px; margin: 0 auto; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 15px; margin-bottom: 30px; text-align: center; }
.header h1 { font-size: 2em; margin-bottom: 10px; }
.grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(500px, 1fr)); gap: 20px; margin-bottom: 30px; }
.card { background: white; border-radius: 12px; padding: 25px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); }
.card h3 { color: #333; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
/* 生命周期流程 */
.lifecycle-flow { display: flex; flex-direction: column; gap: 10px; }
.stage-item {
display: flex;
align-items: flex-start;
padding: 15px;
background: #f8f9fa;
border-radius: 10px;
border-left: 4px solid #667eea;
transition: all 0.3s;
cursor: pointer;
}
.stage-item:hover { background: #e8f4f8; transform: translateX(5px); }
.stage-item.active { background: #d4edda; border-left-color: #27ae60; }
.stage-icon {
font-size: 28px;
margin-right: 15px;
min-width: 40px;
text-align: center;
}
.stage-content { flex: 1; }
.stage-name { font-weight: bold; color: #333; margin-bottom: 5px; font-size: 15px; }
.stage-desc { font-size: 13px; color: #666; margin-bottom: 8px; }
.stage-components { display: flex; flex-wrap: wrap; gap: 5px; }
.stage-component {
background: white;
padding: 3px 10px;
border-radius: 12px;
font-size: 11px;
border: 1px solid #ddd;
}
.stage-detail {
display: none;
margin-top: 10px;
padding: 12px;
background: white;
border-radius: 8px;
font-size: 12px;
color: #555;
border-left: 3px solid #3498db;
}
.stage-detail.show { display: block; }
/* 拦截器链 */
.interceptor-chain { position: relative; padding: 20px 0; }
.chain-line {
position: absolute;
left: 30px;
top: 0;
bottom: 0;
width: 3px;
background: linear-gradient(to bottom, #667eea, #764ba2);
}
.interceptor-item {
display: flex;
align-items: center;
margin-bottom: 15px;
position: relative;
padding-left: 60px;
}
.interceptor-dot {
position: absolute;
left: 22px;
width: 16px;
height: 16px;
border-radius: 50%;
background: #667eea;
border: 3px solid white;
box-shadow: 0 0 0 3px #667eea;
}
.interceptor-item.framework .interceptor-dot { background: #3498db; box-shadow: 0 0 0 3px #3498db; }
.interceptor-item.custom .interceptor-dot { background: #27ae60; box-shadow: 0 0 0 3px #27ae60; }
.interceptor-card {
background: #f8f9fa;
padding: 12px 15px;
border-radius: 8px;
flex: 1;
border-left: 3px solid #667eea;
}
.interceptor-item.framework .interceptor-card { border-left-color: #3498db; }
.interceptor-item.custom .interceptor-card { border-left-color: #27ae60; }
.interceptor-name { font-weight: bold; color: #333; margin-bottom: 3px; }
.interceptor-desc { font-size: 12px; color: #666; }
.interceptor-meta {
display: flex;
gap: 10px;
margin-top: 8px;
font-size: 11px;
}
.interceptor-type {
padding: 2px 8px;
border-radius: 10px;
background: #e8f4f8;
color: #2980b9;
}
.interceptor-phase {
padding: 2px 8px;
border-radius: 10px;
background: #eafaf1;
color: #27ae60;
}
/* 模拟控制台 */
.console {
background: #1e1e1e;
color: #d4d4d4;
padding: 15px;
border-radius: 8px;
font-family: 'Monaco', 'Menlo', monospace;
font-size: 13px;
max-height: 400px;
overflow-y: auto;
}
.console-line {
padding: 3px 0;
border-bottom: 1px solid #333;
}
.console-line:last-child { border-bottom: none; }
.console-line.indent-1 { padding-left: 20px; }
.console-line.indent-2 { padding-left: 40px; }
.console-timestamp { color: #999; font-size: 11px; margin-right: 10px; }
.console-arrow { color: #67eea; }
.console-action { color: #f39c12; }
.console-success { color: #2ecc71; }
/* 值栈可视化 */
.value-stack { display: flex; flex-direction: column; gap: 15px; }
.stack-section {
background: #f8f9fa;
border-radius: 10px;
padding: 15px;
border-left: 4px solid #667eea;
}
.stack-section.context { border-left-color: #f39c12; }
.stack-title { font-weight: bold; color: #333; margin-bottom: 10px; }
.stack-desc { font-size: 12px; color: #666; margin-bottom: 10px; }
.stack-objects { display: flex; flex-direction: column; gap: 8px; }
.stack-object {
background: white;
padding: 10px;
border-radius: 6px;
border: 1px solid #e0e0e0;
}
.stack-object-name { font-weight: bold; color: #667eea; font-size: 13px; }
.stack-object-type { font-size: 11px; color: #999; margin-top: 2px; }
.stack-object-props { font-size: 11px; color: #666; margin-top: 5px; }
.btn { padding: 10px 20px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: all 0.3s; margin-right: 10px; }
.btn-primary { background: #667eea; color: white; }
.btn-primary:hover { background: #5a6fd6; }
.btn-success { background: #27ae60; color: white; }
.btn-success:hover { background: #219a52; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.nav a:hover { background: #667eea; color: white; }
.lab { background: #fff7e6; border-left: 4px solid #fa8c16; padding: 15px; border-radius: 8px; margin-bottom: 20px; }
.lab strong { color: #874d00; }
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.executing { animation: pulse 1s infinite; background: #fff3cd !important; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>⚡ Action生命周期可视化</h1>
<p>深入理解Struts2处理HTTP请求的完整流程</p>
</div>
<div class="nav">
<a href="index.jsp">← 返回首页</a>
<a href="learn">学习中心</a>
<a href="classloader-visual">类加载可视化</a>
</div>
<div class="lab">
<strong>🧪 实验任务</strong>
<ul>
<li>点击<strong>生命周期阶段</strong>,查看每个阶段的详细说明和涉及的组件</li>
<li>观察<strong>拦截器链</strong>,理解责任链模式的执行顺序</li>
<li>点击<strong>模拟请求执行</strong>,观看完整的请求处理流程</li>
<li>查看<strong>值栈结构</strong>理解OGNL如何访问数据</li>
</ul>
</div>
<div class="grid">
<!-- 生命周期流程 -->
<div class="card">
<h3>📋 Action生命周期流程点击查看详情</h3>
<div id="lifecycleFlow" class="lifecycle-flow">
<div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
</div>
</div>
<!-- 拦截器链 -->
<div class="card">
<h3>⛓️ 拦截器链执行顺序</h3>
<div id="interceptorChain" class="interceptor-chain">
<div class="chain-line"></div>
<div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
</div>
</div>
<!-- 模拟请求执行 -->
<div class="card">
<h3>🎬 模拟请求执行</h3>
<div style="margin-bottom: 15px;">
<button class="btn btn-primary" onclick="simulateRequest()">开始模拟</button>
<button class="btn btn-success" onclick="clearConsole()">清空</button>
</div>
<div id="console" class="console">
<div class="console-line">点击"开始模拟"观看请求处理流程...</div>
</div>
</div>
<!-- 值栈结构 -->
<div class="card">
<h3>📚 值栈ValueStack结构</h3>
<div id="valueStack" class="value-stack">
<div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
</div>
</div>
</div>
<div class="card">
<h3>📖 学习要点</h3>
<ul>
<li><strong>请求入口:</strong> 所有请求先经过StrutsPrepareAndExecuteFilter过滤器</li>
<li><strong>ActionProxy:</strong> 封装Action的调用信息包含拦截器栈配置</li>
<li><strong>拦截器链:</strong> 使用责任链模式,前置处理顺序执行,后置处理逆序执行</li>
<li><strong>值栈:</strong> OGNL表达式的根对象包含Action和上下文数据</li>
<li><strong>结果渲染:</strong> 根据返回字符串查找对应的Result进行视图渲染</li>
<li><strong>线程安全:</strong> 每个请求创建新的Action实例不存在线程安全问题</li>
</ul>
</div>
</div>
<script>
// 加载生命周期流程
async function loadLifecycle() {
try {
const response = await fetch('lifecycle_getLifecycle');
const data = await response.json();
const container = document.getElementById('lifecycleFlow');
container.innerHTML = '';
data.stages.forEach((stage, index) => {
const div = document.createElement('div');
div.className = 'stage-item';
div.style.animationDelay = `${index * 0.1}s`;
div.onclick = () => toggleStageDetail(div, stage);
const componentsHtml = stage.components.map(c =>
`<span class="stage-component">${c}</span>`
).join('');
div.innerHTML = `
<div class="stage-icon">${stage.icon}</div>
<div class="stage-content">
<div class="stage-name">${stage.id}. ${stage.name}</div>
<div class="stage-desc">${stage.description}</div>
<div class="stage-components">${componentsHtml}</div>
<div class="stage-detail" id="stage-detail-${stage.id}">
<strong>详细说明:</strong><br>
${stage.details}
</div>
</div>
`;
container.appendChild(div);
});
} catch (error) {
document.getElementById('lifecycleFlow').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 切换阶段详情
function toggleStageDetail(element, stage) {
document.querySelectorAll('.stage-item').forEach(item => {
item.classList.remove('active');
});
document.querySelectorAll('.stage-detail').forEach(detail => {
detail.classList.remove('show');
});
element.classList.add('active');
element.querySelector('.stage-detail').classList.add('show');
}
// 加载拦截器链
async function loadInterceptorChain() {
try {
const response = await fetch('lifecycle_getInterceptorChain');
const data = await response.json();
const container = document.getElementById('interceptorChain');
container.innerHTML = '<div class="chain-line"></div>';
data.interceptors.forEach((interceptor, index) => {
const div = document.createElement('div');
div.className = `interceptor-item ${interceptor.type}`;
div.style.animationDelay = `${index * 0.1}s`;
div.innerHTML = `
<div class="interceptor-dot"></div>
<div class="interceptor-card">
<div class="interceptor-name">${interceptor.name}</div>
<div class="interceptor-desc">${interceptor.description}</div>
<div class="interceptor-meta">
<span class="interceptor-type">${interceptor.type === 'framework' ? '框架' : '自定义'}</span>
<span class="interceptor-phase">${interceptor.phase}</span>
</div>
</div>
`;
container.appendChild(div);
});
} catch (error) {
document.getElementById('interceptorChain').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 模拟请求执行
async function simulateRequest() {
const console = document.getElementById('console');
console.innerHTML = '<div class="console-line">开始模拟请求处理...</div>';
try {
const response = await fetch('lifecycle_simulate');
const data = await response.json();
let delay = 0;
data.logs.forEach((log, index) => {
setTimeout(() => {
const line = document.createElement('div');
line.className = `console-line indent-${log.indent}`;
let message = log.message;
if (message.includes('▶️')) message = message.replace('▶️', '<span class="console-action">▶️</span>');
if (message.includes('↩️')) message = message.replace('↩️', '<span class="console-arrow">↩️</span>');
if (message.includes('✅')) message = message.replace('✅', '<span class="console-success">✅</span>');
line.innerHTML = `<span class="console-timestamp">${log.timestamp}</span>${message}`;
console.appendChild(line);
console.scrollTop = console.scrollHeight;
}, delay);
delay += 300;
});
} catch (error) {
console.innerHTML += `<div class="console-line" style="color: #e74c3c;">模拟失败: ${error.message}</div>`;
}
}
// 清空控制台
function clearConsole() {
document.getElementById('console').innerHTML = '<div class="console-line">点击"开始模拟"观看请求处理流程...</div>';
}
// 加载值栈
async function loadValueStack() {
try {
const response = await fetch('lifecycle_getValueStack');
const data = await response.json();
const container = document.getElementById('valueStack');
container.innerHTML = '';
data.stack.forEach((section, index) => {
const div = document.createElement('div');
div.className = `stack-section ${section.type}`;
const objectsHtml = section.objects.map(obj => `
<div class="stack-object">
<div class="stack-object-name">${obj.name}</div>
<div class="stack-object-type">${obj.type}</div>
<div class="stack-object-props">${obj.properties}</div>
</div>
`).join('');
div.innerHTML = `
<div class="stack-title">${section.name}</div>
<div class="stack-desc">${section.description}</div>
<div class="stack-objects">${objectsHtml}</div>
`;
container.appendChild(div);
});
// 添加OGNL示例
const examplesDiv = document.createElement('div');
examplesDiv.className = 'stack-section';
examplesDiv.innerHTML = `
<div class="stack-title">OGNL表达式示例</div>
<div class="stack-desc">${data.ognl}</div>
<div class="stack-objects">
${data.examples.map(ex => `
<div class="stack-object">
<div class="stack-object-props">${ex}</div>
</div>
`).join('')}
</div>
`;
container.appendChild(examplesDiv);
} catch (error) {
document.getElementById('valueStack').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 页面加载时初始化
window.onload = function() {
loadLifecycle();
loadInterceptorChain();
loadValueStack();
};
</script>
</body>
</html>

View File

@@ -0,0 +1,507 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>OGNL表达式可视化 - 对象图导航语言</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f7fa; padding: 20px; }
.container { max-width: 1400px; margin: 0 auto; }
.header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 30px; border-radius: 15px; margin-bottom: 30px; text-align: center; }
.header h1 { font-size: 2em; margin-bottom: 10px; }
.grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 30px; }
@media (max-width: 900px) { .grid { grid-template-columns: 1fr; } }
.card { background: white; border-radius: 12px; padding: 25px; box-shadow: 0 4px 20px rgba(0,0,0,0.08); }
.card h3 { color: #333; margin-bottom: 15px; border-bottom: 2px solid #eee; padding-bottom: 10px; }
/* 表达式编辑器 */
.expression-editor { margin-bottom: 20px; }
.expression-input {
width: 100%;
padding: 15px;
font-size: 16px;
font-family: 'Monaco', monospace;
border: 2px solid #ddd;
border-radius: 8px;
margin-bottom: 10px;
}
.expression-input:focus { outline: none; border-color: #667eea; }
.btn { padding: 12px 24px; border: none; border-radius: 6px; cursor: pointer; font-size: 14px; transition: all 0.3s; }
.btn-primary { background: #667eea; color: white; }
.btn-primary:hover { background: #5a6fd6; }
.btn-secondary { background: #95a5a6; color: white; margin-left: 10px; }
.btn-secondary:hover { background: #7f8c8d; }
/* 结果显示 */
.result-panel {
background: #1e1e1e;
color: #d4d4d4;
padding: 20px;
border-radius: 8px;
font-family: 'Monaco', monospace;
min-height: 150px;
}
.result-success { border-left: 4px solid #27ae60; }
.result-error { border-left: 4px solid #e74c3c; }
.result-label { color: #999; font-size: 12px; margin-bottom: 5px; }
.result-value { color: #67eea; font-size: 14px; word-break: break-all; }
.result-type { color: #f39c12; font-size: 12px; margin-top: 10px; }
.result-error-msg { color: #e74c3c; }
/* 示例列表 */
.examples-list { max-height: 500px; overflow-y: auto; }
.example-item {
background: #f8f9fa;
border-radius: 8px;
padding: 15px;
margin-bottom: 10px;
cursor: pointer;
transition: all 0.3s;
border-left: 3px solid transparent;
}
.example-item:hover {
background: #e8f4f8;
border-left-color: #3498db;
transform: translateX(5px);
}
.example-category {
display: inline-block;
padding: 3px 10px;
border-radius: 12px;
font-size: 11px;
margin-bottom: 8px;
background: #667eea;
color: white;
}
.example-expression {
font-family: 'Monaco', monospace;
font-size: 14px;
color: #333;
margin-bottom: 5px;
font-weight: bold;
}
.example-desc { font-size: 12px; color: #666; }
.example-result { font-size: 11px; color: #27ae60; margin-top: 5px; }
/* 数据结构展示 */
.data-structure { background: #f8f9fa; border-radius: 8px; padding: 15px; }
.data-object { margin-bottom: 15px; }
.data-object-header {
background: #667eea;
color: white;
padding: 8px 12px;
border-radius: 6px;
font-weight: bold;
cursor: pointer;
}
.data-object-content {
padding: 10px;
border: 1px solid #e0e0e0;
border-top: none;
border-radius: 0 0 6px 6px;
background: white;
}
.data-field {
display: flex;
justify-content: space-between;
padding: 5px 0;
border-bottom: 1px solid #f0f0f0;
}
.data-field:last-child { border-bottom: none; }
.data-field-name { color: #667eea; font-weight: 500; }
.data-field-value { color: #333; }
.data-field-type { color: #999; font-size: 11px; }
/* 语法树 */
.syntax-tree { display: flex; flex-direction: column; gap: 10px; }
.tree-node {
background: #f8f9fa;
border-radius: 8px;
padding: 12px 15px;
border-left: 3px solid #667eea;
}
.tree-node-root { background: #667eea; color: white; border-left: none; }
.tree-node-title { font-weight: bold; margin-bottom: 5px; }
.tree-node-example { font-size: 12px; opacity: 0.8; font-family: monospace; }
/* 快速操作按钮 */
.quick-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 15px; }
.quick-btn {
padding: 6px 12px;
background: #e8f4f8;
border: 1px solid #3498db;
border-radius: 15px;
font-size: 12px;
cursor: pointer;
transition: all 0.3s;
}
.quick-btn:hover { background: #3498db; color: white; }
.nav { display: flex; gap: 10px; margin-bottom: 20px; flex-wrap: wrap; }
.nav a { padding: 10px 20px; background: white; border-radius: 20px; text-decoration: none; color: #333; font-size: 0.9em; box-shadow: 0 2px 5px rgba(0,0,0,0.1); }
.nav a:hover { background: #667eea; color: white; }
.lab { background: #fff7e6; border-left: 4px solid #fa8c16; padding: 15px; border-radius: 8px; margin-bottom: 20px; }
.lab strong { color: #874d00; }
.tips { background: #e8f4f8; padding: 15px; border-radius: 8px; margin-top: 15px; }
.tips ul { margin-left: 20px; }
.tips li { margin-bottom: 5px; font-size: 13px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>🎯 OGNL表达式可视化</h1>
<p>交互式学习对象图导航语言Object-Graph Navigation Language</p>
</div>
<div class="nav">
<a href="index.jsp">← 返回首页</a>
<a href="learn">学习中心</a>
<a href="classloader-visual">类加载可视化</a>
<a href="lifecycle">生命周期可视化</a>
</div>
<div class="lab">
<strong>🧪 实验任务</strong>
<ul>
<li>在<strong>表达式编辑器</strong>中输入OGNL表达式观察执行结果</li>
<li>点击<strong>示例列表</strong>中的表达式,快速学习各种语法</li>
<li>查看<strong>测试数据结构</strong>,了解可以访问的数据</li>
<li>尝试组合使用过滤、投影等高级操作</li>
</ul>
</div>
<div class="grid">
<!-- 表达式编辑器 -->
<div class="card">
<h3>✏️ 表达式编辑器</h3>
<div class="expression-editor">
<input type="text" id="expressionInput" class="expression-input"
placeholder="输入OGNL表达式例如: user.name 或 users.{name}">
<div>
<button class="btn btn-primary" onclick="executeExpression()">执行表达式</button>
<button class="btn btn-secondary" onclick="clearExpression()">清空</button>
</div>
</div>
<h4 style="margin-top: 20px; margin-bottom: 10px;">执行结果</h4>
<div id="resultPanel" class="result-panel">
<div class="result-label">输入表达式并点击"执行"查看结果</div>
</div>
<div class="quick-actions">
<span style="font-size: 12px; color: #666; margin-right: 10px;">快速插入:</span>
<span class="quick-btn" onclick="insertExpression('user.name')">user.name</span>
<span class="quick-btn" onclick="insertExpression('user.address.city')">user.address.city</span>
<span class="quick-btn" onclick="insertExpression('users.size()')">users.size()</span>
<span class="quick-btn" onclick="insertExpression('users.{name}')">users.{name}</span>
<span class="quick-btn" onclick="insertExpression('users.{? #this.age > 25}')">过滤</span>
<span class="quick-btn" onclick="insertExpression('#sessionUser.name')">#sessionUser</span>
</div>
</div>
<!-- 示例列表 -->
<div class="card">
<h3>📚 OGNL示例库点击使用</h3>
<div id="examplesList" class="examples-list">
<div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
</div>
</div>
<!-- 测试数据结构 -->
<div class="card">
<h3>📦 测试数据结构</h3>
<div id="dataStructure" class="data-structure">
<div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
</div>
</div>
<!-- OGNL语法 -->
<div class="card">
<h3>🌲 OGNL语法类型</h3>
<div id="syntaxTree" class="syntax-tree">
<div style="text-align: center; padding: 20px; color: #999;">加载中...</div>
</div>
<div class="tips">
<strong>💡 提示</strong>
<ul>
<li><strong>属性访问:</strong> 使用点号(.)访问对象属性,如 user.name</li>
<li><strong>方法调用:</strong> 直接调用方法,如 user.getName() 或 users.size()</li>
<li><strong>集合投影:</strong> 使用.{prop}提取属性列表,如 users.{name}</li>
<li><strong>集合过滤:</strong> 使用.{? condition}过滤元素</li>
<li><strong>上下文访问:</strong> 使用#访问上下文变量,如 #sessionUser</li>
<li><strong>静态访问:</strong> 使用@访问静态成员,如 @java.lang.Math@PI</li>
</ul>
</div>
</div>
</div>
<div class="card">
<h3>📖 学习要点</h3>
<ul>
<li><strong>值栈根对象:</strong> Action对象默认在值栈顶部可以直接访问其属性</li>
<li><strong>OGNL上下文:</strong> 包含request、session、application等Web对象</li>
<li><strong>类型转换:</strong> OGNL自动进行字符串到目标类型的转换</li>
<li><strong>集合操作:</strong> 支持过滤(?)、投影(.{})、选择(^/$)等高级操作</li>
<li><strong>Lambda支持:</strong> 可以使用Lambda表达式进行复杂操作</li>
<li><strong>安全性:</strong> OGNL功能强大注意防范OGNL注入攻击</li>
</ul>
</div>
</div>
<script>
// 加载示例列表
async function loadExamples() {
try {
const response = await fetch('ognl_getExamples');
const data = await response.json();
const container = document.getElementById('examplesList');
container.innerHTML = '';
data.examples.forEach((example, index) => {
const div = document.createElement('div');
div.className = 'example-item';
div.style.animationDelay = `${index * 0.05}s`;
div.onclick = () => useExample(example.expression);
div.innerHTML = `
<span class="example-category">${example.category}</span>
<div class="example-expression">${example.expression}</div>
<div class="example-desc">${example.description}</div>
<div class="example-result">结果: ${example.expectedResult}</div>
`;
container.appendChild(div);
});
} catch (error) {
document.getElementById('examplesList').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 加载测试数据
async function loadTestData() {
try {
const response = await fetch('ognl_getTestData');
const data = await response.json();
const container = document.getElementById('dataStructure');
container.innerHTML = '';
// User对象
const userDiv = document.createElement('div');
userDiv.className = 'data-object';
userDiv.innerHTML = `
<div class="data-object-header" onclick="toggleDataObject(this)">user: User</div>
<div class="data-object-content">
<div class="data-field">
<span class="data-field-name">id</span>
<span class="data-field-value">${data.user.id}</span>
<span class="data-field-type">Long</span>
</div>
<div class="data-field">
<span class="data-field-name">name</span>
<span class="data-field-value">${data.user.name}</span>
<span class="data-field-type">String</span>
</div>
<div class="data-field">
<span class="data-field-name">email</span>
<span class="data-field-value">${data.user.email}</span>
<span class="data-field-type">String</span>
</div>
<div class="data-field">
<span class="data-field-name">age</span>
<span class="data-field-value">${data.user.age}</span>
<span class="data-field-type">Integer</span>
</div>
<div class="data-field">
<span class="data-field-name">address</span>
<span class="data-field-value">${data.user.address.city} ${data.user.address.district}</span>
<span class="data-field-type">Address</span>
</div>
</div>
`;
container.appendChild(userDiv);
// Users列表
const usersDiv = document.createElement('div');
usersDiv.className = 'data-object';
usersDiv.innerHTML = `
<div class="data-object-header" onclick="toggleDataObject(this)">users: List&lt;User&gt; [${data.users.length} items]</div>
<div class="data-object-content" style="display: none;">
${data.users.map(u => `
<div class="data-field">
<span class="data-field-name">${u.name}</span>
<span class="data-field-value">${u.age}岁, ${u.address.city}</span>
</div>
`).join('')}
</div>
`;
container.appendChild(usersDiv);
// Context
const contextDiv = document.createElement('div');
contextDiv.className = 'data-object';
contextDiv.innerHTML = `
<div class="data-object-header" onclick="toggleDataObject(this)">context: Map</div>
<div class="data-object-content" style="display: none;">
${Object.entries(data.context).map(([k, v]) => `
<div class="data-field">
<span class="data-field-name">${k}</span>
<span class="data-field-value">${typeof v === 'object' ? JSON.stringify(v) : v}</span>
</div>
`).join('')}
</div>
`;
container.appendChild(contextDiv);
} catch (error) {
document.getElementById('dataStructure').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 加载语法树
async function loadSyntaxTree() {
try {
const response = await fetch('ognl_getSyntaxTree');
const data = await response.json();
const container = document.getElementById('syntaxTree');
container.innerHTML = '';
data.nodes.forEach((node, index) => {
const rootDiv = document.createElement('div');
rootDiv.className = 'tree-node tree-node-root';
rootDiv.innerHTML = `
<div class="tree-node-title">${node.name}</div>
<div class="tree-node-example">${node.description || ''}</div>
`;
container.appendChild(rootDiv);
if (node.children) {
node.children.forEach((child, childIndex) => {
const childDiv = document.createElement('div');
childDiv.className = 'tree-node';
childDiv.style.marginLeft = '20px';
childDiv.innerHTML = `
<div class="tree-node-title">${child.name}</div>
<div class="tree-node-example">${child.example}</div>
`;
container.appendChild(childDiv);
});
}
});
} catch (error) {
document.getElementById('syntaxTree').innerHTML =
`<div style="color: #e74c3c;">加载失败: ${error.message}</div>`;
}
}
// 执行表达式
async function executeExpression() {
const expression = document.getElementById('expressionInput').value.trim();
if (!expression) {
showResult('请输入表达式', null, '请输入OGNL表达式');
return;
}
try {
const response = await fetch('ognl_execute', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'expression=' + encodeURIComponent(expression)
});
const data = await response.json();
if (data.success) {
showResult(expression, data.result, null, data.resultType);
} else {
showResult(expression, null, data.error);
}
} catch (error) {
showResult(expression, null, '请求失败: ' + error.message);
}
}
// 显示结果
function showResult(expression, result, error, resultType) {
const panel = document.getElementById('resultPanel');
if (error) {
panel.className = 'result-panel result-error';
panel.innerHTML = `
<div class="result-label">表达式</div>
<div class="result-value">${expression}</div>
<div class="result-label" style="margin-top: 15px;">错误</div>
<div class="result-error-msg">${error}</div>
`;
} else {
panel.className = 'result-panel result-success';
let resultStr = result;
if (typeof result === 'object') {
resultStr = JSON.stringify(result, null, 2);
}
panel.innerHTML = `
<div class="result-label">表达式</div>
<div class="result-value">${expression}</div>
<div class="result-label" style="margin-top: 15px;">结果</div>
<div class="result-value">${resultStr}</div>
<div class="result-type">类型: ${resultType}</div>
`;
}
}
// 使用示例
function useExample(expression) {
document.getElementById('expressionInput').value = expression;
executeExpression();
}
// 插入表达式
function insertExpression(expr) {
const input = document.getElementById('expressionInput');
input.value = expr;
input.focus();
}
// 清空表达式
function clearExpression() {
document.getElementById('expressionInput').value = '';
document.getElementById('resultPanel').innerHTML = '<div class="result-label">输入表达式并点击"执行"查看结果</div>';
document.getElementById('resultPanel').className = 'result-panel';
}
// 切换数据对象展开/收起
function toggleDataObject(header) {
const content = header.nextElementSibling;
content.style.display = content.style.display === 'none' ? 'block' : 'none';
}
// 页面加载时初始化
window.onload = function() {
loadExamples();
loadTestData();
loadSyntaxTree();
// 绑定回车键
document.getElementById('expressionInput').addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
executeExpression();
}
});
};
</script>
</body>
</html>

19
struts2.log Normal file
View File

@@ -0,0 +1,19 @@
SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.
WARNING: jetty-runner is deprecated.
See Jetty Documentation for startup options
https://www.eclipse.org/jetty/documentation/
2026-03-07T05:07:01.035940650Z main ERROR Log4j2 could not find a logging implementation. Please add log4j-core to the classpath. Using SimpleLogger to log to the console...
[MonitorInterceptor] 初始化 - Sat Mar 07 05:07:04 UTC 2026
[LoggingInterceptor] 进入 Action: , Method: execute
[TimingInterceptor] 执行时间: 1115.90789 ms
[LoggingInterceptor] 退出 Action: , Result: success, 耗时: 1124ms
[LoggingInterceptor] 进入 Action: , Method: execute
[TimingInterceptor] 执行时间: 46.49766 ms
[LoggingInterceptor] 退出 Action: , Result: success, 耗时: 47ms
[LoggingInterceptor] 进入 Action: , Method: execute
[TimingInterceptor] 执行时间: 36.518364 ms
[LoggingInterceptor] 退出 Action: , Result: success, 耗时: 37ms
[MonitorInterceptor] 销毁 - Sat Mar 07 05:36:55 UTC 2026
[MonitorInterceptor] 最终统计: {=3}

Binary file not shown.

Binary file not shown.

Binary file not shown.

126
target/classes/struts.xml Normal file
View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
"http://struts.apache.org/dtds/struts-6.0.dtd">
<struts>
<!-- 开发模式 -->
<constant name="struts.devMode" value="true" />
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="struts.action.extension" value="action,," />
<package name="default" namespace="/" extends="struts-default">
<!-- ========== 自定义拦截器配置 ========== -->
<interceptors>
<interceptor name="logging" class="com.example.struts2.interceptor.LoggingInterceptor"/>
<interceptor name="timing" class="com.example.struts2.interceptor.TimingInterceptor"/>
<interceptor name="rateLimit" class="com.example.struts2.interceptor.RateLimitInterceptor"/>
<interceptor name="validation" class="com.example.struts2.interceptor.ValidationInterceptor"/>
<interceptor name="monitor" class="com.example.struts2.interceptor.MonitorInterceptor"/>
<interceptor-stack name="customStack">
<interceptor-ref name="logging"/>
<interceptor-ref name="timing"/>
<interceptor-ref name="monitor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
<interceptor-stack name="apiStack">
<interceptor-ref name="logging"/>
<interceptor-ref name="rateLimit">
<param name="maxRequestsPerMinute">100</param>
</interceptor-ref>
<interceptor-ref name="validation"/>
<interceptor-ref name="timing"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<!-- 默认拦截器栈 -->
<default-interceptor-ref name="customStack"/>
<!-- 默认 Action -->
<default-action-ref name="index" />
<!-- 全局结果 -->
<global-results>
<result name="rateLimitExceeded">/error-rate-limit.jsp</result>
<result name="invalidInput">/error-invalid-input.jsp</result>
</global-results>
<!-- ========== Actions ========== -->
<action name="index">
<result>/index.jsp</result>
</action>
<action name="hello" class="com.example.struts2.HelloAction">
<result>/hello.jsp</result>
</action>
<action name="learn" class="com.example.struts2.LearnAction">
<result>/learn.jsp</result>
</action>
<action name="interceptor" class="com.example.struts2.InterceptorDemoAction">
<result>/interceptor-demo.jsp</result>
</action>
<action name="ognl" class="com.example.struts2.OgnlLabAction">
<result>/ognl-lab.jsp</result>
</action>
<action name="ognl_bind" class="com.example.struts2.OgnlLabAction" method="bind">
<result>/ognl-lab.jsp</result>
</action>
<action name="validation" class="com.example.struts2.ValidationLabAction">
<result>/validation-lab.jsp</result>
</action>
<action name="validation_submit" class="com.example.struts2.ValidationLabAction" method="submit">
<param name="actionName">submit</param>
<result>/validation-lab.jsp</result>
<result name="input">/validation-lab.jsp</result>
</action>
<action name="interceptor_api" class="com.example.struts2.InterceptorDemoAction">
<interceptor-ref name="apiStack"/>
<result>/interceptor-demo.jsp</result>
</action>
<action name="calc" class="com.example.struts2.CalculatorAction">
<result>/calculator.jsp</result>
<result name="input">/calculator.jsp</result>
</action>
<action name="calc_execute" class="com.example.struts2.CalculatorAction" method="calculate">
<result>/calculator.jsp</result>
<result name="input">/calculator.jsp</result>
</action>
<action name="user" class="com.example.struts2.UserFormAction" method="list">
<result>/user-list.jsp</result>
</action>
<action name="user_add" class="com.example.struts2.UserFormAction" method="add">
<param name="actionName">user_add</param>
<result type="redirectAction">user</result>
<result name="input">/user-form.jsp</result>
</action>
<action name="user_edit" class="com.example.struts2.UserFormAction" method="edit">
<result>/user-form.jsp</result>
</action>
<action name="user_update" class="com.example.struts2.UserFormAction" method="update">
<param name="actionName">user_update</param>
<result type="redirectAction">user</result>
<result name="input">/user-form.jsp</result>
</action>
<action name="user_delete" class="com.example.struts2.UserFormAction" method="delete">
<result type="redirectAction">user</result>
</action>
</package>
</struts>

View File

@@ -0,0 +1,3 @@
artifactId=struts2-scaffold
groupId=com.example
version=1.0.0

View File

@@ -0,0 +1,14 @@
com/example/struts2/interceptor/LoggingInterceptor.class
com/example/struts2/InterceptorDemoAction.class
com/example/struts2/CalculatorAction.class
com/example/struts2/OgnlLabAction.class
com/example/struts2/interceptor/RateLimitInterceptor.class
com/example/struts2/HelloAction.class
com/example/struts2/LearnAction.class
com/example/struts2/interceptor/ValidationInterceptor.class
com/example/struts2/OgnlLabAction$DemoUser.class
com/example/struts2/UserFormAction$User.class
com/example/struts2/interceptor/TimingInterceptor.class
com/example/struts2/ValidationLabAction.class
com/example/struts2/UserFormAction.class
com/example/struts2/interceptor/MonitorInterceptor.class

View File

@@ -0,0 +1,10 @@
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/interceptor/ValidationInterceptor.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/HelloAction.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/interceptor/LoggingInterceptor.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/UserFormAction.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/interceptor/MonitorInterceptor.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/LearnAction.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/interceptor/TimingInterceptor.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/InterceptorDemoAction.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/CalculatorAction.java
/home/llm/Projects/struts2-scaffold/src/main/java/com/example/struts2/interceptor/RateLimitInterceptor.java

Binary file not shown.

View File

@@ -0,0 +1,103 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 6.0//EN"
"http://struts.apache.org/dtds/struts-6.0.dtd">
<struts>
<!-- 开发模式 -->
<constant name="struts.devMode" value="true" />
<constant name="struts.enable.DynamicMethodInvocation" value="true" />
<constant name="struts.action.extension" value="action,," />
<package name="default" namespace="/" extends="struts-default">
<!-- ========== 自定义拦截器配置 ========== -->
<interceptors>
<interceptor name="logging" class="com.example.struts2.interceptor.LoggingInterceptor"/>
<interceptor name="timing" class="com.example.struts2.interceptor.TimingInterceptor"/>
<interceptor name="rateLimit" class="com.example.struts2.interceptor.RateLimitInterceptor"/>
<interceptor name="validation" class="com.example.struts2.interceptor.ValidationInterceptor"/>
<interceptor name="monitor" class="com.example.struts2.interceptor.MonitorInterceptor"/>
<interceptor-stack name="customStack">
<interceptor-ref name="logging"/>
<interceptor-ref name="timing"/>
<interceptor-ref name="monitor"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
<interceptor-stack name="apiStack">
<interceptor-ref name="logging"/>
<interceptor-ref name="rateLimit">
<param name="maxRequestsPerMinute">100</param>
</interceptor-ref>
<interceptor-ref name="validation"/>
<interceptor-ref name="timing"/>
<interceptor-ref name="defaultStack"/>
</interceptor-stack>
</interceptors>
<!-- 默认拦截器栈 -->
<default-interceptor-ref name="customStack"/>
<!-- 默认 Action -->
<default-action-ref name="index" />
<!-- 全局结果 -->
<global-results>
<result name="rateLimitExceeded">/error-rate-limit.jsp</result>
<result name="invalidInput">/error-invalid-input.jsp</result>
</global-results>
<!-- ========== Actions ========== -->
<action name="index">
<result>/index.jsp</result>
</action>
<action name="hello" class="com.example.struts2.HelloAction">
<result>/hello.jsp</result>
</action>
<action name="learn" class="com.example.struts2.LearnAction">
<result>/learn.jsp</result>
</action>
<action name="interceptor" class="com.example.struts2.InterceptorDemoAction">
<result>/interceptor-demo.jsp</result>
</action>
<action name="interceptor_api" class="com.example.struts2.InterceptorDemoAction">
<interceptor-ref name="apiStack"/>
<result>/interceptor-demo.jsp</result>
</action>
<action name="calc" class="com.example.struts2.CalculatorAction">
<result>/calculator.jsp</result>
</action>
<action name="calc_execute" class="com.example.struts2.CalculatorAction" method="calculate">
<result>/calculator.jsp</result>
<result name="input">/calculator.jsp</result>
</action>
<action name="user" class="com.example.struts2.UserFormAction" method="list">
<result>/user-list.jsp</result>
</action>
<action name="user_add" class="com.example.struts2.UserFormAction" method="add">
<result type="redirectAction">user</result>
</action>
<action name="user_edit" class="com.example.struts2.UserFormAction" method="edit">
<result>/user-form.jsp</result>
</action>
<action name="user_update" class="com.example.struts2.UserFormAction" method="update">
<result type="redirectAction">user</result>
</action>
<action name="user_delete" class="com.example.struts2.UserFormAction" method="delete">
<result type="redirectAction">user</result>
</action>
</package>
</struts>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<display-name>Struts2 Scaffold</display-name>
<!-- 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>
<!-- 欢迎页 -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>

View File

@@ -0,0 +1,85 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<title>计算器 - Struts2 表单示例</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }
h1 { color: #e74c3c; }
.form-group { margin: 15px 0; }
label { display: inline-block; width: 100px; }
input, select { padding: 8px; font-size: 14px; }
button { background: #3498db; color: white; padding: 10px 20px; border: none; cursor: pointer; }
button:hover { background: #2980b9; }
.result { background: #2ecc71; color: white; padding: 15px; margin: 20px 0; border-radius: 5px; }
.error { color: #e74c3c; font-size: 12px; }
.tip { background: #f9f9f9; padding: 15px; border-left: 4px solid #3498db; margin: 20px 0; }
.quickbar { background:#fff7e6; padding:12px; border-left:4px solid #fa8c16; margin:20px 0; border-radius:6px; }
.quickbar button { margin-right:8px; }
</style>
</head>
<body>
<h1>🔢 计算器 - Struts2 表单示例</h1>
<s:if test="result != null">
<div class="result">
计算结果: <s:property value="num1"/>
<s:property value="operator"/>
<s:property value="num2"/>
= <s:property value="result"/>
</div>
</s:if>
<div class="quickbar">
<strong>快速实验:</strong>
<button type="button" onclick="fillExample(12, '+', 8)">填入正确示例</button>
<button type="button" onclick="fillExample(12, '/', 0)">填入除零错误</button>
<button type="button" onclick="fillExample('', '*', '')">填入校验错误</button>
</div>
<s:form action="calc_execute" method="post">
<div class="form-group">
<label>数字 1:</label>
<s:textfield name="num1" placeholder="输入第一个数字"/>
<s:fielderror fieldName="num1" cssClass="error"/>
</div>
<div class="form-group">
<label>运算符:</label>
<s:select name="operator" list="{'+', '-', '*', '/'}" headerKey="" headerValue="选择运算符"/>
</div>
<div class="form-group">
<label>数字 2:</label>
<s:textfield name="num2" placeholder="输入第二个数字"/>
<s:fielderror fieldName="num2" cssClass="error"/>
</div>
<div class="form-group">
<button type="submit">计算</button>
</div>
</s:form>
<div class="tip">
<strong>学习点:</strong>
<ul>
<li><code>name</code> 属性对应 Action 的 setter 方法</li>
<li><code>&lt;s:fielderror&gt;</code> 显示验证错误</li>
<li><code>validate()</code> 方法进行数据验证</li>
</ul>
</div>
<p><a href="learn">← 返回学习中心</a></p>
<script>
function fillExample(n1, op, n2) {
const fields = document.querySelectorAll('input[type="text"]');
const select = document.querySelector('select');
if (fields[0]) fields[0].value = n1;
if (select) select.value = op;
if (fields[1]) fields[1].value = n2;
}
</script>
</body>
</html>

View File

@@ -0,0 +1,21 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>参数无效</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 100px auto; padding: 20px; text-align: center; }
h1 { color: #e74c3c; }
.error-box { background: #fdeaea; border: 1px solid #e74c3c; padding: 30px; border-radius: 10px; }
.info { color: #7f8c8d; margin-top: 20px; }
</style>
</head>
<body>
<div class="error-box">
<h1>🚫 检测到无效参数</h1>
<p>您的请求包含可疑内容,已被拦截。</p>
<p class="info">此页面由 ValidationInterceptor 拦截器生成</p>
</div>
<p><a href="learn">← 返回学习中心</a></p>
</body>
</html>

View File

@@ -0,0 +1,21 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>请求过于频繁</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 100px auto; padding: 20px; text-align: center; }
h1 { color: #e74c3c; }
.error-box { background: #fdeaea; border: 1px solid #e74c3c; padding: 30px; border-radius: 10px; }
.info { color: #7f8c8d; margin-top: 20px; }
</style>
</head>
<body>
<div class="error-box">
<h1>⚠️ 请求过于频繁</h1>
<p>您的请求次数超过限制,请稍后再试。</p>
<p class="info">此页面由 RateLimitInterceptor 拦截器生成</p>
</div>
<p><a href="learn">← 返回学习中心</a></p>
</body>
</html>

View File

@@ -0,0 +1,8 @@
<!DOCTYPE html>
<html>
<head><title>Struts2 Scaffold</title></head>
<body>
<h1>${message}</h1>
<p>Struts2 脚手架部署中...</p>
</body>
</html>

View File

@@ -0,0 +1,33 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<title>Struts2 Scaffold</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; text-align: center; }
h1 { color: #e74c3c; font-size: 2.5em; }
.links { margin: 30px 0; }
.links a { display: inline-block; background: #3498db; color: white; padding: 15px 30px; margin: 10px; text-decoration: none; border-radius: 5px; }
.links a:hover { background: #2980b9; }
.links a.learn { background: #2ecc71; }
.links a.learn:hover { background: #27ae60; }
.info { color: #7f8c8d; margin-top: 40px; }
</style>
</head>
<body>
<h1>🚀 Struts2 Scaffold</h1>
<p>Struts2 学习脚手架已启动!</p>
<div class="links">
<a href="learn" class="learn">📚 学习中心</a>
</div>
<div class="links">
<a href="hello">Hello 示例</a>
<a href="calc">计算器</a>
<a href="user">用户管理</a>
</div>
<p class="info">Powered by Struts2 + Jetty</p>
</body>
</html>

View File

@@ -0,0 +1,80 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<title>拦截器演示 - Struts2</title>
<style>
body { font-family: Arial, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; }
h1 { color: #e74c3c; }
h2 { color: #3498db; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
.card { background: #f9f9f9; padding: 20px; margin: 15px 0; border-radius: 8px; }
.card h3 { margin-top: 0; color: #2c3e50; }
code { background: #eee; padding: 2px 6px; border-radius: 3px; }
pre { background: #2c3e50; color: #ecf0f1; padding: 15px; border-radius: 5px; overflow-x: auto; }
table { width: 100%; border-collapse: collapse; margin: 10px 0; }
th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
th { background: #3498db; color: white; }
.time { color: #27ae60; font-weight: bold; }
.api-link { display: inline-block; background: #9b59b6; color: white; padding: 10px 20px;
text-decoration: none; border-radius: 5px; margin: 5px; }
.lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin:20px 0; }
</style>
</head>
<body>
<h1>🛡️ Struts2 拦截器演示</h1>
<div class="lab">
<strong>实验观察点:</strong>
<ul>
<li>连续刷新页面,观察 Action 调用次数如何累积</li>
<li>切换到“API 限流栈”,理解为什么拦截器顺序会影响结果</li>
<li>注意执行时间显示,这就是拦截器注入到 request 的数据</li>
</ul>
</div>
<div class="card">
<h3>📊 执行统计</h3>
<p>本次请求执行时间: <span class="time"><s:property value="executionTime / 1000000.0"/> ms</span></p>
<h4>Action 调用统计:</h4>
<table>
<tr><th>Action</th><th>调用次数</th></tr>
<s:iterator value="interceptorStats" var="entry">
<tr>
<td><s:property value="#entry.key"/></td>
<td><s:property value="#entry.value"/></td>
</tr>
</s:iterator>
</table>
</div>
<div class="card">
<h3>🔗 拦截器链演示</h3>
<p>当前使用: <code>customStack</code> (日志 + 计时 + 监控 + 默认栈)</p>
<a class="api-link" href="interceptor_api">使用 API 限流栈</a>
<p>API 栈包含: 日志 + 限流 + 验证 + 计时 + 默认栈</p>
</div>
<div class="card">
<h3>📚 拦截器执行顺序</h3>
<pre>
请求 → LoggingInterceptor → TimingInterceptor → MonitorInterceptor → Action
响应 ← LoggingInterceptor ← TimingInterceptor ← MonitorInterceptor ← Result
</pre>
<p><strong>注意:</strong> 拦截器像洋葱一样,先进入的后退出</p>
</div>
<div class="card">
<h3>💡 拦截器核心概念</h3>
<ul>
<li><strong>Interceptor 接口:</strong> init() → intercept() → destroy()</li>
<li><strong>intercept() 方法:</strong> 调用 invocation.invoke() 继续链</li>
<li><strong>拦截器栈:</strong> 多个拦截器按顺序组成链</li>
<li><strong>责任链模式:</strong> 每个拦截器决定是否继续</li>
</ul>
</div>
<p><a href="learn">← 返回学习中心</a></p>
</body>
</html>

View File

@@ -0,0 +1,112 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<title>Struts2 学习中心</title>
<style>
body { font-family: Arial, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; }
h1 { color: #e74c3c; }
h2 { color: #3498db; border-bottom: 2px solid #3498db; padding-bottom: 10px; }
.card { background: #f5f5f5; padding: 20px; border-radius: 8px; margin: 20px 0; }
.card h3 { margin-top: 0; }
ul { line-height: 2; }
a { color: #3498db; text-decoration: none; }
a:hover { text-decoration: underline; }
.btn { display: inline-block; background: #3498db; color: white; padding: 10px 20px;
border-radius: 5px; margin: 5px; }
.btn:hover { text-decoration: none; background: #2980b9; }
.btn-green { background: #27ae60; }
.btn-purple { background: #9b59b6; }
code { background: #eee; padding: 2px 6px; border-radius: 3px; }
.lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin:20px 0; }
.quick-tools { display:flex; gap:10px; flex-wrap:wrap; margin-top:10px; }
</style>
</head>
<body>
<h1>🎓 Struts2 学习中心</h1>
<div class="lab">
<strong>🧪 学习任务卡</strong>
<ul>
<li>先点“拦截器演示”,观察执行统计和链路顺序</li>
<li>再点“计算器”,故意输入非法值体验 Struts2 验证</li>
<li>最后点“用户管理”,理解 Action + JSP + 表单提交流程</li>
</ul>
<div class="quick-tools">
<a class="btn btn-purple" href="interceptor">直接去拦截器实验</a>
<a class="btn" href="calc">直接去计算器实验</a>
<a class="btn btn-green" href="user">直接去用户管理实验</a>
</div>
</div>
<div class="card">
<h3>🛡️ 拦截器 (核心特性)</h3>
<p>拦截器是 Struts2 最强大的特性之一,基于责任链模式实现 AOP。</p>
<div>
<a class="btn btn-purple" href="interceptor">拦截器演示</a>
</div>
<ul>
<li><a href="interceptor">LoggingInterceptor</a> - 日志记录</li>
<li><a href="interceptor">TimingInterceptor</a> - 性能计时</li>
<li><a href="interceptor">RateLimitInterceptor</a> - IP 限流</li>
<li><a href="interceptor">ValidationInterceptor</a> - 参数验证</li>
<li><a href="interceptor">MonitorInterceptor</a> - 状态监控</li>
</ul>
</div>
<div class="card">
<h3>📝 基础示例</h3>
<div>
<a class="btn" href="hello">Hello World</a>
<a class="btn" href="calc">计算器</a>
<a class="btn btn-green" href="user">用户管理</a>
</div>
</div>
<h2>📚 学习路径</h2>
<div class="card">
<h3>1. MVC 架构</h3>
<ul>
<li><strong>Model:</strong> Action 类 + JavaBean</li>
<li><strong>View:</strong> JSP + Struts 标签库</li>
<li><strong>Controller:</strong> StrutsPrepareAndExecuteFilter</li>
</ul>
</div>
<div class="card">
<h3>2. 拦截器机制</h3>
<ul>
<li><code>Interceptor</code> 接口: init() → intercept() → destroy()</li>
<li><code>interceptor-stack</code>: 组合多个拦截器</li>
<li>执行顺序: 责任链模式(先入后出)</li>
</ul>
</div>
<div class="card">
<h3>3. OGNL 表达式</h3>
<ul>
<li><code>&lt;s:property value="name"/&gt;</code> - 输出属性</li>
<li><code>&lt;s:iterator value="list"&gt;</code> - 遍历集合</li>
<li><code>#request.key</code> - 访问 request</li>
</ul>
</div>
<div class="card">
<h3>4. 项目结构</h3>
<pre>
├── src/main/java/com/example/struts2/
│ ├── action/ # Action 类
│ └── interceptor/ # 自定义拦截器
├── src/main/resources/
│ └── struts.xml # 核心配置
└── src/main/webapp/
├── WEB-INF/web.xml # Servlet 配置
└── *.jsp # 视图页面
</pre>
</div>
<p><a href="/">← 返回首页</a></p>
</body>
</html>

View File

@@ -0,0 +1,43 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<title>用户表单 - Struts2</title>
<style>
body { font-family: Arial, sans-serif; max-width: 500px; margin: 50px auto; padding: 20px; }
h1 { color: #e74c3c; }
.form-group { margin: 15px 0; }
label { display: block; margin-bottom: 5px; font-weight: bold; }
input { width: 100%; padding: 10px; font-size: 14px; box-sizing: border-box; }
button { background: #3498db; color: white; padding: 12px 24px; border: none; cursor: pointer; margin-top: 10px; }
button:hover { background: #2980b9; }
</style>
</head>
<body>
<h1><s:if test="user.id == null">添加用户</s:if><s:else>编辑用户</s:else></h1>
<s:form action="%{user.id == null ? 'user_add' : 'user_update'}" method="post">
<s:hidden name="user.id"/>
<div class="form-group">
<label>姓名:</label>
<s:textfield name="user.name" placeholder="请输入姓名"/>
</div>
<div class="form-group">
<label>邮箱:</label>
<s:textfield name="user.email" placeholder="请输入邮箱"/>
</div>
<div class="form-group">
<label>年龄:</label>
<s:textfield name="user.age" placeholder="请输入年龄"/>
</div>
<button type="submit">保存</button>
</s:form>
<p><a href="user">← 返回用户列表</a></p>
</body>
</html>

View File

@@ -0,0 +1,59 @@
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<title>用户管理 - Struts2 CRUD 示例</title>
<style>
body { font-family: Arial, sans-serif; max-width: 800px; margin: 50px auto; padding: 20px; }
h1 { color: #e74c3c; }
table { width: 100%; border-collapse: collapse; margin: 20px 0; }
th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }
th { background: #3498db; color: white; }
tr:nth-child(even) { background: #f9f9f9; }
.btn { padding: 5px 10px; text-decoration: none; border-radius: 3px; margin-right: 5px; }
.btn-edit { background: #f39c12; color: white; }
.btn-delete { background: #e74c3c; color: white; }
.btn-add { background: #2ecc71; color: white; padding: 10px 20px; }
.tip { background: #f9f9f9; padding: 15px; border-left: 4px solid #3498db; margin: 20px 0; }
</style>
</head>
<body>
<h1>👥 用户管理 - Struts2 CRUD 示例</h1>
<p><a class="btn btn-add" href="user_edit">+ 添加用户</a></p>
<table>
<tr>
<th>ID</th>
<th>姓名</th>
<th>邮箱</th>
<th>年龄</th>
<th>操作</th>
</tr>
<s:iterator value="userList" var="u">
<tr>
<td><s:property value="#u.id"/></td>
<td><s:property value="#u.name"/></td>
<td><s:property value="#u.email"/></td>
<td><s:property value="#u.age"/></td>
<td>
<a class="btn btn-edit" href="user_edit?id=<s:property value='#u.id'/>">编辑</a>
<a class="btn btn-delete" href="user_delete?id=<s:property value='#u.id'/>" onclick="return confirm('确定删除?')">删除</a>
</td>
</tr>
</s:iterator>
</table>
<div class="tip">
<strong>学习点:</strong>
<ul>
<li><code>&lt;s:iterator&gt;</code> 遍历集合</li>
<li><code>redirectAction</code> 结果类型实现 PRG 模式</li>
<li>动态方法调用处理不同操作</li>
</ul>
</div>
<p><a href="learn">← 返回学习中心</a></p>
</body>
</html>

Binary file not shown.

View File

@@ -0,0 +1,579 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 22:22:00 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class calculator_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(2);
_jspx_dependants.put("file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar", Long.valueOf(1772603570859L));
_jspx_dependants.put("jar:file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar!/META-INF/struts-tags.tld", Long.valueOf(1712452520000L));
}
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fif_0026_005ftest;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssClass_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fselect_0026_005fname_005flist_005fheaderValue_005fheaderKey_005fnobody;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssClass_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fselect_0026_005fname_005flist_005fheaderValue_005fheaderKey_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
}
public void _jspDestroy() {
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest.release();
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.release();
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.release();
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.release();
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssClass_005fnobody.release();
_005fjspx_005ftagPool_005fs_005fselect_0026_005fname_005flist_005fheaderValue_005fheaderKey_005fnobody.release();
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>计算器 - Struts2 表单示例</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 600px; margin: 50px auto; padding: 20px; }\n");
out.write(" h1 { color: #e74c3c; }\n");
out.write(" .form-group { margin: 15px 0; }\n");
out.write(" label { display: inline-block; width: 100px; }\n");
out.write(" input, select { padding: 8px; font-size: 14px; }\n");
out.write(" button { background: #3498db; color: white; padding: 10px 20px; border: none; cursor: pointer; }\n");
out.write(" button:hover { background: #2980b9; }\n");
out.write(" .result { background: #2ecc71; color: white; padding: 15px; margin: 20px 0; border-radius: 5px; }\n");
out.write(" .error { color: #e74c3c; font-size: 12px; }\n");
out.write(" .tip { background: #f9f9f9; padding: 15px; border-left: 4px solid #3498db; margin: 20px 0; }\n");
out.write(" .quickbar { background:#fff7e6; padding:12px; border-left:4px solid #fa8c16; margin:20px 0; border-radius:6px; }\n");
out.write(" .quickbar button { margin-right:8px; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <h1>🔢 计算器 - Struts2 表单示例</h1>\n");
out.write(" \n");
out.write(" ");
if (_jspx_meth_s_005fif_005f0(_jspx_page_context))
return;
out.write("\n");
out.write(" \n");
out.write(" <div class=\"quickbar\">\n");
out.write(" <strong>快速实验:</strong>\n");
out.write(" <button type=\"button\" onclick=\"fillExample(12, '+', 8)\">填入正确示例</button>\n");
out.write(" <button type=\"button\" onclick=\"fillExample(12, '/', 0)\">填入除零错误</button>\n");
out.write(" <button type=\"button\" onclick=\"fillExample('', '*', '')\">填入校验错误</button>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005fform_005f0(_jspx_page_context))
return;
out.write("\n");
out.write(" \n");
out.write(" <div class=\"tip\">\n");
out.write(" <strong>学习点:</strong>\n");
out.write(" <ul>\n");
out.write(" <li><code>name</code> 属性对应 Action 的 setter 方法</li>\n");
out.write(" <li><code>&lt;s:fielderror&gt;</code> 显示验证错误</li>\n");
out.write(" <li><code>validate()</code> 方法进行数据验证</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <p><a href=\"learn\">← 返回学习中心</a></p>\n");
out.write("\n");
out.write(" <script>\n");
out.write(" function fillExample(n1, op, n2) {\n");
out.write(" const fields = document.querySelectorAll('input[type=\"text\"]');\n");
out.write(" const select = document.querySelector('select');\n");
out.write(" if (fields[0]) fields[0].value = n1;\n");
out.write(" if (select) select.value = op;\n");
out.write(" if (fields[1]) fields[1].value = n2;\n");
out.write(" }\n");
out.write(" </script>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
private boolean _jspx_meth_s_005fif_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:if
org.apache.struts2.views.jsp.IfTag _jspx_th_s_005fif_005f0 = (org.apache.struts2.views.jsp.IfTag) _005fjspx_005ftagPool_005fs_005fif_0026_005ftest.get(org.apache.struts2.views.jsp.IfTag.class);
boolean _jspx_th_s_005fif_005f0_reused = false;
try {
_jspx_th_s_005fif_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fif_005f0.setParent(null);
// /calculator.jsp(26,4) name = test type = java.lang.String reqTime = false required = true fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fif_005f0.setTest("result != null");
int _jspx_eval_s_005fif_005f0 = _jspx_th_s_005fif_005f0.doStartTag();
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fif_005f0);
}
do {
out.write("\n");
out.write(" <div class=\"result\">\n");
out.write(" 计算结果: ");
if (_jspx_meth_s_005fproperty_005f0(_jspx_th_s_005fif_005f0, _jspx_page_context))
return true;
out.write(" \n");
out.write(" ");
if (_jspx_meth_s_005fproperty_005f1(_jspx_th_s_005fif_005f0, _jspx_page_context))
return true;
out.write(" \n");
out.write(" ");
if (_jspx_meth_s_005fproperty_005f2(_jspx_th_s_005fif_005f0, _jspx_page_context))
return true;
out.write(" \n");
out.write(" = ");
if (_jspx_meth_s_005fproperty_005f3(_jspx_th_s_005fif_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fif_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fif_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest.reuse(_jspx_th_s_005fif_005f0);
_jspx_th_s_005fif_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fif_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fif_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fif_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f0 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f0_reused = false;
try {
_jspx_th_s_005fproperty_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fif_005f0);
// /calculator.jsp(28,18) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f0.setValue("num1");
int _jspx_eval_s_005fproperty_005f0 = _jspx_th_s_005fproperty_005f0.doStartTag();
if (_jspx_th_s_005fproperty_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f0);
_jspx_th_s_005fproperty_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fif_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f1 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f1_reused = false;
try {
_jspx_th_s_005fproperty_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fif_005f0);
// /calculator.jsp(29,12) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f1.setValue("operator");
int _jspx_eval_s_005fproperty_005f1 = _jspx_th_s_005fproperty_005f1.doStartTag();
if (_jspx_th_s_005fproperty_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f1);
_jspx_th_s_005fproperty_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f1, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f2(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fif_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f2 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f2_reused = false;
try {
_jspx_th_s_005fproperty_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f2.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fif_005f0);
// /calculator.jsp(30,12) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f2.setValue("num2");
int _jspx_eval_s_005fproperty_005f2 = _jspx_th_s_005fproperty_005f2.doStartTag();
if (_jspx_th_s_005fproperty_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f2);
_jspx_th_s_005fproperty_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f2, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f2_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f3(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fif_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f3 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f3_reused = false;
try {
_jspx_th_s_005fproperty_005f3.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f3.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fif_005f0);
// /calculator.jsp(31,14) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f3.setValue("result");
int _jspx_eval_s_005fproperty_005f3 = _jspx_th_s_005fproperty_005f3.doStartTag();
if (_jspx_th_s_005fproperty_005f3.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f3);
_jspx_th_s_005fproperty_005f3_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f3, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f3_reused);
}
return false;
}
private boolean _jspx_meth_s_005fform_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:form
org.apache.struts2.views.jsp.ui.FormTag _jspx_th_s_005fform_005f0 = (org.apache.struts2.views.jsp.ui.FormTag) _005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.get(org.apache.struts2.views.jsp.ui.FormTag.class);
boolean _jspx_th_s_005fform_005f0_reused = false;
try {
_jspx_th_s_005fform_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fform_005f0.setParent(null);
// /calculator.jsp(42,4) name = action type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fform_005f0.setAction("calc_execute");
// /calculator.jsp(42,4) name = method type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fform_005f0.setMethod("post");
int _jspx_eval_s_005fform_005f0 = _jspx_th_s_005fform_005f0.doStartTag();
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fform_005f0);
}
do {
out.write("\n");
out.write(" <div class=\"form-group\">\n");
out.write(" <label>数字 1:</label>\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ffielderror_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"form-group\">\n");
out.write(" <label>运算符:</label>\n");
out.write(" ");
if (_jspx_meth_s_005fselect_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"form-group\">\n");
out.write(" <label>数字 2:</label>\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f1(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ffielderror_005f1(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"form-group\">\n");
out.write(" <button type=\"submit\">计算</button>\n");
out.write(" </div>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fform_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fform_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.reuse(_jspx_th_s_005fform_005f0);
_jspx_th_s_005fform_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fform_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fform_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f0 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f0_reused = false;
try {
_jspx_th_s_005ftextfield_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /calculator.jsp(45,12) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f0.setName("num1");
// /calculator.jsp(45,12) null
_jspx_th_s_005ftextfield_005f0.setDynamicAttribute(null, "placeholder", "输入第一个数字");
int _jspx_eval_s_005ftextfield_005f0 = _jspx_th_s_005ftextfield_005f0.doStartTag();
if (_jspx_th_s_005ftextfield_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.reuse(_jspx_th_s_005ftextfield_005f0);
_jspx_th_s_005ftextfield_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f0, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ffielderror_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:fielderror
org.apache.struts2.views.jsp.ui.FieldErrorTag _jspx_th_s_005ffielderror_005f0 = (org.apache.struts2.views.jsp.ui.FieldErrorTag) _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssClass_005fnobody.get(org.apache.struts2.views.jsp.ui.FieldErrorTag.class);
boolean _jspx_th_s_005ffielderror_005f0_reused = false;
try {
_jspx_th_s_005ffielderror_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005ffielderror_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /calculator.jsp(46,12) name = fieldName type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f0.setFieldName("num1");
// /calculator.jsp(46,12) name = cssClass type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f0.setCssClass("error");
int _jspx_eval_s_005ffielderror_005f0 = _jspx_th_s_005ffielderror_005f0.doStartTag();
if (_jspx_th_s_005ffielderror_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssClass_005fnobody.reuse(_jspx_th_s_005ffielderror_005f0);
_jspx_th_s_005ffielderror_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ffielderror_005f0, _jsp_getInstanceManager(), _jspx_th_s_005ffielderror_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fselect_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:select
org.apache.struts2.views.jsp.ui.SelectTag _jspx_th_s_005fselect_005f0 = (org.apache.struts2.views.jsp.ui.SelectTag) _005fjspx_005ftagPool_005fs_005fselect_0026_005fname_005flist_005fheaderValue_005fheaderKey_005fnobody.get(org.apache.struts2.views.jsp.ui.SelectTag.class);
boolean _jspx_th_s_005fselect_005f0_reused = false;
try {
_jspx_th_s_005fselect_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fselect_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /calculator.jsp(51,12) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fselect_005f0.setName("operator");
// /calculator.jsp(51,12) name = list type = java.lang.String reqTime = false required = true fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fselect_005f0.setList("{'+', '-', '*', '/'}");
// /calculator.jsp(51,12) name = headerKey type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fselect_005f0.setHeaderKey("");
// /calculator.jsp(51,12) name = headerValue type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fselect_005f0.setHeaderValue("选择运算符");
int _jspx_eval_s_005fselect_005f0 = _jspx_th_s_005fselect_005f0.doStartTag();
if (_jspx_th_s_005fselect_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fselect_0026_005fname_005flist_005fheaderValue_005fheaderKey_005fnobody.reuse(_jspx_th_s_005fselect_005f0);
_jspx_th_s_005fselect_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fselect_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fselect_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f1 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f1_reused = false;
try {
_jspx_th_s_005ftextfield_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /calculator.jsp(56,12) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f1.setName("num2");
// /calculator.jsp(56,12) null
_jspx_th_s_005ftextfield_005f1.setDynamicAttribute(null, "placeholder", "输入第二个数字");
int _jspx_eval_s_005ftextfield_005f1 = _jspx_th_s_005ftextfield_005f1.doStartTag();
if (_jspx_th_s_005ftextfield_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.reuse(_jspx_th_s_005ftextfield_005f1);
_jspx_th_s_005ftextfield_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f1, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005ffielderror_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:fielderror
org.apache.struts2.views.jsp.ui.FieldErrorTag _jspx_th_s_005ffielderror_005f1 = (org.apache.struts2.views.jsp.ui.FieldErrorTag) _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssClass_005fnobody.get(org.apache.struts2.views.jsp.ui.FieldErrorTag.class);
boolean _jspx_th_s_005ffielderror_005f1_reused = false;
try {
_jspx_th_s_005ffielderror_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005ffielderror_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /calculator.jsp(57,12) name = fieldName type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f1.setFieldName("num2");
// /calculator.jsp(57,12) name = cssClass type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f1.setCssClass("error");
int _jspx_eval_s_005ffielderror_005f1 = _jspx_th_s_005ffielderror_005f1.doStartTag();
if (_jspx_th_s_005ffielderror_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssClass_005fnobody.reuse(_jspx_th_s_005ffielderror_005f1);
_jspx_th_s_005ffielderror_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ffielderror_005f1, _jsp_getInstanceManager(), _jspx_th_s_005ffielderror_005f1_reused);
}
return false;
}
}

Binary file not shown.

View File

@@ -0,0 +1,170 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 11:40:01 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class hello_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>Hello 示例 - Struts2</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; background:#f7f8fa; }\n");
out.write(" .card { background:#fff; border-radius:14px; padding:24px; box-shadow:0 4px 14px rgba(0,0,0,.06); margin-bottom:20px; }\n");
out.write(" h1 { color:#e74c3c; }\n");
out.write(" .msg { font-size:1.3em; color:#2c3e50; margin-top:10px; }\n");
out.write(" code { background:#f0f0f0; padding:2px 6px; border-radius:4px; }\n");
out.write(" .lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; }\n");
out.write(" a { color:#3498db; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h1>👋 Hello 示例</h1>\n");
out.write(" <p class=\"msg\">");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${message}", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null));
out.write("</p>\n");
out.write(" <p>这是 Struts2 最基础的一条链路:浏览器请求 <code>/hello</code> → Struts2 匹配 Action → Action 返回结果名 → JSP 被渲染。</p>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"lab\">\n");
out.write(" <strong>学习观察点</strong>\n");
out.write(" <ul>\n");
out.write(" <li>访问 URL<code>/hello</code></li>\n");
out.write(" <li>对应配置:<code>struts.xml</code> 里的 <code>&lt;action name=\"hello\" ...&gt;</code></li>\n");
out.write(" <li>对应控制器:<code>HelloAction.execute()</code></li>\n");
out.write(" <li>视图页面:当前这个 <code>hello.jsp</code></li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🔍 为什么这个例子重要</h3>\n");
out.write(" <p>很多人一开始学 Struts2会直接被拦截器、标签库、OGNL、配置文件吓到。Hello 示例的价值在于:先把“请求如何进来、结果如何出去”这条最小主线跑通,再去理解更复杂的机制。</p>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <p><a href=\"learn\">← 返回学习中心</a></p>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,224 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 11:39:53 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class index_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>Struts2 Learning Scaffold</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 1100px; margin: 40px auto; padding: 20px; background:#f7f8fa; }\n");
out.write(" .hero { background: linear-gradient(135deg,#ff7e5f,#feb47b); color:#fff; padding:30px; border-radius:16px; }\n");
out.write(" .hero h1 { margin:0 0 10px; font-size:2.4em; }\n");
out.write(" .hero p { font-size:1.1em; opacity: .95; }\n");
out.write(" .grid { display:grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap:18px; margin-top:24px; }\n");
out.write(" .card { background:#fff; border-radius:14px; padding:20px; box-shadow:0 4px 14px rgba(0,0,0,.06); }\n");
out.write(" .card h3 { margin-top:0; color:#e74c3c; }\n");
out.write(" .btn { display:inline-block; background:#3498db; color:#fff; padding:10px 18px; margin-top:10px; text-decoration:none; border-radius:8px; }\n");
out.write(" .btn:hover { background:#2980b9; }\n");
out.write(" .btn.green { background:#27ae60; }\n");
out.write(" .btn.purple { background:#9b59b6; }\n");
out.write(" .lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:16px; border-radius:10px; margin-top:24px; }\n");
out.write(" .lab ul { line-height:1.8; }\n");
out.write(" .timeline { background:#fff; border-radius:14px; padding:20px; margin-top:24px; box-shadow:0 4px 14px rgba(0,0,0,.06); }\n");
out.write(" .timeline li { margin:10px 0; line-height:1.7; }\n");
out.write(" code { background:#f0f0f0; padding:2px 6px; border-radius:4px; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <div class=\"hero\">\n");
out.write(" <h1>🚀 Struts2 Learning Scaffold</h1>\n");
out.write(" <p>不是单纯的 Struts2 演示页,而是一套带任务卡、表单实验、拦截器观察和 CRUD 流程的学习脚手架。</p>\n");
out.write(" <a href=\"learn\" class=\"btn green\">进入学习中心</a>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"lab\">\n");
out.write(" <strong>推荐学习顺序</strong>\n");
out.write(" <ul>\n");
out.write(" <li><strong>第一步:</strong> 进入 <a href=\"hello\">Hello 示例</a>,理解 Action → JSP 的最小闭环</li>\n");
out.write(" <li><strong>第二步:</strong> 进入 <a href=\"calc\">计算器</a>,体验表单绑定、校验、错误回显</li>\n");
out.write(" <li><strong>第三步:</strong> 进入 <a href=\"interceptor\">拦截器演示</a>,观察请求被增强的过程</li>\n");
out.write(" <li><strong>第四步:</strong> 进入 <a href=\"user\">用户管理</a>,学习列表/表单/增删改的完整流程</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"grid\">\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>👋 Hello 示例</h3>\n");
out.write(" <p>最小 Action 示例,适合理解 Struts2 如何把请求映射到 Action再把数据渲染到 JSP。</p>\n");
out.write(" <a href=\"hello\" class=\"btn\">打开示例</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🔢 计算器实验</h3>\n");
out.write(" <p>学习参数绑定、<code>validate()</code> 校验、字段错误回显,以及成功/失败两条分支。</p>\n");
out.write(" <a href=\"calc\" class=\"btn\">开始实验</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🛡️ 拦截器观察</h3>\n");
out.write(" <p>重点模块。能看到日志、执行时间、限流、监控等拦截器如何织入请求链路。</p>\n");
out.write(" <a href=\"interceptor\" class=\"btn purple\">观察拦截器</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>👥 用户 CRUD</h3>\n");
out.write(" <p>从列表页到表单页,再到新增/编辑/删除,形成完整的 Struts2 业务流学习闭环。</p>\n");
out.write(" <a href=\"user\" class=\"btn green\">进入 CRUD</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🧪 OGNL / 参数绑定实验</h3>\n");
out.write(" <p>可视化体验普通字段、嵌套对象、多选列表是如何被 Struts2 自动绑定到 Action 的。</p>\n");
out.write(" <a href=\"ognl\" class=\"btn purple\">进入实验室</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>⚠️ 验证与错误流实验</h3>\n");
out.write(" <p>通过错误示例/正确示例切换直观看到字段错误、input 返回和成功路径的区别。</p>\n");
out.write(" <a href=\"validation\" class=\"btn\">进入实验室</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🚀 AJAX 异步交互</h3>\n");
out.write(" <p>学习Struts2如何处理AJAX请求返回JSON数据实现前后端分离交互。</p>\n");
out.write(" <a href=\"ajax\" class=\"btn purple\">AJAX演示</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>📁 文件上传</h3>\n");
out.write(" <p>演示单文件、多文件上传,文件类型和大小验证,以及文件处理流程。</p>\n");
out.write(" <a href=\"upload\" class=\"btn green\">文件上传</a>\n");
out.write(" </div>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"timeline\">\n");
out.write(" <h3>📚 你会学到什么</h3>\n");
out.write(" <ul>\n");
out.write(" <li><strong>请求入口:</strong><code>StrutsPrepareAndExecuteFilter</code> 如何接管请求</li>\n");
out.write(" <li><strong>控制层:</strong>Action 如何接收参数、执行业务、返回 result</li>\n");
out.write(" <li><strong>视图层:</strong>JSP + Struts 标签库如何绑定 Action 数据</li>\n");
out.write(" <li><strong>增强机制:</strong>Interceptor Stack 如何像 AOP 一样织入日志、校验、限流</li>\n");
out.write(" <li><strong>状态流转:</strong>输入错误、成功提交、重定向返回列表等典型页面流</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}

View File

@@ -0,0 +1,364 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 22:21:50 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class interceptor_002ddemo_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(2);
_jspx_dependants.put("file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar", Long.valueOf(1772603570859L));
_jspx_dependants.put("jar:file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar!/META-INF/struts-tags.tld", Long.valueOf(1712452520000L));
}
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
}
public void _jspDestroy() {
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.release();
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.release();
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>拦截器演示 - Struts2</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 900px; margin: 50px auto; padding: 20px; }\n");
out.write(" h1 { color: #e74c3c; }\n");
out.write(" h2 { color: #3498db; border-bottom: 2px solid #3498db; padding-bottom: 10px; }\n");
out.write(" .card { background: #f9f9f9; padding: 20px; margin: 15px 0; border-radius: 8px; }\n");
out.write(" .card h3 { margin-top: 0; color: #2c3e50; }\n");
out.write(" code { background: #eee; padding: 2px 6px; border-radius: 3px; }\n");
out.write(" pre { background: #2c3e50; color: #ecf0f1; padding: 15px; border-radius: 5px; overflow-x: auto; }\n");
out.write(" table { width: 100%; border-collapse: collapse; margin: 10px 0; }\n");
out.write(" th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }\n");
out.write(" th { background: #3498db; color: white; }\n");
out.write(" .time { color: #27ae60; font-weight: bold; }\n");
out.write(" .api-link { display: inline-block; background: #9b59b6; color: white; padding: 10px 20px; \n");
out.write(" text-decoration: none; border-radius: 5px; margin: 5px; }\n");
out.write(" .lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin:20px 0; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <h1>🛡️ Struts2 拦截器演示</h1>\n");
out.write("\n");
out.write(" <div class=\"lab\">\n");
out.write(" <strong>实验观察点:</strong>\n");
out.write(" <ul>\n");
out.write(" <li>连续刷新页面,观察 Action 调用次数如何累积</li>\n");
out.write(" <li>切换到“API 限流栈”,理解为什么拦截器顺序会影响结果</li>\n");
out.write(" <li>注意执行时间显示,这就是拦截器注入到 request 的数据</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>📊 执行统计</h3>\n");
out.write(" <p>本次请求执行时间: <span class=\"time\">");
if (_jspx_meth_s_005fproperty_005f0(_jspx_page_context))
return;
out.write(" ms</span></p>\n");
out.write(" \n");
out.write(" <h4>Action 调用统计:</h4>\n");
out.write(" <table>\n");
out.write(" <tr><th>Action</th><th>调用次数</th></tr>\n");
out.write(" ");
if (_jspx_meth_s_005fiterator_005f0(_jspx_page_context))
return;
out.write("\n");
out.write(" </table>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🔗 拦截器链演示</h3>\n");
out.write(" <p>当前使用: <code>customStack</code> (日志 + 计时 + 监控 + 默认栈)</p>\n");
out.write(" <a class=\"api-link\" href=\"interceptor_api\">切换到 API 限流栈</a>\n");
out.write(" <a class=\"api-link\" href=\"interceptor\">恢复默认栈</a>\n");
out.write(" <p>API 栈包含: 日志 + 限流 + 验证 + 计时 + 默认栈</p>\n");
out.write(" <table>\n");
out.write(" <tr><th>拦截器</th><th>作用</th><th>你应该观察什么</th></tr>\n");
out.write(" <tr><td>LoggingInterceptor</td><td>记录请求进入/退出</td><td>看日志顺序,理解责任链</td></tr>\n");
out.write(" <tr><td>TimingInterceptor</td><td>统计执行耗时</td><td>看 executionTime 如何注入 request</td></tr>\n");
out.write(" <tr><td>MonitorInterceptor</td><td>累积 Action 调用统计</td><td>连续刷新看调用数增长</td></tr>\n");
out.write(" <tr><td>RateLimitInterceptor</td><td>限制频率</td><td>API 栈里观察限流触发</td></tr>\n");
out.write(" <tr><td>ValidationInterceptor</td><td>校验输入</td><td>思考错误应该在哪一层拦截</td></tr>\n");
out.write(" </table>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🧪 快速实验建议</h3>\n");
out.write(" <ul>\n");
out.write(" <li>先刷新当前页两次,看调用统计是否增加</li>\n");
out.write(" <li>再切到 <code>interceptor_api</code>,对比多了哪些拦截器</li>\n");
out.write(" <li>观察“先进入后退出”的洋葱模型</li>\n");
out.write(" <li>思考:如果你要加鉴权,应放在哪个拦截器位置最合理?</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>📚 拦截器执行顺序</h3>\n");
out.write(" <pre>\n");
out.write("请求 → LoggingInterceptor → TimingInterceptor → MonitorInterceptor → Action\n");
out.write("响应 ← LoggingInterceptor ← TimingInterceptor ← MonitorInterceptor ← Result\n");
out.write(" </pre>\n");
out.write(" <p><strong>注意:</strong> 拦截器像洋葱一样,先进入的后退出</p>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>💡 拦截器核心概念</h3>\n");
out.write(" <ul>\n");
out.write(" <li><strong>Interceptor 接口:</strong> init() → intercept() → destroy()</li>\n");
out.write(" <li><strong>intercept() 方法:</strong> 调用 invocation.invoke() 继续链</li>\n");
out.write(" <li><strong>拦截器栈:</strong> 多个拦截器按顺序组成链</li>\n");
out.write(" <li><strong>责任链模式:</strong> 每个拦截器决定是否继续</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <p><a href=\"learn\">← 返回学习中心</a></p>\n");
out.write("</body>\n");
out.write("</html>");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
private boolean _jspx_meth_s_005fproperty_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f0 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f0_reused = false;
try {
_jspx_th_s_005fproperty_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f0.setParent(null);
// /interceptor-demo.jsp(39,40) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f0.setValue("executionTime / 1000000.0");
int _jspx_eval_s_005fproperty_005f0 = _jspx_th_s_005fproperty_005f0.doStartTag();
if (_jspx_th_s_005fproperty_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f0);
_jspx_th_s_005fproperty_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fiterator_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:iterator
org.apache.struts2.views.jsp.IteratorTag _jspx_th_s_005fiterator_005f0 = (org.apache.struts2.views.jsp.IteratorTag) _005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.get(org.apache.struts2.views.jsp.IteratorTag.class);
boolean _jspx_th_s_005fiterator_005f0_reused = false;
try {
_jspx_th_s_005fiterator_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fiterator_005f0.setParent(null);
// /interceptor-demo.jsp(44,12) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fiterator_005f0.setValue("interceptorStats");
// /interceptor-demo.jsp(44,12) name = var type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fiterator_005f0.setVar("entry");
int _jspx_eval_s_005fiterator_005f0 = _jspx_th_s_005fiterator_005f0.doStartTag();
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fiterator_005f0);
}
do {
out.write("\n");
out.write(" <tr>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f1(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f2(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" </tr>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fiterator_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fiterator_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.reuse(_jspx_th_s_005fiterator_005f0);
_jspx_th_s_005fiterator_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fiterator_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fiterator_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f1 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f1_reused = false;
try {
_jspx_th_s_005fproperty_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /interceptor-demo.jsp(46,24) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f1.setValue("#entry.key");
int _jspx_eval_s_005fproperty_005f1 = _jspx_th_s_005fproperty_005f1.doStartTag();
if (_jspx_th_s_005fproperty_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f1);
_jspx_th_s_005fproperty_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f1, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f2(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f2 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f2_reused = false;
try {
_jspx_th_s_005fproperty_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f2.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /interceptor-demo.jsp(47,24) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f2.setValue("#entry.value");
int _jspx_eval_s_005fproperty_005f2 = _jspx_th_s_005fproperty_005f2.doStartTag();
if (_jspx_th_s_005fproperty_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f2);
_jspx_th_s_005fproperty_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f2, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f2_reused);
}
return false;
}
}

Binary file not shown.

View File

@@ -0,0 +1,260 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 22:21:47 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class learn_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(2);
_jspx_dependants.put("file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar", Long.valueOf(1772603570859L));
_jspx_dependants.put("jar:file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar!/META-INF/struts-tags.tld", Long.valueOf(1712452520000L));
}
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
}
public void _jspDestroy() {
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>Struts2 学习中心</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 1000px; margin: 40px auto; padding: 20px; background:#f7f8fa; }\n");
out.write(" h1 { color: #e74c3c; }\n");
out.write(" h2 { color: #3498db; border-bottom: 2px solid #3498db; padding-bottom: 10px; }\n");
out.write(" .card { background: #fff; padding: 20px; border-radius: 12px; margin: 20px 0; box-shadow:0 4px 14px rgba(0,0,0,.06); }\n");
out.write(" .card h3 { margin-top: 0; }\n");
out.write(" ul { line-height: 1.9; }\n");
out.write(" a { color: #3498db; text-decoration: none; }\n");
out.write(" a:hover { text-decoration: underline; }\n");
out.write(" .btn { display: inline-block; background: #3498db; color: white; padding: 10px 20px; border-radius: 6px; margin: 5px; }\n");
out.write(" .btn:hover { text-decoration: none; background: #2980b9; }\n");
out.write(" .btn-green { background: #27ae60; }\n");
out.write(" .btn-purple { background: #9b59b6; }\n");
out.write(" code { background: #eee; padding: 2px 6px; border-radius: 3px; }\n");
out.write(" .lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin:20px 0; }\n");
out.write(" .quick-tools { display:flex; gap:10px; flex-wrap:wrap; margin-top:10px; }\n");
out.write(" .grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(280px,1fr)); gap:16px; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <h1>🎓 Struts2 学习中心</h1>\n");
out.write("\n");
out.write(" <div class=\"lab\">\n");
out.write(" <strong>🧪 学习任务卡</strong>\n");
out.write(" <ul>\n");
out.write(" <li>先点“拦截器演示”,观察执行统计和链路顺序</li>\n");
out.write(" <li>再点“计算器”,故意输入非法值体验 Struts2 校验</li>\n");
out.write(" <li>最后点“用户管理”,理解 Action + JSP + 表单提交流程</li>\n");
out.write(" </ul>\n");
out.write(" <div class=\"quick-tools\">\n");
out.write(" <a class=\"btn btn-purple\" href=\"interceptor\">直接去拦截器实验</a>\n");
out.write(" <a class=\"btn\" href=\"calc\">直接去计算器实验</a>\n");
out.write(" <a class=\"btn btn-green\" href=\"user\">直接去用户管理实验</a>\n");
out.write(" </div>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"grid\">\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>👋 最小闭环</h3>\n");
out.write(" <p>从 <code>/hello</code> 开始,看 Action 如何返回 JSP 页面。</p>\n");
out.write(" <a class=\"btn\" href=\"hello\">打开 Hello</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🔢 表单与校验</h3>\n");
out.write(" <p>用计算器理解参数绑定、校验失败回显、成功结果显示。</p>\n");
out.write(" <a class=\"btn\" href=\"calc\">打开计算器</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🛡️ 拦截器机制</h3>\n");
out.write(" <p>学习 Struts2 最核心的增强机制:日志、计时、限流、监控。</p>\n");
out.write(" <a class=\"btn btn-purple\" href=\"interceptor\">打开拦截器实验</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>👥 CRUD 业务流</h3>\n");
out.write(" <p>通过用户管理体验列表页、表单页、重定向和状态更新。</p>\n");
out.write(" <a class=\"btn btn-green\" href=\"user\">打开用户管理</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🧪 OGNL / 参数绑定实验</h3>\n");
out.write(" <p>通过真正可交互的表单观察 Struts2 的字段绑定、嵌套对象绑定和集合绑定。</p>\n");
out.write(" <a class=\"btn btn-purple\" href=\"ognl\">打开 OGNL 实验室</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>⚠️ 验证与错误流实验</h3>\n");
out.write(" <p>学习为什么校验失败不会直接 500而是回到 input 页面并显示字段级错误。</p>\n");
out.write(" <a class=\"btn\" href=\"validation\">打开验证实验室</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>🚀 AJAX 异步交互</h3>\n");
out.write(" <p>学习Struts2如何处理AJAX请求返回JSON数据实现无刷新交互和实时数据更新。</p>\n");
out.write(" <a class=\"btn purple\" href=\"ajax\">打开AJAX演示</a>\n");
out.write(" </div>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>📁 文件上传</h3>\n");
out.write(" <p>演示单文件和多文件上传,学习文件类型验证、大小限制和文件处理流程。</p>\n");
out.write(" <a class=\"btn green\" href=\"upload\">打开文件上传</a>\n");
out.write(" </div>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <h2>📚 学习路径</h2>\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>1. MVC 架构</h3>\n");
out.write(" <ul>\n");
out.write(" <li><strong>Model:</strong> Action 类 + JavaBean</li>\n");
out.write(" <li><strong>View:</strong> JSP + Struts 标签库</li>\n");
out.write(" <li><strong>Controller:</strong> StrutsPrepareAndExecuteFilter</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>2. 拦截器机制</h3>\n");
out.write(" <ul>\n");
out.write(" <li><code>Interceptor</code> 接口: init() → intercept() → destroy()</li>\n");
out.write(" <li><code>interceptor-stack</code>: 组合多个拦截器</li>\n");
out.write(" <li>执行顺序: 责任链模式(先入后出)</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>3. OGNL 与标签库</h3>\n");
out.write(" <ul>\n");
out.write(" <li><code>&lt;s:property value=\"name\"/&gt;</code> - 输出属性</li>\n");
out.write(" <li><code>&lt;s:iterator value=\"list\"&gt;</code> - 遍历集合</li>\n");
out.write(" <li><code>&lt;s:form&gt;</code> + <code>&lt;s:textfield&gt;</code> - 表单绑定</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>4. 你当前项目里有哪些实验</h3>\n");
out.write(" <ul>\n");
out.write(" <li><strong>Hello</strong>最小 Action/JSP 映射</li>\n");
out.write(" <li><strong>Calculator</strong>参数绑定 + 校验 + 错误回显</li>\n");
out.write(" <li><strong>Interceptor</strong>理解自定义拦截器与请求链</li>\n");
out.write(" <li><strong>User CRUD</strong>模拟真实业务增删改查</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <p><a href=\"/\">← 返回首页</a></p>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}

Binary file not shown.

View File

@@ -0,0 +1,642 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 22:21:44 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class ognl_002dlab_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(2);
_jspx_dependants.put("file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar", Long.valueOf(1772603570859L));
_jspx_dependants.put("jar:file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar!/META-INF/struts-tags.tld", Long.valueOf(1712452520000L));
}
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fcheckboxlist_0026_005fname_005flist_005flabel_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fcheckboxlist_0026_005fname_005flist_005flabel_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
}
public void _jspDestroy() {
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.release();
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody.release();
_005fjspx_005ftagPool_005fs_005fcheckboxlist_0026_005fname_005flist_005flabel_005fnobody.release();
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.release();
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.release();
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.release();
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>OGNL / 参数绑定实验室 - Struts2</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 1000px; margin: 40px auto; padding: 20px; background:#f7f8fa; }\n");
out.write(" h1 { color:#8e44ad; }\n");
out.write(" .card { background:#fff; border-radius:12px; padding:20px; margin:18px 0; box-shadow:0 4px 14px rgba(0,0,0,.06); }\n");
out.write(" .lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin:20px 0; }\n");
out.write(" .form-row { display:flex; gap:12px; flex-wrap:wrap; margin:10px 0; }\n");
out.write(" input, select { padding:10px; min-width:180px; }\n");
out.write(" button { background:#8e44ad; color:#fff; border:none; padding:10px 18px; border-radius:6px; cursor:pointer; }\n");
out.write(" table { width:100%; border-collapse:collapse; margin-top:12px; }\n");
out.write(" th, td { border:1px solid #ddd; padding:10px; text-align:left; }\n");
out.write(" th { background:#8e44ad; color:white; }\n");
out.write(" code { background:#f0f0f0; padding:2px 6px; border-radius:4px; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <h1>🧪 OGNL / 参数绑定实验室</h1>\n");
out.write("\n");
out.write(" <div class=\"lab\">\n");
out.write(" <strong>实验任务卡</strong>\n");
out.write(" <ul>\n");
out.write(" <li>输入关键字和最小年龄,观察 Struts2 如何自动绑定请求参数到 Action 字段</li>\n");
out.write(" <li>注意 <code>keyword</code>、<code>minAge</code>、<code>user.name</code> 这类命名会如何映射</li>\n");
out.write(" <li>观察页面里 <code>&lt;s:property&gt;</code>、<code>&lt;s:iterator&gt;</code> 如何读取 Action 中的数据</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>参数过滤实验</h3>\n");
out.write(" ");
if (_jspx_meth_s_005fform_005f0(_jspx_page_context))
return;
out.write("\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>绑定结果观察</h3>\n");
out.write(" <p>keyword = <code>");
if (_jspx_meth_s_005fproperty_005f0(_jspx_page_context))
return;
out.write("</code></p>\n");
out.write(" <p>minAge = <code>");
if (_jspx_meth_s_005fproperty_005f1(_jspx_page_context))
return;
out.write("</code></p>\n");
out.write(" <p>user.name = <code>");
if (_jspx_meth_s_005fproperty_005f2(_jspx_page_context))
return;
out.write("</code></p>\n");
out.write(" <p>tags = <code>");
if (_jspx_meth_s_005fproperty_005f3(_jspx_page_context))
return;
out.write("</code></p>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>过滤后的用户列表</h3>\n");
out.write(" <table>\n");
out.write(" <tr><th>姓名</th><th>邮箱</th><th>年龄</th></tr>\n");
out.write(" ");
if (_jspx_meth_s_005fiterator_005f0(_jspx_page_context))
return;
out.write("\n");
out.write(" </table>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>学习点</h3>\n");
out.write(" <ul>\n");
out.write(" <li><code>keyword</code> → 直接绑定到 Action 同名字段</li>\n");
out.write(" <li><code>user.name</code> → 绑定到嵌套对象属性</li>\n");
out.write(" <li><code>tags</code> → 多选值绑定到 <code>List&lt;String&gt;</code></li>\n");
out.write(" <li><code>&lt;s:iterator&gt;</code> 会遍历 Action 暴露出来的集合</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <p><a href=\"learn\">← 返回学习中心</a></p>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
private boolean _jspx_meth_s_005fform_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:form
org.apache.struts2.views.jsp.ui.FormTag _jspx_th_s_005fform_005f0 = (org.apache.struts2.views.jsp.ui.FormTag) _005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.get(org.apache.struts2.views.jsp.ui.FormTag.class);
boolean _jspx_th_s_005fform_005f0_reused = false;
try {
_jspx_th_s_005fform_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fform_005f0.setParent(null);
// /ognl-lab.jsp(36,8) name = action type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fform_005f0.setAction("ognl_bind");
// /ognl-lab.jsp(36,8) name = method type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fform_005f0.setMethod("post");
int _jspx_eval_s_005fform_005f0 = _jspx_th_s_005fform_005f0.doStartTag();
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fform_005f0);
}
do {
out.write("\n");
out.write(" <div class=\"form-row\">\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f1(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" <div class=\"form-row\">\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f2(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005fcheckboxlist_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" <button type=\"submit\">执行绑定与过滤</button>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fform_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fform_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.reuse(_jspx_th_s_005fform_005f0);
_jspx_th_s_005fform_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fform_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fform_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f0 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f0_reused = false;
try {
_jspx_th_s_005ftextfield_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /ognl-lab.jsp(38,16) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f0.setName("keyword");
// /ognl-lab.jsp(38,16) name = label type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f0.setLabel("关键字");
// /ognl-lab.jsp(38,16) null
_jspx_th_s_005ftextfield_005f0.setDynamicAttribute(null, "placeholder", "例如:张 / example");
int _jspx_eval_s_005ftextfield_005f0 = _jspx_th_s_005ftextfield_005f0.doStartTag();
if (_jspx_th_s_005ftextfield_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody.reuse(_jspx_th_s_005ftextfield_005f0);
_jspx_th_s_005ftextfield_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f0, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f1 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f1_reused = false;
try {
_jspx_th_s_005ftextfield_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /ognl-lab.jsp(39,16) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f1.setName("minAge");
// /ognl-lab.jsp(39,16) name = label type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f1.setLabel("最小年龄");
// /ognl-lab.jsp(39,16) null
_jspx_th_s_005ftextfield_005f1.setDynamicAttribute(null, "placeholder", "例如20");
int _jspx_eval_s_005ftextfield_005f1 = _jspx_th_s_005ftextfield_005f1.doStartTag();
if (_jspx_th_s_005ftextfield_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody.reuse(_jspx_th_s_005ftextfield_005f1);
_jspx_th_s_005ftextfield_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f1, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f2(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f2 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f2_reused = false;
try {
_jspx_th_s_005ftextfield_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f2.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /ognl-lab.jsp(42,16) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f2.setName("user.name");
// /ognl-lab.jsp(42,16) name = label type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f2.setLabel("嵌套对象 user.name");
// /ognl-lab.jsp(42,16) null
_jspx_th_s_005ftextfield_005f2.setDynamicAttribute(null, "placeholder", "例如:测试用户");
int _jspx_eval_s_005ftextfield_005f2 = _jspx_th_s_005ftextfield_005f2.doStartTag();
if (_jspx_th_s_005ftextfield_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005flabel_005fnobody.reuse(_jspx_th_s_005ftextfield_005f2);
_jspx_th_s_005ftextfield_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f2, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f2_reused);
}
return false;
}
private boolean _jspx_meth_s_005fcheckboxlist_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:checkboxlist
org.apache.struts2.views.jsp.ui.CheckboxListTag _jspx_th_s_005fcheckboxlist_005f0 = (org.apache.struts2.views.jsp.ui.CheckboxListTag) _005fjspx_005ftagPool_005fs_005fcheckboxlist_0026_005fname_005flist_005flabel_005fnobody.get(org.apache.struts2.views.jsp.ui.CheckboxListTag.class);
boolean _jspx_th_s_005fcheckboxlist_005f0_reused = false;
try {
_jspx_th_s_005fcheckboxlist_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fcheckboxlist_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /ognl-lab.jsp(43,16) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fcheckboxlist_005f0.setName("tags");
// /ognl-lab.jsp(43,16) name = label type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fcheckboxlist_005f0.setLabel("兴趣标签");
// /ognl-lab.jsp(43,16) name = list type = java.lang.String reqTime = false required = true fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fcheckboxlist_005f0.setList("{'MVC','OGNL','Interceptor','JSP'}");
int _jspx_eval_s_005fcheckboxlist_005f0 = _jspx_th_s_005fcheckboxlist_005f0.doStartTag();
if (_jspx_th_s_005fcheckboxlist_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fcheckboxlist_0026_005fname_005flist_005flabel_005fnobody.reuse(_jspx_th_s_005fcheckboxlist_005f0);
_jspx_th_s_005fcheckboxlist_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fcheckboxlist_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fcheckboxlist_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f0 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f0_reused = false;
try {
_jspx_th_s_005fproperty_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f0.setParent(null);
// /ognl-lab.jsp(51,27) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f0.setValue("keyword");
// /ognl-lab.jsp(51,27) name = default type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f0.setDefault("(空)");
int _jspx_eval_s_005fproperty_005f0 = _jspx_th_s_005fproperty_005f0.doStartTag();
if (_jspx_th_s_005fproperty_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.reuse(_jspx_th_s_005fproperty_005f0);
_jspx_th_s_005fproperty_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f1(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f1 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f1_reused = false;
try {
_jspx_th_s_005fproperty_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f1.setParent(null);
// /ognl-lab.jsp(52,26) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f1.setValue("minAge");
// /ognl-lab.jsp(52,26) name = default type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f1.setDefault("(空)");
int _jspx_eval_s_005fproperty_005f1 = _jspx_th_s_005fproperty_005f1.doStartTag();
if (_jspx_th_s_005fproperty_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.reuse(_jspx_th_s_005fproperty_005f1);
_jspx_th_s_005fproperty_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f1, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f2(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f2 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f2_reused = false;
try {
_jspx_th_s_005fproperty_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f2.setParent(null);
// /ognl-lab.jsp(53,29) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f2.setValue("user.name");
// /ognl-lab.jsp(53,29) name = default type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f2.setDefault("(空)");
int _jspx_eval_s_005fproperty_005f2 = _jspx_th_s_005fproperty_005f2.doStartTag();
if (_jspx_th_s_005fproperty_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.reuse(_jspx_th_s_005fproperty_005f2);
_jspx_th_s_005fproperty_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f2, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f2_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f3(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f3 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f3_reused = false;
try {
_jspx_th_s_005fproperty_005f3.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f3.setParent(null);
// /ognl-lab.jsp(54,24) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f3.setValue("tags");
// /ognl-lab.jsp(54,24) name = default type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f3.setDefault("[]");
int _jspx_eval_s_005fproperty_005f3 = _jspx_th_s_005fproperty_005f3.doStartTag();
if (_jspx_th_s_005fproperty_005f3.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fdefault_005fnobody.reuse(_jspx_th_s_005fproperty_005f3);
_jspx_th_s_005fproperty_005f3_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f3, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f3_reused);
}
return false;
}
private boolean _jspx_meth_s_005fiterator_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:iterator
org.apache.struts2.views.jsp.IteratorTag _jspx_th_s_005fiterator_005f0 = (org.apache.struts2.views.jsp.IteratorTag) _005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.get(org.apache.struts2.views.jsp.IteratorTag.class);
boolean _jspx_th_s_005fiterator_005f0_reused = false;
try {
_jspx_th_s_005fiterator_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fiterator_005f0.setParent(null);
// /ognl-lab.jsp(61,12) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fiterator_005f0.setValue("filteredUsers");
// /ognl-lab.jsp(61,12) name = var type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fiterator_005f0.setVar("u");
int _jspx_eval_s_005fiterator_005f0 = _jspx_th_s_005fiterator_005f0.doStartTag();
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fiterator_005f0);
}
do {
out.write("\n");
out.write(" <tr>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f4(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f5(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f6(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" </tr>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fiterator_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fiterator_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.reuse(_jspx_th_s_005fiterator_005f0);
_jspx_th_s_005fiterator_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fiterator_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fiterator_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f4(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f4 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f4_reused = false;
try {
_jspx_th_s_005fproperty_005f4.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f4.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /ognl-lab.jsp(63,24) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f4.setValue("#u.name");
int _jspx_eval_s_005fproperty_005f4 = _jspx_th_s_005fproperty_005f4.doStartTag();
if (_jspx_th_s_005fproperty_005f4.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f4);
_jspx_th_s_005fproperty_005f4_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f4, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f4_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f5(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f5 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f5_reused = false;
try {
_jspx_th_s_005fproperty_005f5.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f5.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /ognl-lab.jsp(64,24) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f5.setValue("#u.email");
int _jspx_eval_s_005fproperty_005f5 = _jspx_th_s_005fproperty_005f5.doStartTag();
if (_jspx_th_s_005fproperty_005f5.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f5);
_jspx_th_s_005fproperty_005f5_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f5, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f5_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f6(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f6 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f6_reused = false;
try {
_jspx_th_s_005fproperty_005f6.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f6.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /ognl-lab.jsp(65,24) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f6.setValue("#u.age");
int _jspx_eval_s_005fproperty_005f6 = _jspx_th_s_005fproperty_005f6.doStartTag();
if (_jspx_th_s_005fproperty_005f6.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f6);
_jspx_th_s_005fproperty_005f6_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f6, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f6_reused);
}
return false;
}
}

Binary file not shown.

View File

@@ -0,0 +1,561 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 22:22:06 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class user_002dform_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(2);
_jspx_dependants.put("file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar", Long.valueOf(1772603570859L));
_jspx_dependants.put("jar:file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar!/META-INF/struts-tags.tld", Long.valueOf(1712452520000L));
}
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fif_0026_005ftest;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005felse;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fhidden_0026_005fname_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005felse = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fhidden_0026_005fname_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
}
public void _jspDestroy() {
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest.release();
_005fjspx_005ftagPool_005fs_005felse.release();
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.release();
_005fjspx_005ftagPool_005fs_005fhidden_0026_005fname_005fnobody.release();
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.release();
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.release();
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>用户表单 - Struts2</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 700px; margin: 40px auto; padding: 20px; background:#f7f8fa; }\n");
out.write(" h1 { color: #e74c3c; }\n");
out.write(" .form-group { margin: 15px 0; }\n");
out.write(" label { display: block; margin-bottom: 5px; font-weight: bold; }\n");
out.write(" input { width: 100%; padding: 10px; font-size: 14px; box-sizing: border-box; }\n");
out.write(" button { background: #3498db; color: white; padding: 12px 24px; border: none; cursor: pointer; margin-top: 10px; border-radius:6px; }\n");
out.write(" button:hover { background: #2980b9; }\n");
out.write(" .lab, .tip { background:#fff; padding:15px; border-radius:10px; margin:18px 0; box-shadow:0 4px 14px rgba(0,0,0,.06); }\n");
out.write(" .lab { background:#fff7e6; border-left:4px solid #fa8c16; }\n");
out.write(" .quick { display:flex; gap:10px; flex-wrap:wrap; }\n");
out.write(" .quick button { margin-top:0; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <h1>");
if (_jspx_meth_s_005fif_005f0(_jspx_page_context))
return;
if (_jspx_meth_s_005felse_005f0(_jspx_page_context))
return;
out.write("</h1>\n");
out.write("\n");
out.write(" <div class=\"lab\">\n");
out.write(" <strong>实验任务卡</strong>\n");
out.write(" <ul>\n");
out.write(" <li>试着新增一个完整用户,提交后观察为什么回到列表页</li>\n");
out.write(" <li>再故意填一个不合理年龄,看当前脚手架是否已经做服务端校验</li>\n");
out.write(" <li>思考:如果要做更严谨校验,你会把规则放在 Action、拦截器还是 XML/注解里?</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"tip\">\n");
out.write(" <strong>快速填充示例</strong>\n");
out.write(" <div class=\"quick\">\n");
out.write(" <button type=\"button\" onclick=\"fillExample('赵六','zhaoliu@example.com',26)\">填入正常示例</button>\n");
out.write(" <button type=\"button\" onclick=\"fillExample('测试用户','bad-email',-1)\">填入异常示例</button>\n");
out.write(" </div>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" ");
if (_jspx_meth_s_005fform_005f0(_jspx_page_context))
return;
out.write("\n");
out.write(" \n");
out.write(" <div class=\"tip\">\n");
out.write(" <strong>学习点</strong>\n");
out.write(" <ul>\n");
out.write(" <li>表单字段名 <code>user.name</code> / <code>user.email</code> / <code>user.age</code> 会映射到嵌套对象</li>\n");
out.write(" <li>当进入编辑页时Action 会先根据 <code>id</code> 找到已有对象并回填</li>\n");
out.write(" <li>提交成功后通过 <code>redirectAction</code> 返回列表页,避免刷新重复提交</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <p><a href=\"user\">← 返回用户列表</a></p>\n");
out.write("\n");
out.write(" <script>\n");
out.write(" function fillExample(name, email, age) {\n");
out.write(" const inputs = document.querySelectorAll('input[type=\"text\"]');\n");
out.write(" if (inputs[0]) inputs[0].value = name;\n");
out.write(" if (inputs[1]) inputs[1].value = email;\n");
out.write(" if (inputs[2]) inputs[2].value = age;\n");
out.write(" }\n");
out.write(" </script>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
private boolean _jspx_meth_s_005fif_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:if
org.apache.struts2.views.jsp.IfTag _jspx_th_s_005fif_005f0 = (org.apache.struts2.views.jsp.IfTag) _005fjspx_005ftagPool_005fs_005fif_0026_005ftest.get(org.apache.struts2.views.jsp.IfTag.class);
boolean _jspx_th_s_005fif_005f0_reused = false;
try {
_jspx_th_s_005fif_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fif_005f0.setParent(null);
// /user-form.jsp(23,8) name = test type = java.lang.String reqTime = false required = true fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fif_005f0.setTest("user.id == null");
int _jspx_eval_s_005fif_005f0 = _jspx_th_s_005fif_005f0.doStartTag();
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fif_005f0);
}
do {
out.write("添加用户");
int evalDoAfterBody = _jspx_th_s_005fif_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fif_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest.reuse(_jspx_th_s_005fif_005f0);
_jspx_th_s_005fif_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fif_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fif_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005felse_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:else
org.apache.struts2.views.jsp.ElseTag _jspx_th_s_005felse_005f0 = (org.apache.struts2.views.jsp.ElseTag) _005fjspx_005ftagPool_005fs_005felse.get(org.apache.struts2.views.jsp.ElseTag.class);
boolean _jspx_th_s_005felse_005f0_reused = false;
try {
_jspx_th_s_005felse_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005felse_005f0.setParent(null);
int _jspx_eval_s_005felse_005f0 = _jspx_th_s_005felse_005f0.doStartTag();
if (_jspx_eval_s_005felse_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005felse_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005felse_005f0);
}
do {
out.write("编辑用户");
int evalDoAfterBody = _jspx_th_s_005felse_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005felse_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005felse_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005felse.reuse(_jspx_th_s_005felse_005f0);
_jspx_th_s_005felse_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005felse_005f0, _jsp_getInstanceManager(), _jspx_th_s_005felse_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fform_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:form
org.apache.struts2.views.jsp.ui.FormTag _jspx_th_s_005fform_005f0 = (org.apache.struts2.views.jsp.ui.FormTag) _005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.get(org.apache.struts2.views.jsp.ui.FormTag.class);
boolean _jspx_th_s_005fform_005f0_reused = false;
try {
_jspx_th_s_005fform_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fform_005f0.setParent(null);
// /user-form.jsp(42,4) name = action type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fform_005f0.setAction("%{user.id == null ? 'user_add' : 'user_update'}");
// /user-form.jsp(42,4) name = method type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fform_005f0.setMethod("post");
int _jspx_eval_s_005fform_005f0 = _jspx_th_s_005fform_005f0.doStartTag();
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fform_005f0);
}
do {
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005fhidden_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" \n");
out.write(" <div class=\"form-group\">\n");
out.write(" <label>姓名:</label>\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ffielderror_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"form-group\">\n");
out.write(" <label>邮箱:</label>\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f1(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ffielderror_005f1(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <div class=\"form-group\">\n");
out.write(" <label>年龄:</label>\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f2(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ffielderror_005f2(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <button type=\"submit\">保存</button>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fform_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fform_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.reuse(_jspx_th_s_005fform_005f0);
_jspx_th_s_005fform_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fform_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fform_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fhidden_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:hidden
org.apache.struts2.views.jsp.ui.HiddenTag _jspx_th_s_005fhidden_005f0 = (org.apache.struts2.views.jsp.ui.HiddenTag) _005fjspx_005ftagPool_005fs_005fhidden_0026_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.HiddenTag.class);
boolean _jspx_th_s_005fhidden_005f0_reused = false;
try {
_jspx_th_s_005fhidden_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fhidden_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /user-form.jsp(43,8) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fhidden_005f0.setName("user.id");
int _jspx_eval_s_005fhidden_005f0 = _jspx_th_s_005fhidden_005f0.doStartTag();
if (_jspx_th_s_005fhidden_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fhidden_0026_005fname_005fnobody.reuse(_jspx_th_s_005fhidden_005f0);
_jspx_th_s_005fhidden_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fhidden_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fhidden_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f0 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f0_reused = false;
try {
_jspx_th_s_005ftextfield_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /user-form.jsp(47,12) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f0.setName("user.name");
// /user-form.jsp(47,12) null
_jspx_th_s_005ftextfield_005f0.setDynamicAttribute(null, "placeholder", "请输入姓名");
int _jspx_eval_s_005ftextfield_005f0 = _jspx_th_s_005ftextfield_005f0.doStartTag();
if (_jspx_th_s_005ftextfield_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.reuse(_jspx_th_s_005ftextfield_005f0);
_jspx_th_s_005ftextfield_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f0, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ffielderror_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:fielderror
org.apache.struts2.views.jsp.ui.FieldErrorTag _jspx_th_s_005ffielderror_005f0 = (org.apache.struts2.views.jsp.ui.FieldErrorTag) _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.get(org.apache.struts2.views.jsp.ui.FieldErrorTag.class);
boolean _jspx_th_s_005ffielderror_005f0_reused = false;
try {
_jspx_th_s_005ffielderror_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005ffielderror_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /user-form.jsp(48,12) name = fieldName type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f0.setFieldName("user.name");
// /user-form.jsp(48,12) name = cssStyle type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f0.setCssStyle("color:#e74c3c;font-size:12px;");
int _jspx_eval_s_005ffielderror_005f0 = _jspx_th_s_005ffielderror_005f0.doStartTag();
if (_jspx_th_s_005ffielderror_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.reuse(_jspx_th_s_005ffielderror_005f0);
_jspx_th_s_005ffielderror_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ffielderror_005f0, _jsp_getInstanceManager(), _jspx_th_s_005ffielderror_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f1 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f1_reused = false;
try {
_jspx_th_s_005ftextfield_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /user-form.jsp(53,12) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f1.setName("user.email");
// /user-form.jsp(53,12) null
_jspx_th_s_005ftextfield_005f1.setDynamicAttribute(null, "placeholder", "请输入邮箱");
int _jspx_eval_s_005ftextfield_005f1 = _jspx_th_s_005ftextfield_005f1.doStartTag();
if (_jspx_th_s_005ftextfield_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.reuse(_jspx_th_s_005ftextfield_005f1);
_jspx_th_s_005ftextfield_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f1, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005ffielderror_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:fielderror
org.apache.struts2.views.jsp.ui.FieldErrorTag _jspx_th_s_005ffielderror_005f1 = (org.apache.struts2.views.jsp.ui.FieldErrorTag) _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.get(org.apache.struts2.views.jsp.ui.FieldErrorTag.class);
boolean _jspx_th_s_005ffielderror_005f1_reused = false;
try {
_jspx_th_s_005ffielderror_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005ffielderror_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /user-form.jsp(54,12) name = fieldName type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f1.setFieldName("user.email");
// /user-form.jsp(54,12) name = cssStyle type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f1.setCssStyle("color:#e74c3c;font-size:12px;");
int _jspx_eval_s_005ffielderror_005f1 = _jspx_th_s_005ffielderror_005f1.doStartTag();
if (_jspx_th_s_005ffielderror_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.reuse(_jspx_th_s_005ffielderror_005f1);
_jspx_th_s_005ffielderror_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ffielderror_005f1, _jsp_getInstanceManager(), _jspx_th_s_005ffielderror_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f2(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f2 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f2_reused = false;
try {
_jspx_th_s_005ftextfield_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f2.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /user-form.jsp(59,12) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f2.setName("user.age");
// /user-form.jsp(59,12) null
_jspx_th_s_005ftextfield_005f2.setDynamicAttribute(null, "placeholder", "请输入年龄");
int _jspx_eval_s_005ftextfield_005f2 = _jspx_th_s_005ftextfield_005f2.doStartTag();
if (_jspx_th_s_005ftextfield_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fplaceholder_005fname_005fnobody.reuse(_jspx_th_s_005ftextfield_005f2);
_jspx_th_s_005ftextfield_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f2, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f2_reused);
}
return false;
}
private boolean _jspx_meth_s_005ffielderror_005f2(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:fielderror
org.apache.struts2.views.jsp.ui.FieldErrorTag _jspx_th_s_005ffielderror_005f2 = (org.apache.struts2.views.jsp.ui.FieldErrorTag) _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.get(org.apache.struts2.views.jsp.ui.FieldErrorTag.class);
boolean _jspx_th_s_005ffielderror_005f2_reused = false;
try {
_jspx_th_s_005ffielderror_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005ffielderror_005f2.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /user-form.jsp(60,12) name = fieldName type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f2.setFieldName("user.age");
// /user-form.jsp(60,12) name = cssStyle type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f2.setCssStyle("color:#e74c3c;font-size:12px;");
int _jspx_eval_s_005ffielderror_005f2 = _jspx_th_s_005ffielderror_005f2.doStartTag();
if (_jspx_th_s_005ffielderror_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.reuse(_jspx_th_s_005ffielderror_005f2);
_jspx_th_s_005ffielderror_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ffielderror_005f2, _jsp_getInstanceManager(), _jspx_th_s_005ffielderror_005f2_reused);
}
return false;
}
}

Binary file not shown.

View File

@@ -0,0 +1,453 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 11:40:06 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class user_002dlist_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(2);
_jspx_dependants.put("file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar", Long.valueOf(1772603570859L));
_jspx_dependants.put("jar:file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar!/META-INF/struts-tags.tld", Long.valueOf(1712452520000L));
}
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
}
public void _jspDestroy() {
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.release();
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.release();
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>用户管理 - Struts2 CRUD 示例</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 1000px; margin: 40px auto; padding: 20px; background:#f7f8fa; }\n");
out.write(" h1 { color: #e74c3c; }\n");
out.write(" table { width: 100%; border-collapse: collapse; margin: 20px 0; background:#fff; }\n");
out.write(" th, td { border: 1px solid #ddd; padding: 12px; text-align: left; }\n");
out.write(" th { background: #3498db; color: white; }\n");
out.write(" tr:nth-child(even) { background: #f9f9f9; }\n");
out.write(" .btn { padding: 6px 12px; text-decoration: none; border-radius: 4px; margin-right: 5px; display:inline-block; }\n");
out.write(" .btn-edit { background: #f39c12; color: white; }\n");
out.write(" .btn-delete { background: #e74c3c; color: white; }\n");
out.write(" .btn-add { background: #2ecc71; color: white; padding: 10px 20px; }\n");
out.write(" .tip, .lab { background: #fff; padding: 15px; border-radius: 10px; margin: 20px 0; box-shadow:0 4px 14px rgba(0,0,0,.06); }\n");
out.write(" .lab { border-left: 4px solid #fa8c16; background:#fff7e6; }\n");
out.write(" .stats { display:flex; gap:12px; flex-wrap:wrap; margin:15px 0; }\n");
out.write(" .stat { background:#fff; padding:14px 18px; border-radius:10px; box-shadow:0 4px 14px rgba(0,0,0,.06); min-width:160px; }\n");
out.write(" .stat strong { display:block; font-size:1.4em; color:#3498db; }\n");
out.write(" code { background:#f0f0f0; padding:2px 6px; border-radius:4px; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <h1>👥 用户管理 - Struts2 CRUD 示例</h1>\n");
out.write("\n");
out.write(" <div class=\"lab\">\n");
out.write(" <strong>实验任务卡</strong>\n");
out.write(" <ul>\n");
out.write(" <li>先新增一个用户,观察表单提交后为什么会回到列表页</li>\n");
out.write(" <li>再编辑一个用户,体会 Struts2 如何把已有数据回填到表单</li>\n");
out.write(" <li>最后删除一个用户,理解 <code>redirectAction</code> 的使用场景</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"stats\">\n");
out.write(" <div class=\"stat\"><span>当前用户数</span><strong>");
if (_jspx_meth_s_005fproperty_005f0(_jspx_page_context))
return;
out.write("</strong></div>\n");
out.write(" <div class=\"stat\"><span>演示模式</span><strong>内存列表</strong></div>\n");
out.write(" <div class=\"stat\"><span>学习重点</span><strong>CRUD 流程</strong></div>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <p><a class=\"btn btn-add\" href=\"user_edit\">+ 添加用户</a></p>\n");
out.write(" \n");
out.write(" <table>\n");
out.write(" <tr>\n");
out.write(" <th>ID</th>\n");
out.write(" <th>姓名</th>\n");
out.write(" <th>邮箱</th>\n");
out.write(" <th>年龄</th>\n");
out.write(" <th>操作</th>\n");
out.write(" </tr>\n");
out.write(" ");
if (_jspx_meth_s_005fiterator_005f0(_jspx_page_context))
return;
out.write("\n");
out.write(" </table>\n");
out.write(" \n");
out.write(" <div class=\"tip\">\n");
out.write(" <strong>学习点</strong>\n");
out.write(" <ul>\n");
out.write(" <li><code>&lt;s:iterator&gt;</code> 遍历集合</li>\n");
out.write(" <li><code>redirectAction</code> 结果类型实现 PRG 模式</li>\n");
out.write(" <li>同一个 Action 通过不同 method 处理 list/add/edit/update/delete</li>\n");
out.write(" <li>这里的数据存在内存里,重启后会恢复初始样本</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write(" \n");
out.write(" <p><a href=\"learn\">← 返回学习中心</a></p>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
private boolean _jspx_meth_s_005fproperty_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f0 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f0_reused = false;
try {
_jspx_th_s_005fproperty_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f0.setParent(null);
// /user-list.jsp(40,52) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f0.setValue("userList.size()");
int _jspx_eval_s_005fproperty_005f0 = _jspx_th_s_005fproperty_005f0.doStartTag();
if (_jspx_th_s_005fproperty_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f0);
_jspx_th_s_005fproperty_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fiterator_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:iterator
org.apache.struts2.views.jsp.IteratorTag _jspx_th_s_005fiterator_005f0 = (org.apache.struts2.views.jsp.IteratorTag) _005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.get(org.apache.struts2.views.jsp.IteratorTag.class);
boolean _jspx_th_s_005fiterator_005f0_reused = false;
try {
_jspx_th_s_005fiterator_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fiterator_005f0.setParent(null);
// /user-list.jsp(55,8) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fiterator_005f0.setValue("userList");
// /user-list.jsp(55,8) name = var type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fiterator_005f0.setVar("u");
int _jspx_eval_s_005fiterator_005f0 = _jspx_th_s_005fiterator_005f0.doStartTag();
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fiterator_005f0);
}
do {
out.write("\n");
out.write(" <tr>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f1(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f2(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f3(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" <td>");
if (_jspx_meth_s_005fproperty_005f4(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("</td>\n");
out.write(" <td>\n");
out.write(" <a class=\"btn btn-edit\" href=\"user_edit?id=");
if (_jspx_meth_s_005fproperty_005f5(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("\">编辑</a>\n");
out.write(" <a class=\"btn btn-delete\" href=\"user_delete?id=");
if (_jspx_meth_s_005fproperty_005f6(_jspx_th_s_005fiterator_005f0, _jspx_page_context))
return true;
out.write("\" onclick=\"return confirm('确定删除?')\">删除</a>\n");
out.write(" </td>\n");
out.write(" </tr>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fiterator_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fiterator_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fiterator_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fiterator_0026_005fvar_005fvalue.reuse(_jspx_th_s_005fiterator_005f0);
_jspx_th_s_005fiterator_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fiterator_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fiterator_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f1 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f1_reused = false;
try {
_jspx_th_s_005fproperty_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /user-list.jsp(57,20) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f1.setValue("#u.id");
int _jspx_eval_s_005fproperty_005f1 = _jspx_th_s_005fproperty_005f1.doStartTag();
if (_jspx_th_s_005fproperty_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f1);
_jspx_th_s_005fproperty_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f1, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f2(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f2 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f2_reused = false;
try {
_jspx_th_s_005fproperty_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f2.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /user-list.jsp(58,20) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f2.setValue("#u.name");
int _jspx_eval_s_005fproperty_005f2 = _jspx_th_s_005fproperty_005f2.doStartTag();
if (_jspx_th_s_005fproperty_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f2);
_jspx_th_s_005fproperty_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f2, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f2_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f3(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f3 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f3_reused = false;
try {
_jspx_th_s_005fproperty_005f3.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f3.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /user-list.jsp(59,20) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f3.setValue("#u.email");
int _jspx_eval_s_005fproperty_005f3 = _jspx_th_s_005fproperty_005f3.doStartTag();
if (_jspx_th_s_005fproperty_005f3.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f3);
_jspx_th_s_005fproperty_005f3_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f3, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f3_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f4(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f4 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f4_reused = false;
try {
_jspx_th_s_005fproperty_005f4.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f4.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /user-list.jsp(60,20) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f4.setValue("#u.age");
int _jspx_eval_s_005fproperty_005f4 = _jspx_th_s_005fproperty_005f4.doStartTag();
if (_jspx_th_s_005fproperty_005f4.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f4);
_jspx_th_s_005fproperty_005f4_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f4, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f4_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f5(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f5 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f5_reused = false;
try {
_jspx_th_s_005fproperty_005f5.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f5.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /user-list.jsp(62,63) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f5.setValue("#u.id");
int _jspx_eval_s_005fproperty_005f5 = _jspx_th_s_005fproperty_005f5.doStartTag();
if (_jspx_th_s_005fproperty_005f5.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f5);
_jspx_th_s_005fproperty_005f5_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f5, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f5_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f6(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fiterator_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f6 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f6_reused = false;
try {
_jspx_th_s_005fproperty_005f6.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f6.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fiterator_005f0);
// /user-list.jsp(63,67) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f6.setValue("#u.id");
int _jspx_eval_s_005fproperty_005f6 = _jspx_th_s_005fproperty_005f6.doStartTag();
if (_jspx_th_s_005fproperty_005f6.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f6);
_jspx_th_s_005fproperty_005f6_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f6, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f6_reused);
}
return false;
}
}

View File

@@ -0,0 +1,514 @@
/*
* Generated by the Jasper component of Apache Tomcat
* Version: jetty/9.4.54.v20240208
* Generated at: 2026-03-12 22:22:01 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class validation_002dlab_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
static {
_jspx_dependants = new java.util.HashMap<java.lang.String,java.lang.Long>(2);
_jspx_dependants.put("file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar", Long.valueOf(1772603570859L));
_jspx_dependants.put("jar:file:/home/llm/.m2/repository/org/apache/struts/struts2-core/6.4.0/struts2-core-6.4.0.jar!/META-INF/struts-tags.tld", Long.valueOf(1712452520000L));
}
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fif_0026_005ftest;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody;
private org.apache.jasper.runtime.TagHandlerPool _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody;
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() {
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody = org.apache.jasper.runtime.TagHandlerPool.getTagHandlerPool(getServletConfig());
}
public void _jspDestroy() {
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest.release();
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.release();
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.release();
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody.release();
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.release();
}
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
final java.lang.String _jspx_method = request.getMethod();
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSPs only permit GET, POST or HEAD. Jasper also permits OPTIONS");
return;
}
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html;charset=UTF-8");
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\n");
out.write("\n");
out.write("<!DOCTYPE html>\n");
out.write("<html>\n");
out.write("<head>\n");
out.write(" <meta charset=\"UTF-8\">\n");
out.write(" <title>验证与错误流实验室 - Struts2</title>\n");
out.write(" <style>\n");
out.write(" body { font-family: Arial, sans-serif; max-width: 900px; margin: 40px auto; padding: 20px; background:#f7f8fa; }\n");
out.write(" h1 { color:#c0392b; }\n");
out.write(" .card { background:#fff; border-radius:12px; padding:20px; margin:18px 0; box-shadow:0 4px 14px rgba(0,0,0,.06); }\n");
out.write(" .lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin:20px 0; }\n");
out.write(" .quick { display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px; }\n");
out.write(" button { background:#c0392b; color:white; border:none; padding:10px 16px; border-radius:6px; cursor:pointer; }\n");
out.write(" input { padding:10px; width:100%; box-sizing:border-box; }\n");
out.write(" .field { margin:12px 0; }\n");
out.write(" .ok { background:#eafaf1; color:#1e8449; padding:12px; border-radius:8px; }\n");
out.write(" </style>\n");
out.write("</head>\n");
out.write("<body>\n");
out.write(" <h1>⚠️ 验证与错误流实验室</h1>\n");
out.write("\n");
out.write(" <div class=\"lab\">\n");
out.write(" <strong>实验任务卡</strong>\n");
out.write(" <ul>\n");
out.write(" <li>先点“填入错误示例”,提交后观察字段级错误是如何显示的</li>\n");
out.write(" <li>再点“填入正确示例”,观察 Action 成功后的返回</li>\n");
out.write(" <li>思考:为什么 Struts2 的校验失败会回到 input 页,而不是直接报 500</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <div class=\"quick\">\n");
out.write(" <button type=\"button\" onclick=\"fillBad()\">填入错误示例</button>\n");
out.write(" <button type=\"button\" onclick=\"fillGood()\">填入正确示例</button>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005fif_005f0(_jspx_page_context))
return;
out.write("\n");
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005fform_005f0(_jspx_page_context))
return;
out.write("\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <div class=\"card\">\n");
out.write(" <h3>学习点</h3>\n");
out.write(" <ul>\n");
out.write(" <li>字段错误通过 <code>addFieldError()</code> 收集</li>\n");
out.write(" <li>JSP 使用 <code>&lt;s:fielderror&gt;</code> 精准展示错误</li>\n");
out.write(" <li>成功路径与失败路径在同一个页面闭环,对学习最直观</li>\n");
out.write(" </ul>\n");
out.write(" </div>\n");
out.write("\n");
out.write(" <p><a href=\"learn\">← 返回学习中心</a></p>\n");
out.write("\n");
out.write(" <script>\n");
out.write(" function fillBad() {\n");
out.write(" document.querySelector('input[name=\"username\"]').value = 'a';\n");
out.write(" document.querySelector('input[name=\"email\"]').value = 'bad-email';\n");
out.write(" document.querySelector('input[name=\"age\"]').value = '-1';\n");
out.write(" }\n");
out.write(" function fillGood() {\n");
out.write(" document.querySelector('input[name=\"username\"]').value = 'zhangsan';\n");
out.write(" document.querySelector('input[name=\"email\"]').value = 'zhangsan@example.com';\n");
out.write(" document.querySelector('input[name=\"age\"]').value = '22';\n");
out.write(" }\n");
out.write(" </script>\n");
out.write("</body>\n");
out.write("</html>\n");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
private boolean _jspx_meth_s_005fif_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:if
org.apache.struts2.views.jsp.IfTag _jspx_th_s_005fif_005f0 = (org.apache.struts2.views.jsp.IfTag) _005fjspx_005ftagPool_005fs_005fif_0026_005ftest.get(org.apache.struts2.views.jsp.IfTag.class);
boolean _jspx_th_s_005fif_005f0_reused = false;
try {
_jspx_th_s_005fif_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fif_005f0.setParent(null);
// /validation-lab.jsp(38,8) name = test type = java.lang.String reqTime = false required = true fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fif_005f0.setTest("resultMessage != null");
int _jspx_eval_s_005fif_005f0 = _jspx_th_s_005fif_005f0.doStartTag();
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fif_005f0);
}
do {
out.write("\n");
out.write(" <div class=\"ok\">");
if (_jspx_meth_s_005fproperty_005f0(_jspx_th_s_005fif_005f0, _jspx_page_context))
return true;
out.write("</div>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fif_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fif_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fif_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fif_0026_005ftest.reuse(_jspx_th_s_005fif_005f0);
_jspx_th_s_005fif_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fif_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fif_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fproperty_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fif_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:property
org.apache.struts2.views.jsp.PropertyTag _jspx_th_s_005fproperty_005f0 = (org.apache.struts2.views.jsp.PropertyTag) _005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.get(org.apache.struts2.views.jsp.PropertyTag.class);
boolean _jspx_th_s_005fproperty_005f0_reused = false;
try {
_jspx_th_s_005fproperty_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fproperty_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fif_005f0);
// /validation-lab.jsp(39,28) name = value type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fproperty_005f0.setValue("resultMessage");
int _jspx_eval_s_005fproperty_005f0 = _jspx_th_s_005fproperty_005f0.doStartTag();
if (_jspx_th_s_005fproperty_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fproperty_0026_005fvalue_005fnobody.reuse(_jspx_th_s_005fproperty_005f0);
_jspx_th_s_005fproperty_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fproperty_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fproperty_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005fform_005f0(javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:form
org.apache.struts2.views.jsp.ui.FormTag _jspx_th_s_005fform_005f0 = (org.apache.struts2.views.jsp.ui.FormTag) _005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.get(org.apache.struts2.views.jsp.ui.FormTag.class);
boolean _jspx_th_s_005fform_005f0_reused = false;
try {
_jspx_th_s_005fform_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005fform_005f0.setParent(null);
// /validation-lab.jsp(42,8) name = action type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fform_005f0.setAction("validation_submit");
// /validation-lab.jsp(42,8) name = method type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005fform_005f0.setMethod("post");
int _jspx_eval_s_005fform_005f0 = _jspx_th_s_005fform_005f0.doStartTag();
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.SKIP_BODY) {
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = org.apache.jasper.runtime.JspRuntimeLibrary.startBufferedBody(_jspx_page_context, _jspx_th_s_005fform_005f0);
}
do {
out.write("\n");
out.write(" <div class=\"field\">\n");
out.write(" <label>用户名</label>\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ffielderror_005f0(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" <div class=\"field\">\n");
out.write(" <label>邮箱</label>\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f1(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ffielderror_005f1(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" <div class=\"field\">\n");
out.write(" <label>年龄</label>\n");
out.write(" ");
if (_jspx_meth_s_005ftextfield_005f2(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" ");
if (_jspx_meth_s_005ffielderror_005f2(_jspx_th_s_005fform_005f0, _jspx_page_context))
return true;
out.write("\n");
out.write(" </div>\n");
out.write(" <button type=\"submit\">提交实验</button>\n");
out.write(" ");
int evalDoAfterBody = _jspx_th_s_005fform_005f0.doAfterBody();
if (evalDoAfterBody != javax.servlet.jsp.tagext.BodyTag.EVAL_BODY_AGAIN)
break;
} while (true);
if (_jspx_eval_s_005fform_005f0 != javax.servlet.jsp.tagext.Tag.EVAL_BODY_INCLUDE) {
out = _jspx_page_context.popBody();
}
}
if (_jspx_th_s_005fform_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005fform_0026_005fmethod_005faction.reuse(_jspx_th_s_005fform_005f0);
_jspx_th_s_005fform_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005fform_005f0, _jsp_getInstanceManager(), _jspx_th_s_005fform_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f0 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f0_reused = false;
try {
_jspx_th_s_005ftextfield_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /validation-lab.jsp(45,16) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f0.setName("username");
int _jspx_eval_s_005ftextfield_005f0 = _jspx_th_s_005ftextfield_005f0.doStartTag();
if (_jspx_th_s_005ftextfield_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody.reuse(_jspx_th_s_005ftextfield_005f0);
_jspx_th_s_005ftextfield_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f0, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ffielderror_005f0(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:fielderror
org.apache.struts2.views.jsp.ui.FieldErrorTag _jspx_th_s_005ffielderror_005f0 = (org.apache.struts2.views.jsp.ui.FieldErrorTag) _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.get(org.apache.struts2.views.jsp.ui.FieldErrorTag.class);
boolean _jspx_th_s_005ffielderror_005f0_reused = false;
try {
_jspx_th_s_005ffielderror_005f0.setPageContext(_jspx_page_context);
_jspx_th_s_005ffielderror_005f0.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /validation-lab.jsp(46,16) name = fieldName type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f0.setFieldName("username");
// /validation-lab.jsp(46,16) name = cssStyle type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f0.setCssStyle("color:#e74c3c;font-size:12px;");
int _jspx_eval_s_005ffielderror_005f0 = _jspx_th_s_005ffielderror_005f0.doStartTag();
if (_jspx_th_s_005ffielderror_005f0.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.reuse(_jspx_th_s_005ffielderror_005f0);
_jspx_th_s_005ffielderror_005f0_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ffielderror_005f0, _jsp_getInstanceManager(), _jspx_th_s_005ffielderror_005f0_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f1 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f1_reused = false;
try {
_jspx_th_s_005ftextfield_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /validation-lab.jsp(50,16) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f1.setName("email");
int _jspx_eval_s_005ftextfield_005f1 = _jspx_th_s_005ftextfield_005f1.doStartTag();
if (_jspx_th_s_005ftextfield_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody.reuse(_jspx_th_s_005ftextfield_005f1);
_jspx_th_s_005ftextfield_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f1, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005ffielderror_005f1(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:fielderror
org.apache.struts2.views.jsp.ui.FieldErrorTag _jspx_th_s_005ffielderror_005f1 = (org.apache.struts2.views.jsp.ui.FieldErrorTag) _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.get(org.apache.struts2.views.jsp.ui.FieldErrorTag.class);
boolean _jspx_th_s_005ffielderror_005f1_reused = false;
try {
_jspx_th_s_005ffielderror_005f1.setPageContext(_jspx_page_context);
_jspx_th_s_005ffielderror_005f1.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /validation-lab.jsp(51,16) name = fieldName type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f1.setFieldName("email");
// /validation-lab.jsp(51,16) name = cssStyle type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f1.setCssStyle("color:#e74c3c;font-size:12px;");
int _jspx_eval_s_005ffielderror_005f1 = _jspx_th_s_005ffielderror_005f1.doStartTag();
if (_jspx_th_s_005ffielderror_005f1.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.reuse(_jspx_th_s_005ffielderror_005f1);
_jspx_th_s_005ffielderror_005f1_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ffielderror_005f1, _jsp_getInstanceManager(), _jspx_th_s_005ffielderror_005f1_reused);
}
return false;
}
private boolean _jspx_meth_s_005ftextfield_005f2(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:textfield
org.apache.struts2.views.jsp.ui.TextFieldTag _jspx_th_s_005ftextfield_005f2 = (org.apache.struts2.views.jsp.ui.TextFieldTag) _005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody.get(org.apache.struts2.views.jsp.ui.TextFieldTag.class);
boolean _jspx_th_s_005ftextfield_005f2_reused = false;
try {
_jspx_th_s_005ftextfield_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005ftextfield_005f2.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /validation-lab.jsp(55,16) name = name type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ftextfield_005f2.setName("age");
int _jspx_eval_s_005ftextfield_005f2 = _jspx_th_s_005ftextfield_005f2.doStartTag();
if (_jspx_th_s_005ftextfield_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ftextfield_0026_005fname_005fnobody.reuse(_jspx_th_s_005ftextfield_005f2);
_jspx_th_s_005ftextfield_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ftextfield_005f2, _jsp_getInstanceManager(), _jspx_th_s_005ftextfield_005f2_reused);
}
return false;
}
private boolean _jspx_meth_s_005ffielderror_005f2(javax.servlet.jsp.tagext.JspTag _jspx_th_s_005fform_005f0, javax.servlet.jsp.PageContext _jspx_page_context)
throws java.lang.Throwable {
javax.servlet.jsp.PageContext pageContext = _jspx_page_context;
javax.servlet.jsp.JspWriter out = _jspx_page_context.getOut();
// s:fielderror
org.apache.struts2.views.jsp.ui.FieldErrorTag _jspx_th_s_005ffielderror_005f2 = (org.apache.struts2.views.jsp.ui.FieldErrorTag) _005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.get(org.apache.struts2.views.jsp.ui.FieldErrorTag.class);
boolean _jspx_th_s_005ffielderror_005f2_reused = false;
try {
_jspx_th_s_005ffielderror_005f2.setPageContext(_jspx_page_context);
_jspx_th_s_005ffielderror_005f2.setParent((javax.servlet.jsp.tagext.Tag) _jspx_th_s_005fform_005f0);
// /validation-lab.jsp(56,16) name = fieldName type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f2.setFieldName("age");
// /validation-lab.jsp(56,16) name = cssStyle type = java.lang.String reqTime = false required = false fragment = false deferredValue = false expectedTypeName = null deferredMethod = false methodSignature = null
_jspx_th_s_005ffielderror_005f2.setCssStyle("color:#e74c3c;font-size:12px;");
int _jspx_eval_s_005ffielderror_005f2 = _jspx_th_s_005ffielderror_005f2.doStartTag();
if (_jspx_th_s_005ffielderror_005f2.doEndTag() == javax.servlet.jsp.tagext.Tag.SKIP_PAGE) {
return true;
}
_005fjspx_005ftagPool_005fs_005ffielderror_0026_005ffieldName_005fcssStyle_005fnobody.reuse(_jspx_th_s_005ffielderror_005f2);
_jspx_th_s_005ffielderror_005f2_reused = true;
} finally {
org.apache.jasper.runtime.JspRuntimeLibrary.releaseTag(_jspx_th_s_005ffielderror_005f2, _jsp_getInstanceManager(), _jspx_th_s_005ffielderror_005f2_reused);
}
return false;
}
}