Arquitetura e Desenvolvimento de uma Plataforma de Encontros Online com Spring Boot e Vue.js

O desenvolvimento de sistemas web para plataformas de encontros online exige a integração de tecnologias robustas para o backend e frameworks modernos para o frontend, garantindo escalabilidade, segurança e uma experiência de usuário fluida. Este artigo descreve a arquitetura e a implementação de um sistema baseado em Java com Spring Boot para o lado do servidor e Vue.js para a interface do usuário.

Estrutura Tecnológica

Backend: O Poder do Spring Boot

Spring Boot é um framework de código aberto para desenvolvimento Java, projetado para simplificar e acelerar a criação de aplicações Spring autônomas. Ele adere ao princípio de "convenção sobre configuração", oferecendo auto-configuração e um rápido tempo de inicialização, o que otimiza a produtividade dos desenvolvedores. Com Spring Boot, o foco principal reside na lógica de negócio, minimizando a preocupação com configurações de infraestrutura.

Os principais atributos e benefícios do Spring Boot incluem:

  • Inicialização Ágil: Permite que uma aplicação Spring autônoma seja iniciada em questão de segundos.
  • Configuração Automatizada: Reduz drasticamente a necessidade de configuração manual, facilitando a implantação e execução das aplicações.
  • Servidores Embarcados: Suporte a contêineres web embarcados, possibilitando o empacotamento da aplicação como um arquivo JAR executável, sem a necessidade de um servidor externo.
  • Gestão de Dependências: Oferece um gerenciamento de dependências simplificado através de configurações concisas, tornando a gestão de bibliotecas mais conveniente.
  • Monitoramento de Saúde: Inclui funcionalidades de verificação de saúde, facilitando o monitoramento do status operacional da aplicação.
  • Extensibilidade: Apresenta uma vasta gama de pontos de extensão e plugins, permitindo personalização e expansão conforme as necessidades do projeto.

Frontend: Dinamismo com Vue.js

Vue.js é um framework JavaScript progressivo e amplamente adotado para a construção de interfaces de usuário interativas. Sua filosofia de adoção incremental permite que seja facilmente integrado a projetos existentes ou utilizado como o alicerce para Single Page Applications (SPAs).

As características e vantagens chave do Vue.js são:

  • Leveza: Compacto, rápido para carregar e com uma curva de aprendizado suave.
  • Reatividade e Data Binding Duplo: Fornece um mecanismo simples, mas poderoso, de data binding de duas vias, onde as alterações nos dados são automaticamente refletidas na visualização, elevando a eficiência do desenvolvimento.
  • Componentização: Ecnoraja o desenvolvimento baseado em componentes, dividindo a página em módulos independentes, o que otimiza a manutenção e reusabilidade do código.
  • Virtual DOM: Emprega a tecnologia Virtual DOM para atualizar a página de forma eficiente, comparando as diferenças entre o DOM virtual e o DOM real, o que resulta em melhor desempenho de renderização.
  • Diretivas e Filtros: Oferece um rico conjunto de diretivas e filtros para manipular elementos DOM e dados, permitindo a implementação de diversas funcionalidades e efeitos.
  • Gerenciamento de Rotas: Em conjunto com Vue Router, habilita o gerenciamento de rotas no frontend, facilitando transições de página sem recarregar e o gerenciamento de estado.

Análise de Viabilidade do Projeto

A análise de viabilidade é um estudo crítico para avaliar a praticidade e o potencial de sucesso de um projeto. Para este sistema de encontros online, consideramos os seguintes aspectos:

  • Viabilidade de Mercado: Avaliação da demanda e cenário competitivo no nicho de encontros on line. Isso inclui a análise do tamanho do mercado, tendências de crescimento, identificação de concorrentes e suas vantagens/desvantagens, e o posicionamento único da plataforma.
  • Viabilidade Técnica: Verificação da adequação da pilha tecnológica escolhida (Spring Boot, Vue.js, MySQL) aos requisitos do projeto, bem como a existência de um caminho claro para sua implementação. Fatores como maturidade da tecnologia, confiabilidade, segurança e escalabilidade são cruciais.
  • Viabilidade Financeira: Análise dos custos de investimento, despesas operacionais e receitas projetadas, além do período de retorno do investimento. Inclui a avaliação das fontes de financiamento e expectativas de retorno.
  • Viabilidade Organizacional: Consideração da estrutura organizacional necessária, alocação de pessoal e mecanismos de gestão para suportar a implementação e operação do projeto.
  • Viabilidade Ambiental: Análise de qualquer impacto ambiental potencial do projeto e sua conformidade com princípios de sustentabilidade.

Processo de Testes do Sistema

A fase de testes do sistema é fundamental para validar que a aplicação atende aos requisitos funcionais, de desempenho, segurança e confiabilidade. Os principais tipos de testes realizados são:

  • Testes Funcionais: Garantem que cada funcionalidade do sistema opere conforme especificado nos requisitos e documentos de design. Isso abrange validação de entradas, operações e resultados esperados.
  • Testes de Desempenho: Avaliam o comportamento do sistema sob diferentes cargas e pressões, medindo métricas como tempo de resposta, taxa de transferência e capacidade de concorrência para assegurar um desempenho robusto.
  • Testes de Segurança: Verificam a robustez das defesas do sistema, incluindo criptografia de dados, controle de acesso, firewalls e varredura de vulnerabilidades para proteger contra ataques e acessos não autorizados.
  • Testes de Compatibilidade: Confirmam que o sistema funciona corretamente em diversas plataformas (sistemas operacionais, navegadores, dispositivos), garantindo uma experiência consistente.
  • Testes de Confiabilidade: Avaliam a estabilidade do sistema e sua capacidade de recuperação de falhas, tolerância a erros e disponibilidade contínua.
  • Testes de Interface de Usuário (UI): Verificam o design da interface e a experiência de interação do usuário, incluindo layout, estilo e funcionalidades interativas, para garantir usabilidade e amigabilidade.

Objetivos dos Testes de Sistema

Os testes de sistema são um processo meticuloso e essencial que serve como a última barreira de qualidade antes da entrega. Seu propósito primordial é prevenir problemas de usabilidade para o usuário final e aprimorar a experiência geral. Para isso, são considerados diversos cenários e perspectivas para identificar e resolver defeitos. Através de simulações variadas, é possível detectar falhas, que, uma vez corrigidas, elevam significativamente a qualidade do sistema e a satisfação do usuário. O objetivo é verificar a aderência do sistema às especificações e identificar quaisquer inconsistências. Durante todo o processo, a perspectiva do usuário deve ser prioritária, evitando cenários irrealistas que desperdiçam tempo e podem distorcer os resultados.

Exemplos de Testes Funcionais

Avaliamos os módulos funcionais através de testes de caixa preta, como cliques, inserção de valores limites e validações de campos obrigatórios/opcionais. Os resultados são documentados em casos de teste.

Cenários de Teste para Login:

Ao tentar acessar o sistema, a validação é feita com base no nome de usuário e senha. Se alguma credencial estiver incorreta, o sistema deve emitir um aviso. Além disso, a interface de login deve verificar as permissões do usuário.

Dados de Entrada Resultado Esperado Resultado Observado Análise
Usuário: administrador, Senha: 123456, Código Captcha: Correto Acesso ao sistema concedido Acesso bem-sucedido Conforme esperado
Usuário: administrador, Senha: senhaErrada, Código Captcha: Correto Mensagem de "Senha incorreta" Mensagem: "Senha incorreta, por favor, tente novamente" Conforme esperado
Usuário: administrador, Senha: 123456, Código Captcha: Errado Mensagem de "Código Captcha incorreto" Mensagem: "Informação do Captcha incorreta" Conforme esperado
Usuário: (vazio), Senha: 123456, Código Captcha: Correto Mensagem de "Nome de usuário obrigatório" Mensagem: "Por favor, insira o nome de usuário" Conforme esperado
Usuário: administrador, Senha: (vazio), Código Captcha: Correto Mensagem de "Senha incorreta" Mensagem: "Senha incorreta, por favor, tente novamente" Conforme esperado

Cenários de Teste para Gerenciamento de Usuários:

A funcionalidade de gerenciamento de usuários inclui adição, edição, exclusão e busca de usuários. Para adição, verifica-se a validação de campos obrigatórios e a prevenção de nomes de usuário duplicados. Para exclusão, o sistema deve solicitar confirmação. Para edição, a atualização e exibição correta das informações são verificadas.

Dados de Entrada Resultado Esperado Resultado Observado Aálise
Informações básicas de um novo usuário Usuário adicionado e exibido na lista O usuário aparece na lista Conforme esperado
Modificação de informações de um usuário existente Edição bem-sucedida, informações atualizadas Informações do usuário foram modificadas Conforme esperado
Seleção para exclusão de um usuário Sistema solicita confirmação, usuário é removido após confirmação Sistema solicita confirmação, usuário não é encontrado após confirmação Conforme esperado
Tentativa de adicionar usuário sem preencher nome de usuário Mensagem de "Nome de usuário não pode ser vazio" Mensagem: "Nome de usuário não pode ser vazio" Conforme esperado
Tentativa de adicionar usuário com nome de usuário já existente Falha na adição, mensagem de "Nome de usuário duplicado" Falha na adição, mensagem: "Nome de usuário duplicado" Conforme esperado

Projeto do Banco de Dados

O design do banco de dados é um pilar fundamental para qualquer sistema, garantindo a organização e a integridade dos dados. Para uma plataforma de encontros, é essencial estruturar tabelas que suportem perfis de usuário, mensagens e autenticação de forma eficiente.

Abaixo, detalhamos a estrutura de algumas tabelas essenciais:

Tabela: perfis_usuarios (Perfis de Usuários)

Esta tabela armazena os dados principais dos usuários e seus perfis para o sistema de encontros.

Coluna Tipo de Dado Tamanho Restrições
id_perfil BIGINT 20 PRIMARY KEY, AUTO_INCREMENT
id_usuario BIGINT 20 FOREIGN KEY (referencia usuarios.id_usuario)
data_criacao TIMESTAMP - DEFAULT CURRENT_TIMESTAMP
nome_exibicao VARCHAR 200 NOT NULL, UNIQUE
genero VARCHAR 50 DEFAULT NULL
data_nascimento DATE - DEFAULT NULL
cidade VARCHAR 100 DEFAULT NULL
interesses TEXT - DEFAULT NULL (lista de interesses separados por vírgula)
sobre_mim TEXT - DEFAULT NULL (descrição do usuário)
url_foto_perfil VARCHAR 255 DEFAULT NULL
Exemplo de Código

A seguir, um trecho de código refatorado de um controlador de serviços utilitários em Java com Spring Boot. Este controlador gerencia integrações com APIs externas, como serviços de geolocalização e reconhecimento facial.


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.util.ResourceUtils;

import com.alibaba.fastjson.JSONObject; // Assumindo Fastjson para manipulação JSON
import com.baidu.aip.face.AipFace; // Cliente Baidu AI Face
import com.baidu.aip.face.MatchRequest; // Objeto de requisição para comparação facial

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

// Classes auxiliares (assumindo sua existência, conforme o original)
// RespostaAPI seria análogo a 'R'
// ServicoConfiguracao análogo a 'ConfigService'
// EntidadeConfiguracao análogo a 'ConfigEntity'
// UtilitarioBaidu análogo a 'BaiduUtil'
// UtilitarioArquivo análogo a 'FileUtil'
// UtilitarioBase64 análogo a 'Base64Util'

/**
 * Controlador para serviços e utilitários gerais do sistema.
 */
@RestController
@RequestMapping("/api/servicos-gerais") // Novo path base
public class ServicosUtilitariosController {

    @Autowired
    private ServicoComum servicoGeral; // CommonService renomeado

    @Autowired
    private ServicoConfiguracao servicoConfiguracao; // ConfigService renomeado

    private static AipFace clienteReconhecimentoFacial = null; // Cliente Baidu AipFace
    private static String CHAVE_API_MAPS_BAIDU = null; // Chave para API de Mapas

    /**
     * Recupera informações de localização com base nas coordenadas de longitude e latitude.
     * @param longitude String representando a longitude.
     * @param latitude String representando a latitude.
     * @return Objeto RespostaAPI contendo os dados da localização.
     */
    @GetMapping("/obter-localizacao") // Novo endpoint
    public RespostaAPI obterLocalizacao(@RequestParam String longitude, @RequestParam String latitude) {
        if (CHAVE_API_MAPS_BAIDU == null) {
            EntidadeConfiguracao configChave = servicoConfiguracao.buscarPorNome("chave_api_baidu_maps"); // Método renomeado
            if (configChave == null || configChave.getValor() == null || configChave.getValor().isEmpty()) {
                return RespostaAPI.erro("Por favor, configure corretamente a chave_api_baidu_maps no gerenciamento de configurações.");
            }
            CHAVE_API_MAPS_BAIDU = configChave.getValor();
        }
        
        // Assumindo UtilitarioBaidu.obterCidadePorCoordenadas() para a lógica de integração
        Map<String, String> dadosLocal = UtilitarioBaidu.obterCidadePorCoordenadas(CHAVE_API_MAPS_BAIDU, longitude, latitude);
        return RespostaAPI.sucesso().adicionarDados("localizacao", dadosLocal);
    }

    /**
     * Realiza a comparação entre duas imagens faciais.
     * As imagens são identificadas por seus caminhos relativos no diretório de upload.
     * @param caminhoImagem1 Nome do arquivo da primeira imagem facial.
     * @param caminhoImagem2 Nome do arquivo da segunda imagem facial.
     * @return Objeto RespostaAPI com o resultado da comparação.
     */
    @PostMapping("/comparar-faces") // Novo endpoint e método HTTP
    public RespostaAPI compararFaces(@RequestParam("imagem1") String caminhoImagem1, 
                                     @RequestParam("imagem2") String caminhoImagem2) {
        if (clienteReconhecimentoFacial == null) {
            EntidadeConfiguracao configChaveAPI = servicoConfiguracao.buscarPorNome("chave_api_face_baidu");
            EntidadeConfiguracao configChaveSecreta = servicoConfiguracao.buscarPorNome("chave_secreta_face_baidu");

            if (configChaveAPI == null || configChaveAPI.getValor() == null || configChaveAPI.getValor().isEmpty() ||
                configChaveSecreta == null || configChaveSecreta.getValor() == null || configChaveSecreta.getValor().isEmpty()) {
                return RespostaAPI.erro("Por favor, configure corretamente as chaves 'chave_api_face_baidu' e 'chave_secreta_face_baidu'.");
            }
            
            // O token de autenticação pode ser gerado aqui ou por um serviço dedicado
            String tokenAuth = UtilitarioBaidu.gerarTokenAutenticacao(configChaveAPI.getValor(), configChaveSecreta.getValor());
            if (tokenAuth == null) {
                 return RespostaAPI.erro("Falha ao gerar token de autenticação para Baidu Face API.");
            }

            clienteReconhecimentoFacial = new AipFace(null, configChaveAPI.getValor(), configChaveSecreta.getValor());
            clienteReconhecimentoFacial.setConnectionTimeoutInMillis(2000); // Tempo limite de conexão
            clienteReconhecimentoFacial.setSocketTimeoutInMillis(60000);   // Tempo limite de leitura
        }

        JSONObject resultadoComparacao = null;
        try {
            File arquivo1 = new File(ResourceUtils.getFile("classpath:static/uploads/imagens").getAbsolutePath() + "/" + caminhoImagem1); // Path adaptado
            File arquivo2 = new File(ResourceUtils.getFile("classpath:static/uploads/imagens").getAbsolutePath() + "/" + caminhoImagem2);

            if (!arquivo1.exists() || !arquivo2.exists()) {
                 return RespostaAPI.erro("Um ou ambos os arquivos de imagem não foram encontrados no servidor.");
            }

            String base64Img1 = UtilitarioBase64.codificarArquivoParaBase64(arquivo1); // Método renomeado
            String base64Img2 = UtilitarioBase64.codificarArquivoParaBase64(arquivo2);

            MatchRequest reqFace1 = new MatchRequest(base64Img1, "BASE64");
            MatchRequest reqFace2 = new MatchRequest(base64Img2, "BASE64");

            List<MatchRequest> requisicoesComparacao = new ArrayList<>();
            requisicoesComparacao.add(reqFace1);
            requisicoesComparacao.add(reqFace2);

            resultadoComparacao = clienteReconhecimentoFacial.match(requisicoesComparacao);
            System.out.println("Resultado da comparação facial: " + resultadoComparacao.get("result"));

        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return RespostaAPI.erro("Erro: Arquivo de imagem não encontrado. Detalhes: " + e.getMessage());
        } catch (IOException e) {
            e.printStackTrace();
            return RespostaAPI.erro("Erro de E/S ao processar arquivos. Detalhes: " + e.getMessage());
        } catch (Exception e) { // Captura outras exceções da API Baidu
            e.printStackTrace();
            return RespostaAPI.erro("Erro inesperado na comparação facial. Detalhes: " + e.getMessage());
        }
        
        if (resultadoComparacao != null && resultadoComparacao.containsKey("result")) {
             return RespostaAPI.sucesso().adicionarDados("resultado", JSONObject.parseObject(resultadoComparacao.get("result").toString()));
        } else {
             return RespostaAPI.erro("Nenhum resultado de comparação facial retornado pela API.");
        }
    }
}

Script SQL do Banco de Dados

Abaixo, os scripts SQL para a criação das tabelas no banco de dados, essenciais para o funcionamento da plataforma.


-- Tabela para gerenciar os usuários da plataforma
CREATE TABLE `usuarios` (
  `id_usuario` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'Chave primária do usuário',
  `data_registro` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Data e hora de criação do registro',
  `nome_usuario` VARCHAR(200) NOT NULL COMMENT 'Nome de usuário único para login',
  `senha` VARCHAR(200) NOT NULL COMMENT 'Senha do usuário (preferencialmente hash)',
  `nome_completo` VARCHAR(200) DEFAULT NULL COMMENT 'Nome completo do usuário',
  `genero` VARCHAR(50) DEFAULT NULL COMMENT 'Gênero do usuário',
  `url_avatar` VARCHAR(255) DEFAULT NULL COMMENT 'URL para a imagem de perfil do usuário',
  `telefone` VARCHAR(50) DEFAULT NULL COMMENT 'Número de telefone do usuário',
  `documento_identidade` VARCHAR(100) DEFAULT NULL COMMENT 'Número do documento de identidade do usuário',
  `data_nascimento` DATE DEFAULT NULL COMMENT 'Data de nascimento do usuário',
  `cidade` VARCHAR(100) DEFAULT NULL COMMENT 'Cidade onde o usuário reside',
  `interesses` TEXT DEFAULT NULL COMMENT 'Interesses do usuário (ex: "música, cinema")',
  `sobre_mim` TEXT DEFAULT NULL COMMENT 'Pequena biografia do usuário',
  PRIMARY KEY (`id_usuario`),
  UNIQUE KEY `idx_nome_usuario_unico` (`nome_usuario`)
) ENGINE=InnoDB AUTO_INCREMENT=100001 DEFAULT CHARSET=utf8mb4 COMMENT='Usuários da plataforma de encontros';

-- Tabela para armazenar mensagens ou comentários gerais
CREATE TABLE `mensagens_gerais` (
  `id_mensagem` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'Chave primária da mensagem',
  `data_envio` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Data e hora de envio da mensagem',
  `id_remetente` BIGINT NOT NULL COMMENT 'ID do usuário que enviou a mensagem',
  `nome_remetente` VARCHAR(200) DEFAULT NULL COMMENT 'Nome do usuário remetente',
  `conteudo` LONGTEXT NOT NULL COMMENT 'Conteúdo da mensagem ou comentário',
  `resposta` LONGTEXT COMMENT 'Conteúdo da resposta à mensagem',
  PRIMARY KEY (`id_mensagem`),
  KEY `fk_remetente_id` (`id_remetente`),
  CONSTRAINT `fk_remetente_id` FOREIGN KEY (`id_remetente`) REFERENCES `usuarios` (`id_usuario`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=200001 DEFAULT CHARSET=utf8mb4 COMMENT='Tabela de mensagens e comentários gerais';

-- Tabela para gerenciar tokens de autenticação de sessão
CREATE TABLE `tokens_autenticacao` (
  `id_token` BIGINT NOT NULL AUTO_INCREMENT COMMENT 'Chave primária do token',
  `id_usuario` BIGINT NOT NULL COMMENT 'ID do usuário associado ao token',
  `nome_usuario_token` VARCHAR(100) NOT NULL COMMENT 'Nome de usuário para referência',
  `nome_tabela_origem` VARCHAR(100) DEFAULT NULL COMMENT 'Tabela de origem do usuário (ex: usuarios, administradores)',
  `papel_usuario` VARCHAR(100) DEFAULT NULL COMMENT 'Papel do usuário (ex: "user", "admin")',
  `valor_token` VARCHAR(200) NOT NULL COMMENT 'O valor real do token de sessão',
  `data_criacao` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Data de criação do token',
  `data_expiracao` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Data de expiração do token',
  PRIMARY KEY (`id_token`),
  UNIQUE KEY `idx_token_valor_unico` (`valor_token`),
  KEY `fk_usuario_token_id` (`id_usuario`),
  CONSTRAINT `fk_usuario_token_id` FOREIGN KEY (`id_usuario`) REFERENCES `usuarios` (`id_usuario`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=300001 DEFAULT CHARSET=utf8mb4 COMMENT='Tabela para tokens de autenticação';


Tags: SpringBoot vuejs java RESTfulAPI DesenvolvimentoWeb

Publicado em 7-27 23:01