NEW

Entenda o Problema que Afeta Milhares de Aplicações Java

Você já se deparou com uma situação frustrante onde um número perfeitamente legível como 1234567890123456789 simplesmente se transforma em algo como 1.2345678901234568E18 quando sua aplicação Java interage com o banco de dados?

Se você respondeu sim, saiba que não está sozinho. Esse é um dos erros mais comuns enfrentados por desenvolvedores que trabalham com valores extensos, sejam eles códigos de identificação, documentos fiscais, números de conta ou valores monetários de alta precisão.

A boa notícia? Esse problema tem solução, e você vai dominar todas as técnicas necessárias ao final deste artigo.

O Que É Notação Científica e Por Que Ela Aparece?

Antes de mergulharmos nas soluções, é fundamental entender a raiz do problema.

A notação científica é uma forma matemática de representar números muito grandes ou muito pequenos de maneira compacta. Por exemplo, 1.5E6 significa 1.500.000 (1,5 multiplicado por 10 elevado à sexta potência).

Embora seja útil em contextos científicos e matemáticos, essa notação se torna uma verdadeira dor de cabeça quando você precisa de números exatos em aplicações comerciais.

A Limitação dos Tipos Primitivos do Java

O Java utiliza os tipos float e double para trabalhar com números decimais. Esses tipos seguem o padrão internacional IEEE 754, que define como números de ponto flutuante são armazenados na memória.

O problema central está na capacidade limitada de armazenamento:

  • float: consegue armazenar aproximadamente 7 dígitos significativos
  • double: consegue armazenar aproximadamente 15-16 dígitos significativos

Quando você tenta armazenar um número com mais dígitos do que o tipo suporta, o Java automaticamente faz uma conversão para notação científica, perdendo precisão no processo.

Veja este exemplo prático:

double numeroGrande = 1234567890123456789d;
System.out.println("Valor armazenado: " + numeroGrande);

Resultado no console:

Valor armazenado: 1.2345678901234568E18

Perceba que os últimos dígitos foram alterados. Isso não é apenas uma questão de formatação visual – os dados realmente foram modificados na memória!

Quando Esse Problema Realmente Importa?

Você pode estar pensando: "Ok, mas isso realmente faz diferença na prática?" A resposta é: depende muito do contexto.

Situações Críticas Onde a Precisão É Essencial

1. Sistemas Financeiros Imagine uma aplicação bancária que processa valores monetários. Se você está lidando com transações internacionais ou cálculos de juros compostos em investimentos de longo prazo, perder até mesmo uma fração de centavo pode gerar inconsistências graves.

2. Identificadores Únicos CNPJs, CPFs, códigos de barras, números de protocolo – todos esses são tratados como números, mas não podem sofrer nenhuma alteração. Um dígito errado invalida completamente a informação.

3. Integrações com Sistemas Legados Muitos bancos de dados antigos armazenam identificadores como números. Ao migrar ou integrar esses sistemas, a conversão inadequada pode corromper registros inteiros.

4. Relatórios e Auditoria Se seus relatórios mostram valores diferentes dos registrados no banco de dados, você terá sérios problemas em auditorias e conformidade regulatória.

Exemplo Real: O Desastre Silencioso na Extração de Dados

Considere este cenário comum em aplicações empresariais:

Connection conexao = DriverManager.getConnection(urlBanco, usuario, senha);
Statement comando = conexao.createStatement();
ResultSet resultado = comando.executeQuery("SELECT codigo_produto FROM produtos");

while (resultado.next()) {
    double codigo = resultado.getDouble("codigo_produto");
    System.out.println("Código extraído: " + codigo);
}

O que você esperava:

Código extraído: 7891234567890

O que você obtém:

Código extraído: 7.89123456789E12

O impacto? Validações falham, buscas não encontram os registros, e relatórios ficam incompreensíveis para os usuários finais.

Solução 1: Tratando Identificadores Como Texto

A primeira e mais simples solução é reconhecer que nem todo número precisa ser tratado como tipo numérico.

Quando Usar String ao Invés de Tipos Numéricos

Se o valor não será usado em operações matemáticas (soma, subtração, multiplicação), trate-o como texto:

ResultSet resultado = comando.executeQuery("SELECT codigo_produto FROM produtos");

while (resultado.next()) {
    String codigo = resultado.getString("codigo_produto");
    System.out.println("Código preservado: " + codigo);
}

Vantagens desta abordagem:

  • Preservação total dos dígitos originais
  • Sem risco de conversão automática
  • Performance excelente para leitura
  • Ideal para chaves primárias, documentos e identificadores

Cuidado importante: Certifique-se de que a coluna no banco de dados também está definida como VARCHAR ou CHAR, não como NUMBER ou BIGINT.

Solução 2: BigDecimal Para Precisão Absoluta em Cálculos

Quando você realmente precisa fazer operações matemáticas com números grandes, a classe BigDecimal é sua melhor aliada.

Por Que BigDecimal É Superior

Diferente de float e double, o BigDecimal armazena números como objetos, sem limitação de precisão. Ele é especialmente projetado para cálculos financeiros e situações onde cada dígito conta.

ResultSet resultado = comando.executeQuery("SELECT valor_transacao FROM financeiro");

while (resultado.next()) {
    BigDecimal valor = resultado.getBigDecimal("valor_transacao");
    System.out.println("Valor exato: " + valor.toPlainString());
}

O Método toPlainString() É Crucial

Nunca use apenas toString() com BigDecimal, pois ele ainda pode retornar notação científica em alguns casos. Sempre utilize:

valor.toPlainString() // Retorna o número completo, sem notação científica

Exemplo Prático com Cálculos Financeiros

BigDecimal saldo = new BigDecimal("125678.50");
BigDecimal juros = new BigDecimal("0.0075"); // 0,75%
BigDecimal rendimento = saldo.multiply(juros);

System.out.println("Saldo inicial: R$ " + saldo.toPlainString());
System.out.println("Rendimento: R$ " + rendimento.toPlainString());

Resultado garantido:

Saldo inicial: R$ 125678.50
Rendimento: R$ 942.58875

Solução 3: Gravação Segura com PreparedStatement

A prevenção começa no momento da gravação. O PreparedStatement é sua ferramenta essencial para inserir dados no banco sem perda de precisão.

O Jeito Errado (Que Causa o Problema)

PreparedStatement ps = conexao.prepareStatement(
    "INSERT INTO contas (numero_conta, saldo) VALUES (?, ?)"
);

double numeroConta = 9876543210123456d;
double saldo = 50000.75;

ps.setDouble(1, numeroConta); // ERRO: vai virar notação científica
ps.setDouble(2, saldo);
ps.executeUpdate();

O Jeito Correto (Que Preserva os Dados)

PreparedStatement ps = conexao.prepareStatement(
    "INSERT INTO contas (numero_conta, saldo) VALUES (?, ?)"
);

String numeroConta = "9876543210123456";
BigDecimal saldo = new BigDecimal("50000.75");

ps.setString(1, numeroConta); // Preserva todos os dígitos
ps.setBigDecimal(2, saldo);   // Mantém precisão decimal exata
ps.executeUpdate();

Conversão de Valores Já Afetados: Ainda Há Esperança

E se você já tem dados armazenados em notação científica? É possível recuperá-los em muitos casos.

String valorCientifico = "1.23E10";
BigDecimal valorRecuperado = new BigDecimal(valorCientifico);
String valorLegivel = valorRecuperado.toPlainString();

System.out.println("Valor original (científico): " + valorCientifico);
System.out.println("Valor convertido: " + valorLegivel);

Saída:

Valor original (científico): 1.23E10
Valor convertido: 12300000000

Atenção: Essa conversão só funciona se a notação científica ainda contém todos os dígitos significativos. Se houve truncamento severo, pode haver perda de dados irreversível.

Comparativo: Escolhendo o Tipo Certo para Cada Situação

Comparação entre BigDecimal e Double mostrando como o Java converte números grandes em notação científica.













Configuração Adequada no Banco de Dados

O problema não está apenas no código Java – o esquema do banco de dados também desempenha papel fundamental.

Mapeamento Recomendado por Tipo de Dado

Para identificadores longos (CNPJ, códigos, protocolos):

-- Oracle
CREATE TABLE produtos (
    codigo VARCHAR2(50) PRIMARY KEY
);

-- PostgreSQL
CREATE TABLE produtos (
    codigo VARCHAR(50) PRIMARY KEY
);

-- SQL Server
CREATE TABLE produtos (
    codigo VARCHAR(50) PRIMARY KEY
);

Para valores monetários:

-- Oracle
CREATE TABLE transacoes (
    valor NUMBER(15,2)
);

-- PostgreSQL
CREATE TABLE transacoes (
    valor NUMERIC(15,2)
);

-- SQL Server
CREATE TABLE transacoes (
    valor DECIMAL(15,2)
);

Para números muito grandes que precisam de precisão total:

-- Use NUMERIC ou DECIMAL com precisão alta
CREATE TABLE registros (
    valor_exato NUMERIC(38,0)
);

Implementação Completa: Exemplo do Mundo Real

Vamos consolidar tudo em um exemplo completo de uma classe de serviço que gerencia transações financeiras:

import java.math.BigDecimal;
import java.sql.*;

public class ServicoTransacao {
    
    public void registrarTransacao(String codigoTransacao, 
                                   BigDecimal valor, 
                                   String documentoCliente) {
        
        String sql = "INSERT INTO transacoes (codigo, valor, documento_cliente, data_registro) " +
                     "VALUES (?, ?, ?, CURRENT_TIMESTAMP)";
        
        try (Connection conn = obterConexao();
             PreparedStatement ps = conn.prepareStatement(sql)) {
            
            // Usando tipos apropriados para cada campo
            ps.setString(1, codigoTransacao);      // Identificador como texto
            ps.setBigDecimal(2, valor);             // Valor monetário com precisão
            ps.setString(3, documentoCliente);      // Documento como texto
            
            int linhasAfetadas = ps.executeUpdate();
            
            if (linhasAfetadas > 0) {
                System.out.println("Transação registrada com sucesso!");
                System.out.println("Código: " + codigoTransacao);
                System.out.println("Valor: R$ " + valor.toPlainString());
            }
            
        } catch (SQLException e) {
            System.err.println("Erro ao registrar transação: " + e.getMessage());
            throw new RuntimeException("Falha na gravação dos dados", e);
        }
    }
    
    public void consultarTransacoes() {
        String sql = "SELECT codigo, valor, documento_cliente FROM transacoes";
        
        try (Connection conn = obterConexao();
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(sql)) {
            
            while (rs.next()) {
                String codigo = rs.getString("codigo");
                BigDecimal valor = rs.getBigDecimal("valor");
                String documento = rs.getString("documento_cliente");
                
                System.out.println("────────────────────────");
                System.out.println("Código: " + codigo);
                System.out.println("Valor: R$ " + valor.toPlainString());
                System.out.println("Cliente: " + documento);
            }
            
        } catch (SQLException e) {
            System.err.println("Erro ao consultar transações: " + e.getMessage());
        }
    }
    
    private Connection obterConexao() throws SQLException {
        String url = "jdbc:postgresql://localhost:5432/financeiro";
        String usuario = "app_user";
        String senha = "senha_segura";
        return DriverManager.getConnection(url, usuario, senha);
    }
}

Checklist de Boas Práticas para Evitar Problemas

Antes de colocar seu código em produção, verifique:

Identificadores numéricos estão sendo tratados como String?Valores monetários utilizam BigDecimal em vez de double?PreparedStatement está configurado com setBigDecimal() e setString()?Colunas do banco estão com tipos apropriados (VARCHAR para IDs, DECIMAL para valores)?Você está usando toPlainString() ao exibir BigDecimal?Há tratamento de exceções adequado para capturar erros de conversão?Testes automatizados verificam a integridade dos dados gravados?

Conclusão: Precisão É Fundamental em Aplicações Profissionais

O problema da notação científica no Java não é apenas uma curiosidade técnica – é uma questão crítica que pode comprometer a integridade de dados empresariais e financeiros.

Ao entender as limitações dos tipos primitivos e utilizar as ferramentas corretas (BigDecimal para valores monetários e String para identificadores), você garante que seus dados sejam armazenados e recuperados com precisão absoluta.

Lembre-se: um único dígito errado pode invalidar uma transação inteira, causar falhas em integrações ou gerar inconsistências em relatórios. Invista tempo na escolha dos tipos corretos desde o início do desenvolvimento.

Sua aplicação – e seus usuários – agradecem pela atenção aos detalhes!


Gostou deste conteúdo? Implemente essas práticas em seus projetos Java e compartilhe sua experiência nos comentários. Se você tem dúvidas específicas sobre casos mais complexos, deixe sua pergunta que terei prazer em ajudar!

Como Evitar que Números Grandes Virem Notação Científica no Java: Guia Completo para Desenvolvedores

Leia mais

 🧱 Introdução

LEFT JOIN com filtro WHERE vs ON: entenda de uma vez por todas com exemplos práticos em SQL


Um dos temas mais confusos em SQL é o comportamento do LEFT JOIN quando usamos filtros.
Muita gente não percebe que a posição da condição (WHERE ou ON) muda completamente o resultado da consulta.

Neste artigo, você vai aprender:

  • A diferença entre aplicar o filtro no WHERE e no ON

  • Como preservar os registros da tabela principal

  • Exemplos práticos com tabelas de teste

  • Explicação visual com imagens do resultado


⚙️ Cenário de teste — criando o ambiente

Você pode rodar este script em SQL Server, PostgreSQL ou Oracle (ajusta só o CREATE TABLE se quiser):

-- Criando tabelas CREATE TABLE TABELA_PRINCIPAL ( id_produto INT PRIMARY KEY, nome_produto VARCHAR(50) ); CREATE TABLE TABELA_SECUNDARIA ( id_produto INT, preco DECIMAL(10,2) ); -- Inserindo dados na tabela principal INSERT INTO TABELA_PRINCIPAL (id_produto, nome_produto) VALUES (10, 'Teclado'), (11, 'Mouse'), (12, 'Monitor'), (13, 'Webcam'); -- Inserindo dados na tabela secundária INSERT INTO TABELA_SECUNDARIA (id_produto, preco) VALUES (10, 150.00), (11, 80.00), (12, 900.00);

📘 Perceba que o produto 13 (Webcam) não existe na tabela secundária.


🧩 Consulta 1 — LEFT JOIN normal

SELECT p.id_produto, p.nome_produto, s.preco FROM TABELA_PRINCIPAL p LEFT JOIN TABELA_SECUNDARIA s ON p.id_produto = s.id_produto;

🟢 Resultado esperado:

id_produtonome_produtopreco
10Teclado150.00
11Mouse80.00
12Monitor900.00
13WebcamNULL

✅ Todos os registros da tabela principal aparecem,
mesmo sem correspondência na secundária (Webcam → NULL).


🚫 Consulta 2 — Filtro no WHERE (perde o comportamento do LEFT JOIN)

SELECT p.id_produto, p.nome_produto, s.preco FROM TABELA_PRINCIPAL p LEFT JOIN TABELA_SECUNDARIA s ON p.id_produto = s.id_produto WHERE s.id_produto = 12;

🟡 Resultado:

id_produtonome_produtopreco
12Monitor900.00

💬 Explicação:
Ao colocar s.id_produto = 12 no WHERE, o SQL ignora as linhas onde s é NULL.
O LEFT JOIN perde o sentido e o resultado fica igual a um INNER JOIN filtrado.


✅ Consulta 3 — Filtro dentro do ON (mantém o comportamento do LEFT JOIN)

SELECT p.id_produto, p.nome_produto, s.preco FROM TABELA_PRINCIPAL p LEFT JOIN TABELA_SECUNDARIA s ON p.id_produto = s.id_produto AND s.id_produto = 12;

🟢 Resultado:

id_produtonome_produtopreco
10TecladoNULL
11MouseNULL
12Monitor900.00
13WebcamNULL

💬 Explicação:
Agora sim!
Todos os produtos da tabela principal aparecem.
Apenas o produto 12 traz dados da tabela secundária; os outros permanecem com NULL

LEFT JOIN com filtro WHERE vs ON: entenda de uma vez por todas com exemplos práticos em SQL

Leia mais

SketchBoard Free — desenhe e salve (sem login) SketchBoard Free — desenhe e salve

SketchBoard Free

SketchBoard Free — desenhe e salve no seu computador • sem login

Drawly Studio – Crie, desenhe e salve suas ideias online (Em desenvolvimento)

Leia mais

 Introdução rápida

Se sua conta do WhatsApp foi comprometida (mensagens estranhas, perda de acesso ou sessão desconhecida), siga imediatamente os 10 passos abaixo. Isso maximiza chances de recuperar o número e reduzir danos.


10 passos urgentes

1) Tente reativar sua conta IMEDIATAMENTE

Abra o WhatsApp no seu celular, solicite o código de verificação por SMS e insira-o. Se você ainda controla o chip, isso pode derrubar o invasor.

2) Ative a verificação em duas etapas (PIN) assim que recuperar o acesso

Vá em Configurações → Conta → Verificação em duas etapas → Ativar. Escolha um PIN forte e um e-mail de recuperação.

3) Encerre sessões desconhecidas do WhatsApp Web / Desktop

No app, toque em Aparelhos conectados e finalize todas as sessões que você não reconhece.

4) Contate sua operadora imediatamente (suspeita de SIM swap)

Peça bloqueio temporário do número e registre solicitação de investigação por fraude/portabilidade indevida.

5) Altere senhas dos serviços vinculados (email, banco, redes sociais)

Se o invasor teve acesso, troque senhas e ative 2FA (autenticação de dois fatores) em e-mail e contas financeiras.

6) Denuncie ao suporte do WhatsApp e registre ocorrência policial

Use o formulário do WhatsApp (“Meu número foi roubado”) e registre Boletim de Ocorrência na delegacia (importante para operadora/banco).

7) Informe e oriente seus contatos (modelo pronto abaixo)

Envie SMS ou outra via confiável: “Minha conta do WhatsApp foi comprometida. Ignore pedidos de dinheiro e códigos. Vou avisar quando recuperar.”

8) Faça scan por malware e avalie restauração do aparelho

Rode antivírus confiável; se houver suspeita forte, faça backup e reset de fábrica do celular para eliminar app espião.

9) Monitore transações e tentativas de fraude vinculadas ao número

Verifique movimentos bancários, cadastros e notifique bancos caso veja atividade suspeita.

10) Adote medidas permanentes de proteção

  • Use PIN para operadora (senha de atendimento).

  • Nunca compartilhe códigos SMS/OTP.

  • Revise rotineiramente Aparelhos conectados e backups do WhatsApp.

  • Atualize sistema e apps sempre.


Modelo de mensagem para avisar contatos (copiar e enviar)

Alerta: minha conta do WhatsApp foi comprometida. Ignore mensagens pedindo dinheiro ou códigos. Estou tomando providências e avisarei quando estiver normalizado.


Checklist rápido (imprima/cole)

  • Tentei reativar com SMS

  • Ativei verificação em duas etapas

  • Encerrei sessões do WhatsApp Web

  • Contatei a operadora (SIM swap)

  • Troquei senhas importantes

  • Denunciei ao WhatsApp + BO

  • Avisei meus contatos

  • Rodei antivírus/reset se necessário

  • Verifiquei contas bancárias

  • Configurei proteção permanente


Observações importantes (segurança & legal)

  • Não compartilhe códigos de verificação com ninguém — nem com “suporte”.

  • Em casos de SIM swap, a operadora pode reverter o número, mas é essencial o BO para fins legais.

  • Preserve prints e horários; serão úteis em investigações.

🛡️ Como Recuperar e Proteger Sua Conta do WhatsApp Roubada — 10 Passos Urgentes

Leia mais

servidor web local, JBoss WildFly, Windows 11, servidor Java

Você pode estar em qualquer lugar do mundo — Brasil, Portugal, Estados Unidos, Angola, Japão ou Índia — e ainda assim precisará, em algum momento, criar um ambiente local confiável para rodar uma aplicação web em Java. Ter um servidor web local no Windows 11 usando JBoss WildFly é uma das formas mais profissionais de desenvolver e testar APIs, sistemas corporativos e aplicações Java EE / Jakarta EE com segurança e alta performance.

🔧 1. O que é o JBoss WildFly?

O WildFly (antigo JBoss AS) é um servidor de aplicações Java open-source focado em alto desempenho, modularidade e fácil administração. Ele é muito usado em empresas, principalmente em projetos que precisam de:

  • APIs REST ou SOAP

  • Aplicações Web Java rodando com Servlets, JSP, JSF, EJB ou Spring

  • Conexão com bancos Oracle, PostgreSQL, SQL Server ou MySQL

  • Deploy corporativo em ambientes de desenvolvimento, homologação e produção


🧰 2. Requisitos para o ambiente

ItemVersão Recomendada
WindowsWindows 10 ou 11
Java JDK11, 17 ou superior
WildFly24+ ou última versão estável
Ferramentas extras (opcional)IntelliJ, Eclipse ou VS Code

📌 Dica: Em qualquer sistema operacional, o essencial é que o Java esteja instalado e configurado no PATH.


💻 3. Baixando e instalando o WildFly

  1. Acesse o site oficial do WildFly

  2. Baixe a versão Final (ZIP)

  3. Extraia para um diretório, ex.:

    C:\wildfly

🔧 4. Configurando as variáveis de ambiente no Windows 11

Abra o Prompt de Comando (CMD) e verifique o Java:

java -version

Depois configure o JAVA_HOME e PATH no Windows.


🚀 5. Subindo o servidor local

No CMD, execute:

cd C:\wildfly\bin standalone.bat

Depois abra no navegador:

http://localhost:8080

Se aparecer a tela do WildFly, o servidor está ativo.


🔐 6. Criando usuário administrador

add-user.bat

Crie usuário Management User e depois acesse o console:

http://localhost:9990

🌎 7. Como adaptar o servidor para diferentes regiões do mundo 

(Locale, Timezone e Encoding)

Quando um servidor WildFly atende usuários em diferentes países, ele precisa estar preparado para lidar corretamente com:

RecursoExemploEvita problemas como
TimezoneAmerica/Sao_Paulo, UTC, Europe/Lisbonhorários incorretos em logs, agendamentos e auditoria
Localept-BR, en-US, es-ESdatas e números exibidos em formato errado
EncodingUTF-8caracteres quebrados (ç, ã, á, ñ, ü etc.)

7.1 Configurando o Timezone no Windows + WildFly

  1. Configure o timezone no Windows (PowerShell):

tzutil /s "E. South America Standard Time"
  1. Garanta que o WildFly siga o mesmo timezone, adicionando no standalone.conf.bat:

set "JAVA_OPTS=%JAVA_OPTS% -Duser.timezone=America/Sao_Paulo"

Dica: para servidores globais, use sempre UTC

set "JAVA_OPTS=%JAVA_OPTS% -Duser.timezone=UTC"

7.2 Configurando o Locale (Idioma/Formato de Data e Número)

Edite também o standalone.conf.bat e adicione:

set "JAVA_OPTS=%JAVA_OPTS% -Duser.language=pt -Duser.country=BR"

Para servidores multilíngues, o mais recomendado é en-US como padrão, decidindo o idioma na aplicação.


7.3 Garantindo UTF-8 em toda a aplicação (fundamental)

No mesmo arquivo:

set "JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8"

Isso evita:

✅ caracteres estranhos
✅ � trocando acentos
✅ erro em XML/JSON retornado pela API


Se estiver tudo certo até aqui, me responda apenas:

👉 "Continuar para o tópico 8"

Assim eu já continuo com a próxima seção:

🔐8. Segurança e Hardening do Servidor WildFly no Windows 11


Quando você transforma o WildFly em um servidor web — mesmo que local ou em rede interna — segurança precisa ser prioridade. Um servidor mal configurado pode expor dados, credenciais e aplicações, além de ser um alvo para ataques comuns como:
  • Brute Force
  • Port Scanning
  • Ataques via HTTP (XSS, Request Flood, Path Traversal, etc.)
  • Sequestro de sessão
  • Interceptação de tráfego (quando não há HTTPS)

A meta do hardening é simples: reduzir a superfície de ataque e proteger as portas críticas do servidor.

8.1 Use HTTPS (TLS) ao invés de HTTP


Mesmo em ambiente local, é boa prática habilitar HTTPS.
Opções para gerar certificados

CenárioCertificadoRede local Certificado self-signed
Produção global Let's Encrypt ou autoridade confiável (DigiCert, GlobalSign etc.)
Empresa Certificado interno fornecido pela TI

Gerando um certificado self-signed (PowerShell)

keytool -genkeypair -alias wildfly https \ -keyalg RSA -keystore wildfly.keystore \ -storepass changeit -keypass changeit \ -validity 365 -dname "CN=localhost"



Depois, edite o standalone.xml e configure o listener HTTPS:
<https-listener name="https" socket-binding="https" security-realm="ApplicationRealm" enable-http2="true"/>

Benefícios imediatos: criptografia, integridade dos dados e compatibilidade com HTTP/2.


8.2 Bloqueie o acesso externo ao Console Admin

Por padrão, a console de administração fica acessível na porta 9990. Em um ambiente seguro, apenas a máquina local ou a rede restrita deve acessá-la.

Edite o standalone.xml e altere o binding para localhost:
<interface name="management"> <inet-address value="127.0.0.1"/> </interface>
Resultado: ninguém de fora consegue gerenciar o WildFly.

8.3 Crie usuários e funções com o mínimo de privilégios

Nunca use usuário admin para tudo.

Categorias recomendadas:

FunçãoIndicado paraManagement Administradores do servidor
Application User Apps, sistemas e serviços
Read-Only Admin Auditoria ou monitoramento


Crie usuários com:
add-user.bat

Seguindo a política:
✅ Menor privilégio possível
✅ Senhas fortes com expiração periódica

8.4 Firewall e portas do WildFly

Portas mais comuns do WildFly:

PortaFunção8080 HTTP
8443 HTTPS
9990 Admin Console
9999 CLI remota

No Windows, ative regras no Firewall do Windows Defender, liberando apenas o que for necessário.

Boa prática global:

✅ Liberar 8080/8443 somente para acesso interno ou VPN
✅ Bloquear 9990 e 9999 para acesso público
✅ Preferir HTTPS sempre 8.5 Remova serviços e módulos que não usa

  • Quanto mais módulos ativos, maior o risco. No standalone.xml, desative subsystems que não usa, como:
  • WebSockets (se não houver necessidade)
  • Messaging
  • EJB Remoting
  • Deploy Scanner externo

Com isso você:

✅ reduz memória
✅ aumenta segurança
✅ melhora desempenho


8.5 Remova serviços e módulos que não usa

Quanto mais módulos ativos, maior o risco. No standalone.xml, desative subsystems que não usa, como:

  • WebSockets (se não houver necessidade)

  • Messaging

  • EJB Remoting

  • Deploy Scanner externo

Com isso você:

✅ reduz memória
✅ aumenta segurança
✅ melhora desempenho


8.6 Proteções adicionais (blindagem de servidor)


ProteçãoResultadoRate Limit (no proxy ou firewall) Ajuda contra DoS simples
Desativar TRACE e OPTIONS Evita fingerprint HTTP
HSTS e CSP (via headers) Protege front-end e cookies
Logar falhas de login Detecção precoce de ataque

9. Monitoramento e Logs no WildFly — Mantendo seu Servidor Saudável e Observável

Após ter seu servidor WildFly rodando no Windows 11, com segurança aplicada e aplicações no ar, o próximo passo é garantir visibilidade total do ambiente. Monitorar o servidor não é opcional — é o que permite identificar gargalos, prever falhas e agir antes que o usuário perceba qualquer instabilidade.

Uma aplicação sem monitoramento é como dirigir à noite com os faróis apagados.
Então, nesta seção, você vai aprender como monitorar, analisar métricas, gerenciar logs e implementar observabilidade real.


9.1 Logs principais do WildFly no Windows

No modo standalone, os logs ficam em:

WILDFLY_HOME\standalone\log\

Os arquivos mais importantes são:

LogFunção
server.logLog principal do servidor e da aplicação
boot.logLogs da inicialização do servidor
audit.logEventos administrativos e de segurança

Dicas práticas ao trabalhar com logs:

✅ Sempre usar log rotation
✅ Arquivar logs antigos automaticamente
✅ Ajustar nível de log (INFO → WARN → DEBUG conforme necessidade)

No standalone.xml, você pode alterar o nível de log facilmente:

<root-logger> <level name="INFO"/> </root-logger>
Em produção, evite DEBUG ou TRACE, pois geram muito volume e impactam desempenho.

9.2 Monitorando via Console Web (modo GUI)

O WildFly já oferece, nativamente, um painel de monitoramento.
Acesse: http://localhost:9990

Na console você acompanha:

  • Consumo de memória

  • Threads

  • Pools de conexão JDBC

  • Estado dos deployments

  • Subsistemas ativos

  • Tempo de resposta e status do servidor

É ideal para monitoramento rápido e visual.


9.3 Monitoramento via CLI (administradores avançados)

Para automação, o CLI é poderoso:

jboss-cli.bat --connect

Comandos úteis:

ComandoO que faz
/core-service=platform-mbean/type=memory:read-resource()Métricas de memória
/subsystem=datasources:read-resource()Monitora datasources
:reloadReinicia serviços sem desligar o servidor

9.4 Observabilidade real — integração com ferramentas globais

Para ambientes distribuídos ou quando o servidor atende usuários em diferentes países, você pode integrar o WildFly com:

FerramentaFinalidadeEscala
PrometheusColeta de métricas (pull)Global
GrafanaDashboards avançadosGlobal
Elastic Stack (ELK)Análise de logsCorporativo
ZabbixMonitoramento tradicionalEnterprise
JaegerTrace distribuídoMicrosserviços

Com isso, você transforma o WildFly em um ambiente observável com:

✅ Monitoramento em tempo real
✅ Alertas automáticos
✅ Dashboards acessíveis internacionalmente
✅ Tracing de requisições (ótimo para APIs)


9.5 Log Rotation e boas práticas

Para não encher disco em servidores Windows, configure rotation, por tamanho (recomendado) ou por data:

<periodic-rotating-file-handler name="FILE" autoflush="true"> <level name="INFO"/> <file relative-to="jboss.server.log.dir" path="server.log"/> <suffix value=".yyyy-MM-dd"/> <append value="true"/> </periodic-rotating-file-handler>

Checklist final de monitoramento inteligente:

ItemSituação ideal
Logs rotacionando
Alertas configurados
Painel de métricas
Console e CLI acessíveis
Tracing ativado em produção

10. Otimização de Desempenho (HTTP, Thread, Datasource e Windows)

(Resumo — porque este é um tópico grande e sensível, mas essencial)

Otimize:

ComponenteAjuste
HTTP/2 + HTTPSRespostas mais rápidas
Connection PoolPool adequado ao volume
GZIPReduz tamanho da resposta
CacheAcelera recursos estáticos
Windows ServicesDesativar serviços inúteis

11. Conclusão — Seu Servidor WildFly Local Está Pronto

Agora você possui:

✅ WildFly instalado e executando localmente no Windows 11
✅ Deploy de aplicações (WAR) funcionando
✅ Datasource configurado
✅ Segurança com HTTPS, firewall e usuários corretos
✅ Monitoramento, logs e observabilidade
✅ Um ambiente preparado para desenvolvimento global

Este servidor agora pode servir:

🌍 APIs
🌍 Aplicações corporativas
🌍 Portais Java
🌍 Microservices (com ajustes)

Chamada final (CTA):

Se este guia ajudou você, compartilhe, salve nos favoritos e visite nosso blog para mais conteúdos sobre servidores, segurança e desenvolvimento Java.


🌍 Criando um servidor WEB local no Windows 11 com JBoss WildFly (Guia Completo)

Leia mais


 

Diagrama de arquitetura microserviços FastAPI: Auth, Product, Sales com SQLite e chamadas HTTP entre serviços
Diagrama de arquitetura microserviços FastAPI: Auth, Product, Sales com SQLite e chamadas HTTP entre serviços

Introdução

Neste tutorial você vai aprender a construir uma arquitetura de micro-APIs similar ao diagrama:

  • Auth API: gera e valida tokens JWT;

  • Product API: CRUD de produtos com SQLite;

  • Sales API: registra vendas (SQLite) e faz chamadas para outras APIs (ex: validação de produto);

Tudo sem containers, ideal para desenvolvimento local e testes rápidos. Tudo em FastAPI, com exemplos prontos para rodar em portas diferentes.

Por que essa arquitetura?

  • Permite separar responsabilidades (autenticação, catálogo, vendas).

  • Cada serviço pode escalar de forma independente no futuro.

  • Fácil evolução para filas assíncronas (RabbitMQ) ou bancos separados (Postgres/Mongo) quando desejar.

Requisitos (instalação rápida)

No seu ambiente Python (recomendo criar um venv):

python -m venv venv

source venv/bin/activate   # macOS / Linux

venv\Scripts\activate      # Windows

pip install fastapi uvicorn sqlalchemy pydantic jwt passlib[bcrypt] requests

Arquivo requirements.txt sugerido:

 fastapi

uvicorn[standard]

sqlalchemy

pydantic

PyJWT

passlib[bcrypt]

requests

Estrutura de pastas (sugestão)

microservices-fastapi/
├── auth_api/
│   └── main.py
├── product_api/
│   └── main.py
├── sales_api/
│   └── main.py
└── README.md

1) Auth API — gerar e validar JWT

Objetivo: emitir token JWT ao autenticar usuário (aqui exemplo simples com usuário hardcoded para demo).

Arquivo: auth_api/main.py

# auth_api/main.py

from fastapi import FastAPI, HTTPException

from pydantic import BaseModel

import jwt, datetime

from passlib.context import CryptContext


app = FastAPI(title="Auth API")

SECRET_KEY = "troque_isto_por_um_segredo_forte"

ALGORITHM = "HS256"

ACCESS_TOKEN_EXPIRE_MINUTES = 60


pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")


# Exemplo simples: usuário fixo (em produção, use DB)

fake_user = {

    "username": "admin",

    "hashed_password": pwd_context.hash("123")

}


class LoginIn(BaseModel):

    username: str

    password: str


@app.post("/login")

def login(payload: LoginIn):

    if payload.username != fake_user["username"] or not pwd_context.verify(payload.password, fake_user["hashed_password"]):

        raise HTTPException(status_code=401, detail="Usuário ou senha incorretos")

    expire = datetime.datetime.utcnow() + datetime.timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)

    token = jwt.encode({"sub": payload.username, "exp": expire}, SECRET_KEY, algorithm=ALGORITHM)

    return {"access_token": token, "token_type": "bearer"}

Executar:
uvicorn auth_api.main:app --host 0.0.0.0 --port 8000 --reload
Teste:
curl -X POST "http://localhost:8000/login" -H "Content-Type: application/json" -d '{"username":"admin","password":"123"}'

2) Product API — CRUD com SQLite

Objetivo: fornecer endpoints para criar/listar produtos; protegido por JWT.

Arquivo: product_api/main.py

# product_api/main.py

from fastapi import FastAPI, Depends, HTTPException

from pydantic import BaseModel

from sqlalchemy import create_engine, Column, Integer, String, Float

from sqlalchemy.orm import sessionmaker, declarative_base

import jwt

from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials

import requests


DATABASE_URL = "sqlite:///./product.db"

SECRET_KEY = "troque_isto_por_um_segredo_forte"  # o mesmo do Auth em demo


engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})

SessionLocal = sessionmaker(bind=engine)

Base = declarative_base()


class Product(Base):

    __tablename__ = "products"

    id = Column(Integer, primary_key=True, index=True)

    name = Column(String, index=True)

    price = Column(Float)


Base.metadata.create_all(bind=engine)


app = FastAPI(title="Product API")

security = HTTPBearer()


class ProductIn(BaseModel):

    name: str

    price: float


def verify_token(creds: HTTPAuthorizationCredentials = Depends(security)):

    token = creds.credentials

    try:

        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])

    except jwt.PyJWTError:

        raise HTTPException(status_code=401, detail="Token inválido")

    return payload


@app.post("/products")

def create_product(prod: ProductIn, payload=Depends(verify_token)):

    db = SessionLocal()

    p = Product(name=prod.name, price=prod.price)

    db.add(p)

    db.commit()

    db.refresh(p)

    db.close()

    return {"id": p.id, "name": p.name, "price": p.price}


@app.get("/products")

def list_products(skip: int = 0, limit: int = 100, payload=Depends(verify_token)):

    db = SessionLocal()

    items = db.query(Product).offset(skip).limit(limit).all()

    db.close()

    return items

Executar:
uvicorn product_api.main:app --host 0.0.0.0 --port 8001 --reload

Fluxo de teste (usar token do Auth):

  1. Obter token no Auth (/login).

  2. Criar produto:

curl -X POST "http://localhost:8001/products" \
 -H "Authorization: Bearer <TOKEN>" \
 -H "Content-Type: application/json" \
 -d '{"name":"Mouse","price":29.9}'
Listar:
curl -H "Authorization: Bearer <TOKEN>" "http://localhost:8001/products"

3) Sales API — registrar venda e validar produto via Product API

Objetivo: registrar vendas localmente em SQLite e validar produto consultando Product API (HTTP).

Arquivo: sales_api/main.py

# sales_api/main.py

from fastapi import FastAPI, HTTPException, Depends

from pydantic import BaseModel

from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime

from sqlalchemy.orm import sessionmaker, declarative_base

import datetime

import requests


DATABASE_URL = "sqlite:///./sales.db"

engine = create_engine(DATABASE_URL, connect_args={"check_same_thread": False})

SessionLocal = sessionmaker(bind=engine)

Base = declarative_base()


class Sale(Base):

    __tablename__ = "sales"

    id = Column(Integer, primary_key=True, index=True)

    product_id = Column(Integer)

    product_name = Column(String)

    quantity = Column(Integer)

    total = Column(Float)

    created_at = Column(DateTime, default=datetime.datetime.utcnow)


Base.metadata.create_all(bind=engine)


app = FastAPI(title="Sales API")


class SaleIn(BaseModel):

    product_id: int

    quantity: int


PRODUCT_API_URL = "http://localhost:8001/products"  # endpoint base


@app.post("/sales")

def create_sale(sale: SaleIn):

    # Consulta Product API para validar produto (simples: buscar lista e filtrar)

    resp = requests.get(PRODUCT_API_URL)

    if resp.status_code != 200:

        raise HTTPException(status_code=502, detail="Product API indisponível")

    products = resp.json()

    product = next((p for p in products if p["id"] == sale.product_id), None)

    if not product:

        raise HTTPException(status_code=404, detail="Produto não encontrado")


    total = product["price"] * sale.quantity

    db = SessionLocal()

    s = Sale(product_id=product["id"], product_name=product["name"], quantity=sale.quantity, total=total)

    db.add(s)

    db.commit()

    db.refresh(s)

    db.close()


    # Aqui você poderia publicar uma mensagem na fila RabbitMQ (opcional)

    return {"sale_id": s.id, "product": s.product_name, "total": s.total}

Executar:
uvicorn sales_api.main:app --host 0.0.0.0 --port 8002 --reload

Testando (exemplo):

  1. Criar produto via Product API (veja acima).

  2. Criar venda:

curl -X POST "http://localhost:8002/sales" -H "Content-Type: application/json" -d '{"product_id":1,"quantity":2}'

Comunicação entre serviços (HTTP calls)

No exemplo da Sales API usamos requests.get para consultar GET /products e validar o produto. Em arquiteturas reais, você pode:

  • Usar chamadas HTTP síncronas (como no exemplo) — simples, mas acoplamento temporal.

  • Mudar para mensageria (RabbitMQ) para eventos assíncronos (venda registrada → event published).

  • Implementar retries, circuit breaker e timeouts (ex.: requests.get(url, timeout=3)).


Boas práticas e melhorias recomendadas

  • Variáveis de ambiente: mova segredos (SECRET_KEY) e URLs para variáveis (use python-decouple ou pydantic.Settings).

  • Migrations: use Alembic para gerenciar schema do SQLAlchemy em produção.

  • Autenticação real: troque usuário hardcoded por tabela users no DB e endpoint de registro.

  • HTTPS em produção (Nginx/Traefik + certificado).

  • Logs estruturados e monitoramento (Prometheus/Grafana).

  • Testes automatizados: unit + integration tests com pytest e httpx.


Erros comuns e tratamento

  • Token expirado: implemente refresh token (rota /refresh).

  • Product API indisponível: adicione fallback ou fila para processar vendas offline.

  • SQLite limita concorrência: para produção use PostgreSQL (mais robusto para multi-conexões).


Conclusão (call to action)

Com esse guia você tem uma base funcional para montar as três APIs em FastAPI com SQLite, imitando a arquitetura do seu diagrama. É um ponto de partida rápido para testes locais e evolução para um ambiente em containers ou nuvem.

👉 Próximos passos sugeridos:

  • Migrar Product e Sales para PostgreSQL/Mongo;

  • Adicionar RabbitMQ para comunicação assíncrona;

  • Implementar testes automáticos e CI/CD.

Recursos adicionais e links úteis

🔐 Construindo 3 Micro-APIs em Python com FastAPI (Auth, Product, Sales) — Arquitetura, JWT e SQLite

Leia mais

✝ Copyright © Blog do KDS - Isaías 40:5 “A glória do Senhor se manifestará, e toda a humanidade a verá.”