Arquitetura do Sistema
O sistema é construído com uma pilha de tecnologia moderna, dividida em camadas de backend, frontend e aplicativo móvel. O backend utiliza SpringBoot para fornecer APIs RESTful robustas, enquanto o frontend emprega Vue.js para uma interface de usuário responsiva. O aplicativo móvel é desenvolvido com uniapp, garantindo compatibilidade multiplataforma. A persistência de dados é gerenciada pelo MyBatis-Plus, que simplifica as operações de banco de dados.
Pilares Tecnológicos
Backend com SpringBoot
SpringBoot facilita o desenvolvimento de aplicações Java ao fornecer configuração automática, servidores integrados e suporte a plugins como Spring Data e Spring Security. Isso permite criar aplicações escaláveis com mínima configuração manual, acelerando o desenvolvimento e a integração com outros sistemas.
Frontend com Vue.js
Vue.js utiliza o conceito de DOM virtual e data binding reativo para atualizar a interface de forma eficiente. A abordagem baseada em componentes promove a reutilização de código e manutenção simplificada, permitindo que os desenvolvadores se concentrem na lógica de negócios em vez de manipulação manual do DOM.
Persistência de Dados com MyBatis-Plus
MyBatis-Plus é uma extensão do MyBatis que reduz a necessidade de código SQL manual. Ele oferece recursos como consulta dinâmica, paginação e geração de código automática, suportando múltiplos bancos de dados como MySQL e PostgreSQL. Isso otimiza a camada de acesso a dados e melhora a produtividade.
Testes do Sistema
Objetivos dos Testes
Os testes visam identificar defeitos e garantir que o sistema atenda aos requisitos funcionais e não funcionais. Simulações de cenários reais são conduzidas para verificar a usabilidade, segurança e desempenho, assegurando uma experiência de usuário confiável.
Testes Funcionais
Testes de caixa negra são aplicados para validar módulos como autenticação e gerenciamento de usuários. Por exemplo, a funcionalidade de login é testada com entradas válidas e inválidas, verificando mensagens de erro e flluxos de autenticação.
| Dados de Entrada | Resultado Esperado | Resultado Atual |
|---|---|---|
| Usuário: admin, Senha: correta, Captcha: correto | Login bem-sucedido | Sistema acessado |
| Usuário: admin, Senha: incorreta, Captcha: correto | Erro de credenciais | Mensagem de senha inválida |
| Usuário: vazio, Senha: correta, Captcha: correto | Erro de campo obrigatório | Solicitação de nome de usuário |
Testes de gerenciamento de usuários incluem operações CRUD, com validações para campos obrigatórios e exclusão segura. Os testes confirmam que o sistema responde adequadamente a entradas válidas e inválidas.
Conclusão dos Testes
Os testes concluídos demonstram que o sistema satisfaz os requisitos de design, com funcionalidades operando corretamente sob condições diversas. A análise de resultados permite refinamentos contínuos para aprimorar a robustez.
Exemplos de Código
Autenticação e Autorização
O código de backend implementa endpoints para login e geração de tokens. A autenticação é realizada verificando credenciais no banco de dados, e tokens JWT são gerados para sessões seguras.
@IgnorarAutenticacao
@RequestMapping(value = "/autenticar", method = RequestMethod.POST)
public ResponseEntity<Map<String, Object>> autenticar(@RequestParam String nomeUsuario, @RequestParam String senha, @RequestParam String captcha, HttpServletRequest requisicao) {
Usuario usuario = servicoUsuario.obterPorNome(nomeUsuario);
if (usuario == null || !verificarSenha(senha, usuario.getSenhaHash())) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(Collections.singletonMap("erro", "Credenciais inválidas"));
}
String token = servicoToken.criarToken(usuario.getId(), nomeUsuario, "tabela_usuarios", usuario.getPapel());
Map<String, Object> resposta = new HashMap<>();
resposta.put("token", token);
return ResponseEntity.ok(resposta);
}
@Override
public String criarToken(Long idUsuario, String nomeUsuario, String tabela, String papel) {
Token tokenExistente = repositorioToken.obterPorUsuarioEidPapel(idUsuario, papel);
String valorToken = GeradorUtil.gerarStringAleatoria(32);
Date dataExpiracao = new Date(System.currentTimeMillis() + 3600000); // 1 hora
if (tokenExistente != null) {
tokenExistente.setValor(valorToken);
tokenExistente.setDataExpiracao(dataExpiracao);
repositorioToken.atualizar(tokenExistente);
} else {
Token novoToken = new Token(idUsuario, nomeUsuario, tabela, papel, valorToken, dataExpiracao);
repositorioToken.inserir(novoToken);
}
return valorToken;
}
Um interceptor de autorização verifica tokens em requisições HTTP, permitindo acesso a rotas protegidas ou retornando erro 401 para autenticação necessária.
@Component
public class InterceptorAutorizacao implements HandlerInterceptor {
private static final String CABECALHO_TOKEN = "Authorization";
@Autowired
private ServicoToken servicoToken;
@Override
public boolean preHandle(HttpServletRequest requisicao, HttpServletResponse resposta, Object manipulador) throws Exception {
resposta.setHeader("Access-Control-Allow-Origin", requisicao.getHeader("Origin"));
if ("OPTIONS".equalsIgnoreCase(requisicao.getMethod())) {
resposta.setStatus(HttpStatus.OK.value());
return false;
}
if (manipulador instanceof HandlerMethod) {
IgnorarAutenticacao anotacao = ((HandlerMethod) manipulador).getMethodAnnotation(IgnorarAutenticacao.class);
if (anotacao != null) {
return true;
}
}
String token = requisicao.getHeader(CABECALHO_TOKEN);
if (StringUtils.hasText(token)) {
Token tokenEntity = servicoToken.obterPorValor(token);
if (tokenEntity != null) {
requisicao.getSession().setAttribute("idUsuario", tokenEntity.getIdUsuario());
requisicao.getSession().setAttribute("papel", tokenEntity.getPapel());
return true;
}
}
resposta.setStatus(HttpStatus.UNAUTHORIZED.value());
resposta.getWriter().write("{\"erro\": \"Autenticação requerida\"}");
return false;
}
}
Estrutura do Banco de Dados
O esquema de banco de dados inclui tabelas para armazenar tokens de autanticação, com campos para expiração e metadados de usuário.
-- Tabela para tokens de sessão
CREATE TABLE sessao_token (
id BIGINT PRIMARY KEY AUTO_INCREMENT,
id_usuario BIGINT NOT NULL,
nome_usuario VARCHAR(100) NOT NULL,
tabela_origem VARCHAR(100),
papel VARCHAR(50),
valor_token VARCHAR(255) NOT NULL,
data_criacao TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
data_expiracao TIMESTAMP NOT NULL
);
Dados de exemplo demonstram registros de tokens para diferentes usuários e papéis.