缘起
在某些项目中可能会采用相对路径或者绝对路径方式来引入js或css文件,这在某些情况下会出现问题。下面我们就来说说问题出在哪里,我们先将以下所有的例子中的页面设定为a.jsp。
相对路径存在的问题
采用相对路径的写法如下两种
<script type="text/javascript" src="js/a.js"></script>
或
<script type="text/javascript" src="../js/a.js"></script>
这在你直接访问某个页面的时候比如如下是没有问题,。
http://localhost:8081/a.jsp
但在实际项目中我们很少直接去请求一个jsp页面,一般都是通过后来跳转,或是servlet,或是springmvc,亦或是springboot+tymeleaf。比如你想跳转到某个添加页面,你通过请求
http://localhost:8081/home/saveIndex.do
假设你使用的spring mvc。并且你的@requestMapping(“home”)是写在类上的话,那么返回的页面中引入的静态文件的路径就会变成如下这种
http://localhost:8081/home/js/a.js
也就是说他会在路径前面多了一个@requestMapping的路径,而正确的请求路径应该是
http://localhost:8081/js/a.js
绝对路径存在的问题
绝对路径写法有两种
- 以/开头
- 以http开头
比如如下两种写法就是通过绝对路径引用js的方法
<script type="text/javascript" src="/js/a.js"></script>
<script type="text/javascript" src="http://abc.com/js/a.js"></script>
但是以/开头的存在问题
这种写法在你项目部署在tomcat的root下是没有任何问题的,但是当你项目部署在webapp下,也就是存在application context的时候这种方式是存在问题的。比如你的项目为UserDemo。
你期望得到的JS的路径为
http://localhost:8081/UserDemo/a.js
你实际得到的JS的路径为
http://localhost:8081/a.js
所以你也会得到一个404。那么绝对路径中以/开头的会存在某些问题,那么以http开头的引用方式该怎么写呢?
正确的姿势引入
我们首先要考虑如何得到项目的请求地址和端口
假设我们需要在a.js页面引入某些js,那么我们需要在a.jsp页面引入另一个jsp。这个新的jsp我们把它叫mytags.jsp吧。
a.jsp页面引入的地方如下
<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@include file="/context/mytags.jsp" %>
<!DOCTYPE html>
<html>
<head>
......省略部分代码
mytags.jsp页面内容如下
<%@ taglib prefix="t" uri="/easyui-tags"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jstl/fmt_rt"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
%>
<c:set var="webRoot" value="<%=basePath%>" />
这里的webroot的最终结果就是
http://ip:port/项目名称
比如你的项目名称是UserDemo,那么就是如下
http://localhost:8081/UserDemo/
而如果你是放到tomcat的root目录下 那么是不加项目名的 类似
http://localhost:8081/
这个webroot就是项目的请求路径了
这样的话,我们就可以在a.jsp通过以下写法来使用绝对路径来引入JS或者css.例如
<link href="${webRoot}/asset/css/base.css" rel="stylesheet">
上诉翻译过来的真是路径就类似于
http://localhost:8081/asset/css/base.css
这个路径是绝对没有问题的。
这种写法的另一个好处是我们可以把每个页面都需要的js获取类库放到mytags.jsp里面,而不需要每个页面都引入一次。例如这里有一个相对复杂的mytags.jsp
如何把webRoot去掉
对于如上的一个mytags.jsp写法,可以看到每个引入的JS前面都加了${webRoot}。那么有没有什么办法可以省略掉这个呢,答案是有的,JS中提供了一个全局的前缀的写法
你可以在mytags.jsp文件中加入
<base target="_self" href="<%=basePath%>">
它代表每个引入JS的地方都需要加上这个前缀。这样的话下面引入JS的地方就可以省略掉${webRoot}了。比如我上诉的页面就可以看到引入js的时候都不需要再前面加 webroot
但是相比你也注意到了,为什么上诉在引入最后一个js的时候,也就是WdatePicker.js的时候前面加了ctx呢。
这其实是由于WdatePicker.js的特殊性导致的,由于其在内部还引用了其他的JS和CSS,并且其引用方式采用的是相对路径方式,.
在查找这些文件的时候路径就变成了下面这样
所以,对于这样的js我们需要特殊处理一下,即在前面加对应的项目名,也就是request.getContextPath()。由于上诉已经使用ctx定义了request.getContextPath()。所以可以写成如下这样
<script src="${ctx}/assets/plugins/My97DatePicker/WdatePicker.js" type="text/javascript"></script>