一、問題
在做一個demo,因為很久沒有重新用 jsp 頁面直接 EL 取數據了,遇到了問題,記錄一下。
簡單來說就是用 EL 在 jsp 頁面里面從域中用 ${ xxx } 取數據:
- 但是瀏覽器對應頁面的位置是空白。
- 也沒有顯示 ${ xxx } 這個表達式的字符串本身。
二、前置條件:
- 已經引入了 jstl 和 taglibs 的依賴;
- 引入依賴之后在 jsp 頁面的頭部需要添加命名空間,也就是 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 這樣的聲明,否則在 IDEA 里面寫 EL 表達式時沒有提示的,也會報錯;
- EL 表達式語法正確,idea的提示里面可以直接寫一個域里的屬性名稱,比如我的例子 requestScope.xxx,用點操作符反倒沒有后面的提示,而直接寫 xxx 會有提示。
因為這些都沒有問題,所以我先排查了一下會不會是數據本身:
- 重新發請求看了一下網絡狀態:沒有問題;
- 檢查 jsp 的網頁代碼,html 的 body 都是空白,於是重新寫了點數據,再次顯示發現,除了 El 表達式的部分,其他都是可以正常顯示的。
三、解決
查了很多資料,jstl 的依賴、servlet版本匹配等等。(未解決)
3.1 版本匹配:沒問題
3.2 是否添加 jstl 依賴:正常無錯誤,並且引入了命名空間,結果就是在編寫 EL 的時候本身並不會報錯。
3.3 web.xml 中有個元素:
的約束版本(解決)
后來又看到一個博主提到web.xml 中有個元素:
因為在idea 里面用原型模式構建一個 maven : web-app 項目,然后添加 springmvc 的依賴,這是構建的過程,但是點開 web.xml 之后可以看到根元素
web.xml頭部指定的模式(Schema)文件中定義了多少種標簽元素,web.xml中就可以出現它的模式文件所定義的標簽元素,它就能擁有定義出來的那些功能。
事實上,web.xml的模式文件是由Sun公司定義的,每個 web.xml 文件的根元素
- xmlns:申明了web.xml文件的名稱空間的xml方案文檔的位置;
- xmls:xsi:指定了命名空間的案例;
- xsi:schemeLocation:指定了發方案的位置;
- version:制定方案的版本;
誒?那我們重新看一眼格式確實有點問題,其實和對應 servlet 的版本有關,用 idea 自動生成的時候,根元素里面表面它使用的是 2.3 版本的文件,實際上模式文件和對應的 java 版本更新早就已經到了4.0版本了,不同版本之間的特性也有差異,並且從對應 servlet 2.3 往后的約束文件,都已經不再是 dtd 而是 xsd 文件格式了。
那么對於使用 2.3 servlet 版本的這個dtd文件的約束,里面是有一個默認的屬性 isELIgnored,如果 isELIgnored 是 true,當 EL 表達式出現在文本或者標簽屬性時被忽略。
- 使用Servlet2.4的描述符的JSP頁面默認是解析EL表達式,即表達式有效。這默認提供了大部分應用想要的情況。
- 而使用 Servlet2.3 或者更早的描述符的 JSP 頁面默認是忽略EL表達式的,即不解析EL表達式,這樣就提供了向后兼容性。
因此對於我的問題,顯然就是整個指定的可以這樣:
- 在每一個 jsp 文件的頭部都添加:
<%@page isELIgnored="false" %>
將保證 EL 表達式的有效。修改之后成功。
- 修改web.xml。只要修改成對應版本為 2.4 以后的就可以了,那么看到 javaEE 版本和servlet、以及 tomcat 的對應關系,還可以直接改成 servlet4 以后的就可以了。(這個寫法我認為官網應該有個統一示例,但是沒找到)參考了一個人的總結,比如3.1如下:
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
</web-app>
這樣,最前面的那個 !DOCTYPE 就可以刪掉,修改之后成功。
- 后來我又想,我在 pom.xml 創建 servlet 依賴的時候,指定的 servlet 版本是很高的,那么對應的 EL 表達式應該是有效的。如果這里不聲明,那么 web.xml 解析的時候會不會自己去找對應的版本?試了一下,直接把前面 !DOCTYPE 刪掉,后面的
元素也保持空的。事實上也可以 成功。
