Importação de Dados de Excel com Vue.js 2

Para implementar a importação de arquivos Excel em uma aplicação Vue.js 2, é necessário uitlizar a biblioteca xlsx. A seguir, apresenta-se uma abordagem completa para o frontend e backend.

1. Configuração do Frontend

Primeiramente, instale a dependência no projeto:

npm install xlsx

No componente Vue, utilize um componnete de upload para selecionar o arquivo:

<el-upload
    style="display: inline-block"
    action=""
    accept=".xlsx, .xls"
    :auto-upload="false"
    :show-file-list="false"
    :on-change="selecionarArquivo"
>
    <el-button type="primary" icon="el-icon-upload2" round>Importar</el-button>
</el-upload>

2. Lógica de Processamento no Frontend

Implemente o método para ler e processar o arquivo Excel:

import * as XLSX from "xlsx";

export default {
    methods: {
        selecionarArquivo(evento) {
            const periodo = this.formulario.periodo;
            const temDadosExistentes = this.quantidadeDados > 0;

            const processarLeitura = (arquivo) => {
                const leitor = new FileReader();
                leitor.readAsArrayBuffer(arquivo);
                leitor.onload = (eventoLeitura) => {
                    const dadosBinarios = new Uint8Array(eventoLeitura.target.result);
                    const planilha = XLSX.read(dadosBinarios, { type: 'array' });
                    const nomePrimeiraAba = planilha.SheetNames[0];
                    const aba = planilha.Sheets[nomePrimeiraAba];

                    const intervalo = { s: { r: 2, c: 3 }, e: { r: 32, c: 18 } };
                    const dadosConvertidos = XLSX.utils.sheet_to_json(aba, {
                        header: 1,
                        defval: '',
                        range: intervalo
                    });

                    const corpoRequisicao = {
                        registros: JSON.parse(JSON.stringify(dadosConvertidos)),
                        periodo: periodo
                    };

                    this.enviarDadosParaApi(corpoRequisicao);
                };
            };

            if (temDadosExistentes) {
                this.$confirm(`${periodo} já contém dados. Deseja substituí-los?`, 'Confirmação', {
                    confirmButtonText: 'Confirmar',
                    cancelButtonText: 'Cancelar',
                    type: 'warning'
                }).then(() => processarLeitura(evento.raw));
            } else {
                processarLeitura(evento.raw);
            }
        },

        enviarDadosParaApi(dados) {
            importarDados(dados).then((resposta) => {
                if (resposta.codigo === 200) {
                    this.carregarDados();
                    this.notificarSucesso("Importação concluída com sucesso");
                } else {
                    this.notificarErro("Falha na importação. Verifique o modelo do arquivo.");
                }
            });
        }
    }
};

3. Serviço de API

Defina a função para comunicação com o backend:

import axios from 'axios';

export function importarDados(payload) {
    return axios.post('/api/relatorio-operacional/importar', payload);
}

4. Implementação do Backend (Spring Boot)

No controlador, defina o endpoint para receber os dados:

@RestController
@RequestMapping("/api/relatorio-operacional")
public class RelatorioController {

    @Autowired
    private RelatorioServico servico;

    @PostMapping("/importar")
    public ResponseEntity<?> importarDados(@RequestBody @Valid RequisicaoImportacao requisicao) {
        return servico.processarImportacao(requisicao.getRegistros(), requisicao.getPeriodo());
    }
}

No serviço, implemente a lógica de negócio e persistência:

@Service
public class RelatorioServico {

    @Autowired
    private RelatorioRepositorio repositorio;

    @Transactional(rollbackFor = Exception.class)
    public ResponseEntity<?> processarImportacao(List<String> registros, String periodo) {
        try {
            List<RegistroRelatorio> entidades = new ArrayList<>();

            for (String linha : registros) {
                JSONArray valores = JSON.parseArray(linha);
                String nomeEmpresa = valores.getString(0);
                Integer codigoEmpresa = MapeamentoEmpresas.obterCodigo(nomeEmpresa);

                if (codigoEmpresa == null) {
                    throw new RuntimeException("Empresa não encontrada: " + nomeEmpresa);
                }

                RegistroRelatorio entidade = new RegistroRelatorio();
                entidade.setId(GeradorId.gerarNovo());
                entidade.setPeriodo(periodo);
                entidade.setEmpresaId(codigoEmpresa);
                preencherCamposNumericos(entidade, valores);
                entidades.add(entidade);
            }

            if (!entidades.isEmpty()) {
                repositorio.deletarPorPeriodo(periodo);
                repositorio.inserirEmLote(entidades);
            }

            return ResponseEntity.ok().build();
        } catch (Exception e) {
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    private void preencherCamposNumericos(RegistroRelatorio entidade, JSONArray valores) {
        // Lógica para preencher campos numéricos a partir do JSONArray
        entidade.setTotalPessoas(parseValorInteiro(valores.getString(1)));
        entidade.setPessoasAdministrativas(parseValorInteiro(valores.getString(2)));
        // ... outros campos
    }

    private Integer parseValorInteiro(String valor) {
        return StringUtils.isNotBlank(valor) ? Integer.parseInt(valor) : 0;
    }
}

Crie uma classe auxiliar para mapeamento de empresas:

public final class MapeamentoEmpresas {
    private static final Map<String, Integer> MAPEAMENTO = new HashMap<>();

    static {
        MAPEAMENTO.put("Empresa A", 1001);
        MAPEAMENTO.put("Empresa B", 1002);
        // ... outros mapeamentos
    }

    public static Integer obterCodigo(String nomeEmpresa) {
        return MAPEAMENTO.get(nomeEmpresa);
    }
}

Para a inserção em lote no banco de dados, configure o Mapper XML do MyBatis:

<mapper namespace="com.projeto.dao.RelatorioRepositorio">
    <insert id="inserirEmLote">
        INSERT INTO relatorio_operacional 
            (id, empresa_id, periodo, total_pessoas, pessoas_administrativas) 
        VALUES
        <foreach collection="lista" item="item" separator=",">
            (#{item.id}, #{item.empresaId}, #{item.periodo}, #{item.totalPessoas}, #{item.pessoasAdministrativas})
        </foreach>
    </insert>

    <delete id="deletarPorPeriodo">
        DELETE FROM relatorio_operacional WHERE periodo = #{periodo}
    </delete>
</mapper>

Tags: Vue.js Excel javascript java Spring Boot

Publicado em 7-19 08:39