在数据库中存储您的消息

发布者:    |      

Seam拥有强大的i18n功能 - 它提供了一个内置的区域选择器,用于提供本地化消息包。您可以为不同的页面加载不同的消息包。

Seam内置的消息包使用属性文件来定义资源 - 但如果您想在数据库中存储消息怎么办?例如,您可能想允许管理员通过Web管理面板编辑属性。在这里,我们将介绍基本实体和连接所需的内容 - 您可能还需要为资源添加一些CRUD视图。

实体

我们创建了两个实体,首先是资源包实体,它定义了包名称和它所属的区域

@Entity
public class ResourceBundle {
        
   @Id @GeneratedValue
   private Integer id;

   private String name;

   private ResourceLocale resourceLocale;
        
   @OneToMany(mappedBy="resourceBundle")
   ¨¨private List<Resource> resources;
}

以及嵌入的区域

@Embeddable
public class ResourceLocale {
        
        @Column(length=2)
        @Length(max=2)
        private String language;
        
        @Column(length=2)
        @Length(max=2)
        private String country;
        
        @Column(length=2)
        @Length(max=2)
        private String variant;

}

以及资源本身,包括键和值

@Entity
@NamedQueries({
   @NamedQuery(
      name="keys", 
      query="select r.key from Resource r where 
         r.resourceBundle.name = :bundleName and
         r.resourceBundle.resourceLocale.language = :language and 
         r.resourceBundle.resourceLocale.country = :country and
         r.resourceBundle.resourceLocale.variant = :variant"),
   @NamedQuery(
      name="value", 
      query="select r.value from Resource r where 
         r.resourceBundle.name = :bundleName and 
         r.resourceBundle.resourceLocale.language = :language and 
         r.resourceBundle.resourceLocale.country = :country and 
         r.resourceBundle.resourceLocale.variant = :variant and r.key = :key")
})
public class Resource 
{
   @Id @GeneratedValue
   private Integer id;

   @Column(name="_key")
   private String key;

   @Column(name="_value")
   private String value;
   
   @ManyToOne
   private ResourceBundle resourceBundle;
}

连接

我们需要让Seam使用我们新的资源加载方案

@Name("org.jboss.seam.core.resourceLoader")
@BypassInterceptors
public class DatabaseResourceLoader extends ResourceLoader {
   
   // Redefine how we load a resource bundle
   public ResourceBundle loadBundle(final String bundleName) {
      return new ResourceBundle() {

         public Enumeration<String> getKeys() {
            Locale locale = org.jboss.seam.core.Locale.instance();
            EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
            List resources = entityManager.createNamedQuery("keys")
               .setParameter("bundleName", bundleName)
               .setParameter("language", locale.getLanguage())
               .setParameter("country", locale.getCountry())
               .setParameter("variant", locale.getVariant())
               .getResultList();
            return Collections.enumeration(resources);
         }

         protected Object handleGetObject(String key) {
            Locale locale = org.jboss.seam.core.Locale.instance();
            EntityManager entityManager = (EntityManager) Component.getInstance("entityManager");
            try {
               return entityManager.createNamedQuery("value")
                  .setParameter("bundleName", bundleName)
                  .setParameter("language", locale.getLanguage())
                  .setParameter("country", locale.getCountry())
                  .setParameter("variant", locale.getVariant())
                  .setParameter("key", key)
                  .getSingleResult();
            } catch (NoResultException e) {
               return null;
            }
         }
      };
   }
}

Java 6

此方法在Java 5上也可以工作 - 但我相信Java 6提供了增强的ResourceBundle支持(但由于没有为Mac提供Java 6,所以我没试过;-))。您可能想调查一下这一点。

缓存

我们在这里没有使用任何缓存 - 每个键的请求都将导致数据库查找。您可以使用JavaMap来缓存资源,当它们被加载时(注意在区域更改时刷新现金 - 使用Seam的事件总线来观察org.jboss.seam.localeSelected),或者您可能可以依赖Hibernate的第二级缓存... 看您了!


返回顶部