Поиграйтесь с интернационализацией взаимодействия данных внутреннего интерфейса с нуля
Поиграйтесь с интернационализацией взаимодействия данных внутреннего интерфейса с нуля

🎑 1. Предисловие

Когда наш проект предполагает мультиязычную поддержку,Разработано задней частью,интерфейсданныеинтернационализацияЭто проблема, которую мы должны преодолеть。

иSpringBootобеспечивает мощныйинтернационализация(i18n)поддерживать,Позволяет разработчикам предоставлять индивидуальные текстовые ресурсы для разных регионов.

Тогда давай сделаем это вместе «Разорвите завесу интернационализации интерфейсных данных»,Узнайте больше о том, как SpringBoot Внедрите интернационализацию в приложениях для удовлетворения многоязычных потребностей пользователей по всему миру.

🎃2. Что такое интернационализация?

✨ 2.1 Что такое интернационализация

Интернационализация, также называемая i18n, почему она называется i18n?

Это потому, что английское слово, обозначающее интернационализацию, — интернационализация, а между i и n 18 слов. Как и в наших k8, между k и s 8 слов (очень непринужденно🥰)


🎉 2.2 Зачем использовать интернационализацию

одинвеб-сайтилиприложение,Первоначально он предоставлял услуги только отечественным пользователям.,Отображение страницыи Различные советы по эксплуатациитолько китайский язык。Позже с егоБизнес расширяется, добавляется больше функций, пользователей становится все больше.,Начинаем двигаться к международной платформе,тогда этоТип пользователяНе только отечественный,Может быть Франция、США、Пользователи из Японии и др. наций.

нравиться Если в это времявеб-сайтилиприложениеизпоказыватьи Различные операции по-прежнему выполняются на китайском языке.(илитолько одна странаязык),Потом другоенация Пользователи могут полностьюне могу читатьвеб-сайтилиприложениеили ВОЗТрудно работать

Так сильно ли снизится его удобство для клиентов? Будет ли невозможно удержать таких клиентов?

Итак, для этого сценария сейчасинтернационализацияЭто очень важно。


🎍 2.3 Международная сегментация

Для нашего проекта,интернационализацияМожно разделить на фронтендизадняя часть Две части:

Интернационализация внешнего интерфейса

Интернационализация внешнего интерфейса в основном фокусируется на отображении страниц и локализации пользовательского интерфейса. Он включает в себя перевод и адаптацию элементов интерфейса приложения, таких как текст, метки, кнопки и т. д., к языку и региону пользователя. Интерфейсная интернационализация обычно использует файлы ресурсов, языковые пакеты или службы перевода для хранения текста на разных языках и управления им. Разработчики внешнего интерфейса могут реализовывать функции интернационализации внешнего интерфейса с помощью фреймворков или библиотек интернационализации, таких как React Intl, Vue I18n или Angular i18n.

Интернационализация серверной части

Внутренняя интернационализация в основном фокусируется на решении проблем интернационализации, связанных с бизнес-логикой и данными. Сюда входят, помимо прочего, форматы даты и времени, символы валют, числовые форматы, правила сортировки, подсказки интерфейса и т. д. Цель интернационализации серверной части — обеспечить возможность адаптации приложения к различным языкам и регионам и предоставление правильных локализованных данных. Интернационализация серверной части может быть достигнута с помощью библиотек или фреймворков интернационализации, таких как SpringBoot I18n.

Короче говоря, интернационализация внешнего интерфейса в основном фокусируется на локализации отображения страниц и пользовательского интерфейса, тогда как интернационализация внутреннего интерфейса занимается вопросами интернационализации, связанными с бизнес-логикой и данными. Для достижения полной функциональности интернационализации обычно необходимо работать вместе.


🏆3. Мало знаний

Прежде чем мы начнем интернационализировать внутренний интерфейс, давайте сначала разберемся с некоторыми базовыми знаниями.

🛒 3.1 Объект локали

нуждатьсяподдерживатьинтернационализация,Сначала вы должны знать, какой регион и язык вы выбираете.,javaиспользуется вjava.util.LocaleПриходитьУказывает региональный язык,Этот объект содержит информацию о нациязык.

Наиболее часто используемые методы построения в Locale:

кодязык:java
копировать
public Locale(String language, String country) {
    this(language, country, "");
}

Конструктор имеет два параметра:language:язык、country:нация

Значения этих двух параметров пишутся не случайно.,На международном уровне существуют единые стандарты.,нравиться:zh-CNвыражатьМатериковый Китайрегиональный китайский,zh-TWвыражатьТайвань, Китайрегиональный китайский,en-USвыражатьрегион СШАпо-английски,en-GBвыражатьрегион Великобританиипо-английскии т. д.。проходитьязыкинацияструктура Объект локали,СравниватьнравитьсяLocale locale = new Locale("zh", "CN");,выражать Материковый Китайцы в регионе Китая.


Многие часто используемые объекты Locale созданы в классе Locale и могут использоваться напрямую. Давайте рассмотрим некоторые из них:

кодязык:java
копировать
static public final Locale SIMPLIFIED_CHINESE = createConstant("zh", "CN");
static public final Locale TRADITIONAL_CHINESE = createConstant("zh", "TW");
static public final Locale FRANCE = createConstant("fr", "FR");
static public final Locale GERMANY = createConstant("de", "DE");

🥼 3.2 Интерфейс источника сообщений

Это основной интерфейс интернационализации Spring, который определяется следующим образом:

кодязык:java
копировать
public interface MessageSource {
    /**
     * Получите международную информацию
     */
    @Nullable
    String getMessage(String code, @Nullable Object[] args, @Nullable String defaultMessage, Locale locale);

    /**
     * Аналогичен описанному выше методу, за исключением того, что если соответствующее имя атрибута в ресурсе не может быть найдено, исключение NoSuchMessageException создается напрямую.
     */
    String getMessage(String code, @Nullable Object[] args, Locale locale) throws NoSuchMessageException;

    /**
     * @param MessageSourceResolvable Инкапсулируйте имя атрибута, массив параметров и информацию по умолчанию. Его функция такая же, как и у первого метода.
     */
    String getMessage(MessageSourceResolvable resolvable, Locale locale) throws NoSuchMessageException;
}

MessageSourceинтерфейс Предусмотрено три приобретенияинтернационализацияметод сообщения,В основном оно основано на Locale информацию для получения соответствующего набора интернационализированных сообщений, а затем на основе code Получите соответствующее сообщение,ипроходитьпоставлятьизпараметр args Вы также можете отформатировать полученное сообщение.

Конкретные значения параметров следующие:

Имя параметра

значение

code

Представляет имя атрибута в интернационализированных ресурсах.

args

Значения для заполнения параметров в сообщении

defaultMessage

Сообщение по умолчанию, если не найдено, будет возвращено сообщение по умолчанию.

resolvable

Параметры сообщения, инкапсулирующий код, аргументы, defaultMessage

locale

Представляет объект локализации


Три общих класса реализации:

Имя класса

значение

ResourceBundleMessageSource

Это основано на реализации базового класса Java ResourceBundle, позволяющей загружать интернационализированные файлы только через имена ресурсов.

ReloadableResourceBundleMessageSource

Эта функция аналогична функции первого класса с добавлением функции запланированного обновления, позволяющей обновлять информацию интернационализированных файлов без перезапуска системы.

StaticMessageSource

Это позволяет программно предоставлять интернационализированную информацию.


Ключевой момент: В проекте мы создадим MessageSource, но независимо от того, какой класс реализации или наш пользовательский класс используется, для имени компонента должно быть установлено значениеmessageSource

При загрузке ApplicationContext автоматически выполняется поиск bean-компонента MessagesSource, определенного в контексте (имя должно быть messageSource). Если источник сообщения не найден, создается пустой экземпляр messageSource.


🎁 3.3 Интерфейс LocaleResolver

Этот интерфейс используется для установки языка интернационализации по умолчанию для текущего сеанса. Он определяется следующим образом:

кодязык:java
копировать
public interface LocaleResolver {
   /**
    * Анализ информации о локализации текущего запроса на основе текущего запроса.
    */
    Locale resolveLocale(HttpServletRequest request);

   /**
    * Установите информацию о локализации текущего запроса и ответа.
    */
    void setLocale(HttpServletRequest request, @Nullable HttpServletResponse response, @Nullable Locale locale);
}

resolveLocaleметод используется для изменения текущегоrequestВ анализе соответствующиеLocaleобъект,Такие сценарии, как:

Например, когда в программу (сервер) отправляется запрос, как мы узнаем, из какой он страны? Нужно ли нам получать IP-адрес через запрос, а затем анализировать его в соответствующем регионе на основе IP-адреса? Нет, нет, это будет слишком много хлопот.

Интерфейс LocaleResolver, предоставляемый Spring, используется для анализа региона, используемого клиентом. Мы можем передать соответствующий язык в заголовке запроса или URL-адресе запроса, а LocaleResolver может создать соответствующий объект Locale в соответствии с правилами.


Существует 4 общих класса реализации:

Имя класса

значение

AcceptHeaderLocalResovler

проходить Заголовок запросавнутриAccept-Language:zh,en;q=0.9,zh-HK;q=0.8Приходить РешатьиспользоватьспецифическийизЭкземпляр локали,Фактически AcceptHeaderLocalResovler использует экземпляр Locale в экземпляре HttpServletRequest.,При входе в DispatcherServlet в экземпляре HttpServletRequest уже есть экземпляр Locale.,Вы можете получить экземпляр Locale через request.getLocale();,HttpServletRequestвнутри Экземпляр локалито естьиспользовать Заголовок запросавнутриAccept-Language:zh,en;q=0.9,zh-HK;q=0.8Приходить Строитьиз,Сравниватьнравиться Заголовок запросавнутриAccept-Language:zh,en;q=0.9,zh-HK;q=0.8 СразувыражатьzhВес1,en;q=0,9 означает, что вес en равен 0,9,zh-HK;q=0,8 означает, что вес zh-HK равен 0,8.,Затем с помощью request.getLocale() мы получаем zh с наибольшим весом, а затем создаем экземпляр локали zh, после чего AcceptHeaderLocalResovler вернет экземпляр локали zh при анализе локали.

CookieLocaleResovler

Определите конкретный локализованный экземпляр локали на основе определенного параметра, установленного пользователем в файле cookie.

SessionLocaleResovler

Определите конкретный локализованный экземпляр Locale в соответствии с определенным параметром, установленным пользователем в HttpSession.

FixedLocalResovler

Используйте экземпляр Locale по умолчанию, который поставляется с jdk.


🎠 3.4 Файлы интернационализации

В проекте,существоватьresourcesСоздайте каталог с именемi18nкаталог файлов,тогда мысуществоватьi18nСоздание каталогафайлы интернационализации

Формат::имя_язык_область.properties

Давайте сначала создадим два языка, например:

message.properties

кодязык:text
копировать
name=ваше имя
текст = текст по умолчанию

В этом имени файла не указана локальная информация. Если система не может его найти, она будет использовать имя по умолчанию.

message_cn_ZH.properties: китайский [Китай]

кодязык:text
копировать
имя=имя
текст=текст

message_en_GB.properties: английский [Великобритания]

кодязык:text
копировать
name=Full name
text=text

наспроходитьMessageSourceинтерфейсизgetMessageметодвходящийверноотвечатьизkey(нравитьсяnaem、text),Тогда ты сможешьфайлы Возьмите ценность от интернационализации. В то же время мы также можем указать Объект локали, вы можете найти соответствующие файлы интернационализации Затем получите значение。


☕ 4. Реальные онлайн-решения

в растворе,приметВ то же время прочитайте информацию о интернационализации из базы данных и файла свойств.,достигатьинтернационализация Высокая информационная гибкость。

🧤 4.1 Создание интернационализированных файлов

существоватьresources/i181n/messagesОглавление,Создайте три файла отдельно(keyизимярекомендоватьНапишите с большой буквы и подчеркнитеиз Способ)

message.properties:

кодязык:text
копировать
OK_NAME=ваше имя
OK_TEXT=Текст по умолчанию

В этом имени файла не указана локальная информация. Если система не может его найти, она будет использовать имя по умолчанию.

message_cn_ZH.properties: китайский [Китай]

кодязык:text
копировать
OK_NAME=Имя
OK_TEXT=Текст

message_en_GB.properties: английский [Великобритания]

кодязык:text
копировать
OK_NAME=Full name
OK_TEXT=text

Укажите путь к файлу интернационализации i18n:

кодязык:yaml
копировать
spring:
  messages:
    basename: i18n/messages
    encoding: UTF-8

👔 4.2 Создать международную таблицу

Содержимое таблицы (таблица просто создается, вы можете ее улучшить самостоятельно):

кодязык:sql
копировать
CREATE TABLE `ok_i18message` (
  `code` varchar(255) NOT NULL COMMENT 'Имя атрибута',
  `locale` varchar(100) DEFAULT NULL COMMENT 'код нации',
  `message` varchar(255) DEFAULT NULL COMMENT «Соответствующее содержание»,
  PRIMARY KEY (`code`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Данные таблицы:

кодязык:sql
копировать
INSERT INTO `ok_i18message` (`code`, `locale`, `message`) VALUES ('OK_PASSWORD', 'cn_ZH', 'пароль');
INSERT INTO `ok_i18message` (`code`, `locale`, `message`) VALUES ('OK_PASSWORD', 'en_GB', 'password');
INSERT INTO `ok_i18message` (`code`, `locale`, `message`) VALUES ('OK_AGE', 'cn_ZH', 'возраст');
INSERT INTO `ok_i18message` (`code`, `locale`, `message`) VALUES ('OK_AGE', 'en_GB', 'age');

Класс сущности:

кодязык:java
копировать
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * Таблица интернационализации
 * @ClassName I18message
 * @Author Blue
 * @Date 2023/11/5
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@TableName("ok_i18message")
@ApiModel(description = "Таблица интернационализации")
public class I18message {

    @ApiModelProperty("имя свойства")
    private String code;

    @ApiModelProperty("нациякод")    private String locale;

    @ApiModelProperty("соответствующее содержимое")
    private String message;

}

класс картографа:

кодязык:java
копировать
import com.github.yulichang.base.MPJBaseMapper;
import org.apache.ibatis.annotations.Mapper;

/**
 * Таблица интернационализации
 * @ClassName AssetsLogMapper
 * @Author Blue
 * @Date 2023/11/5
 */
@Mapper
public interface I18messageMapper extends MPJBaseMapper<I18message> {
}

Случай:использоватьmybatis-plusПриходить Заканчиватьверноповерхностьизcrud


🎒 4.3 Пользовательский класс MessageSource

насиспользовать Пользовательский класс MessageSourceПриходить Интегрироватьинтернационализацияинформация,существовать3.2 MessageSourceинтерфейсЕсть поговоркаStaticMessageSourceвыполнитьдобрый Можетпроходитьпрограммированиеиз Способпоставлятьинтернационализацияинформация,Так почему бы нам просто не использовать его? Но настроить класс? Объяснение я оставил напоследок.

Исходный код сообщения:

кодязык:java
копировать
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.context.support.AbstractMessageSource;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.text.MessageFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.stream.Collectors;

// @Component("messageSource"): Вы также можете указать здесь имя bean-компонента как messageSource
public class MyMessageSource extends AbstractMessageSource implements InitializingBean {

    // Внедрить объект интерфейса запроса
    @Resource
    private I18messageMapper i18messageMapper;

    /**
     * Это используется для кэширования конфигурации, полученной из базы данных.
     * Когда конфигурация базы данных изменится, вы можете вызвать метод reload для перезагрузки.
     */
    private static final Map<String, Map<String, String>> LOCAL_CACHE = new ConcurrentHashMap<>();

    /**
     * После запуска программы она автоматически загрузится
     */
    @Override
    public void afterPropertiesSet() {
        this.reload();
    }

    /**
     * Перезагрузить сообщения в кэш карты класса.
     */
    public void reload() {
        // Очистить кеш этого класса
        LOCAL_CACHE.clear();
        // Загрузить все интернационализированные ресурсы
        LOCAL_CACHE.putAll(this.loadAllMessageResources());
    }

    /**
     * Цель: загрузить все интернационализированные ресурсы сообщений.
     * В то же время прочитайте информацию о интернационализации из базы данных и файла свойств.
     */
    private Map<String, Map<String, String>> loadAllMessageResources() {
        // Запросить все международные ресурсы из базы данных
        List<I18message> allLocaleMessage = i18messageMapper.selectList(null);
        if (ObjectUtils.isEmpty(allLocaleMessage)) {
            allLocaleMessage = new ArrayList<>();
        }

        // Преобразуйте запрошенные международные ресурсы в Map<областькод, Map<code, информация>> формат данных
        Map<String, Map<String, String>> localeMsgMap = allLocaleMessage
                // транслировать
                .stream()
                // Группа
                .collect(Collectors.groupingBy(
                        // в соответствии снацияобласть Группа
                        I18message::getLocale,
                        // Собрано как карта, ключ — это код, значение — информация.
                        Collectors.toMap(
                                I18message::getCode
                                , I18message::getMessage
                        )
                ));

        // Получить список регионов страны
        List<Locale> localeList = localeMsgMap.keySet().stream().map(Locale::new).collect(Collectors.toList());
        for (Locale locale : localeList) {

            // Читайте локальные интернационализированные файлы ресурсов в соответствии с национальным регионом. Наши интернационализированные файлы ресурсов размещаются в папке i18n.
            ResourceBundle resourceBundle = ResourceBundle.getBundle("i18n/messages", locale);
            // Получите ключ-значение в интернационализированном файле ресурсов.
            Set<String> keySet = resourceBundle.keySet();

            // Воля код=информация Формат сбора данных: Map<code,информация> формат
            Map<String, String> msgFromFileMap = keySet.stream()
                    .collect(
                            Collectors.toMap(
                                    Function.identity(),
                                    resourceBundle::getString
                            )
                    );

            // Воляместныйизинтернационализацияинформацияиданныебиблиотекаизинтернационализацияинформацияслить
            Map<String, String> localeFileMsgMap = localeMsgMap.get(locale.getLanguage());
            localeFileMsgMap.putAll(msgFromFileMap);
            localeMsgMap.put(locale.getLanguage(), localeFileMsgMap);
        }

        return localeMsgMap;
    }

    /**
     * Загрузка интернационализированных ресурсов в кэш-карту
     */
    private String getSourceFromCacheMap(String code, Locale locale) {
        String language = ObjectUtils.isEmpty(locale)
                ? LocaleContextHolder.getLocale().getLanguage() : locale.getLanguage();

        // Получить все элементы данных, соответствующие языку, в кеше.
        Map<String, String> propMap = LOCAL_CACHE.get(language);
        if (!ObjectUtils.isEmpty(propMap) && propMap.containsKey(code)) {
            // Если элемент данных может быть сопоставлен на соответствующем языке, вернитесь напрямую.
            return propMap.get(code);
        }

        // Если интернационализированное сообщение не может быть найдено, код будет возвращен напрямую.
        return code;
    }

    /**
     * Метод реализации для внутреннего использования метода getMessage
     */
    @Override
    protected MessageFormat resolveCode(String code, Locale locale) {
        String msg = this.getSourceFromCacheMap(code, locale);
        return new MessageFormat(msg, locale);
    }

    /**
     * Метод реализации для внутреннего использования метода getMessage
     */
    @Override
    protected String resolveCodeWithoutArguments(String code, Locale locale) {
        return this.getSourceFromCacheMap(code, locale);
    }

}

Мы настроилиMyMessageSourceкласс наследуетAbstractMessageSourceабстрактныйдобрый и ОсуществленныйInitializingBeanинтерфейс,оти ОсуществленныйотИнтернационализированные сообщения, полученные из базы данныхиСообщения интернационализации в локальных файлах свойствИнтегрироватьиз Функция。

имя

значение

AbstractMessageSource

Абстрактный класс наследует интерфейс HierarchicalMessageSource, который, в свою очередь, наследует MessageSource. Это абстрактный класс, поддерживающий метод «файла конфигурации». Он предоставляет общедоступный файл конфигурации сообщения, который не имеет ничего общего с настройками локали. Код сообщения является ключевым словом.

InitializingBean

Предоставляет метод инициализации для bean-компонентов. Он включает только метод afterPropertiesSet. Все классы, наследующие этот интерфейс, будут выполнять этот метод при инициализации bean-компонента.


Возможно, вы заметили,нассуществоватьнаследоватьAbstractMessageSourceабстрактныйдобрый Позже переписал дваметод:resolveCoderesolveCodeWithoutArguments,Эти два метода предназначены дляgetMessageметодвнутреннийиспользоватьиз。

мы входимAbstractMessageSourceИсходный код,ПроверятьgetMessageметод,существоватьвызовэто时входящийcodeиlocale,оно позвонитresolveCodeметодили ВОЗвызовresolveCodeWithoutArgumentsметодполучитьинформация,в конце концов вернутьсяверноотвечатьизинтернационализацияинформация。

Эти два метода были переписаны нами.,этоизданные都отнас自定义изMyMessageSourceдобрыйизLOCAL_CACHE(объект карты)Залезай,


⚾ 4.4 Парсер интернационализированных локалей

LocaleResolver:использовать Приходить Установить текущий сеанс по умолчаниюизинтернационализацияязык

кодязык:java
копировать
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleResolver;

import javax.annotation.Nullable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Locale;

/**
 * преобразователь локали
 * @ClassName MyLocaleResolver
 * @Author Blue
 * @Date 2023/11/6
 */
@Configuration
public class MyLocaleResolver implements LocaleResolver {

   /**
    * Анализ информации о локализации текущего запроса на основе текущего запроса.
    */
    @Override
    public Locale resolveLocale(HttpServletRequest httpServletRequest) {
        // Запросить параметры URL
        String l = httpServletRequest.getParameter("lang");
        // Параметры заголовка запроса
        String header = httpServletRequest.getHeader("lang");
        // Интернационализация: каждый объект локали представляет определенную политическую культуру, регион и метод создания.
        Locale locale = null;
        // суждение Запросить параметры Есть ли в URL-адресе параметр lang (предпочтительно)
        if (!StrUtil.isEmpty(l)) {
            // Разделить по подчеркиванию
            String[] split = l.split("_");
            // Создание международных объектов
            locale = new Locale(split[0], split[1]);

        // суждение Параметры заголовка Есть ли в запросе параметр lang?
        } else if(!StrUtil.isEmpty(header)) {
            // Заменить пустым
            header = header.replaceAll("\"","");
            // Разделить по подчеркиванию
            String[] split = header.split("_");
            // Создание международных объектов
            locale = new Locale(split[0], split[1]);
        }
        return locale;
    }

   /**
    * Установите информацию о локализации текущего запроса и ответа.
    */
    @Override
    public void setLocale(HttpServletRequest httpServletRequest, @Nullable HttpServletResponse
            httpServletResponse, @Nullable Locale locale) {
    }

}

👑 4.5 Международный класс комплектации

здесьиз Ключевым моментом являетсясуществовать В:Волянас自定义изMyMessageSourceдобрый,Оставьте это контейнеру Spring для создания и управления.,иимяустановлен наmessageSource

кодязык:java
копировать
/**
 * Web Mvc Конфигуратор
 * Решайте междоменные проблемы, добавляйте перехватчики, настраивайте преобразователи представлений, обработку статических ресурсов, интернационализацию и т. д.
 * @ClassName ApplicationConfig
 * @Author Blue
 * @Date 2023/11/5
 */
@Configuration
public class ApplicationConfig implements WebMvcConfigurer {

   /**
    * преобразователь локали
    */
    @Bean
    public LocaleResolver localeResolver() {
        return new MyLocaleResovel();
    }

    /**
     * Когда Spring запускается и загружает контекст, он запрашивает, существует ли bean-компонент с именем контейнера в качестве messageSource.
     * В противном случае будет создан компонент с именем messageSource и помещен в контекст.
     * Мы вручную создаем bean-компонент с именем messageSource вместо того, чтобы Spring создавал его автоматически.
     */
    @Bean
    public MessageSource messageSource() {
        return new MyMessageSource();
    }
    

}

🎁 4.6 Международные услуги

верноMessageSourceИнкапсулировать,Нам удобно пользоваться

кодязык:java
копировать
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Component;

import java.util.Locale;

/**
 * Служба источника сообщений локали
 * @ClassName LocaleMessageSourceService
 * @Author Blue
 * @Date 2022/11/14
 */
@Component
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class LocaleMessageSourceService {

    private final MessageSource messageSource;

    /**
     * @param code Ключ, соответствующий конфигурации сообщений
     * @return String
     */
    public String getMessage(String code){
        return getMessage(code,null);
    }

    /**
     * @param code Ключ, соответствующий конфигурации сообщений
     * @param args Параметры массива
     * @return String
     */
    public String getMessage(String code,Object[] args){
        return getMessage(code, args,"");
    }


    /**
     * @param code Ключ, соответствующий конфигурации сообщений
     * @param args Параметры массива
     * @param defaultMessage Значение по умолчанию, если ключ не установлен
     * @return String
     */
    public String getMessage(String code,Object[] args,String defaultMessage){
        Locale locale = LocaleContextHolder.getLocale();
        return messageSource.getMessage(code, args, defaultMessage, locale);
    }

}

🎁 4.7 Сценарии использования

Есть много способов сказать Сценарии использования,нравитьсяВзаимодействие с валидатором проверки параметров, глобальным исключением и информацией об интерфейсе.Возврат и так далее,Реальные проекты могут быть более сложными, поэтому я здесь для того, чтобы использовать его просто для того, чтобы каждый мог использовать его самостоятельно.

🥙 4.7.1 Глобальное исключение
кодязык:java
копировать
/**
 * глобальное обработчик файлов
 * @ClassName GlobalExceptionHandler
 * @Author Blue
 * @Date 2023/11/6
 */
@Slf4j
@RestControllerAdvice
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class GlobalExceptionHandler {

    private final LocaleMessageSourceService localeMessageSourceService;

    /**
     * Пользовательская обработка исключений проверки
     * Советы по безопасности интернационализации-проверка-jsr303
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        log.error(e.getMessage(), e);
        // Получите значение ключа, соответствующее решению параметра безопасности.
        String message = e.getBindingResult().getFieldError().getDefaultMessage();
        return Result.fail(message);
    }
    
    /**
     * Пользовательская обработка исключений проверки
     * Assert - Обработка исключений
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public Result handleIllegalArgumentException(IllegalArgumentException e) {
        log.error(e.getMessage(), e);
        // Параметры метода getMessage заполняются соответствующим образом. файлы интернационализации или Таблица интернационализации Просто код в
        return Result.fail(localeMessageSourceService.getMessage("OK_NAME"));
    }

    /**
     * Пользовательская обработка исключений проверки
     * Ошибка формата электронной почты
     */
    @ExceptionHandler({MailSendException.class,SendFailedException.class,SMTPAddressFailedException.class})
    public Result handleMailSendException(Exception e) {
        log.error(e.getMessage(), e);
        // Параметры метода getMessage заполняются соответствующим образом. файлы интернационализации или Таблица интернационализации Просто код в
        return Result.fail(localeMessageSourceService.getMessage("OK_AGE"));
    }

    /**
     * Пользовательская обработка исключений проверки
     * Возможно, WebSocketServer неправильно отправил сообщение.
     */
    @ExceptionHandler(IOException.class)
    public Result handleIOException(IOException e) {
        log.error(e.getMessage(), e);
        // Параметры метода getMessage заполняются соответствующим образом. файлы интернационализации или Таблица интернационализации Просто код в
        return Result.fail(localeMessageSourceService.getMessage("OK_WS_ERROR"));
    }

    /**
     * все Обработка исключений
     */
    @ExceptionHandler
    public Result handlerException(Exception e) {
        log.error(e.getMessage(), e);
        return Result.fail(localeMessageSourceService.getMessage("OK_ERROR"));
    }

}
📯 4.7.2 Интерфейс
кодязык:java
копировать
@Slf4j
@CrossOrigin
@RefreshScope
@RestController
@Api(tags = «Тестовый интерфейс возвращает информацию о интернационализации»)
@RequestMapping("/test")
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class TestController {

    private final LocaleMessageSourceService localeMessageSourceService;
    private final MyMessageSource myMessageSource;

    @ApiOperation("Безопасность параметров")
    @PostMapping("/is")
    public Result is(String password,Integer age) {
        if (StrUtil.isBlank(password)) {
            return Result.fail(localeMessageSourceService.getMessage("OK_PASSWORD"));
        }
        if (ObjectUtil.isEmpty(age)) {
            return Result.fail(localeMessageSourceService.getMessage("OK_AGE"));
        }
        // бизнес...
        return Result.succeed("succeed");
    }

    @ApiOperation("Перезагрузить интернационализированные сообщения")
    @PostMapping("/reloadMessage")
    public void reloadMessage() {
        myMessageSource.reload();
    }

}

Конечно, мне нет нужды судить подобным образом о безопасности параметров.,слишком долго,Я просто хочу выразить сцену более интуитивно.,Каждый может объединитьВалидатор проверки параметров,Одна аннотация может обеспечить безопасность параметров.интернационализациянамекать。

Здесь я напишу только два типа Сценариев. использования,Каждый может попробовать,Объедините свой бизнес и идеи,Сделайте свой код более мощным и простым в использовании!


📖 5. Описание источника сообщения

существовать4.3 Пользовательский класс MessageSourceПочему мы должны Пользовательский класс MessageSourceШерстяная ткань?StaticMessageSourceдобрый明明Может Это позволяет программно предоставлять интернационализированную информацию.

Вот почему:

  • StaticMessageSourceдобрый也能выполнить同样из Функция,Однако его не рекомендуется использовать в производственной среде.,и Нетподдерживатьинтернационализацияинформацияудалить
  • StaticMessageSourceПодходящийинтернационализацияинформациятест,поддерживать硬编кодизметоддобавить винтернационализацияинформация

Когда мы посмотрим на его исходный код, мы увидим:

Исходный кодиз В аннотации также упоминается:Intended for testing rather than for use in production systems.В переводе на китайский язык этоИспользуется для тестирования, а не для производственных систем.

И все интернационализированные сообщения в конечном итоге будут кэшироваться в messageMap. Поскольку StaticMessageSource не предоставляет метода очистки данных карты, только при перезапуске программы интернационализированные сообщения, удаленные из базы данных, могут быть отражены в messageMap.

📚 6. Наконец

хорошо,До сих пор,насизПоиграйтесь с интернационализацией взаимодействия данных внутреннего интерфейса с нуляконец,Я надеюсь, что каждый сможет что-то получить!

Если у вас есть какие-либо вопросы или вам нужна помощь по этой статье, оставьте сообщение в области комментариев, и я постараюсь ответить на него. Если эта статья была для вас полезна, пожалуйста, поставьте лайк в знак вашей поддержки, большое спасибо! 💗

Я участвую в третьем этапе специального тренировочного лагеря Tencent Technology Creation 2023 с эссе, получившими приз, и сформирую команду, которая разделит приз!

boy illustration
Учебное пособие по Jetpack Compose для начинающих, базовые элементы управления и макет
boy illustration
Код js веб-страницы, фон частицы, код спецэффектов
boy illustration
【новый! Суперподробное】Полное руководство по свойствам компонентов Figma.
boy illustration
🎉Обязательно к прочтению новичкам: полное руководство по написанию мини-программ WeChat с использованием программного обеспечения Cursor.
boy illustration
[Забавный проект Docker] VoceChat — еще одно приложение для мгновенного чата (IM)! Может быть встроен в любую веб-страницу!
boy illustration
Как реализовать переход по странице в HTML (html переходит на указанную страницу)
boy illustration
Как решить проблему зависания и низкой скорости при установке зависимостей с помощью npm. Существуют ли доступные источники npm, которые могут решить эту проблему?
boy illustration
Серия From Zero to Fun: Uni-App WeChat Payment Practice WeChat авторизует вход в систему и украшает страницу заказа, создает интерфейс заказа и инициирует запрос заказа
boy illustration
Серия uni-app: uni.navigateЧтобы передать скачок значения
boy illustration
Апплет WeChat настраивает верхнюю панель навигации и адаптируется к различным моделям.
boy illustration
JS-время конвертации
boy illustration
Обеспечьте бесперебойную работу ChromeDriver 125: советы по решению проблемы chromedriver.exe не найдены
boy illustration
Поле комментария, щелчок мышью, специальные эффекты, js-код
boy illustration
Объект массива перемещения объекта JS
boy illustration
Как открыть разрешение на позиционирование апплета WeChat_Как использовать WeChat для определения местонахождения друзей
boy illustration
Я даю вам два набора из 18 простых в использовании фонов холста Power BI, так что вам больше не придется возиться с цветами!
boy illustration
Получить текущее время в js_Как динамически отображать дату и время в js
boy illustration
Вам необходимо изучить сочетания клавиш vsCode для форматирования и организации кода, чтобы вам больше не приходилось настраивать формат вручную.
boy illustration
У ChatGPT большое обновление. Всего за 45 минут пресс-конференция показывает, что OpenAI сделал еще один шаг вперед.
boy illustration
Copilot облачной разработки — упрощение разработки
boy illustration
Микросборка xChatGPT с низким кодом, создание апплета чат-бота с искусственным интеллектом за пять шагов
boy illustration
CUDA Out of Memory: идеальное решение проблемы нехватки памяти CUDA
boy illustration
Анализ кластеризации отдельных ячеек, который должен освоить каждый&MarkerгенетическийВизуализация
boy illustration
vLLM: мощный инструмент для ускорения вывода ИИ
boy illustration
CodeGeeX: мощный инструмент генерации кода искусственного интеллекта, который можно использовать бесплатно в дополнение к второму пилоту.
boy illustration
Машинное обучение Реальный бой LightGBM + настройка параметров случайного поиска: точность 96,67%
boy illustration
Бесшовная интеграция, мгновенный интеллект [1]: платформа больших моделей Dify-LLM, интеграция без кодирования и встраивание в сторонние системы, более 42 тысяч звезд, чтобы стать свидетелями эксклюзивных интеллектуальных решений.
boy illustration
LM Studio для создания локальных больших моделей
boy illustration
Как определить количество слоев и нейронов скрытых слоев нейронной сети?
boy illustration
[Отслеживание целей] Подробное объяснение ByteTrack и детали кода