Tratamento de Exceções e Suporte Multilíngue em Spring Boot com Dubbo

Suporte Multilíngue

Para integrar suporte multilíngue em uma aplicação Spring Boot, configure um bean de resolução de localização. Defina o idioma padrão e o local dos arquivos de propriedades de internacionalização (i18n) usando uma classe de configuração.

package org.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.LocaleContextResolver;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;

import java.util.Locale;

@Configuration
public class ConfiguracaoIdioma {

    private final String idiomaPadrao = "pt-BR"; // Idioma padrão definido como português brasileiro

    @Bean
    public LocaleContextResolver resolvedorLocal() {
        CookieLocaleResolver resolvedor = new CookieLocaleResolver();
        resolvedor.setDefaultLocale(Locale.forLanguageTag(idiomaPadrao));
        resolvedor.setCookieName("APP_IDIOMA");
        resolvedor.setCookieMaxAge(Integer.MAX_VALUE);
        return resolvedor;
    }
}

Em ambientes de microsserviços, sessões podem não ser adequadas, então cookies são usados para armazenar a localização. A chave padrão do cookie é configurada na classe.

Troca de Linguagem

Adicione um endpoint em um controlador para permitir a troca de idioma via API. Isso permite que o cliente altere o idioma dinamicamente.

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.LocaleContextResolver;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@RestController
public class ControladorIdioma {

    private final LocaleContextResolver resolvedorLocal;

    public ControladorIdioma(LocaleContextResolver resolvedorLocal) {
        this.resolvedorLocal = resolvedorLocal;
    }

    @GetMapping("/mudar-idioma")
    public ResponseEntity<void> alterarIdioma(@RequestParam String codigoIdioma, HttpServletRequest requisicao, HttpServletResponse resposta) {
        resolvedorLocal.resolveLocaleContext(requisicao);
        resolvedorLocal.setLocale(requisicao, resposta, Locale.forLanguageTag(codigoIdioma));
        return ResponseEntity.ok().build();
    }
}</void>

Exceções Multilíngues

No tratamento de exceções, diferencie entre exceções de negócio e exceções do sistema, especialmente ao integrar com Dubbo, onde exceções podem ser encapsuladas.

Exceções de Negócio

Defina uma exceção de negócio que carrega uma chave de mensagem e argumentos para internacionalização.

package org.example.excecao;

public class ExcecaoNegocio extends RuntimeException {

    private final String chaveMsg;
    private final Object[] argumentos;

    public ExcecaoNegocio(String chaveMsg, Object... argumentos) {
        super(chaveMsg);
        this.chaveMsg = chaveMsg;
        this.argumentos = argumentos;
    }

    public String getChaveMsg() {
        return chaveMsg;
    }

    public Object[] getArgumentos() {
        return argumentos;
    }
}

Use uma chave especial para mensagens diretas, como definido no arquivo de propriedades: mensagem.direta={0}.

Exceções do Sistema

Quando Dubbo ou Lombok encapsulam exceções em RuntimeException, a classe original pode não ser acessível diretamente. Porém, a mensagem da exceção muitas vezes contém o nome da classe original. Extraia esse nome usando uma expressão regular para buscar recursos de internacionalização.

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ExtratorExcecao {

    private static final Pattern PADRAO_CLASSE = Pattern.compile("^([a-z]+(\\.[a-z_][a-z0-9_]*)*\\.[A-Za-z0-9_]*Exception): ");

    public static String extrairChaveExcecao(String mensagem) {
        Matcher correspondencia = PADRAO_CLASSE.matcher(mensagem);
        if (correspondencia.find()) {
            return correspondencia.group(1);
        }
        return null;
    }
}

Implementação Global de Tratamento de Exceções

Use uma classe de aconselhamento controlador para capturar exceções e retornar respostas padronizadas com mensagens internacionalizadas.

package org.example.mvc;

import org.example.excecao.ExcecaoNegocio;
import org.springframework.context.MessageSource;
import org.springframework.context.NoSuchMessageException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.LocaleResolver;

import javax.servlet.http.HttpServletRequest;
import java.util.Locale;

@RestControllerAdvice
public class AconselhadorExcecoes {

    private final MessageSource fonteMensagem;
    private final LocaleResolver resolvedorLocal;

    public AconselhadorExcecoes(MessageSource fonteMensagem, LocaleResolver resolvedorLocal) {
        this.fonteMensagem = fonteMensagem;
        this.resolvedorLocal = resolvedorLocal;
    }

    @ExceptionHandler(ExcecaoNegocio.class)
    public ResponseEntity<string> tratarExcecaoNegocio(HttpServletRequest requisicao, ExcecaoNegocio excecao) {
        Locale localAtual = resolvedorLocal.resolveLocale(requisicao);
        String mensagem;
        try {
            mensagem = fonteMensagem.getMessage(excecao.getChaveMsg(), excecao.getArgumentos(), localAtual);
        } catch (NoSuchMessageException e) {
            mensagem = excecao.getMessage();
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(mensagem);
    }

    @ExceptionHandler(Throwable.class)
    public ResponseEntity<string> tratarExcecaoSistema(HttpServletRequest requisicao, Throwable excecao) {
        Locale localAtual = resolvedorLocal.resolveLocale(requisicao);
        String chave = ExtratorExcecao.extrairChaveExcecao(excecao.getMessage());
        String mensagem;
        if (chave != null) {
            try {
                mensagem = fonteMensagem.getMessage(chave, new Object[]{}, localAtual);
            } catch (NoSuchMessageException e) {
                mensagem = excecao.getMessage();
            }
        } else {
            mensagem = excecao.getMessage();
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(mensagem);
    }
}</string></string>

Esta abordagem permite que o frontend trate diferentes tipos de exceções com base nas mnesagens retornadas, suportando múltiplos idiomas de forma integrada.

Tags: Spring Boot dubbo i18n java Tratamento de Exceções

Publicado em 6-7 06:24 por Thomas