项目简介 Apache Struts是一个开源的Java Web应用框架,基于Model-View-Controller(MVC)设计模式。它为开发者提供了一个强大的框架来构建可维护、可扩展的Java Web应用程序。Struts最初由Craig McClanahan开发,后来成为Apache软件基金会的项目。
Struts通过将业务逻辑、数据和表现层分离,帮助开发者构建结构良好的Web应用程序。它提供了丰富的标签库、数据验证、国际化支持等功能,极大地简化了Java Web开发的复杂性。
主要特性
MVC架构 :清晰的模型-视图-控制器分离
声明式验证 :XML和注解两种验证方式
国际化支持 :多语言和本地化功能
标签库 :丰富的JSP标签库
插件机制 :可扩展的插件架构
异常处理 :统一的异常处理机制
项目原理 MVC架构 Struts严格遵循MVC设计模式:
1 用户请求 → ActionServlet → RequestProcessor → Action → Model → View → 响应
Model(模型) :
ActionForm:封装用户输入数据
Business Objects:业务逻辑对象
Data Access Objects:数据访问对象
View(视图) :
JSP页面:用户界面展示
Struts标签:简化JSP开发
国际化资源:多语言支持
Controller(控制器) :
ActionServlet:前端控制器
Action类:业务逻辑控制
RequestProcessor:请求处理器
核心组件 ActionServlet :
前端控制器,接收所有HTTP请求
根据配置文件分发请求到相应的Action
管理应用程序的生命周期
Action :
业务逻辑的控制点
处理用户请求并调用业务服务
决定下一个要显示的视图
ActionForm :
封装HTML表单数据
提供数据验证功能
在不同层之间传递数据
struts-config.xml :
配置Action映射
定义表单Bean
配置全局转发和异常处理
使用场景 1. 企业级Web应用 构建大型企业级Web应用程序,如ERP、CRM、OA系统等。
2. 电子商务平台 开发在线购物网站、B2B平台等电子商务应用。
3. 内容管理系统 构建新闻发布系统、博客平台、论坛等内容管理应用。
4. 政府门户网站 开发政府部门的官方网站和在线服务平台。
5. 教育管理系统 构建学校管理系统、在线学习平台等教育相关应用。
具体案例 案例1:用户登录功能实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts-config PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN" "http://struts.apache.org/dtds/struts-config_1_3.dtd" > <struts-config > <form-beans > <form-bean name ="loginForm" type ="com.example.form.LoginForm" /> <form-bean name ="userForm" type ="com.example.form.UserForm" /> </form-beans > <action-mappings > <action path ="/login" type ="com.example.action.LoginAction" name ="loginForm" scope ="request" validate ="true" input ="/login.jsp" > <forward name ="success" path ="/welcome.jsp" /> <forward name ="failure" path ="/login.jsp" /> </action > <action path ="/userList" type ="com.example.action.UserListAction" > <forward name ="success" path ="/userList.jsp" /> </action > </action-mappings > <global-forwards > <forward name ="login" path ="/login.jsp" /> <forward name ="home" path ="/index.jsp" /> </global-forwards > <message-resources parameter ="com.example.resources.ApplicationResources" /> <plug-in className ="org.apache.struts.validator.ValidatorPlugIn" > <set-property property ="pathnames" value ="/WEB-INF/validator-rules.xml,/WEB-INF/validation.xml" /> </plug-in > </struts-config >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 package com.example.form;import org.apache.struts.action.ActionForm;import org.apache.struts.action.ActionMapping;import org.apache.struts.action.ActionErrors;import org.apache.struts.action.ActionError;import javax.servlet.http.HttpServletRequest;public class LoginForm extends ActionForm { private String username; private String password; private boolean rememberMe; public LoginForm () { reset(); } public void reset (ActionMapping mapping, HttpServletRequest request) { username = "" ; password = "" ; rememberMe = false ; } public ActionErrors validate (ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors (); if (username == null || username.trim().length() == 0 ) { errors.add("username" , new ActionError ("error.username.required" )); } if (password == null || password.trim().length() == 0 ) { errors.add("password" , new ActionError ("error.password.required" )); } else if (password.length() < 6 ) { errors.add("password" , new ActionError ("error.password.minlength" )); } return errors; } 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 boolean isRememberMe () { return rememberMe; } public void setRememberMe (boolean rememberMe) { this .rememberMe = rememberMe; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 package com.example.action;import org.apache.struts.action.*;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import javax.servlet.http.HttpSession;import com.example.form.LoginForm;import com.example.service.UserService;import com.example.model.User;public class LoginAction extends Action { public ActionForward execute (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { LoginForm loginForm = (LoginForm) form; try { UserService userService = new UserService (); User user = userService.authenticate(loginForm.getUsername(), loginForm.getPassword()); if (user != null ) { HttpSession session = request.getSession(); session.setAttribute("currentUser" , user); session.setAttribute("username" , user.getUsername()); if (loginForm.isRememberMe()) { handleRememberMe(response, user); } userService.logLogin(user.getId(), request.getRemoteAddr()); return mapping.findForward("success" ); } else { ActionErrors errors = new ActionErrors (); errors.add(ActionErrors.GLOBAL_ERROR, new ActionError ("error.login.invalid" )); saveErrors(request, errors); return mapping.findForward("failure" ); } } catch (Exception e) { ActionErrors errors = new ActionErrors (); errors.add(ActionErrors.GLOBAL_ERROR, new ActionError ("error.system.unavailable" )); saveErrors(request, errors); return mapping.findForward("failure" ); } } private void handleRememberMe (HttpServletResponse response, User user) { Cookie cookie = new Cookie ("rememberedUser" , user.getUsername()); cookie.setMaxAge(7 * 24 * 60 * 60 ); cookie.setPath("/" ); response.addCookie(cookie); } }
案例2:数据验证配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE form-validation PUBLIC "-//Apache Software Foundation//DTD Commons Validator Rules Configuration 1.3.0//EN" "http://jakarta.apache.org/commons/dtds/validator_1_3_0.dtd" > <form-validation > <formset > <form name ="loginForm" > <field property ="username" depends ="required,minlength,maxlength" > <arg0 key ="label.username" /> <arg1 key ="${var:minlength}" name ="minlength" resource ="false" /> <arg2 key ="${var:maxlength}" name ="maxlength" resource ="false" /> <var > <var-name > minlength</var-name > <var-value > 3</var-value > </var > <var > <var-name > maxlength</var-name > <var-value > 20</var-value > </var > </field > <field property ="password" depends ="required,minlength" > <arg0 key ="label.password" /> <arg1 key ="${var:minlength}" name ="minlength" resource ="false" /> <var > <var-name > minlength</var-name > <var-value > 6</var-value > </var > </field > </form > <form name ="userForm" > <field property ="email" depends ="required,email" > <arg0 key ="label.email" /> </field > <field property ="phone" depends ="mask" > <arg0 key ="label.phone" /> <var > <var-name > mask</var-name > <var-value > ^\d{11}$</var-value > </var > </field > <field property ="birthdate" depends ="date" > <arg0 key ="label.birthdate" /> <var > <var-name > datePattern</var-name > <var-value > yyyy-MM-dd</var-value > </var > </field > </form > </formset > </form-validation >
案例3:JSP页面实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 <%-- login.jsp --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="html" uri="http://struts.apache.org/tags-html" %> <%@ taglib prefix="bean" uri="http://struts.apache.org/tags-bean" %> <%@ taglib prefix="logic" uri="http://struts.apache.org/tags-logic" %> <!DOCTYPE html> <html> <head> <meta charset="UTF-8" > <title><bean:message key="title.login" /></title> <link rel="stylesheet" type="text/css" href="css/style.css" > <script type="text/javascript" src="js/validation.js" ></script> </head> <body> <div class="login-container" > <h2><bean:message key="header.login" /></h2> <!-- 显示错误信息 --> <logic:messagesPresent> <div class="error-messages" > <html:errors/> </div> </logic:messagesPresent> <!-- 登录表单 --> <html:form action="/login" method="post" onsubmit="return validateLoginForm(this)" > <div class="form-group" > <label for ="username" ><bean:message key="label.username" />:</label> <html:text property="username" styleClass="form-control" styleId="username" /> </div> <div class="form-group" > <label for ="password" ><bean:message key="label.password" />:</label> <html:password property="password" styleClass="form-control" styleId="password" /> </div> <div class="form-group" > <html:checkbox property="rememberMe" styleId="rememberMe" /> <label for ="rememberMe" ><bean:message key="label.rememberme" /></label> </div> <div class="form-group" > <html:submit styleClass="btn btn-primary" > <bean:message key="button.login" /> </html:submit> <html:reset styleClass="btn btn-secondary" > <bean:message key="button.reset" /> </html:reset> </div> </html:form> <div class="links" > <html:link page="/register.jsp" > <bean:message key="link.register" /> </html:link> | <html:link page="/forgotPassword.jsp" > <bean:message key="link.forgot.password" /> </html:link> </div> </div> <script> function validateLoginForm (form) { var username = form.username.value; var password = form.password.value; if (username.trim() == '' ) { alert('<bean:message key="error.username.required"/>' ); form.username.focus(); return false ; } if (password.trim() == '' ) { alert('<bean:message key="error.password.required"/>' ); form.password.focus(); return false ; } return true ; } </script> </body> </html>
案例4:国际化配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 title.login =User Login header.login =Please Login label.username =Username label.password =Password label.rememberme =Remember Me button.login =Login button.reset =Reset link.register =Register New Account link.forgot.password =Forgot Password? error.username.required =Username is required error.password.required =Password is required error.password.minlength =Password must be at least 6 characters error.login.invalid =Invalid username or password error.system.unavailable =System temporarily unavailable
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 title.login =用户登录 header.login =请登录 label.username =用户名 label.password =密码 label.rememberme =记住我 button.login =登录 button.reset =重置 link.register =注册新账户 link.forgot.password =忘记密码? error.username.required =用户名不能为空 error.password.required =密码不能为空 error.password.minlength =密码至少需要6个字符 error.login.invalid =用户名或密码错误 error.system.unavailable =系统暂时不可用
案例5:业务逻辑服务 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 package com.example.service;import com.example.model.User;import com.example.dao.UserDAO;import java.security.MessageDigest;import java.util.List;public class UserService { private UserDAO userDAO; public UserService () { this .userDAO = new UserDAO (); } public User authenticate (String username, String password) throws Exception { if (username == null || password == null ) { return null ; } User user = userDAO.findByUsername(username); if (user == null ) { return null ; } String hashedPassword = hashPassword(password); if (user.getPassword().equals(hashedPassword)) { user.setLastLoginTime(new java .util.Date()); userDAO.update(user); return user; } return null ; } public boolean registerUser (User user) throws Exception { if (userDAO.findByUsername(user.getUsername()) != null ) { throw new Exception ("Username already exists" ); } if (userDAO.findByEmail(user.getEmail()) != null ) { throw new Exception ("Email already exists" ); } user.setPassword(hashPassword(user.getPassword())); user.setCreateTime(new java .util.Date()); user.setActive(true ); return userDAO.save(user); } public List<User> getUserList (int page, int pageSize) throws Exception { return userDAO.findAll(page, pageSize); } public boolean updateUser (User user) throws Exception { return userDAO.update(user); } public boolean deleteUser (int userId) throws Exception { return userDAO.delete(userId); } public void logLogin (int userId, String ipAddress) { try { System.out.println("User " + userId + " logged in from " + ipAddress); } catch (Exception e) { e.printStackTrace(); } } private String hashPassword (String password) throws Exception { MessageDigest md = MessageDigest.getInstance("SHA-256" ); byte [] hashedBytes = md.digest(password.getBytes("UTF-8" )); StringBuilder sb = new StringBuilder (); for (byte b : hashedBytes) { sb.append(String.format("%02x" , b)); } return sb.toString(); } }
最佳实践 1. 项目结构组织 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 webapp/ ├── WEB-INF/ │ ├── web.xml │ ├── struts-config.xml │ ├── validation.xml │ ├── validator-rules.xml │ ├── classes/ │ └── lib/ ├── jsp/ │ ├── common/ │ ├── user/ │ └── admin/ ├── css/ ├── js/ └── images/
2. Action设计原则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class UserAction extends DispatchAction { public ActionForward list (ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) { UserService service = new UserService (); List<User> users = service.getUserList(); request.setAttribute("users" , users); return mapping.findForward("success" ); } private ActionForward handleException (Exception e, ActionMapping mapping, HttpServletRequest request) { ActionErrors errors = new ActionErrors (); errors.add(ActionErrors.GLOBAL_ERROR, new ActionError ("error.system" )); saveErrors(request, errors); return mapping.findForward("error" ); } }
3. 性能优化建议 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <context-param > <param-name > org.apache.struts.action.LOCALE</param-name > <param-value > true</param-value > </context-param > <context-param > <param-name > org.apache.struts.util.CANCEL</param-name > <param-value > true</param-value > </context-param > <filter > <filter-name > CompressionFilter</filter-name > <filter-class > com.example.filter.CompressionFilter</filter-class > </filter >
Apache Struts作为经典的Java Web开发框架,其成熟的MVC架构和丰富的功能特性为企业级Web应用开发提供了稳定可靠的解决方案。虽然现在有更现代的框架,但Struts在维护现有系统和特定场景下仍有其价值。
版权所有,如有侵权请联系我