feat: finish bilingual session auth learning lab
This commit is contained in:
44
web/WEB-INF/classes/com/demo/action/DashboardAction.java
Normal file
44
web/WEB-INF/classes/com/demo/action/DashboardAction.java
Normal file
@@ -0,0 +1,44 @@
|
||||
package com.demo.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class DashboardAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private Map<String, Object> session;
|
||||
private String displayName;
|
||||
private String role;
|
||||
private String loginTime;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
displayName = value(LoginAction.SESSION_USER, "ops-admin");
|
||||
role = value(LoginAction.SESSION_ROLE, "admin");
|
||||
loginTime = value(LoginAction.SESSION_LOGIN_TIME, "--");
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
private String value(String key, String fallback) {
|
||||
Object value = session == null ? null : session.get(key);
|
||||
return value == null ? fallback : String.valueOf(value);
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public String getLoginTime() {
|
||||
return loginTime;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
@@ -27,11 +27,11 @@ public class FileUploadAction extends ActionSupport {
|
||||
}
|
||||
|
||||
if (fileCount == 0) {
|
||||
addActionError("Select at least one file before submitting the demo.");
|
||||
addActionError("请至少选择一个文件再提交。 / Select at least one file before submitting the demo.");
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
summary = "This demo captures upload metadata only. It does not persist files to disk, which keeps the sample safe for classroom use.";
|
||||
summary = "metadata-only";
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,25 @@
|
||||
package com.demo.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Map;
|
||||
|
||||
public class LoginAction extends ActionSupport {
|
||||
public class LoginAction extends ActionSupport implements SessionAware {
|
||||
|
||||
public static final String SESSION_USER = "demoUser";
|
||||
public static final String SESSION_ROLE = "demoRole";
|
||||
public static final String SESSION_LOGIN_TIME = "demoLoginTime";
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private Map<String, Object> session;
|
||||
private String username;
|
||||
private String password;
|
||||
private String displayName;
|
||||
private String role;
|
||||
private String loginTime;
|
||||
private String recommendation;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
@@ -26,14 +31,15 @@ public class LoginAction extends ActionSupport {
|
||||
}
|
||||
|
||||
if ("admin".equals(username) && "123456".equals(password)) {
|
||||
displayName = "System Demo Admin";
|
||||
role = "Administrator";
|
||||
displayName = "ops-admin";
|
||||
loginTime = LocalDateTime.now().format(TIME_FORMATTER);
|
||||
recommendation = "Continue with the user form, validation sample, or upload flow to explore the rest of the demo.";
|
||||
session.put(SESSION_USER, displayName);
|
||||
session.put(SESSION_ROLE, "admin");
|
||||
session.put(SESSION_LOGIN_TIME, loginTime);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
addActionError("Invalid demo credentials. Use admin / 123456.");
|
||||
addActionError("演示账号不正确,请使用 admin / 123456。 / Invalid demo credentials. Use admin / 123456.");
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
@@ -43,10 +49,10 @@ public class LoginAction extends ActionSupport {
|
||||
return;
|
||||
}
|
||||
if (username == null || username.length() < 3) {
|
||||
addFieldError("username", "Username must be at least 3 characters.");
|
||||
addFieldError("username", "用户名至少 3 个字符。 / Username must be at least 3 characters.");
|
||||
}
|
||||
if (password == null || password.length() < 6) {
|
||||
addFieldError("password", "Password must be at least 6 characters.");
|
||||
addFieldError("password", "密码至少 6 个字符。 / Password must be at least 6 characters.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,15 +85,12 @@ public class LoginAction extends ActionSupport {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public String getLoginTime() {
|
||||
return loginTime;
|
||||
}
|
||||
|
||||
public String getRecommendation() {
|
||||
return recommendation;
|
||||
@Override
|
||||
public void setSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
|
||||
26
web/WEB-INF/classes/com/demo/action/LogoutAction.java
Normal file
26
web/WEB-INF/classes/com/demo/action/LogoutAction.java
Normal file
@@ -0,0 +1,26 @@
|
||||
package com.demo.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
import org.apache.struts2.interceptor.SessionAware;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class LogoutAction extends ActionSupport implements SessionAware {
|
||||
|
||||
private Map<String, Object> session;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
if (session != null) {
|
||||
session.remove(LoginAction.SESSION_USER);
|
||||
session.remove(LoginAction.SESSION_ROLE);
|
||||
session.remove(LoginAction.SESSION_LOGIN_TIME);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSession(Map<String, Object> session) {
|
||||
this.session = session;
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ public class UserAction extends ActionSupport {
|
||||
private String phone;
|
||||
private String submittedAt;
|
||||
private String profileStage;
|
||||
private boolean profileReady;
|
||||
|
||||
public String submit() {
|
||||
username = normalize(username);
|
||||
@@ -25,22 +26,23 @@ public class UserAction extends ActionSupport {
|
||||
}
|
||||
|
||||
submittedAt = LocalDateTime.now().format(TIME_FORMATTER);
|
||||
profileStage = (phone != null && phone.length() >= 7) ? "Profile ready for follow-up demos." : "Profile captured. Add a stronger phone number next time.";
|
||||
profileReady = phone != null && phone.length() >= 7;
|
||||
profileStage = profileReady ? "ready" : "review";
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
private boolean isValid() {
|
||||
boolean valid = true;
|
||||
if (username == null || username.length() < 3) {
|
||||
addFieldError("username", "Username must be at least 3 characters.");
|
||||
addFieldError("username", "用户名至少 3 个字符。 / Username must be at least 3 characters.");
|
||||
valid = false;
|
||||
}
|
||||
if (email == null || !email.contains("@")) {
|
||||
addFieldError("email", "Enter a valid email address.");
|
||||
addFieldError("email", "请输入有效邮箱。 / Enter a valid email address.");
|
||||
valid = false;
|
||||
}
|
||||
if (phone == null || phone.replaceAll("[^0-9]", "").length() < 7) {
|
||||
addFieldError("phone", "Enter at least 7 digits for the phone number.");
|
||||
addFieldError("phone", "手机号至少 7 位数字。 / Enter at least 7 digits for the phone number.");
|
||||
valid = false;
|
||||
}
|
||||
return valid;
|
||||
@@ -81,4 +83,8 @@ public class UserAction extends ActionSupport {
|
||||
public String getProfileStage() {
|
||||
return profileStage;
|
||||
}
|
||||
|
||||
public boolean isProfileReady() {
|
||||
return profileReady;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,13 +15,15 @@ public class ValidationAction extends ActionSupport {
|
||||
private String bio;
|
||||
private String scoreBand;
|
||||
private String submittedAt;
|
||||
private boolean seniorTrack;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
username = normalize(username);
|
||||
email = normalize(email);
|
||||
bio = normalize(bio);
|
||||
scoreBand = age >= 30 ? "Mid-career operator profile" : "Early-career operator profile";
|
||||
seniorTrack = age >= 30;
|
||||
scoreBand = seniorTrack ? "mid" : "early";
|
||||
submittedAt = LocalDateTime.now().format(TIME_FORMATTER);
|
||||
return SUCCESS;
|
||||
}
|
||||
@@ -29,16 +31,16 @@ public class ValidationAction extends ActionSupport {
|
||||
@Override
|
||||
public void validate() {
|
||||
if (username == null || username.trim().length() < 3 || username.trim().length() > 20) {
|
||||
addFieldError("username", "Username must be between 3 and 20 characters.");
|
||||
addFieldError("username", "用户名长度需在 3 到 20 之间。 / Username must be between 3 and 20 characters.");
|
||||
}
|
||||
if (email == null || !email.contains("@") || email.indexOf('@') == email.length() - 1) {
|
||||
addFieldError("email", "Enter a valid email address.");
|
||||
addFieldError("email", "请输入有效邮箱。 / Enter a valid email address.");
|
||||
}
|
||||
if (age == null || age < 18 || age > 60) {
|
||||
addFieldError("age", "Age must be between 18 and 60.");
|
||||
addFieldError("age", "年龄需在 18 到 60 之间。 / Age must be between 18 and 60.");
|
||||
}
|
||||
if (bio != null && bio.trim().length() > 240) {
|
||||
addFieldError("bio", "Bio must stay under 240 characters.");
|
||||
addFieldError("bio", "简介不能超过 240 个字符。 / Bio must stay under 240 characters.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,4 +87,8 @@ public class ValidationAction extends ActionSupport {
|
||||
public String getSubmittedAt() {
|
||||
return submittedAt;
|
||||
}
|
||||
|
||||
public boolean isSeniorTrack() {
|
||||
return seniorTrack;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.demo.action.interceptor;
|
||||
|
||||
import com.demo.action.LoginAction;
|
||||
import com.opensymphony.xwork2.ActionInvocation;
|
||||
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class AuthInterceptor extends AbstractInterceptor {
|
||||
|
||||
@Override
|
||||
public String intercept(ActionInvocation invocation) throws Exception {
|
||||
Map<String, Object> session = invocation.getInvocationContext().getSession();
|
||||
if (session != null && session.get(LoginAction.SESSION_USER) != null) {
|
||||
return invocation.invoke();
|
||||
}
|
||||
return "login";
|
||||
}
|
||||
}
|
||||
@@ -4,13 +4,30 @@
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<constant name="struts.devMode" value="true"/>
|
||||
<constant name="struts.devMode" value="false"/>
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
|
||||
<constant name="struts.i18n.encoding" value="UTF-8"/>
|
||||
<constant name="struts.action.extension" value="action"/>
|
||||
|
||||
<package name="default" namespace="/" extends="json-default">
|
||||
<interceptors>
|
||||
<interceptor name="auth" class="com.demo.action.interceptor.AuthInterceptor"/>
|
||||
<interceptor-stack name="secureStack">
|
||||
<interceptor-ref name="auth"/>
|
||||
<interceptor-ref name="defaultStack"/>
|
||||
</interceptor-stack>
|
||||
</interceptors>
|
||||
|
||||
<global-results>
|
||||
<result name="login" type="redirectAction">loginPage</result>
|
||||
</global-results>
|
||||
|
||||
<package name="default" namespace="/" extends="struts-default">
|
||||
<action name="index">
|
||||
<result>/index.jsp</result>
|
||||
<result>/WEB-INF/views/index.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="loginPage">
|
||||
<result>/WEB-INF/views/user/login.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="hello" class="com.demo.action.HelloAction" method="execute">
|
||||
@@ -18,18 +35,44 @@
|
||||
</action>
|
||||
|
||||
<action name="login" class="com.demo.action.LoginAction" method="execute">
|
||||
<result name="success">/user/success.jsp</result>
|
||||
<result name="input">/user/login.jsp</result>
|
||||
<result name="success" type="redirectAction">dashboard</result>
|
||||
<result name="input">/WEB-INF/views/user/login.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="dashboard" class="com.demo.action.DashboardAction" method="execute">
|
||||
<interceptor-ref name="secureStack"/>
|
||||
<result>/WEB-INF/views/user/dashboard.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="logout" class="com.demo.action.LogoutAction" method="execute">
|
||||
<result type="redirectAction">loginPage</result>
|
||||
</action>
|
||||
|
||||
<action name="userFormPage">
|
||||
<interceptor-ref name="secureStack"/>
|
||||
<result>/WEB-INF/views/user/form.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="validationPage">
|
||||
<interceptor-ref name="secureStack"/>
|
||||
<result>/WEB-INF/views/validation/form.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="uploadPage">
|
||||
<interceptor-ref name="secureStack"/>
|
||||
<result>/WEB-INF/views/upload/index.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="submitUser" class="com.demo.action.UserAction" method="submit">
|
||||
<result name="success">/user/success.jsp</result>
|
||||
<result name="input">/user/form.jsp</result>
|
||||
<interceptor-ref name="secureStack"/>
|
||||
<result name="success">/WEB-INF/views/user/success.jsp</result>
|
||||
<result name="input">/WEB-INF/views/user/form.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="upload" class="com.demo.action.FileUploadAction" method="execute">
|
||||
<result name="success">/upload/success.jsp</result>
|
||||
<result name="input">/upload/index.jsp</result>
|
||||
<interceptor-ref name="secureStack"/>
|
||||
<result name="success">/WEB-INF/views/upload/success.jsp</result>
|
||||
<result name="input">/WEB-INF/views/upload/index.jsp</result>
|
||||
</action>
|
||||
|
||||
<action name="ajax" class="com.demo.action.AjaxAction" method="execute">
|
||||
@@ -37,12 +80,13 @@
|
||||
</action>
|
||||
|
||||
<action name="validate" class="com.demo.action.ValidationAction" method="execute">
|
||||
<result name="success">/validation/success.jsp</result>
|
||||
<result name="input">/validation/form.jsp</result>
|
||||
<interceptor-ref name="secureStack"/>
|
||||
<result name="success">/WEB-INF/views/validation/success.jsp</result>
|
||||
<result name="input">/WEB-INF/views/validation/form.jsp</result>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
<package name="rest" namespace="/api" extends="struts-default">
|
||||
<package name="rest" namespace="/api" extends="json-default">
|
||||
<action name="users" class="com.demo.action.rest.UserRestAction" method="execute">
|
||||
<result type="json"/>
|
||||
</action>
|
||||
|
||||
Reference in New Issue
Block a user