首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将I18n实现为JPA或Hibernate实体的JSON对象?

如何将I18n实现为JPA或Hibernate实体的JSON对象?
EN

Stack Overflow用户
提问于 2020-06-16 13:37:53
回答 2查看 2.1K关注 0票数 1

我有一个Spring-boot应用程序,它使用JPAHibernate。您可以在这个GitHub存储库上找到整个代码。

我的问题是,如何在没有外键的情况下并使用JSON结构向特定列添加国际化功能?

例如,我想像这样定义一个JPA实体:

代码语言:javascript
运行
复制
@Entity
class Book {

    @Id
    private int id;

    private Author author;

    @I18n  //<- this annotation is something that I am looking for 
    private String title;

}

然后,title列中的数据将存储如下,用于ende区域设置:

代码语言:javascript
运行
复制
{"en":"Cologne","de":"Köln"}

然后,当当前区域设置为de时,Kölnen设置为locale时,Cologne在读取数据时提取!

另外,当我们存储数据时,传递的字符串以JSON格式存储在相关属性中。例如,如果区域设置为es,并且用户传递Kolne,那么我们必须在DB中拥有以下数据:

代码语言:javascript
运行
复制
{"en":"Cologne","de":"Köln","es":"Kolne"}

对我来说很有趣的是,web中大多数hibernate和JPA的解决方案都是基于我们有languagestranslations表的一种旧方法。比如这里这里

然而,我要寻找的是一些解决方案,如这一个,这是为Laravel建议的,并按照我解释的方式存储翻译(即在JSON对象中和在同一列中)!

我找到的唯一的解决方案,并可能在某种程度上相关(不是100%)是这一个,然而,当我试图测试它时,它不工作,它似乎不再支持!

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2020-09-16 16:12:46

几周后,我可以再次回到我的olingo2 odata服务器项目。

我想做的事情比我预期的要简单。

弗拉德·米哈西建议的解决方案是好的,我很感激,但是正如我在问题中提到的,我需要一个解决方案,它可以在Olingo JPA库之外工作!但是,建议的解决方案存在一个问题,Olingo无法处理JsonBinaryType

这里是我的建议,实现国际化,除了Olingo JPA。

假设我们有这样一个BasicModel.java

代码语言:javascript
运行
复制
import java.io.Serializable;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.core.JsonProcessingException;

import java.util.HashMap;
import java.util.Locale;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.i18n.LocaleContextHolder;

import java.io.IOException;

public abstract class BaseModel implements Serializable {
    private static final long serialVersionUID = 1L;
    private static ObjectMapper mapper = new ObjectMapper();

    @SuppressWarnings("unchecked")
    protected static Map<String, String> jsonToMap(String json) {
        Map<String, String> map = new HashMap<>();
        try {
            // convert JSON string to Map
            if (json != null) {
                map = (Map<String, String>) mapper.readValue(json, Map.class);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return map;
    }

    protected static String mapToJson(Map<String, String> map) {
        String json = "";
        try {
            // convert map to JSON string
            json = mapper.writeValueAsString(map);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return json;
    }

    protected static String getLang() {
        Locale currentLocale = LocaleContextHolder.getLocale();
        String[] localeStrings = (currentLocale.getLanguage().split("[-_]+"));
        return localeStrings.length > 0 ? localeStrings[0] : "en";
    }
}

这个类为我们提供了将JSON字符串转换为Map的机制,反之亦然。

转换器的代码是从这里改编而来的。为了使用这个代码片段,我们需要添加这个maven依赖项:

代码语言:javascript
运行
复制
  <!-- Convert JSON string to Map -->        
  <dependency>
     <groupId>com.fasterxml.jackson.core</groupId>
     <artifactId>jackson-databind</artifactId>
  </dependency>

最后,每当在JPA实体模型中,我们希望字符串属性有i18n时,我们只需要稍微修改setter和getter方法。例如:

代码语言:javascript
运行
复制
import javax.persistence.*;

import java.util.Map;
import java.util.Set;

/**
 * The persistent class for the actions database table.
 * 
 */
@Entity
@Table(name = "actions")
@NamedQuery(name = "Action.findAll", query = "SELECT a FROM Action a")
public class Action extends BaseModel {
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "id", unique = true, nullable = false, length = 255)
    private String id;

    @Column(nullable = false, length = 255)
    private String name;

    public Action() {
    }

    public String getId() {
        return this.id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        Map<String, String> map = jsonToMap(this.name);
        return map.get(getLang());
    }

    public void setName(String name) {
        Map<String, String> map = jsonToMap(this.name);
        map.put(getLang(), name);
        this.name = mapToJson(map);
    }

}
票数 0
EN

Stack Overflow用户

发布于 2020-06-18 08:36:28

Hibernate类型项目

首先,您需要添加冬眠型项目依赖项。

之后,您可以使用HStoreJSONB列来存储特定于位置的标题:

代码语言:javascript
运行
复制
@Entity
@TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
class Book {

    @Id
    private int id;

    private Author author;

    @Type(type = "jsonb")
    @Column(name = "localized_titles", columnDefinition = "jsonb")
    private Map<String, String> localizedTitles = new HashMap<>();

    public String getLocalizedTitle(String locale) {
        return localizedTitles.get(locale);
    }

    public String getLocalizedTitle() {
        return localizedTitles.get(LocaleUtil.getDefaultLocale());
    }
}

因此,您可以调用getLocalizedTitle并传递当前区域设置以获得当前本地化的标题。

代码语言:javascript
运行
复制
Book book = entityManager.find(Book.class, bookId);
String title = book.getLocalizedTitle("en");

或者,您可以将当前区域设置存储在名为ThreadLocal的类LocaleUtil中。

代码语言:javascript
运行
复制
public class LocaleUtil {
  
    private static final ThreadLocal<String> LOCALE_HOLDER =
        new ThreadLocal<>();

    public static String getLocale() {
        return LOCALE_HOLDER.get();
    }
 
    public static void setLocale(String locale) {
        LOCALE_HOLDER.set(locale);
    }
 
    public static void reset() {
        LOCALE_HOLDER.remove();
    }
}

并按以下方式存储当前区域:

代码语言:javascript
运行
复制
LocaleUtil.setLocale("en");

然后,只需调用不带任何参数的getLocalizedTitle方法:

代码语言:javascript
运行
复制
Book book = entityManager.find(Book.class, bookId);
String title = book.getLocalizedTitle();

有关使用Hibernate类型将测试用例 Map作为JSON列类型持久化的更多详细信息,请参阅GitHub上的JSON

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62409871

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档