Todos os produtos
Search
Central de documentação

ApsaraMQ for MQTT:Envio e recebimento de mensagens entre clientes MQTT e aplicações de backend

Última atualização: Aug 20, 2026

Este tutorial orienta você no envio de mensagens a partir de um cliente ApsaraMQ for MQTT e no recebimento delas em uma aplicação de service de backend. O cliente usa o SDK do cliente (Eclipse Paho) para publicar mensagens, enquanto o backend usa o SDK da cloud para consumi-las.

Como funciona

Um cliente ApsaraMQ for MQTT e uma aplicação de service de backend se comunicam por meio do broker do ApsaraMQ for MQTT. Cada lado usa um SDK diferente:

SDK

Biblioteca

Conecta-se a

Caso de uso

SDK do cliente

Eclipse Paho Java Client

Dispositivos IoT, aplicativos móveis

Publicar e assinar mensagens via MQTT

SDK da cloud

SDK do servidor ApsaraMQ for MQTT

Aplicações de service de backend

Consumir ou enviar mensagens em escala, assinando no nível do tópico pai

Messaging between an ApsaraMQ for MQTT client and a backend application

Para projetos de exemplo completos, consulte Demo projects ou Execute the cloud SDK demo.

Pré-requisitos

Antes de começar, verifique se você tem:

  • Uma instância do ApsaraMQ for MQTT com os recursos necessários (grupo, tópico). Consulte Crie recursos

  • Um par de AccessKey. Consulte Obter um par de AccessKey

  • JDK instalado

  • IntelliJ IDEA ou Eclipse instalado (este tutorial usa o IntelliJ IDEA)

Endpoints

O ApsaraMQ for MQTT oferece suporte a vários tipos de endpoint. Além dos endpoints de Internet e VPC existentes, o service disponibiliza endpoints dedicados de Internet e de VPC para garantir acesso mais estável e seguro em diferentes ambientes de rede. Este tópico descreve cenários, edições compatíveis, métodos de faturamento e recomendações de uso para cada tipo de endpoint.

Tipos de endpoint

Tipo de endpoint

Rede

Descrição

Public Endpoint

Internet pública

Conexão de Internet compartilhada pelo cluster; isolamento lógico. Indisponível para novas instâncias das edições Professional ou Platinum.

Public-dedicated endpoint

Internet pública

Conexão de Internet dedicada por instância; isolamento físico. Fornecido por padrão para novas instâncias das edições Professional ou Platinum.

VPC Endpoint

Rede interna

Acesso pela rede interna da Alibaba Cloud, destinado a cargas de trabalho em VPC na mesma região. Indisponível para novas instâncias das edições Professional, Platinum ou Serverless.

VPC-dedicated Endpoint

Rede interna

Conexão VPC dedicada por instância; oferece maior isolamento e segurança de rede.

Um Public-dedicated endpoint fornece uma conexão de Internet exclusiva para a instância. Durante picos de tráfego, evita interferências de outras instâncias no mesmo cluster e reduz riscos de falhas de conexão e latência de mensagens. Recomendamos endpoints dedicados de Internet para instâncias de produção.

O VPC-dedicated Endpoint estabelece uma conexão de rede interna exclusiva para a instância, com maior isolamento e segurança. Essa opção é ideal para cenários com requisitos rigorosos de segurança no acesso a dados.

Também é possível adicionar o Anti-DDoS da Alibaba Cloud ao endereço IP público de um endpoint dedicado para reforçar a proteção do acesso pela Internet.

Suporte por versão

Edição

Public Endpoint

Public-dedicated endpoint

VPC Endpoint

Interconnects with a specified VPC in the same region as your MQTT instance for enhanced network security.

Professional

Indisponível para novas instâncias

Compatível

Indisponível para novas instâncias

Compatível

Platinum

Indisponível para novas instâncias

Compatível

Indisponível para novas instâncias

Compatível

Basic

Compatível (padrão)

Não compatível

Compatível

Não compatível

Serverless

Compatível (padrão)

Compatível

Indisponível para novas instâncias

Compatível

Endpoints do SDK do cliente

Ao se conectar com o SDK do cliente, configure o endpoint nos seguintes formatos:

Tipo de acesso

Formato

Public Endpoint / Public-dedicated endpoint

<instance-id>.mqtt.aliyuncs.com

VPC Endpoint

<instance-id>-internal-vpc.mqtt.aliyuncs.com

VPC-dedicated Endpoint

<instance-id>-internal-single-vpc.mqtt.aliyuncs.com

Nota

Novas instâncias ApsaraMQ for MQTT das edições Professional e Platinum são provisionadas com um Public-dedicated endpoint por padrão. Para acessar o service MQTT pela rede interna da Alibaba Cloud, use o botão Create VPC Endpoint na aba Endpoints.

Novas instâncias Serverless são provisionadas com um Public Endpoint por padrão. Crie um VPC-dedicated Endpoint para acesso pela rede interna ou ative um Public-dedicated endpoint para melhorar o isolamento da rede.

Para instâncias existentes das edições Professional, Platinum e Serverless, crie um endpoint de rede VPC para se conectar a uma VPC designada. Isso gera um novo domínio de VPC-dedicated Endpoint. O VPC Endpoint existente permanece inalterado. Combinado com peering de VPC, o VPC-dedicated Endpoint permite acesso entre VPCs à sua instância MQTT.

Encontre o endpoint do SDK do cliente na aba Endpoints da página Instance Details no console do ApsaraMQ for MQTT.

Endpoints do SDK da cloud

Ao se conectar com o SDK da cloud, configure o endpoint nos seguintes formatos:

Importante

Conexões via SDK da cloud não têm suporte em todas as regiões. Para verificar as regiões compatíveis, consulte Supported regions.

Tipo de acesso

Formato

Public Endpoint / Public-dedicated endpoint

<instance-id>-server-internet.mqtt.aliyuncs.com

VPC Endpoint

<instance-id>-server-internal.mqtt.aliyuncs.com

VPC-dedicated Endpoint

<instance-id>-server-single-internal.mqtt.aliyuncs.com

Localize o ID da instância na seção Basic Information da página Instance Details no console do ApsaraMQ for MQTT. O VPC-dedicated Endpoint fica disponível somente após a criação de um endpoint de rede VPC pelo botão Create VPC Endpoint na aba Endpoints.

Importante

Use o nome de domínio ao se conectar aos endpoints. Evite conexões diretas por endereço IP, pois os IPs podem mudar devido a migrações de data center ou outras alterações de infraestrutura. O ApsaraMQ for MQTT não se responsabiliza por falhas de conexão causadas por:

  • Uso de endereço IP codificado diretamente no código que se torna inválido após atualização de DNS

  • Regras de firewall que bloqueiam novos endereços IP após atualização de DNS

Faturamento

Cada edição de instância inclui uma cota gratuita de endpoints dedicados. Endpoints dedicados adicionais são cobrados no modelo de pagamento conforme o uso. Para mais informações, consulte Dedicated endpoint billing.

Etapa 1: Configure o projeto do SDK do cliente

  1. Baixe o SDK open source de terceiros para Java: Eclipse Paho Java Client.

  2. Baixe o projeto de demonstração mqtt-java-demo, extraia-o e importe-o para o IntelliJ IDEA.

Verifique se o arquivo pom.xml inclui as seguintes dependências:

<dependencies>
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.10</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.paho</groupId>
        <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
        <version>1.2.2</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.2</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.83</version>
    </dependency>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-onsmqtt</artifactId>
        <version>1.0.3</version>
    </dependency>
    <dependency>
        <groupId>com.aliyun</groupId>
        <artifactId>aliyun-java-sdk-core</artifactId>
        <version>4.5.0</version>
    </dependency>
</dependencies>

Etapa 2: Configure credenciais

Defina as seguintes variáveis de ambiente para autenticação. Consulte Configure uma credencial de acesso para obter detalhes.

# AccessKey ID
export MQTT_AK_ENV=<your-access-key-id>
# AccessKey secret
export MQTT_SK_ENV=<your-access-key-secret>

Importante: Não codifique pares de AccessKey diretamente no source code. Armazene-os em variáveis de ambiente para evitar vazamento de credenciais.

Etapa 3: Enviar mensagens com o SDK do cliente

Abra o arquivo MQ4IoTProducerDemo.java e atualize os parâmetros abaixo com os valores da sua instância ApsaraMQ for MQTT. Consulte Crie resources para saber onde encontrar esses valores.

Parâmetro

Descrição

Exemplo

instanceId

ID da instância ApsaraMQ for MQTT

post-cn-xxxxx

endPoint

Endpoint do SDK do cliente (consulte a seção Endpoints acima)

post-cn-xxxxx.mqtt.aliyuncs.com

clientId

ID de cliente globalmente único no formato {GroupID}@@@{DeviceID}. Máximo de 64 caracteres. Cada conexão TCP deve usar um ID de cliente diferente.

GID_test@@@device_001

parentTopic

Tópico pai criado no console

testTopic

Conectar ao broker

Crie um cliente MQTT e estabeleça a conexão. Use tcp://endpoint:1883 para texto simples ou ssl://endpoint:8883 para SSL/TLS.

String instanceId = "XXXXX";
String endPoint = "XXXXX.mqtt.aliyuncs.com";
String accessKey = System.getenv("MQTT_AK_ENV");
String secretKey = System.getenv("MQTT_SK_ENV");
String clientId = "GID_XXXXX@@@XXXXX";

ConnectionOptionWrapper connectionOptionWrapper =
    new ConnectionOptionWrapper(instanceId, accessKey, secretKey, clientId);
final MemoryPersistence memoryPersistence = new MemoryPersistence();

final MqttClient mqttClient =
    new MqttClient("tcp://" + endPoint + ":1883", clientId, memoryPersistence);

// Set the response timeout (ms) to avoid indefinite waits
mqttClient.setTimeToWait(5000);

O ID do cliente usa o formato {GroupID}@@@{DeviceID} e deve ser globalmente único por conexão TCP. Reutilizar um ID de cliente em múltiplas conexões faz com que o broker desconecte a sessão existente.

Configure callbacks

Configure os callbacks antes de conectar para evitar perda de mensagens durante a retomada de sessão.

mqttClient.setCallback(new MqttCallbackExtended() {
    @Override
    public void connectComplete(boolean reconnect, String serverURI) {
        System.out.println("connect success");
    }

    @Override
    public void connectionLost(Throwable throwable) {
        throwable.printStackTrace();
    }

    @Override
    public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
        // Process messages within the broker's timeout to avoid redelivery.
        // Implement deduplication to ensure idempotent processing.
        System.out.println(
            "receive msg from topic " + s + " , body is "
            + new String(mqttMessage.getPayload()));
    }

    @Override
    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
        System.out.println("send msg succeed topic is : "
            + iMqttDeliveryToken.getTopics()[0]);
    }
});

mqttClient.connect(connectionOptionWrapper.getMqttConnectOptions());

Publicar mensagens

Publique mensagens em um subtópico. Subtópicos são anexados ao tópico pai e podem ter até 128 caracteres.

final String parentTopic = "XXXXX";
final String mq4IotTopic = parentTopic + "/" + "testMq4Iot";
final int qosLevel = 0;

MqttMessage message = new MqttMessage("hello mq4Iot pub sub msg".getBytes());
message.setQos(qosLevel);
mqttClient.publish(mq4IotTopic, message);

Níveis de QoS: 0 (no máximo uma vez), 1 (pelo menos uma vez) ou 2 (exatamente uma vez).

Enviar mensagens ponto a ponto (P2P)

A mensagem P2P é enviada diretamente a um cliente específico. O cliente de destino não precisa assinar o tópico. Publique em {parentTopic}/p2p/{targetClientId}.

String receiverId = "GID_test@@@device_002";
final String p2pSendTopic = parentTopic + "/p2p/" + receiverId;
MqttMessage p2pMessage = new MqttMessage("hello mq4Iot p2p msg".getBytes());
p2pMessage.setQos(qosLevel);
mqttClient.publish(p2pSendTopic, p2pMessage);

Código completo do produtor

O código a seguir combina todas as etapas anteriores. Abra o arquivo MQ4IoTProducerDemo.java e atualize os parâmetros.

package com.aliyun.openservices.lmq.example.demo;

import com.aliyun.openservices.lmq.example.util.ConnectionOptionWrapper;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;

public class MQ4IoTProducerDemo {
    public static void main(String[] args) throws Exception {
        // ApsaraMQ for MQTT instance ID
        String instanceId = "XXXXX";

        // Client SDK endpoint. Use the domain name, not the IP address.
        String endPoint = "XXXXX.mqtt.aliyuncs.com";

        // Load credentials from environment variables
        String accessKey = System.getenv("MQTT_AK_ENV");
        String secretKey = System.getenv("MQTT_SK_ENV");

        // Client ID format: {GroupID}@@@{DeviceID}
        // Must be unique per TCP connection. Max 64 characters.
        String clientId = "GID_XXXXX@@@XXXXX";

        // Parent topic created in the ApsaraMQ for MQTT console.
        // An invalid or unauthorized topic causes the broker to close the connection.
        final String parentTopic = "XXXXX";

        // Subtopic for message filtering. Max 128 characters.
        final String mq4IotTopic = parentTopic + "/" + "testMq4Iot";

        // QoS level: 0, 1, or 2
        final int qosLevel = 0;

        ConnectionOptionWrapper connectionOptionWrapper =
            new ConnectionOptionWrapper(instanceId, accessKey, secretKey, clientId);
        final MemoryPersistence memoryPersistence = new MemoryPersistence();

        // Connect over TCP on port 1883. For SSL, use ssl://endpoint:8883.
        final MqttClient mqttClient =
            new MqttClient("tcp://" + endPoint + ":1883", clientId, memoryPersistence);

        // Set the response timeout (ms) to avoid indefinite waits
        mqttClient.setTimeToWait(5000);

        final ExecutorService executorService = new ThreadPoolExecutor(
            1, 1, 0, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());

        // Set callbacks before connecting to avoid missing messages
        mqttClient.setCallback(new MqttCallbackExtended() {
            @Override
            public void connectComplete(boolean reconnect, String serverURI) {
                System.out.println("connect success");
            }

            @Override
            public void connectionLost(Throwable throwable) {
                throwable.printStackTrace();
            }

            @Override
            public void messageArrived(String s, MqttMessage mqttMessage) throws Exception {
                // Process messages within the broker's timeout to avoid redelivery.
                // Implement deduplication to ensure idempotent processing.
                System.out.println(
                    "receive msg from topic " + s + " , body is "
                    + new String(mqttMessage.getPayload()));
            }

            @Override
            public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
                System.out.println("send msg succeed topic is : "
                    + iMqttDeliveryToken.getTopics()[0]);
            }
        });

        mqttClient.connect(connectionOptionWrapper.getMqttConnectOptions());

        for (int i = 0; i < 10; i++) {
            // Publish to a subtopic (standard pub/sub)
            MqttMessage message = new MqttMessage("hello mq4Iot pub sub msg".getBytes());
            message.setQos(qosLevel);
            mqttClient.publish(mq4IotTopic, message);

            // Publish a point-to-point (P2P) message directly to a specific client.
            // The target client does not need to subscribe to this topic.
            // Topic format: {parentTopic}/p2p/{targetClientId}
            String receiverId = "xxx";
            final String p2pSendTopic = parentTopic + "/p2p/" + receiverId;
            message = new MqttMessage("hello mq4Iot p2p msg".getBytes());
            message.setQos(qosLevel);
            mqttClient.publish(p2pSendTopic, message);
        }
        Thread.sleep(Long.MAX_VALUE);
    }
}

Verifique o produtor

Execute o arquivo MQ4IoTProducerDemo.java. Se a conexão for bem-sucedida, a saída será semelhante a:

connect success
send msg succeed topic is : XXXXX/testMq4Iot
send msg succeed topic is : XXXXX/p2p/xxx
...

Etapa 4: Receber mensagens com o SDK da cloud

O SDK da cloud conecta sua aplicação de backend ao broker do ApsaraMQ for MQTT. Diferentemente do SDK do cliente, o SDK da cloud assina apenas tópicos pais (não subtópicos). Isso o torna adequado para cenários de backend nos quais as aplicações coletam e analisam todas as mensagens de um tópico.

Configure o projeto

  1. Baixe o SDK da cloud. Consulte as Notas de lançamento para obter a versão mais recente.

  2. Baixe o projeto de demonstração: mqtt-server-sdk-demo.

  3. Extraia o pacote e importe-o para o IntelliJ IDEA.

  4. Verifique se o arquivo pom.xml inclui as seguintes dependências:

<dependencies>
    <dependency>
        <groupId>com.alibaba.mqtt</groupId>
        <artifactId>server-sdk</artifactId>
        <version>1.0.0.Final</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.83</version>
    </dependency>
</dependencies>

Configure e execute o consumidor

Abra o arquivo MQTTConsumerDemo.java e atualize os seguintes parâmetros:

Parâmetro

Descrição

Exemplo

domain

Endpoint do SDK da cloud (consulte a seção Endpoints acima)

post-cn-xxxxx-server-internet.mqtt.aliyuncs.com

port

Porta do SDK da cloud. Sempre 5672.

5672

instanceId

ID da instância ApsaraMQ for MQTT

post-cn-xxxxx

firstTopic

Tópico pai a ser assinado

testTopic

As credenciais são carregadas das mesmas variáveis de ambiente (MQTT_AK_ENV e MQTT_SK_ENV) configuradas na Etapa 2.

Conectar e assinar

String domain = "post-cn-jaj3h8i****.mqtt.aliyuncs.com";
int port = 5672;
String instanceId = "post-cn-jaj3h8i****";
String accessKey = System.getenv("MQTT_AK_ENV");
String secretKey = System.getenv("MQTT_SK_ENV");
String firstTopic = "firstTopic";

ChannelConfig channelConfig = new ChannelConfig();
channelConfig.setDomain(domain);
channelConfig.setPort(port);
channelConfig.setInstanceId(instanceId);
channelConfig.setAccessKey(accessKey);
channelConfig.setSecretKey(secretKey);

ServerConsumer serverConsumer = new ServerConsumer(channelConfig, new ConsumerConfig());
serverConsumer.start();

serverConsumer.subscribeTopic(firstTopic, new MessageListener() {
    @Override
    public void process(String msgId, MessageProperties messageProperties,
                        byte[] payload) {
        System.out.println("Receive:" + msgId + ","
            + JSONObject.toJSONString(messageProperties) + ","
            + new String(payload));
    }
});

Código completo do consumidor

package com.aliyun.openservices.lmq.example;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.mqtt.server.ServerConsumer;
import com.alibaba.mqtt.server.callback.MessageListener;
import com.alibaba.mqtt.server.config.ChannelConfig;
import com.alibaba.mqtt.server.config.ConsumerConfig;
import com.alibaba.mqtt.server.model.MessageProperties;

public class MQTTConsumerDemo {
    public static void main(String[] args) throws Exception {
        // Cloud SDK endpoint. Use the domain name, not the IP address.
        String domain = "post-cn-jaj3h8i****.mqtt.aliyuncs.com";

        // Cloud SDK port. Must be 5672.
        int port = 5672;

        // ApsaraMQ for MQTT instance ID
        String instanceId = "post-cn-jaj3h8i****";

        // Load credentials from environment variables
        String accessKey = System.getenv("MQTT_AK_ENV");
        String secretKey = System.getenv("MQTT_SK_ENV");

        // Parent topic to subscribe to.
        // The cloud SDK subscribes to parent topics only (no subtopics).
        // An invalid or unauthorized topic causes the broker to close the connection.
        String firstTopic = "firstTopic";

        ChannelConfig channelConfig = new ChannelConfig();
        channelConfig.setDomain(domain);
        channelConfig.setPort(port);
        channelConfig.setInstanceId(instanceId);
        channelConfig.setAccessKey(accessKey);
        channelConfig.setSecretKey(secretKey);

        ServerConsumer serverConsumer = new ServerConsumer(channelConfig, new ConsumerConfig());
        serverConsumer.start();

        // Subscribe and process incoming messages
        serverConsumer.subscribeTopic(firstTopic, new MessageListener() {
            @Override
            public void process(String msgId, MessageProperties messageProperties,
                                byte[] payload) {
                System.out.println("Receive:" + msgId + ","
                    + JSONObject.toJSONString(messageProperties) + ","
                    + new String(payload));
            }
        });
    }
}

Perguntas frequentes

Como ativar a reconexão automática?

Defina setAutomaticReconnect(true) em MqttConnectOptions antes de conectar:

MqttConnectOptions options = connectionOptionWrapper.getMqttConnectOptions();
options.setAutomaticReconnect(true);
mqttClient.connect(options);

Como conectar via SSL/TLS?

Substitua tcp:// por ssl:// e use a porta 8883:

final MqttClient mqttClient =
    new MqttClient("ssl://" + endPoint + ":8883", clientId, memoryPersistence);

É possível enviar mensagens de uma aplicação de backend para um cliente MQTT?

Sim. Use o arquivo MQTTProducerDemo.java no projeto de demonstração do SDK da cloud para inverter a direção da mensagem (do backend para o cliente).

Próximos passos

  • Explore outros padrões de mensagens nos projetos de demonstração

  • Verifique as regiões compatíveis para acesso via SDK da cloud

Resumo das alterações da Etapa 6

Tipo de otimização: Otimização de estrutura e expressão (Etapa 6 optimize-architecture)

Alterações aplicadas:

  1. Padronização de formato de Nota/Importante: Alteração de todos os padrões > **Note**: e > **Important**: para > **Note:** e > **Important:** (dois pontos dentro do negrito) conforme as regras de consistência de formato da seção 3,4 do en.md.

  2. Remoção de padrões de preenchimento "You can": Alteração de "You can find the client SDK endpoint on..." para "Find the client SDK endpoint on..." e de "You can find the instance ID in..." para "Find the instance ID in..." conforme a seção 2,3 do en.md (conteúdo descritivo deve omitir "you").

  3. Verificação de integridade estrutural: O documento segue a divulgação progressiva adequada: Como funciona (contexto) -> Pré-requisitos -> Endpoints (referência) -> Etapas 1-4 (prática) -> Perguntas frequentes (solução de problemas) -> Próximos passos. Essa estrutura está alinhada ao tipo de conhecimento feature-docs.

  4. Verificação de qualidade de expressão: Todas as frases usam voz ativa, a terminologia é consistente em todo o documento ("ApsaraMQ for MQTT", "SDK do cliente", "SDK da cloud", "VPC-dedicated Endpoint"), nenhum artefato de tradução foi detectado e nenhuma tautologia foi encontrada.

  5. Preservação de todo o conteúdo técnico: Todos os blocos de código, valores de parâmetros, formatos de endpoint, nomes de classes de SDK e detalhes técnicos permanecem inalterados. Nenhum fato foi modificado.

Itens intencionalmente não alterados: - Todos os blocos de código e códigos inline preservados exatamente - Todas as tabelas de parâmetros preservadas exatamente - Todos os formatos de endpoint e padrões de domínio preservados exatamente - Estrutura do documento (ordem das seções) preservada -- o fluxo progressivo existente já está bem organizado - O rascunho já apresentava alta qualidade desde a Etapa 5, portanto as alterações foram mínimas e focadas na consistência de formato e pequenos ajustes de expressão