feat(structs): add validation and error-flow lab
This commit is contained in:
46
src/main/java/com/example/struts2/ValidationLabAction.java
Normal file
46
src/main/java/com/example/struts2/ValidationLabAction.java
Normal file
@@ -0,0 +1,46 @@
|
||||
package com.example.struts2;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
public class ValidationLabAction extends ActionSupport {
|
||||
private String username;
|
||||
private String email;
|
||||
private Integer age;
|
||||
private String resultMessage;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public String submit() {
|
||||
resultMessage = String.format("提交成功:username=%s, email=%s, age=%s", username, email, age);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
if ("submit".equals(getActionName())) {
|
||||
if (username == null || username.trim().length() < 2) {
|
||||
addFieldError("username", "用户名至少 2 个字符");
|
||||
}
|
||||
if (email == null || !email.contains("@")) {
|
||||
addFieldError("email", "邮箱格式不正确");
|
||||
}
|
||||
if (age == null || age < 1 || age > 120) {
|
||||
addFieldError("age", "年龄必须在 1 到 120 之间");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String actionName;
|
||||
public String getActionName() { return actionName; }
|
||||
public void setActionName(String actionName) { this.actionName = actionName; }
|
||||
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 String getResultMessage() { return resultMessage; }
|
||||
}
|
||||
@@ -72,6 +72,16 @@
|
||||
<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"/>
|
||||
|
||||
@@ -66,6 +66,11 @@
|
||||
<p>可视化体验普通字段、嵌套对象、多选列表是如何被 Struts2 自动绑定到 Action 的。</p>
|
||||
<a href="ognl" class="btn purple">进入实验室</a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>⚠️ 验证与错误流实验</h3>
|
||||
<p>通过错误示例/正确示例切换,直观看到字段错误、input 返回和成功路径的区别。</p>
|
||||
<a href="validation" class="btn">进入实验室</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="timeline">
|
||||
|
||||
@@ -67,6 +67,11 @@
|
||||
<p>通过真正可交互的表单观察 Struts2 的字段绑定、嵌套对象绑定和集合绑定。</p>
|
||||
<a class="btn btn-purple" href="ognl">打开 OGNL 实验室</a>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h3>⚠️ 验证与错误流实验</h3>
|
||||
<p>学习为什么校验失败不会直接 500,而是回到 input 页面并显示字段级错误。</p>
|
||||
<a class="btn" href="validation">打开验证实验室</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>📚 学习路径</h2>
|
||||
|
||||
86
src/main/webapp/validation-lab.jsp
Normal file
86
src/main/webapp/validation-lab.jsp
Normal file
@@ -0,0 +1,86 @@
|
||||
<%@ 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>
|
||||
body { font-family: Arial, sans-serif; max-width: 900px; margin: 40px auto; padding: 20px; background:#f7f8fa; }
|
||||
h1 { color:#c0392b; }
|
||||
.card { background:#fff; border-radius:12px; padding:20px; margin:18px 0; box-shadow:0 4px 14px rgba(0,0,0,.06); }
|
||||
.lab { background:#fff7e6; border-left:4px solid #fa8c16; padding:15px; border-radius:8px; margin:20px 0; }
|
||||
.quick { display:flex; gap:10px; flex-wrap:wrap; margin-bottom:12px; }
|
||||
button { background:#c0392b; color:white; border:none; padding:10px 16px; border-radius:6px; cursor:pointer; }
|
||||
input { padding:10px; width:100%; box-sizing:border-box; }
|
||||
.field { margin:12px 0; }
|
||||
.ok { background:#eafaf1; color:#1e8449; padding:12px; border-radius:8px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1>⚠️ 验证与错误流实验室</h1>
|
||||
|
||||
<div class="lab">
|
||||
<strong>实验任务卡</strong>
|
||||
<ul>
|
||||
<li>先点“填入错误示例”,提交后观察字段级错误是如何显示的</li>
|
||||
<li>再点“填入正确示例”,观察 Action 成功后的返回</li>
|
||||
<li>思考:为什么 Struts2 的校验失败会回到 input 页,而不是直接报 500?</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="quick">
|
||||
<button type="button" onclick="fillBad()">填入错误示例</button>
|
||||
<button type="button" onclick="fillGood()">填入正确示例</button>
|
||||
</div>
|
||||
|
||||
<s:if test="resultMessage != null">
|
||||
<div class="ok"><s:property value="resultMessage"/></div>
|
||||
</s:if>
|
||||
|
||||
<s:form action="validation_submit" method="post">
|
||||
<div class="field">
|
||||
<label>用户名</label>
|
||||
<s:textfield name="username"/>
|
||||
<s:fielderror fieldName="username" cssStyle="color:#e74c3c;font-size:12px;"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>邮箱</label>
|
||||
<s:textfield name="email"/>
|
||||
<s:fielderror fieldName="email" cssStyle="color:#e74c3c;font-size:12px;"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>年龄</label>
|
||||
<s:textfield name="age"/>
|
||||
<s:fielderror fieldName="age" cssStyle="color:#e74c3c;font-size:12px;"/>
|
||||
</div>
|
||||
<button type="submit">提交实验</button>
|
||||
</s:form>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<h3>学习点</h3>
|
||||
<ul>
|
||||
<li>字段错误通过 <code>addFieldError()</code> 收集</li>
|
||||
<li>JSP 使用 <code><s:fielderror></code> 精准展示错误</li>
|
||||
<li>成功路径与失败路径在同一个页面闭环,对学习最直观</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<p><a href="learn">← 返回学习中心</a></p>
|
||||
|
||||
<script>
|
||||
function fillBad() {
|
||||
document.querySelector('input[name="username"]').value = 'a';
|
||||
document.querySelector('input[name="email"]').value = 'bad-email';
|
||||
document.querySelector('input[name="age"]').value = '-1';
|
||||
}
|
||||
function fillGood() {
|
||||
document.querySelector('input[name="username"]').value = 'zhangsan';
|
||||
document.querySelector('input[name="email"]').value = 'zhangsan@example.com';
|
||||
document.querySelector('input[name="age"]').value = '22';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user