如何覆盖Spring MVC中的LocaleContext

时间:2015-09-04 05:42:38

标签: spring-mvc

我正在尝试在Spring MVC中自定义LocaleContext以存储一些其他信息。

我已经设置了一个自定义的localeResolver,到目前为止工作正常。但我不确定如何自定义区域设置上下文。

我写了这堂课:

/**
 * Creates a store aware localisation context
 */
public class SimpleStoreAwareLocaleContext extends SimpleTimeZoneAwareLocaleContext {

    private Location location;

    public SimpleStoreAwareLocaleContext(Locale locale, TimeZone timeZone) {
        super(locale, timeZone);
    }

    public Location getLocation() {
        return location;
    }

    public void setLocation(Location location) {
        this.location = location;
    }
}

但是如何让它成为LocaleContextHolder上的默认LocaleContext? 所以当我调用它时,我希望得到一个我的语言环境上下文的实例。 LocaleContextHolder.getLocaleContext();

是否有过滤器或我需要覆盖的东西?

另外,我确保我的理解是正确的 - LocaleContext线程是否是本地的?那么每个用户应该有所不同吗?

谢谢!

1 个答案:

答案 0 :(得分:1)

好的,没有答案,但我主要有这个工作所以这就是我做的。我基本上复制&粘贴了大量CookieLocaleResolver,因为我需要私有方法,还有其他一些原因。但我想出了我自己的cookie解析器版本,并修改了cookie值中的格式以支持更多参数:

/**
 * <p>The custom locale resolver will also handle setting up the customer's local store in the
 * locale context.</p>
 *
 *
 */
public class StoreLocaleResolver extends CookieLocaleResolver {

    private static Logger logger = LogManager.getLogger(StoreLocaleResolver.class.getName());

    private Location defaultLocation;

    private Location location;

    @Autowired
    private LocationService locationService;


    /**
     * The name of the request attribute that holds the Location Information.
     * <p>Only used for overriding a cookie value if the locale has been
     * changed in the course of the current request!
     * <p>Use {@code RequestContext(Utils).getTimeZone()}
     * to retrieve the current time zone in controllers or views.
     * @see org.springframework.web.servlet.support.RequestContext#getTimeZone
     * @see org.springframework.web.servlet.support.RequestContextUtils#getTimeZone
     */
    public static final String LOCAL_STORE_REQUEST_ATTRIBUTE_NAME = CookieLocaleResolver.class.getName() + ".LOCAL_STORE";

    @Override
    public void setLocaleContext(HttpServletRequest request, HttpServletResponse response, LocaleContext localeContext) {
        //super.setLocaleContext(request, response, localeContext);
        Locale locale = null;
        TimeZone timeZone = null;
        Location location = null;
        if (localeContext != null) {
            removeCookie(response);
            if (localeContext instanceof SimpleStoreAwareLocaleContext) {
                locale = localeContext.getLocale();
                location = ((SimpleStoreAwareLocaleContext) localeContext).getLocation();
                timeZone = ((TimeZoneAwareLocaleContext) localeContext).getTimeZone();
            }
            StringBuilder bud = new StringBuilder();
            if (locale != null)
                bud.append("locale:" + locale);

            if (timeZone != null)
            {
                bud.append("::");
                bud.append("timezone:" + timeZone.getID());
            }
            if (location != null)
            {
                bud.append("::");
                bud.append("location:" + location.getExternalIdentifier());
            }
            String cookieValue = bud.toString();

            addCookie(response, bud.toString());
        }
        else {
            removeCookie(response);
        }
        request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
                (locale != null ? locale: determineDefaultLocale(request)));
        request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
                (timeZone != null ? timeZone : determineDefaultTimeZone(request)));
        request.setAttribute(LOCAL_STORE_REQUEST_ATTRIBUTE_NAME,
                (location != null ? location: determineDefaultLocalStore(request)));
    }

    @Override
    public void setLocale(HttpServletRequest request, HttpServletResponse response, Locale locale) {
        SimpleStoreAwareLocaleContext localeContext = new SimpleStoreAwareLocaleContext(locale, null);
        Location loc = (Location)request.getAttribute(StoreLocaleResolver.LOCAL_STORE_REQUEST_ATTRIBUTE_NAME);
        if (loc != null)
        {
            localeContext.setLocation(loc);

        }
        setLocaleContext(request, response, (locale != null ? localeContext : null));
    }

    @Override
    public Locale resolveLocale(HttpServletRequest request) {
        parseLocaleCookieIfNecessary(request);
        return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
    }

    @Override
    public LocaleContext resolveLocaleContext(final HttpServletRequest request) {
        parseLocaleCookieIfNecessary(request);
        return new StoreAwareLocaleContext() {
            @Override
            public Locale getLocale() {
                return (Locale) request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME);
            }
            @Override
            public TimeZone getTimeZone() {
                return (TimeZone) request.getAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME);
            }
            @Override
            public Location getLocation() {
                return (Location) request.getAttribute(LOCAL_STORE_REQUEST_ATTRIBUTE_NAME);
            }
        };
    }

    // copied from the parent class and extended to support parsing out the store location.
    private void parseLocaleCookieIfNecessary(HttpServletRequest request) {
        if (request.getAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME) == null) {
            // Retrieve and parse cookie value.
            Cookie cookie = WebUtils.getCookie(request, getCookieName());
            Locale locale = null;
            TimeZone timeZone = null;
            if (cookie != null) {
                String value = cookie.getValue();

                Map<String, String> params = new HashMap<String, String>();
                String[] tokens1 = value.split("::");
                for (String token: tokens1){
                    String[] tokens2 = token.split(":");
                    params.put(tokens2[0], tokens2[1]);
                }

                String localeString = params.get("locale");
                String timezoneString = params.get("timezone");
                String locationString = params.get("location");
                if (localeString != null)
                {
                    locale = StringUtils.parseLocaleString(localeString);
                }
                if (timezoneString != null)
                {
                    timeZone = StringUtils.parseTimeZoneString(timezoneString);
                }

                if (locationString != null)
                {
                    location = locationService.findForLocaleContext(locationString, false);

                }

                if (logger.isDebugEnabled()) {
                    logger.debug("Parsed cookie value [" + cookie.getValue() + "] into locale '" + locale +
                            "'" + (timeZone != null ? " and time zone '" + timeZone.getID() + "'" : ""));
                }
            }
            request.setAttribute(LOCALE_REQUEST_ATTRIBUTE_NAME,
                    (locale != null ? locale: determineDefaultLocale(request)));
            request.setAttribute(TIME_ZONE_REQUEST_ATTRIBUTE_NAME,
                    (timeZone != null ? timeZone : determineDefaultTimeZone(request)));
            request.setAttribute(LOCAL_STORE_REQUEST_ATTRIBUTE_NAME,
                    (location != null ? location : determineDefaultLocalStore(request)));
        }
    }

    /**
     * Determine the default time zone for the given request,
     * Called if no TimeZone cookie has been found.
     * <p>The default implementation returns the specified default time zone,
     * if any, or {@code null} otherwise.
     * @param request the request to resolve the time zone for
     * @return the default time zone (or {@code null} if none defined)
     * @see #setDefaultTimeZone
     */
    protected Location determineDefaultLocalStore(HttpServletRequest request) {
        return getDefaultLocation();
    }

    @Override
    protected Locale getDefaultLocale() {
        logger.debug("Getting the default locale");
        LocaleContextHolder.getLocaleContext();
        return super.getDefaultLocale();
    }

    public Location getDefaultLocation() {
        return defaultLocation;
    }

    public void setDefaultLocation(Location defaultLocation) {
        this.defaultLocation = defaultLocation;
    }

    public Location getLocation() {
        return location;
    }

    public void setLocation(Location location) {
        this.location = location;
    }
}

另一个主要类是扩展LocaleChangeInterceptor,它允许我通过向任何控制器URL添加参数来更改本地存储。

/**
 * <p>The custom locale resolver will also handle setting up the customer's local store in the
 * locale context.</p>
 *
 *
 */
@Component
public class StoreLocaleChangeInterceptor extends LocaleChangeInterceptor {

    private static Logger logger = LogManager.getLogger(StoreLocaleChangeInterceptor.class.getName());
    /**
     * Default name of the store locale specification parameter: "store".
     */
    public static final String DEFAULT_STORE_PARAM_NAME = "store";

    private String storeParamName = DEFAULT_STORE_PARAM_NAME;

    @Autowired
    private LocationService locationService;

    public String getStoreParamName() {
        return storeParamName;
    }

    public void setStoreParamName(String storeParamName) {
        this.storeParamName = storeParamName;
    }

    public LocationService getLocationService() {
        return locationService;
    }

    public void setLocationService(LocationService locationService) {
        this.locationService = locationService;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws ServletException {

        String newLocale = request.getParameter(getParamName());
        String newStore = request.getParameter(this.storeParamName);
        if (newStore != null || newLocale != null) {
            LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
            if (localeResolver instanceof StoreLocaleResolver)
            {
                Location location = locationService.findByIdentifier(newStore);
                if (location != null) {
                    ((StoreLocaleResolver) localeResolver).setLocation(location);
                    request.setAttribute(StoreLocaleResolver.LOCAL_STORE_REQUEST_ATTRIBUTE_NAME, location);
                }
                if (newLocale != null)
                {
                    localeResolver.setLocale(request, response, StringUtils.parseLocaleString(newLocale));
                }else
                {
                    Locale currentLocale = localeResolver.resolveLocale(request);
                    localeResolver.setLocale(request, response, currentLocale);

                }
            }
        }
        // Proceed in any case.
        return true;
    }
}

然后从LocaleContextHolder我必须转发到上下文类型(现在是一个接口)。

@ModelAttribute("myStore")
protected Location getCurrentStore() {
    LocaleContext ctx = LocaleContextHolder.getLocaleContext();
    if (StoreAwareLocaleContext.class.isAssignableFrom(ctx.getClass())){
        return ((StoreAwareLocaleContext) ctx).getLocation();
    }else
    {
        return null;
    }
}