Web子產品支援為子產品化開發、架構使用提供了巨大的友善,例如需要在Web應用中使用Web架構,這就隻要将該架構的JAR包複制到Web應用中即可。因為這個Jar包的META—INF目錄下可以通過web-fragment.xml檔案來配置該架構所需要的服務和資源等,進而避免修改已經有的應用。Web子產品支援對于子產品化開發也有很大的幫助,開發都可以将不同子產品的Web元件部署在不同的子產品中,進而避免所有子產品的配置、部署資訊都寫在Web.xml檔案中,這對以後的更新、維護将更加友善。
子產品化的3大特點:
1、允許在沒有架構配置的情況下使用架構
—— 為您的應用程式保留Web.xml
—— 将架構配置工作放在架構這邊
2、允許架構将它們的Web.xml存儲在自己的JAR中
—— 在應用程式啟動期間合并它們
3、Web.xml的分段概念
從上面的3大特點,我們可以看出,Servlet3.0子產品化,就是把Web.xml分段,然後把分段的web-fragment.xml配置和資源打成Jar包,
然後在Web容器在啟動時,動态加載這個子產品的web-fragment.xml到web.xml中。
子產品化的資源構成:
<webModule>.jar Web子產品是jar包,結構如下:
|—— META-INF
|—— web-fragment.xml
|—— resources (可選,可呈現的資源,例如:jsp,圖檔等,在這裡還可以再建子目錄,這個目前相當于父項目的webapp目錄,如果出現同目錄同檔案的情況,會顯示父目錄的檔案,是以大家要注意這方面,注意檔案名和目錄的命名)
|—— Java代碼
|—— 子產品功能的相關配置檔案
在這裡我不去介紹web-fragment.xml的結構,因為這個檔案與Web.xml幾乎是一樣的,下面在給出例子的時候,會在例子中的web-fragment.xml中
添加了說明,到時一看就明了。
下面我們以一個實踐來舉例說明,當然我們的例子是最簡單的,重點的講解Web子產品的知識:
1、在這裡我們需要建立2個Web子產品,一個是beforemodule,它提供了檢視線上使用者的功能,差別登入使用者或者遊客,在這個子產品中有4個檔案:
web-fragmemnt.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment id="WebFragment_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">
<display-name>beforemodule</display-name>
<!-- 指定該Web子產品的唯一辨別 -->
<name>beforemodule</name>
<listener>
<listener-class>Web.listener.OnlineListener</listener-class>
</listener>
<welcome-file-list>
<welcome-file>/Web/jsp/online.jsp</welcome-file>
</welcome-file-list>
<ordering>
<!-- 用于配置該Web子產品必須位于哪些子產品之前加載 -->
<before>
<!-- 用于指定于其他所有子產品之前加載 -->
<others/>
</before>
</ordering>
</web-fragment>
OnlineListener.java:
public class OnlineListener implements ServletContextListener
{
//模拟儲存使用者名和最近的通路時間
public static Map<String,Long> map = new HashMap<String,Long>();
//超過該時間(10分鐘)沒有通路本站即認為使用者已經離線
public final int MAX_MILLIS = 10 * 60 * 1000;
//這裡隻是一個加載配置檔案的示例,隻是為了說明配置檔案應該放在那個目錄
private Properties properties = new Properties();
@Override
public void contextInitialized(ServletContextEvent arg0)
{
try
{
//使用目前的Class的ResourceAsStream即可得到該檔案
properties.load(this.getClass().getResourceAsStream("/config.properties"));
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
//第5秒檢查一次
new javax.swing.Timer(1000 * 5, new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
System.out.println(properties.getProperty("username")+"==================");
Set<String> keys = map.keySet();
String username = "";
Iterator<String> iter = keys.iterator();
while(iter.hasNext())
{
username = iter.next();
//如果距離上交通路時間超過了指定時間
if(System.currentTimeMillis() - map.get(username) > MAX_MILLIS)
{
//則超過的使用者删除
map.remove(username);
}
}
}
}).start();
}
@Override
public void contextDestroyed(ServletContextEvent arg0)
{
// TODO Auto-generated method stub
}
}
online.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ page import="Web.listener.OnlineListener,java.util.*" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>線上使用者</title>
</head>
<body>
<table>
<%
Set<String> keys = OnlineListener.map.keySet();
String username = "";
Iterator<String> iter = keys.iterator();
while(iter.hasNext())
{
username = iter.next();
%>
<tr><td>使用者名</td><td><%=username==null?"遊客":username %></td><td>時間</td><td><%=OnlineListener.map.get(username) %></td></tr>
<%
}
%>
</table>
</body>
</html>
config.properties
username=lyndon
編譯成Jar包後,放到一個已經存在的Web項目中的WEB-INF/lib檔案夾下,(大家可以放在/ROOT/WEB-INF/lib工程下)
2、一個aftermodule子產品,它提供了使用者登入頁面,監聽使用者請求的功能。在這個子產品中有3個檔案:
web-fragment.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-fragment id="WebFragment_ID" version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd">
<display-name>aftermodule</display-name>
<name>aftermodule</name>
<listener>
<listener-class>org.after.listener.RequestListener</listener-class>
</listener>
<ordering>
<!-- 用于配置該子產品位于那個子產品後加載 -->
<after>
<!-- 指定該子產品是位于beforemodule配置後加載 -->
<name>beforemodule</name>
</after>
</ordering>
</web-fragment>
RequestListener.java:
public class RequestListener implements ServletRequestListener
{
@Override
public void requestInitialized(ServletRequestEvent arg0)
{
HttpServletRequest request = (HttpServletRequest)arg0.getServletRequest();
HttpSession session = request.getSession();
//從Session擷取Username,如果存在,則是登入使用者,為Null則為遊客
String username = (String) session.getAttribute("username");
System.out.println(username);
//每通路一次,更新一次通路時間
OnlineListener.map.put(username, System.currentTimeMillis());
}
@Override
public void requestDestroyed(ServletRequestEvent arg0)
{
// TODO Auto-generated method stub
}
}
request.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>通路頁面</title>
</head>
<body>
<%
String username = request.getParameter("username");
if (null != username)
{
session.setAttribute("username", username);
}
if (null == session.getAttribute("username"))
{
%>
<FORM action="/app/request.jsp" method="post">
<INPUT type="text" id="username" name="username" value="" /> <INPUT
type="submit" value="送出" />
</FORM>
<%
}
else
{
%>
<span><%=session.getAttribute("username")%>,你好</span>
<%
}
%>
</body>
</html>
編譯成Jar包後,放到一個已經存在的Web項目中的WEB-INF/lib檔案夾下
要注意上面2個的順序,因為在web-fragment.xml中指定的前後順序,先放beforemodule,再放aftermodule,重新開機Web容器,即可。
如果檢視效果,不斷打開IE,然後通路requst.jsp,然後關閉浏覽器,再打開再做重複的動作,因為在這裡我們是用session來判斷不同的使用者的,是以當多次登入後,
然後再打開online.jsp頁面,就會看到線上使用者了,過了10分鐘後,再檢視online.jsp,就會看到一些使用者過時了。
最近把代碼傳上,因為我是使用Maven建立的項目,是以目錄是按Maven的要求的文檔目錄放的,但是POM.xml編譯後,打成Jar包後,結構是正确的,如果想自己
編譯,需要同學會Maven基本知識。
http://lyndon-lin.iteye.com/blog/1879609