从后台读取项目文件在前端iframe中展示
项目中有个需求是:
对于外部提供的前端项目,包含css、js、html、图片等的项目,将这个项目存进数据库,然后iframe中展示html,然后html中引用的js、css等文件
也能从数据库中读取并正确的展现;
所以其实我们这边分为两步:
1)将整个项目,中的所有文件,js、css等都以路径形式存进数据库,路径其实就是js等文件在html中的引用路径;
2)iframe中引用了HTML,然后html中js等文件从数据库读取出来,正确引用;
(其中,参考了博客:
主要是获取路径时,想了好久,restful的表达式中可以正则等等。。
)
我这边只做了第二步,下面是过程+思路:
假设现在要展现这个项目,前端demo项目:
直接打开mobile_nav.html是能访问的,直接访问结果:
现在要把htmldemo这个项目存进数据库,然后再我们的jsp页面中iframe中引用mobile_nav.html,也能正确展现。
怎么做呢?代码:
1.数据库表格式:
t_fileinfo:
create table t_fileinfo(
zipname varchar2(200),
filepath varchar2(500),
filecontent blob
);
假设htmldemo中的文件都已经被正确存储了:
2.showMobile.jsp中创建ifrmae,并引用mobile_nav.html:
<%@ page language="java" contentType="text/html; charset=utf-8" pageEncoding="utf-8"%> <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>展示iframe中的页面</title> <style> #iframe{ width: 100%; height: 500px; } </style> </head> <body> <center>展示iframe中的页面,html页面从数据库读取</center> <iframe id="iframe" src="${pageContext.request.contextPath}/iframe/htmldemo.zip/mobile_nav.html"/> </body> </html>
3.思路是:
- iframe中src使用路径是:/iframe/包名/路径,根据包名+路径获取文件的二进制流,response根据文件后缀类型设置相应的content-type,
- html就采用html的contenttype,js文件采用js的contenttype等。。
- controller中采用restful风格的requestMapping来接受,就能获取到包名、和路径,就能获取文件流了。
- 值得注意的一点是:iframe里面的文件的引用地址,也会带上/iframe/包名 父路径,这样子页面中的文件引用也能根据包名+路径获取,非常关键。
4.htmlController:
package com.cy.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.cy.service.HtmlService; /** * 控制展示iframe中的HTML页面 * @author CY * */ @Controller public class HtmlController { private static Logger logger = Logger.getLogger(HtmlController.class); @Autowired private HtmlService htmlService; /** * 对于iframe/path开头的url的处理 */ @RequestMapping("/iframe/{zipName}/**") public void iframeRequest(@PathVariable("zipName") String zipName, HttpServletResponse response, HttpServletRequest request) { String filePath = extractPathFromPattern(request); logger.info("---->>>zipName:"+zipName); logger.info("---->>>filePath:"+filePath); byte[] fileContent = htmlService.getFileContent(zipName, filePath); String contentType = htmlService.getContentType(filePath); //把html等文件写出去; response.setContentType(contentType); response.setCharacterEncoding("utf-8"); //有些引用的多余,例如bootstrap/bootstrap.min.css.map、jquery/jquery.min.map就会报空指针异常 if(fileContent!=null){ try{ InputStream picture = new ByteArrayInputStream(fileContent); OutputStream outputStream=response.getOutputStream(); int len = 0; byte[] buf = new byte[1024]; while((len = picture.read(buf,0,1024)) != -1){ outputStream.write(buf, 0, len); } outputStream.close(); }catch (IOException e) { e.printStackTrace(); } } } // 把指定URL后的字符串全部截断当成参数 // 这么做是为了防止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); } /* @RequestMapping("/iframe/{zipName}/{filePath:.+}") public void iframeRequest(@PathVariable("zipName") String zipName, @PathVariable("filePath") String filePath, HttpServletResponse response) { logger.info("---->>>zipName:"+zipName); logger.info("---->>>filePath:"+filePath); byte[] fileContent = htmlService.getFileContent(zipName, filePath); //把html页面写出去; response.setContentType("text/html"); response.setCharacterEncoding("utf-8"); try{ InputStream picture = new ByteArrayInputStream(fileContent); OutputStream outputStream=response.getOutputStream(); int len = 0; byte[] buf = new byte[1024]; while((len = picture.read(buf,0,1024)) != -1){ outputStream.write(buf, 0, len); } outputStream.close(); }catch (IOException e) { e.printStackTrace(); } }*/ }
htmlService:
package com.cy.service; import java.util.HashMap; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.cy.dao.HtmlMapper; import com.cy.model.FileInfo; @Service public class HtmlService { @Autowired private HtmlMapper htmlMapper; /** * 根据文件zip、文件名、文件path,获取fileContent * @return */ public byte[] getFileContent(String zipName, String filePath){ byte[] b = null; FileInfo fi = htmlMapper.getFileContent(zipName, filePath); if(fi!=null){ b = fi.getFileContent(); } return b; } /** * 根据文件后缀名拿到文件的ContentType * @param filePath * @return */ @SuppressWarnings("serial") public String getContentType(String filePath){ int pos = filePath.lastIndexOf("."); String suffix = filePath.substring(pos+1); String contentType = "application/octet-stream"; //默认二进制流数据类型; Map<String, String> contentMap = new HashMap<String, String>(){ { put("html", "text/html"); put("jpg", "image/jpeg"); put("png", "image/png"); put("css", "text/css"); put("js", "application/x-javascript"); } }; for(Map.Entry<String, String> entry : contentMap.entrySet()){ if(entry.getKey().equals(suffix)){ contentType = entry.getValue(); break; } } return contentType; } }
HtmlMapper:
package com.cy.dao; import org.apache.ibatis.annotations.Param; import com.cy.model.FileInfo; public interface HtmlMapper { public FileInfo getFileContent(@Param("zipName")String zipName, @Param("filePath")String filePath); }
HtmlMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace="com.cy.dao.HtmlMapper" > <select id="getFileContent" resultType="com.cy.model.FileInfo"> select * from t_fileInfo where zipName=#{zipName} and filePath=#{filePath} </select> </mapper>
FileInfo.java:(model):
package com.cy.model; /** * 项目每个文件实体类 * @author CY * */ public class FileInfo { private String zipName; private String filePath; private byte[] fileContent; public String getZipName() { return zipName; } public void setZipName(String zipName) { this.zipName = zipName; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } public byte[] getFileContent() { return fileContent; } public void setFileContent(byte[] fileContent) { this.fileContent = fileContent; } }
测试:
输入url后,iframe中能正确展示:
附: