迁移至Spring MVC:使用spring:message标签时指定资源包名称
解决方案:Spring MVC中指定资源包获取歧义键值
针对你遇到的多资源包键冲突问题,这里提供两种无需大规模修改代码的可行方案:
方案一:定义多个独立MessageSource + 自定义标签
1. 配置多个MessageSource Bean
在SpringContext.xml中为每个资源包单独定义MessageSource,同时保留默认的全局MessageSource处理无歧义键:
<!-- 对应abc资源包的MessageSource --> <bean id="abcMessageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <value>/WEB-INF/lookups/abc</value> </list> </property> </bean> <!-- 对应xyz资源包的MessageSource --> <bean id="xyzMessageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <value>/WEB-INF/lookups/xyz</value> </list> </property> </bean> <!-- 全局默认MessageSource,处理无歧义键 --> <bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource"> <property name="basenames"> <list> <value>/WEB-INF/lookups/abc</value> <value>/WEB-INF/lookups/xyz</value> ... </list> </property> </bean>
2. 自定义JSP标签指定资源包
编写自定义标签类,通过传入的资源包名称获取对应MessageSource:
public class BundleMessageTag extends TagSupport { private String bundleName; private String code; private String var; @Override public int doStartTag() throws JspException { WebApplicationContext ctx = WebApplicationContextUtils.getWebApplicationContext(pageContext.getServletContext()); MessageSource messageSource = (MessageSource) ctx.getBean(bundleName + "MessageSource"); String message = messageSource.getMessage(code, null, pageContext.getRequest().getLocale()); if (var != null) { pageContext.setAttribute(var, message); } else { try { pageContext.getOut().write(message); } catch (IOException e) { throw new JspException(e); } } return SKIP_BODY; } // 生成getter/setter方法 public void setBundleName(String bundleName) { this.bundleName = bundleName; } public void setCode(String code) { this.code = code; } public void setVar(String var) { this.var = var; } }
3. 注册标签并使用
在自定义TLD文件(如/WEB-INF/tlds/custom.tld)中注册标签:
<tag> <name>bundleMessage</name> <tag-class>com.yourcompany.tags.BundleMessageTag</tag-class> <body-content>empty</body-content> <attribute> <name>bundleName</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>code</name> <required>true</required> <rtexprvalue>true</rtexprvalue> </attribute> <attribute> <name>var</name> <required>false</required> <rtexprvalue>true</rtexprvalue> </attribute> </tag>
在JSP中调用:
<%@ taglib prefix="custom" uri="/WEB-INF/tlds/custom.tld" %> <!-- 从abc资源包获取键值 --> <custom:bundleMessage bundleName="abc" code="common.submit"/> <!-- 从xyz资源包获取相同键值 --> <custom:bundleMessage bundleName="xyz" code="common.submit"/>
方案二:扩展MessageSource支持键前缀指定资源包
1. 自定义MessageSource类
扩展ReloadableResourceBundleMessageSource,通过键前缀识别目标资源包:
public class PrefixedResourceBundleMessageSource extends ReloadableResourceBundleMessageSource { private Map<String, String> bundlePrefixMap = new HashMap<>(); // 配置前缀与资源包basename的映射 public void setBundlePrefixMap(Map<String, String> bundlePrefixMap) { this.bundlePrefixMap = bundlePrefixMap; } @Override protected MessageFormat resolveCode(String code, Locale locale) { int colonIndex = code.indexOf(':'); // 检测是否包含资源包前缀(格式:前缀:键名) if (colonIndex > 0) { String prefix = code.substring(0, colonIndex); String actualCode = code.substring(colonIndex + 1); String basename = bundlePrefixMap.get(prefix); if (basename != null) { ResourceBundle bundle = getResourceBundle(basename, locale); if (bundle != null && bundle.containsKey(actualCode)) { return createMessageFormat(bundle.getString(actualCode), locale); } } } // 无前缀或前缀不匹配时,走默认查找逻辑 return super.resolveCode(code, locale); } }
2. 配置自定义MessageSource
在SpringContext.xml中替换默认MessageSource:
<bean id="messageSource" class="com.yourcompany.PrefixedResourceBundleMessageSource"> <property name="basenames"> <list> <value>/WEB-INF/lookups/abc</value> <value>/WEB-INF/lookups/xyz</value> ... </list> </property> <property name="bundlePrefixMap"> <map> <entry key="abc" value="/WEB-INF/lookups/abc"/> <entry key="xyz" value="/WEB-INF/lookups/xyz"/> </map> </property> </bean>
3. 在JSP中使用前缀指定资源包
直接通过spring:message标签,给歧义键添加前缀:
<!-- 从abc资源包获取键值 --> <spring:message code="abc:common.submit"/> <!-- 从xyz资源包获取相同键值 --> <spring:message code="xyz:common.submit"/> <!-- 无歧义键保持原有用法 --> <spring:message code="unique.key"/>
方案对比
- 方案一:无需修改原有无歧义键的调用,仅在冲突场景使用自定义标签,但需要维护多个MessageSource和自定义标签代码。
- 方案二:复用原生
spring:message标签,仅需修改冲突键的调用(添加前缀),代码侵入性更低,但需确保前缀与现有键无格式冲突。
内容的提问来源于stack exchange,提问作者Anirudh Giran
相关产品推荐
相关产品推荐

