你瞭解jsp中的c:forEach嗎?

走不完的長巷發表於2018-11-05

       最近由於業務需求,幫同事把jsp頁面上的select控制元件進行了改動。但是在改完程式碼之後,在某幾個擁有大量select元件的頁面下出現了報錯資訊:_jspService超過了65535位元組的限制。

  // 舊的程式碼
  <form:options items="${opts}" itemLabel="label" itemValue="value" htmlEscape="false"/>
// 新的程式碼
<c:forEach items="${opts}" var="d">
    <option value="d.value" label="d.label" title="d.label"></option>
</c:forEach>複製程式碼

       雖然這個問題通過其他方式解決了。但是這個錯誤還是一直困擾著我。正好今天沒什麼事情,就決定來看看這個的問題到底出在什麼地方。 因為問題頁面的其他程式碼都沒有改動過,所以我們可以很輕易的定位到我們的問題程式碼,也就是從optionsc:forEach的改動。

       我們先來了解一下jsp的編譯過程:首先,客戶端傳送請求給web容器;然後,web容器將jsp檔案編譯成servlet原始碼,再將servlet原始碼編譯成class檔案;web容器執行class檔案並將響應返回給客戶端。而我們的遇到的錯誤資訊是“unable to compile class for JSP”,而compile失敗的原因呢就是_jspService太大了。

根據報錯資訊,我們得先找到_jspService這個方法。先從最簡單的空頁面開始除錯,編譯執行後在瀏覽器裡訪問該頁面以生成java檔案和class檔案。下圖就是編譯後的class檔案,我們成功的找到了_jspService方法,同時我們可以看到,就是這個方法輸出了我們的頁面。

你瞭解jsp中的c:forEach嗎?

     接下來,我同時建立了兩個jsp頁面,裡面的內容就是最上面的程式碼示例,一個頁面用options標籤,另一個頁面用了c:forEach。下面貼上兩個jsp的編譯出來的class檔案裡面的out.write()部分程式碼:

你瞭解jsp中的c:forEach嗎?

      第一個jsp用的是options標籤,從圖中可以看到options標籤沒有做任何的處理就編譯成了class檔案。

你瞭解jsp中的c:forEach嗎?

      第二個檔案是用的c:forEach,我們發現class檔案裡面已經沒有c:forEach標籤了,取而代之的是一個if語句,而它的判斷條件是一個看起來與forEach有關的方法的返回值。來到這一步,答案其實已經呼之欲出了。我們在這個檔案中繼續查詢,果然在下面出現了這個方法。

你瞭解jsp中的c:forEach嗎?

       這個方法內部有一個do{}while()迴圈,所有的option都在這個迴圈中輸出。由於這個方法太長了就不貼整個方法了,這個方法最終會返回false,然後繼續執行_jspService方法後續的out.write()

總結             

options元素在jsp編譯成class的過程中會被保留,到後面由spring MVC來處理,而每一個c:forEach標籤在編譯階段就已經被編譯成一個函式來輸出目標元素。如果form表單中需要大量的select控制元件,最好能用options來實現。當然,最好的方法還是不要把太多的元素放到一個jsp中,可以靈活的運用<jsp:include page="" flush="true" />等方法來分解檔案。


相關文章