我正在尝试从 Struts2 2.3.36 迁移到 Struts2 6.1.2.1 以获取旧版多模块 Web 应用程序。
在每个模块的初始化文件中,我们像这样注册区域设置消息属性文件 -
//inside init class of XYZ module
static {
LocalizedTextUtil.addDefaultResourceBundle("XYZMessageResources");
}
但是,在升级了struts2依赖后,我发现这个类从Struts2 2.5.17开始就被删除了,并且在查看Apache Struts2的源代码后,我发现StrutsLocalizedTextProvider和GlobalLocalizedTextProvider提供了类似的方法。 所以我在所有初始化类中替换了上面的行,就像这样 -
static {
StrutsLocalizedTextProvider strutsLocalizedTextProvider = new StrutsLocalizedTextProvider();
strutsLocalizedTextProvider.addDefaultResourceBundle("XYZMessageResources");
}
添加此解决了编译问题。
此外,我们还有一个自定义的 TextProviderSupport 类,它实现了 com.opensymphony.xwork2.TextProvider 类,并且有一些额外的方法将 ANSI 转换为 UTF8。这个类看起来像这样 -
public class TextProviderSupport implements TextProvider {
private static final Log LOGGER = LogFactory.getLog(TextProviderSupport.class);
final private DefaultTextProvider mProvider =new DefaultTextProvider();
public String getText(final String key, final List args) {
final String msg = mProvider.getText(key, args);
return convertFromANSIToUTF8(key, null, msg, args);
}
//All other overloaded getText methods are overridden similarly which have some business logic
此 TextProviderSupport 类被推送到 I18nInterceptor 类的自定义实现内的调用堆栈:
public class I18nInterceptor implements Interceptor {
//intercept method
public String intercept(final ActionInvocation invocation) throws Exception {
invocation.addPreResultListener(new I18nHandler());
// get requested locale
Object requested_locale = invocation.getInvocationContext().getLocale();
// save it in session
final Map session = invocation.getInvocationContext().getSession();
if (session != null) {
if (requested_locale != null) {
final Locale locale = (requested_locale instanceof Locale) ?
(Locale)requested_locale
:StrutsLocalizedTextProvider.localeFromString(requested_locale.toString(), null);
if (locale != null) {
// put the locale in the session
session.put(attributeName, locale);
// put the javaScript pattern in the session so that
// we can access it in Header.jsp
final String aPattern = getAndUpdateDatePattern(locale);
session.put(patternDate, aPattern);
}
}
// this piece of code checks that a pattern for date has been set
// if not, it sets one according to context locale
if (!session.containsKey(patternDate)) {
final String aPattern = getAndUpdateDatePattern(invocation
.getInvocationContext().getLocale());
session.put(patternDate, aPattern);
}
// set locale for action
final Object locale = session.get(attributeName);
if (locale != null && locale instanceof Locale) {
saveLocale(invocation, (Locale) locale);
}
}
return invocation.invoke();
}
protected void saveLocale(final ActionInvocation invocation, final Locale locale) {
//ActionSupport actionInstance = (ActionSupport) invocation.getAction();
//ActionContext.getContext().setLocale(locale);
invocation.getInvocationContext().withLocale(locale);
}
private static class I18nHandler implements PreResultListener {
public void beforeResult(final ActionInvocation invocation,
final String resultCode) {
// Push com text provider on top of the stack
invocation.getStack().push(new TextProviderSupport());
}
}
这个 TextProviderSupport 类被添加到我们自己的 ActionSupport 类中,该类扩展了 com.opensymphony.xwork2.ActionSupport 类 -
public class ActionSupport extends com.opensymphony.xwork2.ActionSupport {
private final transient TextProvider textProvider = new TextProviderSupport();
public TextProvider getTextProviderInstance() {
return textProvider;
}
但是,在调试时,我发现
protected LocalizedTextProvider localizedTextProvider
字段始终为空,当我尝试部署应用程序战争时,我在 com.opensymphony.xwork2.DefaultTextProvider 类中的 getText 方法的第 72 行中得到 NPE -
public String getText(String key, List<?> args) {
Object[] params;
if (args != null) {
params = args.toArray();
} else {
params = EMPTY_ARGS;
}
//NPE on this line as localizedTextProvider is null
return localizedTextProvider.findDefaultText(key, ActionContext.getContext().getLocale(), params);
}
堆栈跟踪 -
Caused by: java.lang.NullPointerException
at com.opensymphony.xwork2.DefaultTextProvider.getText(DefaultTextProvider.java:72)
at com.opensymphony.xwork2.DefaultTextProvider.getText(DefaultTextProvider.java:87)
at com.opensymphony.xwork2.DefaultTextProvider.getText(DefaultTextProvider.java:134)
at XXXXX.XXXX.XXXX.i18n.TextProviderSupport.getText(TextProviderSupport.java:73)
at org.apache.struts2.util.TextProviderHelper.getText(TextProviderHelper.java:55)
at org.apache.struts2.components.Text.end(Text.java:183)
at org.apache.struts2.views.jsp.ComponentTagSupport.doEndTag(ComponentTagSupport.java:40)
at org.apache.jsp.hac.redirectlogin_jsp._jspx_meth_s_005ftext_005f0(redirectlogin_jsp.java:228)
at org.apache.jsp.hac.redirectlogin_jsp._jspService(redirectlogin_jsp.java:112)
at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:590)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:433)
... 44 more
我在 Stackoverflow 上遇到了类似的问题 - 从 Struts 2.3.33 迁移到 Struts 2.5.12 LocalizedTextUtil 已删除
它建议实现 CustomStrutsTextProviderFactory 类,但我无法理解如何在我的应用程序中使用此类以及需要在哪里连接它。
我用过这个类(看
inject
它来自com.opensymphony.xwork2.inject
):
@WebListener
public class CustomStrutsTextProviderFactory extends
StrutsTextProviderFactory implements ServletContextListener{
protected LocalizedTextProvider localizedTextProvider;
@Override
@Inject //this should be from com.opensymphony.xwork2.inject.Inject;
public void setLocalizedTextProvider(LocalizedTextProvider localizedTextProvider) {
localizedTextProvider.addDefaultResourceBundle("messages/resources");
localizedTextProvider.addDefaultResourceBundle("messages/help");
}
@Override
protected TextProvider getTextProvider( Class clazz) {
return new CustomTextProvider(clazz, localeProviderFactory.createLocaleProvider(), localizedTextProvider);
}
@Override
protected TextProvider getTextProvider(ResourceBundle bundle) {
return new CustomTextProvider(bundle, localeProviderFactory.createLocaleProvider(), localizedTextProvider);
}
}
并在
struts.xml
<bean type="com.opensymphony.xwork2.TextProviderFactory" name="customStrutsTextProviderFactory" class="foo.bar.CustomStrutsTextProviderFactory" scope="singleton"/>