Java Servlet Spec 寫得還真是精簡(陽春?),得配合 Java Docs 才免強奏齊拼圖。
web.xml
以前寫 Servlet,得先寫一隻 Servlet class,然後再到 web.xml 加上定義與設定 URL Pattern。現在 web.xml 這段省了,不用寫任何 Servlet 資訊到 web.xml。
<?xml version="1.0" encoding="UTF-8"?> <web-app 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-app_3_0.xsd" version="3.0"> <display-name>Servlet 3.0</display-name> </web-app>只要直接寫 Servlet class 就可以了>
兩個原則:
- 第一、繼承 HttpServlet。
- 第二,加上 @WebServlet,並設定 value 或 urlPatterns。
@WebServlet("/servlet1") public class Servlet1 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello Servlet 1!"); } }這樣就可以用 /servlet1 連到了。
value or urlPatterns
前面第一種 @WebServlet 用法為捷徑,設定的是 value 屬性,標準用法如下。@WebServlet(name = "Servlet2", urlPatterns = "/servlet2") public class Servlet2 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello Servlet 2!"); } }@WebServlet 至少要有 urlPatterns 或者 value 兩者之一,作用相同,但不能同時有,其他屬性都是非必要。
Spec 建議只設定 url 屬性,不需要設定其他屬性時,用 value;需要設定 url 以外的屬性時,用 urlPatterns。
urlPatterns 可以同時指定多個值,如以下作法,/servlet3a 與 /servlet3b 都可以連到 Servlet3。
@WebServlet(name = "Servlet3", urlPatterns = { "/servlet3a", "/servlet3b" }) public class Servlet3 extends HttpServlet { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello Servlet 3!"); } }
loadOnStartup
@WebServlet 也有 loadOnStartup 屬性,預設為 -1。設定 loadOnStartup 為 20。
@WebServlet(urlPatterns = "/servlet4a", loadOnStartup = 20) public class Servlet4a extends HttpServlet { public Servlet4a() { super(); System.out.println("loadOnStartup at 20 with servlet4a"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello Servlet 4a!"); } }設定 loadOnStartup 為 10。
@WebServlet(urlPatterns = "/servlet4b", loadOnStartup = 10) public class Servlet4b extends HttpServlet { public Servlet4b() { super(); System.out.println("loadOnStartup at 10 with servlet4b"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello Servlet 4b!"); } }不設定 loadOnStartup,使用預設值 -1。
@WebServlet(urlPatterns = "/servlet4c") public class Servlet4c extends HttpServlet { public Servlet4c() { super(); System.out.println("loadOnStartup at -1 with servlet4c"); } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.getWriter().write("Hello Servlet 4c!"); } }啟動 Tomcat 後,尚未開啟任何連結前,可以在 console 看到
loadOnStartup at 10 with servlet4b loadOnStartup at 20 with servlet4a開啟連結 /servlet4c,才會看到
loadOnStartup at -1 with servlet4c所以當 loadOnStartup 不設定或者設為 -1 時,啟動 Tomcat 時是不會初始化該 Servlet 的,只有在設定 loadOnStartup 為正值時,才會在 Tomcat 啟動時初始化,不然就得等到第一次連結發生時。
initParams
@WebServlet 也可以設定 initParameter,是透過另一個 Annotation @WebInitParam 設定的。@WebServlet(urlPatterns = "/servlet5", initParams = @WebInitParam(name = "name", value = "neil"))
public class Servlet5 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("Hello Servlet 5 - " + this.getServletConfig().getInitParameter("name") + "!");
}
}
特別要注意的是取用 initParameter 的方法。疑?Tomcat 怎麼知道要去哪找 Servlet 呢?
按照 Spec 說法,WEB-INF/classes 與 WEB-INF/lib/*.jar 兩個地方都會找(怪?還有其他地方可以放嗎)。但是,若是在 web.xml 裡的 web-app 加上 metadata-complete=true 的屬性,那 Tomcat 就不會去找 Annotation 了,完全只看 web.xml 裡的設定。
<?xml version="1.0" encoding="UTF-8"?> <web-app 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-app_3_0.xsd" version="3.0" metadata-complete="true"> <display-name>Servlet 3.0</display-name> </web-app>metadata-complete 預設為 false。
web.xml 與 @WebServlet 同時使用
如果同一個 Servlet class 的 name 屬性不相同,那就會同時存在兩個不同 name 的 instance。但是如果同一個 Servlet class 的 name 屬性相同,那麼 web.xml 的設定會蓋過 @WebServlet,也就是 web.xml 的 url-pattern 會蓋掉 @WebServlet 的 urlPatterns。
Spec 上提到,除了 web.xml 與 @WebServlet 可以建立 Servlet,還可以動態建立 Servlet,就是寫程式立刻產生,在這種情況下,同名的話當然是程式建立的 Servlet 倖存。
Server push
Spec 裡還提到 @WebServlet 還有一個神奇的屬性,asyncSupported,據說可以讓 Server 一直一直一直灌資料給 client,這太艱深了,改天再研究。最後,解釋一下一開始說得,為何 @WebServlet 幫助不大,因為現在沒有人會在一個 Web Application 裡寫一堆 Servlet。
多半搭配 Web Framework,這樣只要一隻 Servlet 就將所有 request 轉到 Web Framwork 裡處理了。
而且這一隻 Servlet 還是 Web Framework 提供的,根本沒機會用 @WebServlet。
---
---
---
沒有留言:
張貼留言