Exibindo Projetos Web em Iframes com Arquivos Armazenados no Banco de Dados

Em um projeto recente, enfrentamos o desafio de:

Para projetos frontend fornecidos por terceiros, contendo CSS, JS, HTML, imagens e outros recursos, precisávamos armazenar esses projetos em um banco de dados e exibi-los em um iframe. Além disso, os recursos referenciados pelo HTML (como scripts e folhas de estilo) também precisavam ser carregados coretamente a partir do banco de dados.

A abordagem foi dividida em duas etapas:

  1. Amrazenar todos os arquivos do projeto (JS, CSS, HTML, imagens, etc.) no banco de dados, mantendo suas referências de origem;
  2. Exibir o HTML principal em um iframe, garantindo que os recursos referenciados sejam carregados corretamente do banco de dados.

Este artigo foca na segunda etapa, detalhando o processo e a implementação.

Consideremos um exemplo de projeto frontend que precisa ser exibido:

O projeto contém vários arquivos, incluindo HTML, CSS, JavaScript e imagens. Quando aberto diretamente, o projeto exibe corretamente. Nosso objetivo é armazenar esses arquivos em um banco de dados e exibi-los em um iframe em nossa aplicação JSP.

  1. Estrutura da tabela do banco de dados:

Para armazenar os arquivos do projeto, criamos a seguinte tabela:

create table t_project_files(
project_name varchar2(200),
resource_path varchar2(500),
file_content blob
);

Neste exemplo, todos os arquivos do projeto já foram armazenados corretamente no banco de dados.

  1. Implementação do JSP com iframe:

No arquivo displayProject.jsp, criamos um iframe que referencia o arquivo HTML principal do projeto:

<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Visualização de Projeto em Iframe</title>
<style>
    #contentFrame{
        width: 100%;
        height: 500px;
        border: 1px solid #ccc;
    }
</style>
</head>
<body>
    <center>Visualização do projeto em iframe, recursos carregados do banco de dados</center>
    <iframe id="contentFrame" src="${pageContext.request.contextPath}/project/demo.zip/mobile_nav.html"/>
</body>
</html>

  1. Lógica de implementação:

A solução funciona da seguinte forma:

  • O src do iframe utiliza um padrão de URL: /project/nomeDoProjeto/caminhoDoArquivo
  • O controlador Spring intercepta essas requisições, extrai o nome do projeto e o caminho do recurso
  • O serviço busca o conteúdo do arquivo no banco de dados com base nesses parâmetros
  • A resposta HTTP é configurada com o Content-Type apropriado para cada tipo de arquivo
  • Um ponto crucial é que os recursos referenciados no HTML também usam o mesmo padrão de URL, permitindo que sejam carrregados corretamente do banco de dados
  1. Controlador Spring (ProjectController):
package com.example.controller;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.HandlerMapping;

import com.example.service.ProjectService;

/**
 * Controlador para exibição de projetos em iframes
 */
@Controller
public class ProjectController {
    private static Logger logger = Logger.getLogger(ProjectController.class);
    
    @Autowired
    private ProjectService projectService;
    
    /**
     * Processa requisições para recursos de projetos
     */
    @RequestMapping("/project/{projectName}/**")
    public void serveProjectResource(@PathVariable("projectName") String projectName, 
            HttpServletResponse response, HttpServletRequest request)
    {
        String resourcePath = extractPathFromPattern(request);
        
        logger.info("Nome do projeto: "+projectName);
        logger.info("Caminho do recurso: "+resourcePath);
        
        byte[] resourceContent = projectService.getResourceContent(projectName, resourcePath);
        String contentType = projectService.getContentType(resourcePath);
        
        response.setContentType(contentType); 
        response.setCharacterEncoding("utf-8");
        
        if(resourceContent != null){            
            try{
                InputStream resourceStream = new ByteArrayInputStream(resourceContent);
                OutputStream outputStream = response.getOutputStream();
                byte[] buffer = new byte[1024];
                int bytesRead;
                
                while((bytesRead = resourceStream.read(buffer)) != -1){
                    outputStream.write(buffer, 0, bytesRead);
                }
                
                outputStream.close();
                resourceStream.close();
            }catch (IOException e) {  
                logger.error("Erro ao servir recurso do projeto", e);
            }
        }
    }
    
    // Extrai o caminho do recurso do padrão da URL
    private static String extractPathFromPattern(final HttpServletRequest request) {
         String path = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
         String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
         return new AntPathMatcher().extractPathWithinPattern(bestMatchPattern, path);
    }
}

  1. Serviço de projeto (ProjectService):
package com.example.service;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.example.dao.ProjectResourceMapper;
import com.example.model.ProjectResource;

@Service
public class ProjectService {
    
    @Autowired
    private ProjectResourceMapper resourceMapper;
    
    /**
     * Obtém o conteúdo de um recurso do projeto
     */
    public byte[] getResourceContent(String projectName, String resourcePath){
        ProjectResource resource = resourceMapper.getResourceContent(projectName, resourcePath);
        return resource != null ? resource.getFileContent() : null;
    }
    
    /**
     * Determina o Content-Type com base na extensão do arquivo
     */
    public String getContentType(String resourcePath){
        int extensionPos = resourcePath.lastIndexOf(".");
        String extension = extensionPos >= 0 ? resourcePath.substring(extensionPos + 1) : "";
        String contentType = "application/octet-stream";    // Tipo padrão para binários
        
        Map<String, String> typeMap = new HashMap<String, String>() {{
            put("html", "text/html");
            put("htm", "text/html");
            put("jpg", "image/jpeg");
            put("jpeg", "image/jpeg");
            put("png", "image/png");
            put("gif", "image/gif");
            put("css", "text/css");
            put("js", "application/javascript");
            put("json", "application/json");
            put("svg", "image/svg+xml");
        }};
        
        return typeMap.getOrDefault(extension.toLowerCase(), contentType);
    }
}

  1. Mapper de recursos (ProjectResourceMapper):
package com.example.dao;

import org.apache.ibatis.annotations.Param;
import com.example.model.ProjectResource;

public interface ProjectResourceMapper {
    
    ProjectResource getResourceContent(@Param("projectName")String projectName, 
                                     @Param("resourcePath")String resourcePath);
}

  1. XML do Mapper (ProjectResourceMapper.xml):
<?xml version="1.0" encoding="UTF-8" ?>

<mapper namespace="com.example.dao.ProjectResourceMapper" >
    
    <select id="getResourceContent" resultType="com.example.model.ProjectResource">
        select * from t_project_files 
        where project_name=#{projectName} and resource_path=#{resourcePath}
    </select>
      
</mapper>

  1. Modelo de recurso (ProjectResource.java):
package com.example.model;

/**
 * Representa um arquivo de projeto armazenado no banco de dados
 */
public class ProjectResource {
    private String projectName;
    private String resourcePath;
    private byte[] fileContent;
    
    // Getters e Setters
    public String getProjectName() {
        return projectName;
    }
    
    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }
    
    public String getResourcePath() {
        return resourcePath;
    }
    
    public void setResourcePath(String resourcePath) {
        this.resourcePath = resourcePath;
    }
    
    public byte[] getFileContent() {
        return fileContent;
    }
    
    public void setFileContent(byte[] fileContent) {
        this.fileContent = fileContent;
    }
}

Com essa implementação, ao acessar a URL da página JSP, o iframe exibirá corretamente o projeto, com todos os seus recursos (CSS, JS, imagens, etc.) sendo carregados do banco de dados.

Tags: iframe Spring MVC MyBatis Java Web banco de dados

Publicado em 7-24 22:20