Struts2.3中能否在拦截器参数声明中直接使用请求参数值?
好问题!其实这个需求是完全可以实现的,不过Struts2.3默认不会自动解析拦截器<param>标签里的OGNL表达式,这就是你直接写parameterValue${view.suffix}没生效、最终得到字面字符串的原因。下面给你两种可行的实现方式:
一、最直接的方式:在拦截器内部手动解析OGNL表达式
这种方式不需要修改Struts2的核心配置,只需要调整拦截器代码和struts.xml的参数配置即可:
1. 调整struts.xml的拦截器参数配置
把原来的两个参数合并成一个,直接用Struts2的OGNL语法(%{})声明要动态拼接的参数名,为了准确获取请求参数,建议用#parameters对象直接取:
<action name="actionName" method="methodName" class="com.example.myAction"> <interceptor-ref name="defaultStack"> <!-- 用OGNL表达式直接声明动态参数名 --> <param name="interceptor.parameterName">parameterValue%{#parameters['view.suffix'][0]}</param> </interceptor-ref> <result name="success">/jsp/result.jsp</result> </action>
这里用
#parameters['view.suffix'][0]是因为请求参数在OGNL上下文中是数组形式,[0]取第一个值;如果你的场景中这个参数只会有一个值,这样写就没问题。
2. 修改拦截器代码,解析OGNL表达式
原来的拦截器代码里的拼接逻辑可以删掉,换成手动解析配置的parameterName中的OGNL表达式:
import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import ognl.Ognl; import ognl.OgnlException; public class YourInterceptor extends AbstractInterceptor { private String parameterName = null; // 保留getter和setter方法 @Override public String doIntercept(ActionInvocation invocation) throws Exception { ActionContext context = invocation.getInvocationContext(); String actualParamName = null; try { // 用ValueStack作为OGNL上下文,解析表达式 Object parsedValue = Ognl.getValue(parameterName, context.getValueStack()); actualParamName = parsedValue.toString(); } catch (OgnlException e) { // 处理解析异常,比如回退到默认值 e.printStackTrace(); actualParamName = "parameterValue"; // 设置默认参数名 } // 接下来用actualParamName执行你原来的业务逻辑即可 // ... return invocation.invoke(); } }
3. 修正页面的拼写错误
你页面里的<s:hidden>标签有个拼写错误:value="%{view.suffx}"里的suffx应该是suffix,不然页面提交的参数值可能为空,影响后续解析:
<s:hidden name="view.suffix" value="%{view.suffix}" />
二、更优雅的全局方案:自定义参数解析逻辑
如果你的项目中有多个拦截器都需要动态参数解析,可以扩展Struts2的Parameterizable接口,让拦截器在初始化参数时自动解析OGNL表达式。示例如下:
import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.interceptor.AbstractInterceptor; import com.opensymphony.xwork2.interceptor.Parameterizable; import ognl.Ognl; import ognl.OgnlException; import org.apache.commons.beanutils.BeanUtils; import java.util.HashMap; import java.util.Map; public class OgnlAwareInterceptor extends AbstractInterceptor implements Parameterizable { private Map<String, String> parameters = new HashMap<>(); @Override public void setParameters(Map<String, String> params) { this.parameters = params; ActionContext context = ActionContext.getContext(); // 初始化时自动解析所有参数的OGNL表达式 for (Map.Entry<String, String> entry : params.entrySet()) { try { Object parsedValue = Ognl.getValue(entry.getValue(), context.getValueStack()); // 把解析后的值设置到拦截器的对应字段 BeanUtils.setProperty(this, entry.getKey(), parsedValue.toString()); } catch (Exception e) { e.printStackTrace(); } } } // 其他拦截器业务逻辑... }
这种方式下,struts.xml里的参数配置和第一种方式一致,拦截器会自动完成OGNL解析,不需要在doIntercept方法里重复处理。
总结
直接在拦截器参数里写${view.suffix}不行是因为Struts2默认把参数当作字面量处理,但通过手动在拦截器里解析OGNL表达式,就可以实现动态使用请求参数来配置拦截器的参数,从而去掉原来的额外参数配置和代码中的拼接逻辑。
内容的提问来源于stack exchange,提问作者Nzall

