2012-10-16

借助 Maven 執行 JSP Precompile

本來以為 JSP Precompile 只有提昇執行效能一項好處,而且這好處只有在第一次執行有效果,所以一直不感興趣。

今天才知道另一項好處,保護 Source code,也就是說不只 Java 檔,連 JSP 都可以只交付 class 檔,不用交付原始檔,雖然這需求不常見。

JSP Precompile 不是只有將 JSP 轉成 Java,再編譯成 class 檔就好,還得在 web.xml 加上 JSP 所產生的 Servlet 檔宣告,並加上對應的 url-pattern。

直接看程式。
<servlet>
  <servlet-name>jsp.WEB_002dINF.views.banner_jsp</servlet-name>
  <servlet-class>jsp.WEB_002dINF.views.banner_jsp</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>jsp.WEB_002dINF.views.banner_jsp</servlet-name>
  <url-pattern>/WEB-INF/views/banner.jsp</url-pattern>
</servlet-mapping>
/WEB-INF/views/banner.jsp 先轉檔成 Java Servlet,然後編譯成 class 檔,也就是 jsp.WEB_002dINF.views.banner_jsp,為了能存取,所以得在 web.xml 加上 <servlet> 與 <servlet-mapping>,這樣才能從原來的 jsp 路徑找到產生的 Java Servlet。

因此,JSP Precompile 有兩件事要做:
  • 將 JSP 轉成 Java Servlet,再編譯
  • 登錄到 web.xml

會很麻煩嗎?一點也不會!

問過 Google 之後,Maven 有 plugin 可以辦到,雖然久未更新,但是還可以在 Maven 3 的環境使用。
<plugin>
  <groupId>org.codehaus.mojo.jspc</groupId>
  <artifactId>jspc-maven-plugin</artifactId>
  <version>2.0-alpha-3</version>
  <executions>
    <execution>
      <goals>
        <goal>compile</goal>
      </goals>
    </execution>
  </executions>
  <!-- Use the Tomcat 6 JSP compiler -->
  <dependencies>
    <dependency>
      <groupId>org.codehaus.mojo.jspc</groupId>
      <artifactId>jspc-compiler-tomcat6</artifactId>
      <version>2.0-alpha-3</version>
    </dependency>
  </dependencies>
</plugin>
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-war-plugin</artifactId>
  <version>2.3</version>
  <configuration>
    <webXml>${pom.basedir}/target/jspweb.xml</webXml>
    <warSourceExcludes>**/*.jsp</warSourceExcludes>
  </configuration>
</plugin>
只要在 pom.xml 加上這兩個 plugin 就可以用 mvn package 輕輕鬆鬆產生一個水水的 war 檔,不只 jsp 編譯成 class 放到 classes 裡,連 web.xml 都改好了。

雖然 M2Eclipse 對第一個 plugin 設定有意見,但還是可以執行。

不過事情總是不會那麼美好,JSP 要能 Precompile 有個前提,就是 include 這件事,被 included 的 jsp 檔不能用到 including jsp 的變數,也就是說每一隻 JSP 都要能獨立存在,不能依賴其他 JSP 的變數,否則就會編譯不過,畢竟每一隻 JSP 都是獨立編譯的,基本上只要沒用到 Scriptlet 大抵都不會出錯。

編譯過程中還發生一個有趣的事情,發生錯誤說找不到 JSTL,一開始還以為版本問題,後來才發現是 Maven Dependency 設定的問題。
[ERROR] The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application -> [Help 1]
org.apache.jasper.JasperException: The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar files deployed with this application
 at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:51)
 at org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:409)
 at org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:116)
 at org.apache.jasper.compiler.TagLibraryInfoImpl.generateTLDLocation(TagLibraryInfoImpl.java:315)
 at org.apache.jasper.compiler.TagLibraryInfoImpl.<init>(TagLibraryInfoImpl.java:148)
 at org.apache.jasper.compiler.Parser.parseTaglibDirective(Parser.java:431)
 at org.apache.jasper.compiler.Parser.parseDirective(Parser.java:494)
 at org.apache.jasper.compiler.Parser.parseElements(Parser.java:1444)
 at org.apache.jasper.compiler.Parser.parse(Parser.java:138)
 at org.apache.jasper.compiler.ParserController.doParse(ParserController.java:216)
 at org.apache.jasper.compiler.ParserController.parse(ParserController.java:103)
 at org.apache.jasper.compiler.Compiler.generateJava(Compiler.java:154)
 at org.apache.jasper.compiler.Compiler.compile(Compiler.java:315)
 ...
JSTL 因為只有在執行時才會用到,所以 scope 設為 runtime,導致編譯 JSP 時找不到,只要將 scope 拿掉用預設值或者明定為 compile 就可以了。
---
---
---

沒有留言:

張貼留言