JSR-168 定義了 Portlet 的標準 Java API,遵循此規範開發的 Portlet 具備跨入口網站伺服器的可攜性,並易於透過 WSRP (Web Services for Remote Portlets) 進行內容聯合。本文整理開發符合 JSR-168 規範 Portlet 的七大關鍵實踐。
錯誤寫法:<img src="/<%= request.getContextPath()%>/images/logo.gif"/>
正確寫法:
<img src="<%= renderResponse.encodeURL(renderRequest.getContextPath() + "/images/logo.gif") %>"/>
encodeURL() 可接受絕對路徑 URI 或完整 URL。傳入 encodeURL() 的 URL 必須是完整的。編碼後不可再拼接字串。
// 正確
<%= renderResponse.encodeURL(renderRequest.getContextPath() + "/images/logo.gif") %>
// 錯誤:編碼後再拼接
<%= renderResponse.encodeURL(renderRequest.getContextPath() + "/images/") + "logo.gif" %>
錯誤範例會產生類似 .../images/;PORTAL_TAU=...logo.gif 的無效連結。
避免同頁多個 Portlet 的 JavaScript 函式名稱衝突。使用 <portlet:namespace/> 標籤產生唯一識別碼。
<%@taglib uri="https://java.sun.com/portlet" prefix="portlet"%>
<script>
function validate<portlet:namespace/>(foo) {
if (foo.bar.value == "") return false;
return true;
}
</script>
<form onsubmit="return validate<portlet:namespace/>(this);">...</form>
JavaScript 中預載圖片等靜態資源的 URL,必須透過 encodeURL() 處理,且腳本必須寫在 JSP 或 Portlet 類中,不可置於獨立 .js 檔案。
<script>
function <portlet:namespace/>preloadImages() {
var menuImage = new Image();
menuImage.src = "<%=renderResponse.encodeURL(renderRequest.getContextPath() + "images/icon.gif")%>";
}
</script>
規範要求呼叫 RenderResponse.setContentType()。WebLogic Portal 等容器若未設定內容類型將拒絕執行 Portlet。
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
PrintWriter writer = response.getWriter();
writer.println("I set my content type!");
}
JSR-168 規範規定在 HttpServletResponse 上呼叫 addCookie() 無效。跨請求持久化資料請使用 Portlet Session;長期持久化請存入資料庫、LDAP 或檔案系統。
採用 MVC 架構(如 Struts、Spring Portlet MVC、WebWork)或至少將邏輯委派給 JSP:
public void doView(RenderRequest request, RenderResponse response)
throws PortletException, IOException {
response.setContentType("text/html");
request.setAttribute("foo", "bar");
PortletRequestDispatcher dispatcher = getPortletContext().getRequestDispatcher("/pages/portal.jsp");
dispatcher.include(request, response);
}
JSR-168 的委派機制雖可分離關注點,但成熟框架能提供更完善的開發體驗。
遵循上述原則,可確保 Portlet 符合 JSR-168 規範,實現跨 Java 入口網站伺服器的可攜性,並便於透過 WSRP 進行內容聯合。