【问题标题】:Best way to handle user specific date/timezone conversion with Spring MVC + Freemarker使用 Spring MVC + Freemarker 处理用户特定日期/时区转换的最佳方法
【发布时间】:2014-03-28 22:28:48
【问题描述】:

我想显示使用用户时区格式的存储日期(时区为 UTC)(可能因每个用户而异,并存储在配置文件中)。

我想出的解决方案是以下一个,我想知道这是否是最好的方法,或者是否还有其他更简单的解决方案。

时区设置为 UTC:

-Duser.timezone=UTC

Controller、Freemarker-Template、HandlerInterceptor:

控制器:

@Controller
@RequestMapping("/test")
public class TestController {

        @RequestMapping
        public String dateTest(Model model){
                final Date date = new Date();
                model.addAttribute("formattedDate", new SimpleDateFormat("hh:mm:ss").format(date));
                model.addAttribute("date", date);              
                return "test";
        }
}

Freemarker-模板:

<#setting time_zone="${currentTimeZone}">

UTC Time: ${formattedDate}<br/>
Localized time for timezone <i>${currentTimeZone}</i>: ${date?time}

处理程序拦截器:

public class TimezoneHandlerInterceptor extends HandlerInterceptorAdapter{

        @Override
        public void postHandle(HttpServletRequest request,
                        HttpServletResponse response, Object handler,
                        ModelAndView modelAndView) throws Exception {

                //Only for testing, in production something like: 
                //final String currentUserTimezone = userService.getCurrentUser().getTimezoneId();
                final String currentUserTimezone = "Europe/Berlin";

                modelAndView.addObject("currentTimeZone", currentUserTimezone);            
        }
}

输出:

UTC Time: 08:03:53
Localized time for timezone Europe/Berlin: 09:03:53

那么有没有更标准甚至开箱即用的方法来实现相同的结果?感谢您的帮助。

【问题讨论】:

    标签: java spring date spring-mvc freemarker


    【解决方案1】:

    不,看起来不错。我不建议你依赖 user.timezone 来格式化你的字符串,因为最终有人会用错误的时区启动你的 webapp;相反,您可以使用

    DateFormat formatter = new SimpleDateFormat("hh:mm:ss");
    formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
    

    顺便说一句,你见过CodeReview吗?考虑到您当时的措辞方式,这个问题同样适用于两个网站。

    【讨论】:

    • 非常感谢您的回答。它把我引向了我认为的正确方向。 CodeReview 的提示也很有趣。
    【解决方案2】:

    由于您两次打印相同的日期,只是呈现不同(不同的时区),这可能只是一个演示文稿(MVC 视图)问题,因此不应在模型中解决。相反,您可以这样做是模板:

    <#import "/lib/utils.ftl" as u>
    ...
    UTC Time: ${u.utcTime(date)}<br/>
    Localized time for timezone <i>${currentTimeZone}</i>: ${date?time}
    

    utcTime 应该像 &lt;#assign u = "com.something.freemarker.UtcTimeMethod"?new()&gt; 一样在 utils.ftl 中定义,其中 com.something.freemarker.UtcTimeMethodTemplateMethodModelEx 实现。还有其他方法可以做到这一点,例如 u 可能是 FreeMarker 配置中定义的共享变量等。关键是,您需要打印 UTC 时间不会影响模型。

    &lt;#setting time_zone=currentTimeZone&gt; 部分开始(请注意,那里不需要${...}),当然这取决于Web 应用程序框架,但如果您设置时区(比如基于访问者的locale) 在调用模板之前。 FreeMarker 通过Template.createProcessingEnvironment 支持这一点(参见 JavaDoc),但也许 Spring MVC 不支持。

    此外,Date 对象始终以 UTC 格式存储日期时间。您无需使用-D 设置时区。

    【讨论】:

    • 非常感谢您的回答。你是对的,这只是一个渲染问题,不应该在模型/控制器中完成 - 这只是为了演示目的。我认为这个Template.createProcessingEnvironment 是我实际搜索的内容。 Spring MVC 设置语言环境,但我没有弄清楚如何以相同的方式设置时区 - 但有了这个提示,我可以检查源代码并自己找到最终解决方案。
    【解决方案3】:

    你可以像这样覆盖 FreeMarkerView

    public static class YourFreemarkerView extends FreeMarkerView {
        @Override
        protected void processTemplate(Template template, SimpleHash model, HttpServletResponse response)
                throws IOException, TemplateException {
    
            HttpRequestHashModel httpRequestHashModel = (HttpRequestHashModel)model.get(FreemarkerServlet.KEY_REQUEST);
    
            Environment env = template.createProcessingEnvironment(model, response.getWriter(), null);
            env.setLocale(RequestContextUtils.getLocale(httpRequestHashModel.getRequest()));
            env.setTimeZone(RequestContextUtils.getTimeZone(httpRequestHashModel.getRequest()));
            env.process();
    
        }       
    }
    

    【讨论】:

    • return new FreeMarkerViewResolver().setViewClass(YourFreemarkerView.class);
    猜你喜欢
    • 2016-02-17
    • 1970-01-01
    • 1970-01-01
    • 2012-10-09
    • 2015-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    相关资源
    最近更新 更多