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';