欢迎访问:www.kaoacca.cn · 考ACCA网 · Java技术面试题库

Struts面试题及答案
全面解析Java Web框架核心技术|适合中高级开发者

什么是Struts?

Struts是一套基于MVC模式的Java Web应用开源框架,由Apache软件基金会维护。它通过规范请求处理流程、内置标签库和插件机制,显著提升了企业级Web应用的可维护性与扩展性。

  • Struts 1:2001年发布,采用单例Action,线程安全依赖开发者注意
  • Struts 2:2005年发布,基于WebWork设计,Action为多例,更安全易用
  • Struts 2.5.x:2014–2023主流版本;Struts 2.5.32为最后稳定版(2023.11)

为什么学Struts?

尽管Spring MVC、Spring Boot更流行,但国内大量遗留系统仍基于Struts(尤其银行、电信领域)。理解其设计思想对掌握Java Web架构演进至关重要。

  • 掌握MVC分层思想,理解请求生命周期
  • 深入理解拦截器链、OGNL表达式等高级特性
  • 应对国企/传统企业Java岗技术面试高频考点

典型使用场景

适用于需要强规范、长生命周期维护的中大型项目,尤其在以下场景常见:

  • 政府OA系统、社保/公积金平台(Java 6/7时代建设)
  • 银行核心交易外围接口系统
  • 电信计费系统、营业厅前端展示模块

Struts核心概念与组件详解

Q1:Struts请求处理流程是怎样的?请画出关键组件交互图。

Struts请求流程(以Struts2为例):

  1. 浏览器发起HTTP请求 → FilterDispatcher(或StrutsPrepareAndExecuteFilter)
  2. Filter拦截请求 → 查找struts.xml匹配<action>配置
  3. 创建Action实例(多例)→ 依次执行拦截器栈(Stack)中的preResult前逻辑
  4. 调用ActionSupport的execute()方法 → 返回String结果码
  5. 根据结果码匹配<result>类型(如dispatcher跳转JSP)
  6. 执行postResult拦截器 → 渲染视图 → 返回响应
<action name="user-*" class="com.kaoacca.action.UserAction" method="{1}">
    <result name="success">/WEB-INF/jsp/user.jsp</result>
    <interceptor-ref name="defaultStack"/>
</action>

关键组件说明:

  • Dispatcher:核心控制器,协调各组件
  • ActionProxy:代理,创建ActionInvocation
  • ActionInvocation:封装Action执行环境,驱动拦截器链
  • Result:结果处理器,决定视图渲染方式

Q2:Struts2中Action类有哪几种创建方式?推荐哪种?为什么?

三种创建方式:

方式 配置说明 线程安全 推荐度
无参构造类 默认方式,类中定义execute()方法 ✅ 多例,线程安全 ★★★★★
实现Action接口 需实现execute()等方法 ✅ 多例,线程安全 ★★★★☆
继承ActionSupport 提供校验、国际化等增强功能 ✅ 多例,线程安全 ★★★★★
⚠️ 注意:Struts1采用单例Action,若在Action中定义成员变量会导致线程安全问题,这是其被废弃的关键原因之一。

Q3:struts.xml中常见配置项解析(附实战配置片段)

核心配置项说明:

<struts>
  <constant name="struts.devMode" value="true"/>
  <constant name="struts.i18n.encoding" value="UTF-8"/>
  <package name="default" namespace="/" extends="struts-default">
    <interceptors>
      <interceptor name="log" class="com.kaoacca.interceptor.LogInterceptor"/>
      <interceptor-stack name="myStack">
        <interceptor-ref name="log"/>
        <interceptor-ref name="defaultStack"/>
      </interceptor-stack>
    </interceptors>
    <default-interceptor-ref name="myStack"/>
    <default-action-ref name="notFound"/>
    <action name="*" class="com.kaoacca.action.*Action" method="{1}">
      <result name="success">/WEB-INF/jsp/{1}.jsp</result>
      <result name="input">/WEB-INF/jsp/{1}-input.jsp</result>
    </action>
    <action name="notFound">
      <result>/WEB-INF/jsp/404.jsp</result>
    </action>
  </package>
</struts>

重点参数说明:

  • namespace="/":定义命名空间,影响URL路径(如/user-list)
  • method="{1}":通配符调用,如user-*匹配user-list调用list()
  • struts.devMode:开发模式,启用热加载与详细错误页
  • struts.i18n.encoding:统一字符编码,防止中文乱码

Struts1与Struts2深度对比

架构设计维度

维度 Struts1 Struts2
Action实例 单例(Singleton) 多例(每请求新建)
线程安全 ❌ 需避免成员变量 ✅ 安全
依赖注入 需手动集成Spring ✅ 原生支持(通过Plugin)
请求封装 直接操作HttpServletRequest ✅ 封装为ValueStack,解耦Servlet API
配置方式 仅XML XML + 注解(@Action)
💡 设计哲学差异:Struts1强绑定Servlet API,Struts2采用“无侵入式”设计,便于单元测试。

开发体验维度

功能 Struts1 Struts2
表单验证 需重写validate(),代码冗余 ✅ 支持XML/注解验证,自动回填
结果类型 仅支持JSP ✅ JSON、Freemarker、Velocity等
OGNL支持 ❌ 无 ✅ 核心特性,支持复杂表达式
标签库 JSP标签(<html:form>) ✅ UI标签(<s:form>)+ 自定义

实战建议:新项目优先选择Struts2;若维护旧系统,需重点检查validate()方法是否线程安全。

安全与维护性维度

风险点 Struts1 Struts2
OGNL表达式注入 ❌ 不涉及 ⚠️ 高危(S2-045等漏洞)
默认拦截器 较少 ✅ 默认含params、conversionError等
版本生命周期 2008年停止维护 2023年11月停更(最后版2.5.32)
迁移成本 高(需重写大量代码) 低(继承结构兼容)
🔒 重要提醒:Struts2因OGNL表达式灵活性导致高危漏洞频发(如S2-045、S2-059),企业生产环境必须定期升级并配置struts.excludedPatterns。

拦截器(Interceptor)深度解析

Q4:拦截器与Filter有何区别?请从作用范围、执行顺序说明。

核心区别:

维度 Filter(Servlet规范) Interceptor(Struts2)
作用范围 所有请求(包括静态资源) 仅Struts2 Action请求
配置位置 web.xml struts.xml
执行时机 请求进入容器后 Action执行前后(含preResult)
访问能力 可操作HttpServletRequest 可操作ValueStack、ActionContext

执行顺序示例:

<interceptor-stack name="myStack">
  <interceptor-ref name="log"/>
  <interceptor-ref name="params"/>
  <interceptor-ref name="validation"/>
  <interceptor-ref name="workflow"/>
  <interceptor-ref name="logResult"/>
</interceptor-stack>

Q5:自定义拦截器实战(含参数传递)

步骤1:编写拦截器类

public class AuthInterceptor implements Interceptor {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Map<String, Object> session = invocation.getInvocationContext().getSession();
        if (session.get("user") == null) {
            return "login"; // 未登录跳转
        }
        // 放行前执行逻辑
        String result = invocation.invoke(); // 执行后续拦截器/Action
        // 放行后执行逻辑
        System.out.println("Action执行完成");
        return result;
    }
}

步骤2:配置拦截器

<interceptors>
    <interceptor name="auth" class="com.kaoacca.interceptor.AuthInterceptor"/>
    <interceptor-stack name="secureStack">
        <interceptor-ref name="auth">
            <param name="excludeMethods">login,register</param>
        </interceptor-ref>
        <interceptor-ref name="defaultStack"/>
    </interceptor-stack>
</interceptors>

关键技巧:

  • excludeMethods:排除不需要拦截的方法(如登录页)
  • includeMethods:仅拦截指定方法
  • 通过invocation.getInvocationContext().getSession()获取会话

OGNL表达式与值栈(ValueStack)

Q6:OGNL是什么?在Struts2中如何简化视图开发?

OGNL(Object-Graph Navigation Language)是Struts2的表达式语言,支持:

  • 对象属性访问(user.name)
  • 方法调用(user.getAge() → user.age)
  • 集合操作(list.{?#this>10}过滤)
  • 静态方法调用(@java.lang.Math@max(5,3))

实战示例:

<s:textfield name="user.username" label="用户名"/>
<!-- 自动绑定到Action的user对象 -->
<s:iterator value="userList" var="u">
    <s:property value="#u.username"/>
    <s:if test="#u.age > 18">成年</s:if>
</s:iterator>
💡 重要提示:OGNL是Struts2安全漏洞的高发区(如S2-045),生产环境必须限制OGNL表达式范围!

Q7:ValueStack结构与数据查找顺序

ValueStack = 栈顶对象 + 模型对象 + ActionContext

查找顺序:

  1. 栈顶对象(当前Action实例)
  2. 模型对象(ModelDriven)
  3. ValueStack中的其他对象
  4. Request → Session → Application(域对象)

调试技巧:

<s:debug/>
    

文件上传与下载实现

单文件上传实现

Action类:

public class FileUploadAction extends ActionSupport {
    private File upload;
    private String uploadFileName;
    private String uploadContentType;
    // getter/setter省略
    @Override
    public String execute() throws Exception {
        String savePath = ServletActionContext.getServletContext()
            .getRealPath("/uploads");
        File destFile = new File(savePath, uploadFileName);
        FileUtils.copyFile(upload, destFile);
        return SUCCESS;
    }
}

JSP表单:

<s:form action="fileUpload" method="post" enctype="multipart/form-data">
    <s:file name="upload" label="选择文件"/>
    <s:submit value="上传"/>
</s:form>

配置限制:

<constant name="struts.multipart.maxSize" value="10485760"/>
    

Struts2安全漏洞与防护措施

Q8:S2-045漏洞原理与修复方案

漏洞编号:CVE-2017-5638

原理:Content-Type头未正确过滤,攻击者可注入OGNL表达式执行任意代码

POST /example HTTP/1.1
Content-Type: %{#context['com.opensymphony.xwork2.dispatcher.servletContext'].realPath('/') + 'shell.jsp'}
Content-Length: 1024

修复方案:

  1. 升级至2.5.10.1或更高版本
  2. 配置struts2.xml:
    <constant name="struts.allowed.content.types"
        value="application/x-www-form-urlencoded,multipart/form-data,text/xml,application/xml,application/json"/>
  3. 使用WAF过滤异常Content-Type

Q9:生产环境必备安全配置清单

配置项 建议值 作用
struts.devMode false 关闭开发模式
struts.allowed.content.types 白名单 过滤Content-Type
struts.excludedPatterns .*OGNL.* 拒绝OGNL注入
struts.enable.SlashesInActionNames false 禁用危险路径
🔐 最佳实践:生产环境部署前必须运行struts2-core-checker插件扫描漏洞。

Struts框架版本演进时间轴

2001年 · Struts 1.0发布

Apache Jakarta项目启动,首个MVC框架,奠定Java Web开发标准。

2005年 · Struts 2.0发布

基于WebWork设计,完全重构,支持OGNL与插件机制。

2008年 · Struts 1停止维护

官方宣布停止Struts 1支持,推荐迁移到Struts 2。

2013年 · S2-016漏洞(CVE-2013-2251)

命名空间参数未过滤导致远程代码执行,影响广泛。

2017年 · S2-045漏洞(CVE-2017-5638)

Content-Type头OGNL注入,需紧急升级至2.5.10.1+

2023年11月 · Struts 2.5.32发布

最后稳定版,官方宣布Struts 2进入维护终止(EOL)阶段。

Struts面试高频问题与回答技巧

Q10:如何回答“Struts2的优缺点”这类开放性问题?

推荐回答框架:

✅ 优点(强调工程价值)

  • 严格MVC分层,职责清晰,适合大型团队协作
  • 拦截器链机制实现权限校验、日志记录等横切逻辑复用
  • OGNL表达式简化视图开发,减少JSP脚本

⚠️ 缺点(体现批判性思维)

  • 配置复杂(XML冗长),相比Spring Boot开发效率低
  • OGNL表达式灵活性带来安全风险(需额外防护)
  • 社区活跃度下降,新项目更倾向Spring MVC

💡 建议(展示解决方案)

  • 新项目使用Spring Boot + Spring MVC替代
  • 旧系统迁移时采用渐进式重构(先解耦Action)
  • 通过struts2-spring-plugin无缝集成Spring
斌知网
蜀ICP备2026017620号-5