Update: struts config, new actions and views
This commit is contained in:
36
pom.xml
Normal file
36
pom.xml
Normal 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>
|
||||||
325
src/main/java/com/example/struts2/ActionLifecycleAction.java
Normal file
325
src/main/java/com/example/struts2/ActionLifecycleAction.java
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
126
src/main/java/com/example/struts2/AjaxDemoAction.java
Normal file
126
src/main/java/com/example/struts2/AjaxDemoAction.java
Normal 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; }
|
||||||
|
}
|
||||||
319
src/main/java/com/example/struts2/ClassLoaderAction.java
Normal file
319
src/main/java/com/example/struts2/ClassLoaderAction.java
Normal 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; }
|
||||||
|
}
|
||||||
216
src/main/java/com/example/struts2/FileUploadAction.java
Normal file
216
src/main/java/com/example/struts2/FileUploadAction.java
Normal 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; }
|
||||||
|
}
|
||||||
299
src/main/java/com/example/struts2/OgnlVisualAction.java
Normal file
299
src/main/java/com/example/struts2/OgnlVisualAction.java
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>
|
||||||
26
src/main/webapp/WEB-INF/web.xml
Normal file
26
src/main/webapp/WEB-INF/web.xml
Normal 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>
|
||||||
321
src/main/webapp/ajax-demo.jsp
Normal file
321
src/main/webapp/ajax-demo.jsp
Normal 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>
|
||||||
406
src/main/webapp/classloader-visual.jsp
Normal file
406
src/main/webapp/classloader-visual.jsp
Normal 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>
|
||||||
217
src/main/webapp/file-upload.jsp
Normal file
217
src/main/webapp/file-upload.jsp
Normal 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>
|
||||||
@@ -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">
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
457
src/main/webapp/lifecycle-visual.jsp
Normal file
457
src/main/webapp/lifecycle-visual.jsp
Normal 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>
|
||||||
507
src/main/webapp/ognl-visual.jsp
Normal file
507
src/main/webapp/ognl-visual.jsp
Normal 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<User> [${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
19
struts2.log
Normal 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}
|
||||||
BIN
target/classes/com/example/struts2/CalculatorAction.class
Normal file
BIN
target/classes/com/example/struts2/CalculatorAction.class
Normal file
Binary file not shown.
BIN
target/classes/com/example/struts2/HelloAction.class
Normal file
BIN
target/classes/com/example/struts2/HelloAction.class
Normal file
Binary file not shown.
BIN
target/classes/com/example/struts2/InterceptorDemoAction.class
Normal file
BIN
target/classes/com/example/struts2/InterceptorDemoAction.class
Normal file
Binary file not shown.
BIN
target/classes/com/example/struts2/LearnAction.class
Normal file
BIN
target/classes/com/example/struts2/LearnAction.class
Normal file
Binary file not shown.
BIN
target/classes/com/example/struts2/OgnlLabAction$DemoUser.class
Normal file
BIN
target/classes/com/example/struts2/OgnlLabAction$DemoUser.class
Normal file
Binary file not shown.
BIN
target/classes/com/example/struts2/OgnlLabAction.class
Normal file
BIN
target/classes/com/example/struts2/OgnlLabAction.class
Normal file
Binary file not shown.
BIN
target/classes/com/example/struts2/UserFormAction$User.class
Normal file
BIN
target/classes/com/example/struts2/UserFormAction$User.class
Normal file
Binary file not shown.
BIN
target/classes/com/example/struts2/UserFormAction.class
Normal file
BIN
target/classes/com/example/struts2/UserFormAction.class
Normal file
Binary file not shown.
BIN
target/classes/com/example/struts2/ValidationLabAction.class
Normal file
BIN
target/classes/com/example/struts2/ValidationLabAction.class
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
126
target/classes/struts.xml
Normal file
126
target/classes/struts.xml
Normal 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>
|
||||||
3
target/maven-archiver/pom.properties
Normal file
3
target/maven-archiver/pom.properties
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
artifactId=struts2-scaffold
|
||||||
|
groupId=com.example
|
||||||
|
version=1.0.0
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
BIN
target/struts2-scaffold-1.0.0.war
Normal file
BIN
target/struts2-scaffold-1.0.0.war
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
103
target/struts2-scaffold-1.0.0/WEB-INF/classes/struts.xml
Normal file
103
target/struts2-scaffold-1.0.0/WEB-INF/classes/struts.xml
Normal 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>
|
||||||
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/caffeine-2.9.3.jar
Normal file
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/caffeine-2.9.3.jar
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/commons-io-2.15.1.jar
Normal file
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/commons-io-2.15.1.jar
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/freemarker-2.3.32.jar
Normal file
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/freemarker-2.3.32.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/log4j-api-2.23.1.jar
Normal file
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/log4j-api-2.23.1.jar
Normal file
Binary file not shown.
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/ognl-3.3.4.jar
Normal file
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/ognl-3.3.4.jar
Normal file
Binary file not shown.
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/struts2-core-6.4.0.jar
Normal file
BIN
target/struts2-scaffold-1.0.0/WEB-INF/lib/struts2-core-6.4.0.jar
Normal file
Binary file not shown.
26
target/struts2-scaffold-1.0.0/WEB-INF/web.xml
Normal file
26
target/struts2-scaffold-1.0.0/WEB-INF/web.xml
Normal 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>
|
||||||
85
target/struts2-scaffold-1.0.0/calculator.jsp
Normal file
85
target/struts2-scaffold-1.0.0/calculator.jsp
Normal 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><s:fielderror></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>
|
||||||
21
target/struts2-scaffold-1.0.0/error-invalid-input.jsp
Normal file
21
target/struts2-scaffold-1.0.0/error-invalid-input.jsp
Normal 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>
|
||||||
21
target/struts2-scaffold-1.0.0/error-rate-limit.jsp
Normal file
21
target/struts2-scaffold-1.0.0/error-rate-limit.jsp
Normal 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>
|
||||||
8
target/struts2-scaffold-1.0.0/hello.jsp
Normal file
8
target/struts2-scaffold-1.0.0/hello.jsp
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head><title>Struts2 Scaffold</title></head>
|
||||||
|
<body>
|
||||||
|
<h1>${message}</h1>
|
||||||
|
<p>Struts2 脚手架部署中...</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
33
target/struts2-scaffold-1.0.0/index.jsp
Normal file
33
target/struts2-scaffold-1.0.0/index.jsp
Normal 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>
|
||||||
80
target/struts2-scaffold-1.0.0/interceptor-demo.jsp
Normal file
80
target/struts2-scaffold-1.0.0/interceptor-demo.jsp
Normal 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>
|
||||||
112
target/struts2-scaffold-1.0.0/learn.jsp
Normal file
112
target/struts2-scaffold-1.0.0/learn.jsp
Normal 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><s:property value="name"/></code> - 输出属性</li>
|
||||||
|
<li><code><s:iterator value="list"></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>
|
||||||
43
target/struts2-scaffold-1.0.0/user-form.jsp
Normal file
43
target/struts2-scaffold-1.0.0/user-form.jsp
Normal 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>
|
||||||
59
target/struts2-scaffold-1.0.0/user-list.jsp
Normal file
59
target/struts2-scaffold-1.0.0/user-list.jsp
Normal 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><s:iterator></code> 遍历集合</li>
|
||||||
|
<li><code>redirectAction</code> 结果类型实现 PRG 模式</li>
|
||||||
|
<li>动态方法调用处理不同操作</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p><a href="learn">← 返回学习中心</a></p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/calculator_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/calculator_jsp.class
Normal file
Binary file not shown.
579
target/tmp/jsp/org/apache/jsp/calculator_jsp.java
Normal file
579
target/tmp/jsp/org/apache/jsp/calculator_jsp.java
Normal 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><s:fielderror></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;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/hello_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/hello_jsp.class
Normal file
Binary file not shown.
170
target/tmp/jsp/org/apache/jsp/hello_jsp.java
Normal file
170
target/tmp/jsp/org/apache/jsp/hello_jsp.java
Normal 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><action name=\"hello\" ...></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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/index_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/index_jsp.class
Normal file
Binary file not shown.
224
target/tmp/jsp/org/apache/jsp/index_jsp.java
Normal file
224
target/tmp/jsp/org/apache/jsp/index_jsp.java
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/interceptor_002ddemo_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/interceptor_002ddemo_jsp.class
Normal file
Binary file not shown.
364
target/tmp/jsp/org/apache/jsp/interceptor_002ddemo_jsp.java
Normal file
364
target/tmp/jsp/org/apache/jsp/interceptor_002ddemo_jsp.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/learn_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/learn_jsp.class
Normal file
Binary file not shown.
260
target/tmp/jsp/org/apache/jsp/learn_jsp.java
Normal file
260
target/tmp/jsp/org/apache/jsp/learn_jsp.java
Normal 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><s:property value=\"name\"/></code> - 输出属性</li>\n");
|
||||||
|
out.write(" <li><code><s:iterator value=\"list\"></code> - 遍历集合</li>\n");
|
||||||
|
out.write(" <li><code><s:form></code> + <code><s:textfield></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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/ognl_002dlab_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/ognl_002dlab_jsp.class
Normal file
Binary file not shown.
642
target/tmp/jsp/org/apache/jsp/ognl_002dlab_jsp.java
Normal file
642
target/tmp/jsp/org/apache/jsp/ognl_002dlab_jsp.java
Normal 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><s:property></code>、<code><s:iterator></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<String></code></li>\n");
|
||||||
|
out.write(" <li><code><s:iterator></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;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/user_002dform_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/user_002dform_jsp.class
Normal file
Binary file not shown.
561
target/tmp/jsp/org/apache/jsp/user_002dform_jsp.java
Normal file
561
target/tmp/jsp/org/apache/jsp/user_002dform_jsp.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/user_002dlist_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/user_002dlist_jsp.class
Normal file
Binary file not shown.
453
target/tmp/jsp/org/apache/jsp/user_002dlist_jsp.java
Normal file
453
target/tmp/jsp/org/apache/jsp/user_002dlist_jsp.java
Normal 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><s:iterator></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;
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
target/tmp/jsp/org/apache/jsp/validation_002dlab_jsp.class
Normal file
BIN
target/tmp/jsp/org/apache/jsp/validation_002dlab_jsp.class
Normal file
Binary file not shown.
514
target/tmp/jsp/org/apache/jsp/validation_002dlab_jsp.java
Normal file
514
target/tmp/jsp/org/apache/jsp/validation_002dlab_jsp.java
Normal 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><s:fielderror></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;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user