【问题标题】:How to set Locale in Bean Validation如何在 Bean Validation 中设置语言环境
【发布时间】:2014-05-29 21:32:48
【问题描述】:

默认情况下,Bean Validation 获取基于 Locale.getDefault() 的 Locale,这对整个 JVM 是通用的。

如何更改当前 EJB 方法调用的 BeanValidation 的 Locale?

我正在使用 JavaEE7,并希望从 JPA 和 Bean Validation 的集成中受益,即自动触发插入/更新/删除事件的验证,并尽可能避免手动编写所有内容。

编辑

毕竟,我只是从 EJB 返回非插值消息:

public class DoNothingMessageInterpolator implements MessageInterpolator {
    @Override
    public String interpolate(String message, Context context) {
        return message;
    }
    @Override
    public String interpolate(String message, Context context, Locale locale) {
        return message;
    }
}

然后在 Web 层中插入它们:

try{
    //invoke ejb
}catch( EJBException ejbex ){
    if( ejbex.getCause() instanceof ConstraintViolationException ){
        ConstraintViolationException cve = (ConstraintViolationException) ejbex.getCause();
        WebUtils.printConstraintViolationMessages("NewConferenceForm:", context, cve, new Locale(languageCtrl.getLocaleCode()) );
        return null;
    }else throw ejbex;
}catch( Exception e ){
        context.addMessage(null, new FacesMessage( FacesMessage.SEVERITY_ERROR, "Oops.", ""));
        return null;
}


public class WebUtils {

    public static void printConstraintViolationMessages(
        String formPrependId, 
        FacesContext context, 
        ConstraintViolationException cve,
        Locale locale )
    {
        Iterator<ConstraintViolation<?>> iter = cve.getConstraintViolations().iterator();
        while( iter.hasNext() ){
            final ConstraintViolation<?> cv = iter.next();

            javax.validation.MessageInterpolator.Context c = new javax.validation.MessageInterpolator.Context()
            {
                @Override public <T> T unwrap(Class<T> type) {
                    try {
                        return type.newInstance();
                    } catch (InstantiationException ex) {
                        Logger.getLogger(ConferencesCtrl.class.getName()).log(Level.SEVERE, null, ex);
                    } catch (IllegalAccessException ex) {
                        Logger.getLogger(ConferencesCtrl.class.getName()).log(Level.SEVERE, null, ex);
                    }
                    return null;
                }
                @Override
                public ConstraintDescriptor<?> getConstraintDescriptor() {
                    return cv.getConstraintDescriptor();
                }
                @Override
                public Object getValidatedValue() {
                    return cv.getInvalidValue();
                }
            };

            ResourceBundleMessageInterpolator rbmi = new ResourceBundleMessageInterpolator();
            String interpolatedMsg = rbmi.interpolate(cv.getMessage(), c, locale );

            //TODO: check if clientId exists
            context.addMessage( formPrependId+cv.getPropertyPath().toString(), new FacesMessage( interpolatedMsg ) );
        }
    }

}

【问题讨论】:

    标签: bean-validation java-ee-7


    【解决方案1】:

    我想这取决于您的实际意思

    如何更改当前 EJB 方法调用的 BeanValidation 的 Locale?

    例如,假设每个调用都是由给定用户进行的,并且该用户具有关联的 Locale,您将需要一个自定义 MessageInterpolator。您可以通过 validation.xml 配置您的自定义实现(参见online docs 中的示例)。

    在实施方面,您可以让委托来完成繁重的工作。一旦确定了 Locale,您的自定义消息插值器可以实例化默认的 Hibernate Validator ResourceBundleMessageInterpolator 并将插值调用委托给它。后者可以通过ThreadLocalaL 来实现。 EJB 方法会在 ThreadLocal 中设置用户 Local,您的自定义消息插值器将从那里获取它。

    【讨论】:

    • 好的,我接受答案,看起来我在将用户的区域设置传递给 EJB 时遇到了不同的问题。
    【解决方案2】:

    类似于@Hardy 的回答,您也可以为此目的将Local 存储在资源SessionContext 数据映射中,并在您的MessageInterpolator 实现中检索它。

    在您的远程 bean 方法中,您可以将客户端语言环境作为参数传递并在方法条目中设置它。可能的设置如下所示:

    语言环境检索界面

    interface ILocale
    {
        public Locale getLocale();
    }
    

    LocaleMessageInterpolator

    扩展您的默认 MessageInterpolator。必须使用接口来获取语言环境以使其在 EJB 应用程序之外可用。

    public class LocaleMessageInterpolator extends ResourceBundleMessageInterpolator
    {
        private final ILocale iLocale;
    
        public LocaleMessageInterpolator(final ILocale iLocale)
        {
            this.iLocale = iLocale;
        }
    
        @Override
        public String interpolate(final String messageTemplate, final Context context)
        {
            final Locale locale = this.iLocale == null ? null : this.iLocale.getLocale();
    
            if (locale == null)
                return super.interpolate(messageTemplate, context);
            else
                return this.interpolate(messageTemplate, context, locale);
        }
    }
    

    应用范围的 bean

    在您的验证器工厂中注册新的MessageInterpolator。如果所有其他Beans 注入AppBean,则该常量可以是私有的,并且可以提供setClientLocale() 方法。

    @Startup
    @Singleton
    public class AppBean
    {
        public static final String CONTEXT_CLIENT_LOCALE_KEY =  "CLIENT_LOCALE_KEY";
    
        @Resource
        private SessionContext ctx;
    
        @PostConstruct
        public void init()
        {
            // retrieve client locale from context using anyonymous implementation
            final ILocale ilocale = () -> {
                if (AppBean.this.ctx.getContextData().containsKey(AppBean.CONTEXT_CLIENT_LOCALE_KEY))
                    return (Locale) AppBean.this.ctx.getContextData()
                    .get(AppBean.CONTEXT_CLIENT_LOCALE_KEY);
                return null;
            };
    
            // create client locale aware message interpolator
            final LocaleMessageInterpolator localeMessageInterpolator= new LocaleMessageInterpolator(ilocale);
    
            // configurate validator factory
            ValidatorFactory validatorFactory = Validation.byDefaultProvider().configure().messageInterpolator(localeMessageInterpolator).buildValidatorFactory();
    
            // register validator factory
    

    configuration.getProperties().put("javax.persistence.validation.factory", validatorFactory); }

    远程豆

    将当前客户端区域设置保存在SessionContext

    @Stateless(mappedName = "MyBean")
    @Remote(MyBeanRemote.class)
    public class MyBean
    {
        @Resource
        private SessionContext ctx;
    
        @Override
        public void create(Locale locale, Foo foo)
        {
            this.ctx.getContextData().put(AppBean.CONTEXT_CLIENT_LOCALE_KEY, locale);
            // persist new Foo
            // thrown validation exceptions are localized
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-11-12
      • 2014-01-01
      • 2019-08-27
      • 2019-08-27
      • 2011-01-24
      • 1970-01-01
      • 1970-01-01
      • 2010-09-09
      相关资源
      最近更新 更多