Sistema de Gerenciamento de Tarefas com Spring Boot, Vue.js e Uni-app: Design e Implementação

Entrodução

Este projeto detalha a concepção e implementação de um Sistema de Gerenciamento de Tarefas utilizando as tecnologias Spring Boot, Vue.js e Uni-app. O sistema visa otimizar a organização e o acompanhamento de tarefas em diversos contextos.

Tecnologias Utilizadas

Backend: Spring Boot

O Spring Boot simplifica o desenvolvimento de aplicações Java com seu ecossistema robusto. Ele inclui servidores embarcados como Tomcat, facilitando a implantação e execução sem configurações adicionais. A auto-configuração, uma de suas principais vantagens, ajusta automaticamente as definições da aplicação com base nas dependências detectadas. Além disso, o Spring Boot oferece uma vasta gama de funcionalidades prontas para uso, como Spring Data para persistência de dados e Spring Security para controle de acesso, permitindo a construção rápida e escalável de aplicações de alta qualidade.

Frontend: Vue.js

Vue.js é um framework JavaScript progressivo conhecido por sua abordagem declarativa e eficiente para a construção de interfaces de usuário. Baseado em um Virtual DOM, ele otimiza as atualizações na interface, permitindo que os desenvolvedores se concentrem na lógica de dados. Sua arquitetura baseada em componentes promove um código mais organizado e reutilizável. A reatividade do Vue.js garante que a interface do usuário seja atualizada automaticamente sempre que os dados subjacentes mudam, proporcionando uma experiência de desenvolvimento ágil e produtiva.

Persistência: MyBatis-Plus

MyBatis-Plus é uma extensão poderosa do framework MyBatis, projetada para simplificar o desenvolvimento de acesso a dados em Java. Ele suporta uma variedade de bancos de dados, como MySQL, Oracle e PostgreSQL, e oferece uma API rica com anotações para facilitar as operações ORM, reduzindo significativamente a necessidade de escrever SQL manualmente. O MyBatis-Plus inclui um gerador de código que automatiza a criação de classes de modelo (Entity), interfaces Mapper e arquivos de mapeamento XML, acelerando o fluxo de desenvolvimento. Funcionalidades como paginação, consultas dinâmicas e controle de concorrência também estão integradas, permitindo um manuseio de dados eficiente e robusto.

Testes do Sistema

A fase de testes é crucial para garantir a qualidade e a confiabilidade do sistema. Nosso objetivo é identificar e corrigir defeitos através de testes funcionais e de integração, assegurando que o sistema atenda às expectativas do usuário e aos requisitos definidos.

Objetivos dos Testes

Os testes de sistema visam validar a aderência do produto aos requisitos especificados e assegurar uma experiência de usuário fluida. Ao simular diversos cenários de uso e identificar potenciais falhas, garantimos que o sistema seja estável e confiável. A validação em múltiplos níveis ajuda a refinar a funcionalidade e a usabilidade, resultando em um produto final de maior qualidade.

Testes de Funcionalidade

Os testes de funcionalidade empregam técnicas de caixa-preta, como testes de valor limite e validação de campos obrigatórios, para verificar cada módulo do sistema. Casos de teste são elaborados para abranger cenários específicos, garantindo que as funcionalidades operem conforme o esperado.

Teste de Login

A funcionalidade de login é testada validando a correspondência entre as credenciais fornecidas e os dados armazenados no banco. O sistema deve fornecer feedback claro em caso de falha de autenticação e validar as permissões de acesso baseadas nos papéis dos usuários.

Dados de Entrada Resultado Esperado Resultado Obtido Análise
Usuário: admin, Senha: 123456, Captcha: Correto Login bem-sucedido Login efetaudo com sucesso Correspondente ao espeardo
Usuário: admin, Senha: 111111, Captcha: Correto Erro de senha Mensagem de erro: Senha incorreta Correspondente ao esperado
Usuário: admin, Senha: 123456, Captcha: Incorreto Erro de Captcha Mensagem de erro: Captcha inválido Correspondente ao esperado
Usuário: (vazio), Senha: 123456, Captcha: Correto Campo de usuário obrigatório Mensagem de erro: Digite o nome de usuário Correspondente ao esperado
Usuário: admin, Senha: (vazio), Captcha: Correto Campo de senha obrigatório Mensagem de erro: Digite a senha Correspondente ao esperado

Teste de Gerenciamento de Usuários

Esta funcionalidade abrange a adição, edição, exclusão e busca de usuários. Os testes verificam a validação de campos obrigatórios, a detecção de nomes de usuário duplicados, a confirmação de exclusão e a atualização correta das informações do usuário.

Dados de Entrada Resultado Esperado Resultado Obtido Análise
Informações completas do usuário Adição bem-sucedida, usuário aparece na lista Usuário adicionado com sucesso à lista Correspondente ao esperado
Modificação de informações de usuário Edição bem-sucedida, informações atualizadas Informações do usuário foram alteradas corretamente Correspondente ao esperado
Seleção para exclusão e confirmação Sistema solicita confirmação, usuário é removido Usuário não encontrado após confirmação de exclusão Correspondente ao esperado
Adição sem nome de usuário Mensagem de erro: Nome de usuário é obrigatório Mensagem de erro: Nome de usuário é obrigatório Correspondente ao esperado
Adição com nome de usuário existente Falha na adição, mensagem de erro: Nome de usuário já em uso Falha na adição, mensagem de erro: Nome de usuário já em uso Correspondente ao esperado

Conclusão dos Testes

Através de testes de caixa-preta e casos de uso simulados, validamos a correção dos fluxos e funcionalidades do sistema. A etapa de testes é fundamental para aprimorar a usabilidade e a robustez do sistema, garantindo que ele atenda aos objetivos de design e às necessidades dos usuários. Os testes confirmaram que o sistema, em termos de funcionalidade e performance, cumpre os requisitos estabelecidos.

Exemplo de Código

Controle de Autenticação (Backend)


import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.common.utils.R; // Assumindo uma classe R para respostas padronizadas
import com.example.entity.UsersEntity;
import com.example.service.UserService;
import com.example.service.TokenService;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import javax.servlet.http.HttpServletRequest;
import java.util.Calendar;
import java.util.Date;

@RestController
@RequestMapping("/api")
public class AuthController {

   private final UserService userService;
   private final TokenService tokenService;

   public AuthController(UserService userService, TokenService tokenService) {
       this.userService = userService;
       this.tokenService = tokenService;
   }

   @IgnoreAuth // Assumindo uma anotação para ignorar autenticação
   @PostMapping("/login")
   public R login(String username, String password, String captcha, HttpServletRequest request) {
       UsersEntity user = userService.selectOne(new EntityWrapper<usersentity>().eq("username", username));

       if (user == null || !user.getPassword().equals(password)) {
           return R.error("Usuário ou senha incorretos");
       }

       String token = tokenService.generateAuthToken(user.getUserId(), username, "users", user.getRole());
       return R.ok().put("token", token);
   }
}
 </usersentity>

Serviço de Geração de Token (Backend)


import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.example.entity.TokenEntity;
import com.example.mapper.TokenMapper;
import com.example.service.TokenService;
import com.example.common.utils.CommonUtil; // Assumindo utilitário para strings aleatórias
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import org.springframework.stereotype.Service;
import java.util.Calendar;
import java.util.Date;

@Service
public class TokenServiceImpl extends ServiceImpl<tokenmapper tokenentity=""> implements TokenService {

   @Override
   public String generateAuthToken(Long userId, String username, String tableName, String role) {
       TokenEntity existingToken = this.selectOne(new EntityWrapper<tokenentity>().eq("userId", userId).eq("role", role));
       String newToken = CommonUtil.generateRandomString(32); // Gera uma string aleatória de 32 caracteres

       Calendar expiryCalendar = Calendar.getInstance();
       expiryCalendar.setTime(new Date());
       expiryCalendar.add(Calendar.HOUR_OF_DAY, 1); // Token válido por 1 hora

       if (existingToken != null) {
           existingToken.setToken(newToken);
           existingToken.setExpiryTime(expiryCalendar.getTime());
           this.updateById(existingToken);
       } else {
           TokenEntity newTokenEntity = new TokenEntity(userId, username, tableName, role, newToken, expiryCalendar.getTime());
           this.insert(newTokenEntity);
       }
       return newToken;
   }
}
 </tokenentity></tokenmapper>

Interceptors de Autorização (Backend)


import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import com.alibaba.fastjson.JSONObject; // Assumindo uso de Fastjson para serialização
import com.example.common.utils.R;
import com.example.entity.TokenEntity;
import com.example.service.TokenService;
import com.example.common.annotation.IgnoreAuth; // Anotação para ignorar autenticação
import org.springframework.util.StringUtils;
import java.io.PrintWriter;

@Component
public class AuthorizationInterceptor implements HandlerInterceptor {

   public static final String AUTH_TOKEN_HEADER = "Token";

   @Autowired
   private TokenService tokenService;

   @Override
   public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
       // Configurações CORS
       response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
       response.setHeader("Access-Control-Max-Age", "3600");
       response.setHeader("Access-Control-Allow-Credentials", "true");
       response.setHeader("Access-Control-Allow-Headers", "x-requested-with, request-source, Token, Origin, imgType, Content-Type, cache-control, postman-token, Cookie, Accept, authorization");
       response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));

       // Responde a requisições OPTIONS para CORS
       if (request.getMethod().equalsIgnoreCase(RequestMethod.OPTIONS.name())) {
           response.setStatus(HttpStatus.OK.value());
           return false;
       }

       // Verifica se o handler é um HandlerMethod e se possui a anotação IgnoreAuth
       IgnoreAuth ignoreAuthAnnotation = null;
       if (handler instanceof HandlerMethod) {
           ignoreAuthAnnotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
       } else if (handler instanceof ResourceHttpRequestHandler) {
           // Ignora para recursos estáticos
           return true;
       }

       // Se a anotação IgnoreAuth estiver presente, permite o acesso
       if (ignoreAuthAnnotation != null) {
           return true;
       }

       // Obtém o token do header da requisição
       String authToken = request.getHeader(AUTH_TOKEN_HEADER);

       TokenEntity tokenData = null;
       if (StringUtils.hasText(authToken)) {
           tokenData = tokenService.getTokenDetails(authToken); // Assumindo método para buscar detalhes do token
       }

       // Valida o token e os dados do usuário
       if (tokenData != null) {
           // Armazena informações do usuário na sessão
           request.getSession().setAttribute("userId", tokenData.getUserId());
           request.getSession().setAttribute("role", tokenData.getRole());
           request.getSession().setAttribute("tableName", tokenData.getTableName());
           request.getSession().setAttribute("username", tokenData.getUsername());
           return true;
       }

       // Retorna erro de autenticação se o token for inválido ou ausente
       PrintWriter writer = null;
       response.setCharacterEncoding("UTF-8");
       response.setContentType("application/json; charset=utf-8");
       try {
           writer = response.getWriter();
           writer.print(JSONObject.toJSONString(R.error(401, "Autenticação necessária")));
       } finally {
           if (writer != null) {
               writer.close();
           }
       }
       return false;
   }
}
 

Estrutura do Banco de Dados (Exemplo: Tabela de Tokens)


-- Tabela para armazenar informações de tokens de autenticação
DROP TABLE IF EXISTS `auth_tokens`;
CREATE TABLE `auth_tokens` (
 `token_id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID do token',
 `user_id` bigint(20) NOT NULL COMMENT 'ID do usuário associado',
 `username` varchar(100) NOT NULL COMMENT 'Nome de usuário',
 `table_name` varchar(100) DEFAULT NULL COMMENT 'Nome da tabela de origem do usuário',
 `role` varchar(100) DEFAULT NULL COMMENT 'Papel/permissão do usuário',
 `token_value` varchar(200) NOT NULL COMMENT 'Valor do token',
 `creation_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Data e hora de criação',
 `expiration_time` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Data e hora de expiração',
 PRIMARY KEY (`token_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Tabela de tokens de autenticação';

-- Exemplo de registros na tabela auth_tokens
INSERT INTO `auth_tokens` VALUES 
(9, 23, 'student01', 'students', 'Student', 'a1b2c3d4e5f67890abcdef1234567890', '2023-02-23 21:46:45', '2023-03-15 14:01:36'),
(10, 11, 'student02', 'students', 'Student', 'f0e9d8c7b6a54321fedcba0987654321', '2023-02-27 18:33:52', '2023-03-17 18:27:42'),
(12, 1, 'admin_user', 'users', 'Administrator', 'h1i2j3k4l5m6n7o8p9q0r1s2t3u4v5w6', '2023-02-27 19:37:01', '2023-03-17 18:23:02'),
(15, 29, 'club_pres', 'clubs', 'President', '0v1w2x3y4z5a6b7c8d9e0f1a2b3c4d5e', '2023-03-15 12:58:08', '2023-03-15 14:03:48');
 

Tags: Spring Boot Vue.js uni-app java MyBatis-Plus

Publicado em 6-26 23:24