7

ローカライズ用のプロパティ ファイルがあります。

foo=Bar
title=Widget Application

resource-bundleこれは、faces-config で次のように関連付けられています。

<resource-bundle>
    <base-name>com.example.messages.messages</base-name>
    <var>msgs</var>
</resource-bundle>

EL を使用して facelets ビューでこれに問題なくアクセスできます。

<title>#{msgs.title}</title>

ただし、SQLException などがある場合は、マネージド Bean からメッセージを書き込めるようにする必要があります。これもすべて機能しています:

FacesMessage message = new FacesMessage(FacesMessage.SEVERITY_ERROR, "There was an error saving this widget.", null);
FacesContext.getCurrentInstance().addMessage(null, message);

問題は次のとおりです。これらのメッセージをプロパティ ファイルから取得して、ロケールに基づいて変更できるようにしたいのです。インジェクションを使用してプロパティ ファイルにアクセスする簡単な方法はありますか?

4

5 に答える 5

17

SO でかなり関連する質問をしました: How to inject a non-serializable class (like java.util.ResourceBundle) with Weld

Seam フォーラム内: http://seamframework.org/Community/HowToCreateAnInjectableResourcebundleWithWeld

要約すると、3 つの Producer を持つ注入可能な ResourceBundle を実現しました。まず、FacesContextProducer が必要です。Seam 3 Alpha ソースから 1 つを取得しました。

public class FacesContextProducer {
   @Produces @RequestScoped
   public FacesContext getFacesContext() {
      FacesContext ctx = FacesContext.getCurrentInstance();
      if (ctx == null)
         throw new ContextNotActiveException("FacesContext is not active");
      return ctx;
   }
}

次に、FacesContextProducer を使用する LocaleProducer が必要です。また、Seam 3 Alpha から取得しました。

public class FacesLocaleResolver {
   @Inject
   FacesContext facesContext;

   public boolean isActive() {
      return (facesContext != null) && (facesContext.getCurrentPhaseId() != null);
   }

   @Produces @Faces
   public Locale getLocale() {
      if (facesContext.getViewRoot() != null) 
         return facesContext.getViewRoot().getLocale();
      else
         return facesContext.getApplication().getViewHandler().calculateLocale(facesContext);
   }
}

これで、次のような ResourceBundleProducer を作成するためのすべてが揃いました。

public class ResourceBundleProducer {
  @Inject       
  public Locale locale;

  @Inject       
  public FacesContext facesContext;

  @Produces
  public ResourceBundle getResourceBundle() {
   return ResourceBundle.getBundle("/messages", facesContext.getViewRoot().getLocale() );
  }
}

これで、ResourceBundle を Bean に @Inject できるようになりました。一時的な属性に挿入する必要があることに注意してください。そうしないと、ResourceBundle がシリアル化できないという例外が発生します。

@Named
public class MyBean {
  @Inject
  private transient ResourceBundle bundle;

  public void testMethod() {
    bundle.getString("SPECIFIC_BUNDLE_KEY");
  }
}
于 2010-09-09T11:27:21.700 に答える
2

MyFaces CODIのメッセージモジュールなどを使用する方が簡単です!

于 2010-11-28T21:12:45.473 に答える
2

これは、JSF だけで行うことができます。

バッキング Bean で管理プロパティを定義することから始めます。JSF 構成では、管理プロパティの値を、リソース バンドルを参照する EL 式に設定できます。

Tomcat 6 を使用して次のようなことを行いました。唯一の注意点は、JSF がまだ初期化していないため、バッキング Bean のコンストラクターからこの値にアクセスできないことです。@PostConstructBean のライフサイクルの早い段階で値が必要な場合は、初期化メソッドで使用します。

<managed-bean>
  ...
  <managed-property>
    <property-name>messages</property-name>
    <property-class>java.util.ResourceBundle</property-class>
    <value>#{msgs}</value>
  </managed-property>
  ...
</managed-bean>

<application>
  ...
  <resource-bundle>
    <base-name>com.example.messages.messages</base-name>
    <var>msgs</var>
  </resource-bundle>
  ...
</application>

これには、バッキング Bean メソッドのプレゼンテーション テクノロジへの依存度が低くなるという利点があるため、テストが容易になります。また、バンドルに付けられた名前などの詳細からコードを切り離します。

Mojarra 2.0.4-b09 を使用した一部のテストでは、ユーザーがセッションの途中でロケールを変更すると、わずかな不一致が示されます。ページ内 EL 式は新しいロケールを使用しますが、バッキング Bean には新しい ResourceBundle 参照が与えられません。#{backingBean.messages.greeting}一貫性を持たせるために、代わりにを使用するなど、EL 式で Bean プロパティ値を使用できます#{msgs.greeting}。次に、ページ EL とバッキング Bean は、セッションの開始時にアクティブだったロケールを常に使用します。ユーザーセッション中にロケールを切り替えて新しいメッセージを取得する必要がある場合は、リクエスト スコープの Bean を作成して、セッション Bean とリソース バンドルの両方への参照を与えることができます。

于 2011-11-10T23:19:23.977 に答える
0

これを行う方法の例を次に示します: http://www.laliluna.de/articles/javaserver-faces-message-resource-bundle-tutorial.html

その部分を見てほしいResourceBundle.getBundle()

こんにちは、ラース

于 2010-08-13T15:07:58.867 に答える
0

これは古い質問ですが、これを行う別の方法を追加しています。私は何か他のものを探していて、これに出くわしました。ここでの方法はすべて複雑に見えましたが、それほど難しいとは思いませんでした。言われてみれば可愛いからキラキラで遊んでます。

与えられたファイル:

/com/full/package/path/to/messages/errormessages.properties

ファイル内:

SOME_ERROR_STRING=Your App Just Cratered

ランタイムをキャッチして意味のあるメッセージを追加するのが好きなので、「getBundle()」メソッドを作成して、それがどこから来ているのかを理解できるようにします。なんらかの理由で気まぐれにプロパティ ファイルをいじり、すべてを正しく更新しない場合に役立ちます。クラス内のヘルパーメソッドである場合があるため(私にとっては)、これをプライベートにすることがあります。これにより、意味のあるコードから try catch が乱雑になるのを防ぎます。

ファイルへのフル パスを使用すると、組織に関する他のアイデアがある場合は、既定の場所/ディレクトリ以外の場所に配置できます。

public/private ResourceBundle getMessageResourceBundle(){
    String messageBundle = "com.full.package.path.to.messages.errormessages";
    ResourceBundle bundle = null;
    try{
        bundle = ResourceBundle.getBundle(messageBundle);
    }catch(MissingResourceException ex){
        Logger.getLogger(this.getClass().getName()).log(Level.SEVERE,
                    "Unable to find message bundle in XYZ Class", ex);
        throw ex;
    }

}

public void doSomethingWithBundle(){

    ResourceBundle bundle = getMessageResourceBundle();
    String someString = bundle.getString("SOME_ERROR_STRING");
    ...
}
于 2012-09-05T08:06:27.313 に答える