技术开发 频道

使用WebSphere Portal开发多区域设置网站

IT168 技术文档】

    本文说明了如何使用 Servlet 筛选器来基于业务规则确定区域设置,以及如何对传入请求使用此区域设置。首先,我们将看看 IBM WebSphere Portal V5.1.0.1(以下称为 WebSphere Portal)所使用的区域设置选择算法。然后,我们将说明如何强制 WebSphere Portal 使用通过业务规则选择的区域设置。

    例如,您有一个业务要求,需让 URL 采用 http://hostname/sitename/us/en 形式,其中 us 是国家代码,en 是语言代码,即您希望使用 en_US 区域设置显示结果页。类似地,如果 URL 为 http://hostname/sitename/ca/en,则表明希望使用 en_CA 区域设置显示该页。在这种情况下,区域设置编码在 URL 标记中,您可以使用本文描述的技术确定区域设置,并对请求使用此区域设置。

    或者,假定您有一个业务要求,需使用没有导航状态的初始 URL。您需要使用用户的首选区域设置显示结果页。如果用户已登录,则使用用户概要中指定的区域设置。如果用户未登录,则要使用浏览器中设置的语言首选项。您可以使用此处描述的技术来应用业务规则,以确定区域设置。

    WebSphere Portal 的区域设置选择

    为了确定请求的区域设置,WebSphere Portal 将按照以下顺序从三个位置检索区域设置:

    从门户 URL 的导航状态。
    从用户概要(如果请求是由经过身份验证的用户发出的)。
    从 Accept-Language 请求 Header(其中包含在浏览器语言首选项中设置的语言)。

    有关详细消息,请参见参考资料,以获得指向 WebSphere Portal 信息中心的 Selecting and changing the language section 的链接。

    WebSphere Portal 将使用上面检索到的区域设置为每个传入请求构建一个列表,将使用此列表中的第一个区域设置作为请求的区域设置。将按照以下所示的方式构建列表:

    检索到区域设置时,门户将检查 WebSphere Portal 是否支持此区域设置和语言变体。如果某个区域设置仅有语言代码,且语言代码与另一个区域设置相同,则将第一个区域设置称为第二个区域设置的语言变体。在下面的示例中,en_US 是区域设置,而 en 是语言变体。
    如果受支持,区域设置和语言变体将添加到该请求的区域设置列表中。例如,假定 en_US 是从用户概要检索到的区域设置。如果 en_US 和 en 是受支持的区域设置,将首先添加 en_US,然后还会向列表中添加 en。
    如果遍历了所有检索到的区域设置后,该列表为空,则会将门户缺省区域设置添加到列表中。缺省情况下,缺省区域设置被设置为 en。

    要更改门户缺省区域设置,请在 <PortalInstallDir>/shared/app/config/services/LocalizerService.properties 文件中修改以下属性:

locale.default.language=en locale.default.country = locale.default.variant =

    有关受支持的区域设置的完整列表,请参见文件 <Portal Install Dir>/shared/app/config/language.properties。

    WebSphere Portal 支持 19 种即时可用的区域设置。如果您的应用程序需要支持其他区域设置,请将其添加到 language.properties 文件,同时请确保不存在两个属性名称相同的情况。

    为请求设置区域设置

    现在您已经了解了 WebSphere Portal 如何为请求选择区域设置,接下来将了解如何基于业务规则设置请求的区域设置。第一个方法是在传入请求 URL 的导航状态中设置区域设置。不过,WebSphere Portal 5.1.0.1 并未提供进行此工作的公共 API。第二种方法(也是最好的方法)是在 Accept-Language 请求 Header 中设置区域设置。不过,对于经过身份验证的请求(即用户已登录),WebSphere Portal 将使用从用户概要获得的区域设置。因此,如果您可以确保从用户的概要返回空区域设置,则 WebSphere Portal 必须使用其从请求 Header 获得的区域设置。

    显然,应用程序需要在 WebSphere Portal 处理请求 Header 前对其进行更新。Java Servlet 2.3 规范中提供了此类工具;您可以使用 Servlet 筛选器和请求包装来完成此任务。

    在本文的剩下部分,您将了解如何进行以下工作:

    开发请求包装来在 Accept-Language 请求 Header 中设置区域设置(在下一步中确定)。
    开发和安装 Servlet 筛选器来执行业务逻辑,从而为请求确定区域设置。
    配置门户,以使其在处理经过身份验证的请求时不会从用户概要获取区域设置。

    开发请求包装

    J2EE 规范提供了请求包装机制来修改供下游应用程序或组件使用的请求。本文并不会讨论请求包装和 Servlet 筛选器;有关这两个构件的详细信息,请参见 Java Servlet 2.3 规范。

    要设计请求包装,首先需要 Servlet 筛选器能够指定请求包装的区域设置。因此,您需要一个构造函数,该构造函数接受传入请求对象和 Servlet 筛选器所确定的区域设置作为参数。

    清单 1. LocaleRequestWrapper
public class LocaleRequestWrapper extends HttpServletRequestWrapper implements com.ibm.wsspi.webcontainer.servlet.IServletRequest { private String locale = null; private Locale localeObj; private List locales = new ArrayList(1); public LocaleRequestWrapper(HttpServletRequest request, Locale locale) { super(request); // validate the locale here…if invalid locale is passed // throw illegal argument exception String langCode = locale.getLanguage(); String countryCode = locale.getCountry(); if (langCode != null && langCode.trim().length() > 0 && countryCode != null && countryCode.trim().length() > 0) { this.locale = langCode + "-" + countryCode; localeObj = new Locale(langCode, countryCode); } else if (langCode != null && langCode.trim().length() > 0) { this.locale = langCode; localeObj = new Locale(langCode); } if (locale != null) { locales.add(locale); } } public Object clone() throws CloneNotSupportedException { LocaleRequestWrapper crequest = (LocaleRequestWrapper)super.clone(); javax.servlet.ServletRequest inner = crequest.getRequest(); if (inner instanceof IServletRequest) { crequest.setRequest( (HttpServletRequest)((IServletRequest)inner).clone()); } else { throw new CloneNotSupportedException(); } return crequest; } }
    接下来,请求包装需要重写 getHeader 和 getHeaders 方法,以便能在指定的键为 Accept-Languag 时返回 Servlet 筛选器指定的区域设置。

    清单 2. LocaleRequestWrapper getHeader() 和 getHeaders() 方法
public String getHeader(String key) { // get the original request HttpServletRequest request = (HttpServletRequest)getRequest(); // if the header request is for locale, return the stored locale if ("Accept-Language".equalsIgnoreCase(key)) { if (locale != null) return locale; // if no locale is set, then return a value that would cause // WPS to use default language. else return request.getHeader(key); } // if the requested header is not the locale, return the value // from the wrapped request else return request.getHeader(key); } public Enumeration getHeaders(String key) { // get the original request HttpServletRequest request = (HttpServletRequest)getRequest(); // if the header request is for locale, return the stored locale if ("Accept-Language".equalsIgnoreCase(key)) { if (locale != null) return Collections.enumeration(locales); // if no locale is set, then return a value that would cause // WPS to use default language. else return request.getHeaders(key); } // if the requested header is not the locale, return the value // from the wrapped request else return request.getHeaders(key); }
    您还需要重写 getLocale 和 getLocales 方法,以返回与 getHeader 方法所返回的相同的区域设置。

    清单 3. LocaleRequestWrapper getLocale() 和 getLocales() 方法
public Locale getLocale() { if (localeObj != null) return localeObj; else { // get the original request HttpServletRequest request = (HttpServletRequest)getRequest(); return request.getLocale(); } } public Enumeration getLocales() { if (locale != null) return Collections.enumeration(locales); else { // get the original request HttpServletRequest request = (HttpServletRequest)getRequest(); return request.getLocales(); } }








    开发和安装 Servlet 筛选器

    现在您需要在 Servlet 筛选器(我们将其称为 LocaleServletFilter)中实例化 LocaleRequestWrapper,并将其传递给链中的下一个筛选器。您将开发一个 Servlet 筛选器来执行业务逻辑和确定区域设置。此区域设置用于构造 LocaleRequestWrapper,如清单 4 中所示。

    清单 4. LocaleServletFilter 类

public class LocaleServletFilter extends javax.servlet.Filter { public void doFilter(javax.servlet.ServletRequest request, javax.servlet.ServletResponse response, javax.servlet.FilterChain chain) throws java.io.IOException, javax.servlet.ServletException { HttpServletRequest httpRequest = (HttpServletRequest)request; Locale locale = null; // perform the business logic here to determine the locale of // the request // wrap the request with our locale request wrapper LocaleRequestWrapper wrapper = new LocaleRequestWrapper(httpRequest, locale); // forward the wrapped request to the next filter in the chain if (chain != null) { chain.doFilter(wrapper, response); } } }

    您的业务逻辑还可能涉及到从用户的概要读取首选区域设置。您需要考虑这种可能性,因为您要将门户配置为在处理经过身份验证的请求时不会从用户概要检索首选区域设置。

    我们需要对匿名请求和经过身份验证的请求均使用此筛选器,且要在其他门户 Servlet 筛选器前调用。

    编辑门户的 web.xml。WebSphere Portal 是运行于 WebSphere Application Server 的 Web 容器中的 Web 应用程序。web.xml 文件位于以下目录中:
<App Server Root>/cells/<cell name>/applications/wps.ear/deployments/wps/wps.war/WEB-INF
    将以下 <filter> 和 <filter-mapping> 元素添加到 web.xml 相应的部分中。请确保将该 <filter-mapping> 添加到其他 <filter-mapping> 元素之前,以便先于任何其他门户 Servlet 筛选器调用此筛选器。

    清单 5. LocaleServletFilter 的 <filter> 和 <filter-mapping> 元素

<filter> <filter-name>Locale Filter</filter-name> <filter-class>com.foo.bar.LocaleServletFilter</filter-class> </filter> <filter-mapping> <filter-name>Locale Filter</filter-name> <url-pattern>/myportal/*</url-pattern> </filter-mapping> <filter-mapping> <filter-name>Locale Filter</filter-name> <url-pattern>/portal/*</url-pattern> </filter-mapping>

    将包含筛选器和请求包装的 jar 文件放入位于类路径中的目录,如 <Portal root>/shared/app 目录。

    配置门户

    最后,您需要对门户进行配置,以使其不会从用户概要检索首选区域设置。

    编辑位于以下目录中的 wmmLDAPServerAttributes.xml 文件:<Portal root>/wmm/
    删除 preferredLanguage 的整个 <attributeMap> 元素。

    清单 6. 删除以下 <attributeMap> 元素

<attributeMap wmmAttributeName="preferredLanguage" pluginAttributeName="preferredLanguage" applicableMemberTypes="Person" dataType="String" valueLength="128" multiValued="false"/>

    进行此更改将强制 WebSphere Portal 使用在请求 Header 中设置的区域设置作为请求的区域设置。

    重要:在集群环境中,您需要修改部署管理器的 wmmLDAPServerAttributes.xml 副本(通常位于 <Deployment Manager root>/config/wmm 目录中),然后与所有集群成员同步这些更改。

    结束语

    在本文中,您了解了 WebSphere Portal 用于确定请求的区域设置的算法。然后,您了解了如何使用 Servlet 筛选器来基于业务规则确定区域设置。您使用了请求包装来在 Accept-Language 请求 Header 中设置此区域设置。最后,您强制 WebSphere Portal 对经过身份验证的请求使用请求 Header 中的区域设置。

0
相关文章