背景
在实际工作中,可能会见证公司技术栈的变迁,比如说:从写jsp到前后端分离。但在这个过渡的阶段中,可能会遇到非得在html页面中加载jsp页面的情况。下面来总结一下如何实现这种需求吧~
业务场景
当前是一个前后端分离的项目,使用的是vue-cli脚手架,使用webpack进行打包,入口页为index.html。由于历史原因,需要用到一个公共组件 xxxComponent,由于该公共组件适用于大部分用jsp写的项目,因此提供的引入方式是<%=XXXDef.getPackage("xxxComponent", "~1.1.0")%>
,实际上就是生成加载公共组件资源的link标签和script标签。由于html和jsp不同,我们不能在html页面里面直接使用服务器端代码,那么我们是否可以在html中加载jsp页面,从而获取到需要的组件呢?答案当然是可以的。
解决方案
通过jsonp的方式,将目标作为js形式加载过来,尽管其实对方是一个jsp。
我们可以在项目的public文件夹下看到index.html页面,在同个文件夹下创建xxxComponent.jsp。
在index.html页面请求同路径下的xxxComponent.jsp页面的数据,这个jsp页面自执行函数里生成了需要的link、script标签。
<%-- 引入所需要的包 --%>
<%@ page import="xxx"%>
<%
response.setHeader("Content-Type", "application/javascript; charset=UTF-8");
String root = XXXDef.getXxxComponentRoot(); // 业务需要
String version = "xxxComponent";
// 业务需要
// 1. 由于组件内部需要用到a、b、c、d,我们在window定义好这些变量,且都是从以下jar包拿到的。这也是html里做不到的!
// 2. 创建一段脚本:自执行函数里动态生成link标签用于加载组件的css资源,script用于加载组件的js资源。
// 3. 最后将脚本以字符串的形式输出
String script = "(function(){" +
"window.a='" + root + "/" + version +"';" +
"window.b='//" + Web.getAVal() + "/" + version + "';" +
"window.c='" + Web.getBVal() + "';" +
"window.d=" + Web.getCVal() + ";" +
"var l = document.createElement('link');" +
"l.rel='stylesheet';l.href='" + XXXDef.getXxxComponentPath("css_xxxComponent") + "';" +
"var s = document.createElement('script');" +
"s.src = '" + XXXDef.getXxxComponentPath("js_xxxComponent") + "';" +
"var n = document.getElementsByTagName('script')[0];" +
"n.parentNode.insertBefore(l, n);" +
"n.parentNode.insertBefore(s, n);" +
"})()";
out.print(script);
%>
在index.html页面里,引入这个jsp:
<script type="text/javascript" src="<%= BASE_URL %>xxxComponent.jsp"></script>
由于index.html页面是项目的入口页,我们可以看到访问项目时发起了一个http请求,请求了http://yourProjectDomain/xxxComponent.jsp页面,页面里输出以下内容(通过控制台找到相关请求在Response中可以看到):
(function() {
window.a = '//commonComponents.cn/xxxComponent'; // 解释:这些都是后端拿到的具体的值
window.b = '//commonComponents.cn/xxxComponent';
window.c = 'projectName';
window.d = true;
var l = document.createElement('link');
l.rel = 'stylesheet';
l.href = '//commonComponents.cn/xxxComponent/css/xxxComponent.css?v=202106041200';
var s = document.createElement('script');
s.src = '//commonComponents.cn/xxxComponent/js/xxxComponent.js?v=202106041200';
var n = document.getElementsByTagName('script')[0];
n.parentNode.insertBefore(l, n);
n.parentNode.insertBefore(s, n);
}
)()
因为是以javascript文件形式加载过来的,所以他会在index.html插入动态添加的以下几个标签(打开控制台,在Elements中head标签里可以找到组件相关的资源标签):
<link rel="stylesheet" href="//commonComponents.cn/xxxComponent/css/xxxComponent.css?v=202106041200">
<script src="//commonComponents.cn/xxxComponent/js/xxxComponent.js?v=202106041200"></script>
至此,项目成功引入需要的组件!