feat: expand struts demo lab
This commit is contained in:
48
web/WEB-INF/classes/com/demo/action/AjaxAction.java
Normal file
48
web/WEB-INF/classes/com/demo/action/AjaxAction.java
Normal file
@@ -0,0 +1,48 @@
|
||||
package com.demo.action;
|
||||
|
||||
import com.demo.model.User;
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class AjaxAction extends ActionSupport {
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private boolean success;
|
||||
private String message;
|
||||
private String serverTime;
|
||||
private List<User> users;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
success = true;
|
||||
message = "Mock AJAX response generated from the Struts2 action.";
|
||||
serverTime = LocalDateTime.now().format(TIME_FORMATTER);
|
||||
users = Arrays.asList(
|
||||
new User(1L, "ops-admin", "ops-admin@example.com", "13800000001"),
|
||||
new User(2L, "platform-owner", "platform-owner@example.com", "13800000002"),
|
||||
new User(3L, "release-manager", "release-manager@example.com", "13800000003")
|
||||
);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getServerTime() {
|
||||
return serverTime;
|
||||
}
|
||||
|
||||
public List<User> getUsers() {
|
||||
return users;
|
||||
}
|
||||
}
|
||||
93
web/WEB-INF/classes/com/demo/action/FileUploadAction.java
Normal file
93
web/WEB-INF/classes/com/demo/action/FileUploadAction.java
Normal file
@@ -0,0 +1,93 @@
|
||||
package com.demo.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
|
||||
public class FileUploadAction extends ActionSupport {
|
||||
|
||||
private File upload;
|
||||
private String uploadFileName;
|
||||
private String uploadContentType;
|
||||
private List<File> uploads;
|
||||
private List<String> uploadsFileName;
|
||||
private List<String> uploadsContentType;
|
||||
private int fileCount;
|
||||
private String summary;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
fileCount = 0;
|
||||
if (upload != null) {
|
||||
fileCount++;
|
||||
}
|
||||
if (uploads != null) {
|
||||
fileCount += uploads.size();
|
||||
}
|
||||
|
||||
if (fileCount == 0) {
|
||||
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.";
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
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 List<File> getUploads() {
|
||||
return uploads;
|
||||
}
|
||||
|
||||
public void setUploads(List<File> uploads) {
|
||||
this.uploads = uploads;
|
||||
}
|
||||
|
||||
public List<String> getUploadsFileName() {
|
||||
return uploadsFileName;
|
||||
}
|
||||
|
||||
public void setUploadsFileName(List<String> uploadsFileName) {
|
||||
this.uploadsFileName = uploadsFileName;
|
||||
}
|
||||
|
||||
public List<String> getUploadsContentType() {
|
||||
return uploadsContentType;
|
||||
}
|
||||
|
||||
public void setUploadsContentType(List<String> uploadsContentType) {
|
||||
this.uploadsContentType = uploadsContentType;
|
||||
}
|
||||
|
||||
public int getFileCount() {
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
public String getSummary() {
|
||||
return summary;
|
||||
}
|
||||
}
|
||||
@@ -2,33 +2,50 @@ package com.demo.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
/**
|
||||
* Hello World 示例 Action
|
||||
* 展示 Struts2 最基础的 Action 写法
|
||||
*
|
||||
* ActionSupport 提供了:
|
||||
* - validate() 方法用于表单验证
|
||||
* - getText() 方法用于国际化
|
||||
* - addActionError()/addFieldError() 用于错误消息
|
||||
*/
|
||||
public class HelloAction extends ActionSupport {
|
||||
|
||||
|
||||
private String name;
|
||||
private String message;
|
||||
|
||||
private String tip;
|
||||
private String nextStep;
|
||||
private String requestSample;
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
// 业务逻辑
|
||||
public String execute() {
|
||||
if (name == null || name.trim().isEmpty()) {
|
||||
name = "World";
|
||||
} else {
|
||||
name = name.trim();
|
||||
}
|
||||
message = "Hello, " + name + "! 欢迎学习 Struts2!";
|
||||
|
||||
message = "Hello, " + name + "! Welcome to the Struts2 demo lab.";
|
||||
tip = "Struts2 injected the request parameter into the action property before execute() ran.";
|
||||
nextStep = "Try the login flow or open the demo catalog to compare different action patterns.";
|
||||
requestSample = "/hello?name=Platform%20Team";
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
// Getter/Setter (Struts2 需要这些来获取/设置参数)
|
||||
public String getName() { return name; }
|
||||
public void setName(String name) { this.name = name; }
|
||||
public String getMessage() { return message; }
|
||||
public void setMessage(String message) { this.message = message; }
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getTip() {
|
||||
return tip;
|
||||
}
|
||||
|
||||
public String getNextStep() {
|
||||
return nextStep;
|
||||
}
|
||||
|
||||
public String getRequestSample() {
|
||||
return requestSample;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,46 +2,92 @@ package com.demo.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
/**
|
||||
* 用户登录 Action
|
||||
* 展示:
|
||||
* - 表单参数接收
|
||||
* - 数据验证
|
||||
* - Session 使用
|
||||
* - 返回不同结果
|
||||
*/
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class LoginAction extends ActionSupport {
|
||||
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private String username;
|
||||
private String password;
|
||||
|
||||
private String displayName;
|
||||
private String role;
|
||||
private String loginTime;
|
||||
private String recommendation;
|
||||
|
||||
@Override
|
||||
public String execute() throws Exception {
|
||||
// 模拟登录验证
|
||||
if ("admin".equals(username) && "123456".equals(password)) {
|
||||
// 登录成功,设置 session
|
||||
return SUCCESS;
|
||||
} else if (username != null && !username.isEmpty()) {
|
||||
// 登录失败
|
||||
addActionError("用户名或密码错误!");
|
||||
public String execute() {
|
||||
username = normalize(username);
|
||||
password = normalize(password);
|
||||
|
||||
if (!hasSubmitted()) {
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
if ("admin".equals(username) && "123456".equals(password)) {
|
||||
displayName = "System Demo Admin";
|
||||
role = "Administrator";
|
||||
loginTime = LocalDateTime.now().format(TIME_FORMATTER);
|
||||
recommendation = "Continue with the user form, validation sample, or upload flow to explore the rest of the demo.";
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
addActionError("Invalid demo credentials. Use admin / 123456.");
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
// 表单验证
|
||||
|
||||
@Override
|
||||
public void validate() {
|
||||
if (username == null || username.trim().length() < 3) {
|
||||
addFieldError("username", "用户名至少3个字符");
|
||||
if (!hasSubmitted()) {
|
||||
return;
|
||||
}
|
||||
if (username == null || username.length() < 3) {
|
||||
addFieldError("username", "Username must be at least 3 characters.");
|
||||
}
|
||||
if (password == null || password.length() < 6) {
|
||||
addFieldError("password", "密码至少6个字符");
|
||||
addFieldError("password", "Password must be at least 6 characters.");
|
||||
}
|
||||
}
|
||||
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
public String getPassword() { return password; }
|
||||
public void setPassword(String password) { this.password = password; }
|
||||
}
|
||||
|
||||
private boolean hasSubmitted() {
|
||||
return (username != null && !username.trim().isEmpty())
|
||||
|| (password != null && !password.trim().isEmpty());
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return value == null ? null : value.trim();
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
return displayName;
|
||||
}
|
||||
|
||||
public String getRole() {
|
||||
return role;
|
||||
}
|
||||
|
||||
public String getLoginTime() {
|
||||
return loginTime;
|
||||
}
|
||||
|
||||
public String getRecommendation() {
|
||||
return recommendation;
|
||||
}
|
||||
}
|
||||
|
||||
84
web/WEB-INF/classes/com/demo/action/UserAction.java
Normal file
84
web/WEB-INF/classes/com/demo/action/UserAction.java
Normal file
@@ -0,0 +1,84 @@
|
||||
package com.demo.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class UserAction extends ActionSupport {
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private String username;
|
||||
private String email;
|
||||
private String phone;
|
||||
private String submittedAt;
|
||||
private String profileStage;
|
||||
|
||||
public String submit() {
|
||||
username = normalize(username);
|
||||
email = normalize(email);
|
||||
phone = normalize(phone);
|
||||
|
||||
if (!isValid()) {
|
||||
return INPUT;
|
||||
}
|
||||
|
||||
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.";
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
private boolean isValid() {
|
||||
boolean valid = true;
|
||||
if (username == null || username.length() < 3) {
|
||||
addFieldError("username", "Username must be at least 3 characters.");
|
||||
valid = false;
|
||||
}
|
||||
if (email == null || !email.contains("@")) {
|
||||
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.");
|
||||
valid = false;
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return value == null ? null : value.trim();
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
public String getSubmittedAt() {
|
||||
return submittedAt;
|
||||
}
|
||||
|
||||
public String getProfileStage() {
|
||||
return profileStage;
|
||||
}
|
||||
}
|
||||
88
web/WEB-INF/classes/com/demo/action/ValidationAction.java
Normal file
88
web/WEB-INF/classes/com/demo/action/ValidationAction.java
Normal file
@@ -0,0 +1,88 @@
|
||||
package com.demo.action;
|
||||
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
public class ValidationAction extends ActionSupport {
|
||||
|
||||
private static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
private String username;
|
||||
private String email;
|
||||
private Integer age;
|
||||
private String bio;
|
||||
private String scoreBand;
|
||||
private String submittedAt;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
username = normalize(username);
|
||||
email = normalize(email);
|
||||
bio = normalize(bio);
|
||||
scoreBand = age >= 30 ? "Mid-career operator profile" : "Early-career operator profile";
|
||||
submittedAt = LocalDateTime.now().format(TIME_FORMATTER);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
@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.");
|
||||
}
|
||||
if (email == null || !email.contains("@") || email.indexOf('@') == email.length() - 1) {
|
||||
addFieldError("email", "Enter a valid email address.");
|
||||
}
|
||||
if (age == null || age < 18 || age > 60) {
|
||||
addFieldError("age", "Age must be between 18 and 60.");
|
||||
}
|
||||
if (bio != null && bio.trim().length() > 240) {
|
||||
addFieldError("bio", "Bio must stay under 240 characters.");
|
||||
}
|
||||
}
|
||||
|
||||
private String normalize(String value) {
|
||||
return value == null ? null : value.trim();
|
||||
}
|
||||
|
||||
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 getBio() {
|
||||
return bio;
|
||||
}
|
||||
|
||||
public void setBio(String bio) {
|
||||
this.bio = bio;
|
||||
}
|
||||
|
||||
public String getScoreBand() {
|
||||
return scoreBand;
|
||||
}
|
||||
|
||||
public String getSubmittedAt() {
|
||||
return submittedAt;
|
||||
}
|
||||
}
|
||||
38
web/WEB-INF/classes/com/demo/action/rest/UserRestAction.java
Normal file
38
web/WEB-INF/classes/com/demo/action/rest/UserRestAction.java
Normal file
@@ -0,0 +1,38 @@
|
||||
package com.demo.action.rest;
|
||||
|
||||
import com.demo.model.User;
|
||||
import com.opensymphony.xwork2.ActionSupport;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
public class UserRestAction extends ActionSupport {
|
||||
|
||||
private boolean success;
|
||||
private String message;
|
||||
private List<User> users;
|
||||
|
||||
@Override
|
||||
public String execute() {
|
||||
success = true;
|
||||
message = "REST-style demo payload";
|
||||
users = Arrays.asList(
|
||||
new User(101L, "alpha", "alpha@example.com", "13800001001"),
|
||||
new User(102L, "beta", "beta@example.com", "13800001002"),
|
||||
new User(103L, "gamma", "gamma@example.com", "13800001003")
|
||||
);
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return success;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public List<User> getUsers() {
|
||||
return users;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +1,54 @@
|
||||
package com.demo.model;
|
||||
|
||||
/**
|
||||
* 用户模型
|
||||
* 展示 Struts2 的 ModelDriven 和 Bean 封装
|
||||
*/
|
||||
public class User {
|
||||
private Long id;
|
||||
private String username;
|
||||
private String email;
|
||||
private String phone;
|
||||
|
||||
public User() {}
|
||||
|
||||
|
||||
public User() {
|
||||
}
|
||||
|
||||
public User(Long id, String username, String email) {
|
||||
this(id, username, email, null);
|
||||
}
|
||||
|
||||
public User(Long id, String username, String email, String phone) {
|
||||
this.id = id;
|
||||
this.username = username;
|
||||
this.email = email;
|
||||
this.phone = phone;
|
||||
}
|
||||
|
||||
// Getters and Setters
|
||||
public Long getId() { return id; }
|
||||
public void setId(Long id) { this.id = id; }
|
||||
public String getUsername() { return username; }
|
||||
public void setUsername(String username) { this.username = username; }
|
||||
public String getEmail() { return email; }
|
||||
public void setEmail(String email) { this.email = email; }
|
||||
public String getPhone() { return phone; }
|
||||
public void setPhone(String phone) { this.phone = phone; }
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(String email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
public String getPhone() {
|
||||
return phone;
|
||||
}
|
||||
|
||||
public void setPhone(String phone) {
|
||||
this.phone = phone;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,62 +4,47 @@
|
||||
"http://struts.apache.org/dtds/struts-2.5.dtd">
|
||||
|
||||
<struts>
|
||||
<!-- 开发模式 - 修改配置后自动reload -->
|
||||
<constant name="struts.devMode" value="true"/>
|
||||
<constant name="struts.enable.DynamicMethodInvocation" value="true"/>
|
||||
|
||||
<!-- 编码设置 -->
|
||||
<constant name="struts.i18n.encoding" value="UTF-8"/>
|
||||
|
||||
<!-- ==================== 示例包定义 ==================== -->
|
||||
<package name="default" namespace="/" extends="struts-default">
|
||||
|
||||
<!-- 首页 -->
|
||||
<action name="index">
|
||||
<result>/index.jsp</result>
|
||||
</action>
|
||||
|
||||
<!-- Hello World 示例 -->
|
||||
|
||||
<action name="hello" class="com.demo.action.HelloAction" method="execute">
|
||||
<result>/hello.jsp</result>
|
||||
</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>
|
||||
</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>
|
||||
</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>
|
||||
</action>
|
||||
|
||||
<!-- AJAX 示例 -->
|
||||
|
||||
<action name="ajax" class="com.demo.action.AjaxAction" method="execute">
|
||||
<result type="json"/>
|
||||
</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>
|
||||
</action>
|
||||
|
||||
</package>
|
||||
|
||||
<!-- REST 风格示例 -->
|
||||
|
||||
<package name="rest" namespace="/api" extends="struts-default">
|
||||
<action name="users" class="com.demo.action.rest.UserRestAction">
|
||||
<action name="users" class="com.demo.action.rest.UserRestAction" method="execute">
|
||||
<result type="json"/>
|
||||
</action>
|
||||
</package>
|
||||
|
||||
</struts>
|
||||
</struts>
|
||||
|
||||
@@ -5,14 +5,13 @@
|
||||
http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
|
||||
version="4.0">
|
||||
|
||||
<display-name>Struts2 学习 Demo</display-name>
|
||||
<display-name>Struts2 Demo Lab</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>
|
||||
@@ -21,8 +20,7 @@
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
|
||||
<!-- 错误页面配置 -->
|
||||
|
||||
<error-page>
|
||||
<error-code>404</error-code>
|
||||
<location>/error/404.jsp</location>
|
||||
@@ -31,4 +29,4 @@
|
||||
<error-code>500</error-code>
|
||||
<location>/error/500.jsp</location>
|
||||
</error-page>
|
||||
</web-app>
|
||||
</web-app>
|
||||
|
||||
Reference in New Issue
Block a user