You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Struts2中prepare方法抛出异常时如何保证Action方法正常执行

Struts2 prepare方法异常不阻断Action执行的优化方案

你的核心思路是对的:必须在prepare方法里捕获所有异常,避免异常向外抛出到拦截器层,才不会跳过后续的Action方法调用,现有实现可以从复用性、可维护性角度做进一步优化,不需要每个Action都单独写异常存储和判断逻辑:

方案1:抽取公共BaseAction统一处理(最常用)

把异常存储、prepare异常捕获的逻辑抽到公共父类,所有业务Action继承即可,不需要每个业务类重复写模板代码:

public abstract class BaseAction extends ActionSupport implements Preparable {
    // 存储prepare阶段抛出的异常
    private Exception prepareException;

    @Override
    public final void prepare() throws Exception {
        try {
            // 子类实现具体的prepare业务逻辑
            doPrepare();
        } catch (Exception e) {
            this.prepareException = e;
        }
    }

    /**
     * 子类重写这个方法实现原本的prepare逻辑
     */
    protected abstract void doPrepare() throws Exception;

    /**
     * 供子类Action方法调用,抛出prepare阶段存储的异常
     */
    protected void throwIfPrepareFailed() throws Exception {
        if (prepareException != null) {
            throw prepareException;
        }
    }
}

业务Action使用方式:

public class MyBusinessAction extends BaseAction {
    @Override
    protected void doPrepare() throws Exception {
        // 原来的prepare逻辑,不需要自己加try-catch
        // ...
    }

    @Action("myMethod")
    public String myMethod() {
        try {
            // 直接调用父类方法判断prepare是否有异常
            throwIfPrepareFailed();
            // 业务逻辑
            // ...
        } catch (Exception e) {
            // 统一处理异常,包括prepare阶段抛出的
            // ...
        } finally {
            // ...
        }
        return SUCCESS;
    }
}

方案2:自定义拦截器统一处理(零侵入业务代码)

如果不想改现有Action的继承结构,可以自定义拦截器,放在默认的PrepareInterceptor之后、Action执行之前,统一捕获prepare阶段的异常:

public class PrepareExceptionHolderInterceptor extends AbstractInterceptor {
    @Override
    public String intercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();
        if (action instanceof Preparable) {
            try {
                ((Preparable) action).prepare();
            } catch (Exception e) {
                // 异常存到上下文,不抛出,继续执行Action
                ActionContext.getContext().put("prepareException", e);
            }
        }
        return invocation.invoke();
    }
}

之后在struts配置里把这个拦截器加到你的拦截器栈中,替换原有默认的prepare拦截器即可,Action方法里直接从上下文取异常使用,不需要每个Action单独定义成员变量。

注意事项

  • 不要在prepare方法里捕获Error类型的Throwable,这类系统级错误比如OOM本来就应该终止流程,不需要继续执行Action
  • 如果prepare阶段的异常不需要在Action方法里单独处理,也可以在捕获后直接存到请求上下文,放到统一的全局异常处理逻辑里消费

内容的提问来源于stack exchange,提问作者Lof

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.19 14:45:11