Как локализовать отдельные значения доменных объектов в сборке REST API с помощью Spring Boot? - PullRequest
1 голос
/ 12 февраля 2020

Я хочу реализовать API Rest, который проверяет интернационализированную базу данных и заменяет ее на базу данных MESSAGES в соответствии с региональной конфигурацией. Продукт в базе данных:

Insert into PRODUCTS (ID, NAME, PRICE) VALUES (1, 'products.name.generatedproductcode', 100.00);

Где NAME - это ключ i18n таблицы MESSAGE

В таблице MESSAGES

Insert into MESSAGES (LOCALE,KEY_REFERENCE,VALUE) values ('es_ES','products.name.generatedproductcode','teléfono móvil');
Insert into MESSAGES (LOCALE,KEY_REFERENCE,VALUE) values ('en_GB','products.name.generatedproductcode','mobile phone');

Я хотел бы получить ситуация, когда мне приходится дублировать код, который можно пометить аннотацией, например, in18n в поле, или использовать aspectj, чтобы заменить значение языком, существующим в Locale

@Entity
public class Product {
    private Long id;
    @CustomI18nResource
    private String name;
    private Double price;
}

Существуют некоторые ограничения, например, Locale было бы только в HTTP. В настоящее время я заменяю вручную из контроллера и значение (что-то дорогое на уровне кода, так как есть несколько сущностей). Я думаю о том, что мне следует сделать в качестве решения, чтобы отправить КЛЮЧ на фронтэнд и чтобы администратор i18n находился спереди. Кто-нибудь сталкивался с этой проблемой и как она была решена?

Решение:

Ответ Оливера - именно то, что я пытался сделать, большое спасибо

Я написал решение и опубликовал его на Github здесь:

https://github.com/jestevez/springboot-i18n-database

1 Ответ

1 голос
/ 13 февраля 2020

Абстракция, которая, вероятно, здесь полезна, - MessageSource. В Spring Framework он обычно используется для разрешения сообщений в пакете ресурсов (файл свойств), но вы можете легко реализовать вариант с резервной копией базы данных, возможно, вместо этого используйте JDB C, чтобы избежать накладных расходов и интенсивного кэширования значений.

Если у вас есть это, вы можете использовать MessageSourceAccessor, например, в коде вашего контроллера, чтобы подготовить модель, которая будет отображаться для имеющегося объекта домена, который будет знать, какие значения i18nize, найти переведенное значение и поместить его в модель. Абстракция …Accessor выбирает локаль из всех настроенных LocaleResolver. IIR C, в Spring Boot это AcceptHeaderLocaleResolver, т.е. значение, указанное в заголовке HTTP-запроса Accept-Language, определяет, какой язык будет выбран.

Если вы хотите полностью автоматизировать это, вы можете захотеть подключите ваш механизм сериализации, чтобы сделать перевод прозрачным для вас. Джексон позволяет настроить сериализаторы так, чтобы они могли использовать MessageSourceAccessor для автоматического перевода всех полей, снабженных определенной аннотацией.

@Retention(RetentionPolicy.RUNTIME)
@interface JsonInternationalized {} 

@RequiredArgsConstructor
class I18nModule extends SimpleModule {

  private final MessageSource messageSource;

  @Override
  public void setupModule(SetupContext context) {

    MessageSourceAccessor accessor = new MessageSourceAccessor(messageSource);
    InternationalizedSerializer serializer = new InternationalizedSerializer(accessor);
    context.addBeanSerializerModifier(new InternationalizingBeanSerializerModifier(serializer));
  }

  @RequiredArgsConstructor
  static class InternationalizingBeanSerializerModifier extends BeanSerializerModifier {

    private final InternationalizedSerializer serializer;


    @Override
    public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription beanDesc,
        List<BeanPropertyWriter> beanProperties) {

      for (BeanPropertyWriter writer : beanProperties) {
        if (writer.getAnnotation(JsonInternationalized.class) != null) {
          writer.assignSerializer(serializer);
        }
      }

      return beanProperties;
    }
  }

  @RequiredArgsConstructor
  static class InternationalizedSerializer extends ToStringSerializer {

    private static final long serialVersionUID = -2391442803792997283L;

    private final MessageSourceAccessor accessor;

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider) throws IOException {
      gen.writeString(accessor.getMessage(value.toString()));
    }
  }
}

Вот важные аспекты:

  1. Мы определяем аннотацию для запуска i18n.
  2. I18nModule регистрирует BeanSerializerModifier, который проверяет авторов на наличие свойств бина, аннотированных указанной аннотацией, и регистрирует пользовательский сериализатор для тех свойств, которые разрешают свойство через MessageSource передано в модуль.

В приложении Spring Boot вы можете заставить этот модуль работать, просто зарегистрировав его как Spring bean в классе конфигурации:

@Bean
I18nModule i18nModule(MessageSource messageSource) {
  return new I18nModule(messageSource);
}

Как видите, это требует некоторой церемонии. Я верну это команде, чтобы посмотреть, сможем ли мы немного улучшить нестандартный опыт.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...