javascript
Head First JSP---随笔三
作為Web應用
沒有servlet能獨立存在。當前現代Web應用中,許多之間都在一起協作共同完成一個目標。
Web容器模型
3.1 對于servlet和ServletContext初始化參數:編寫servlet代碼訪問初始化參數,創建部署描述文件元素來聲明初始化參數。
3.2 對于基本的servlet屬性作用域(請求、會話和上下文):編寫servlet代碼來增加、獲取和刪除屬性;給定一種使用場景,明確屬性適當地作用域;明確與各個作用域有關的多線程問題。
3.3 描述Web容器請求模型的元素:過濾器、過濾鏈、請求和響應包裝器,以及Web資源(servlet或JSP頁面)。
3.4 描述請求、會話和Web應用的Web容器生命周期事件模型;為每個作用域生命周期創建和配置監聽者類;創建和配置作用域屬性監聽者類;給定一個場景,明確要使用的適當的屬性監聽者。
3.5 描述RequestDispatcher機制;編寫servlet代碼來創建一個請求分派器;編寫servlet代碼轉發或包含目標資源;明確容器向目標資源提供的額外的請求作用域屬性。
不用硬編碼寫在servlet類中
解決之道分2步:
配置DD文件
<init-param><param-name>adminEmail</param-name><param-value>自己的郵箱</param-value> </init-param>在servlet中
getServletConfig().getInitParameter("adminEmail");這里指出,在servlet初始化(init)之前不能使用servlet初始化參數,因為此時還不是一個“真正的servlet”,并且只初始化一次。
ServletConfig的UML
測試ServletConfig
項目路徑如下:
DD文件如下:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><servlet><servlet-name>BeerParamTests</servlet-name><servlet-class>com.example.TestInitParams</servlet-class><init-param><param-name>adminEmail</param-name><param-value>likewecare@wickedlysmart.com</param-value></init-param><init-param><param-name>mainEmail</param-name><param-value>blooper@wickedlysmart.com</param-value></init-param></servlet><servlet-mapping><servlet-name>BeerParamTests</servlet-name><url-pattern>/Tester.do</url-pattern></servlet-mapping></web-app>Servlet文件如下:
package com.example;import javax.servlet.*; import javax.servlet.http.*; import java.io.*;public class TestInitParams extends HttpServlet {public void doGet(HttpServletRequest request,HttpServletResponse response) throws IOException, ServletException{response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("test init parameters<br>");java.util.Enumeration e = getServletConfig().getInitParameterNames();while(e.hasMoreElements()){out.println("<br>param name = "+e.nextElement()+"<br>");}out.println("main email is "+getServletConfig().getInitParameter("mainEmail"));out.println("<br>");out.println("admin email is "+getServletConfig().getInitParameter("adminEmail"));} }編譯連接:
放置部署環境下:
運行結果:
針對應用的初始化參數ServletContext(上下文)
DD文件:
<context-param><param-name>adminEmail</param-name><param-value>clientheaderror@wickedlysmart.com</param-value> </context-param>servlet代碼:
getServletContext().getInitParameter("adminEmail");ServletConfig與SevletContext區別
上下文初始化參數是<web-app ···></web-app>的孩子元素,應用于整個Web應用。
Servlet初始化參數是<servlet></servlet>的孩子元素,應用于相應的Servlet。
這樣,也說明了每個servlet有一個ServletConfig;每個Web應用有一個ServletContext。
這里注意:分布式應用中,每個JVM都有一個ServletContext。
ServletContext的UML
有兩種不同方式得到ServletContext
監聽者ServletContextListener
在應用為客戶提供服務之前運行的一些代碼。
例如,我們需要一個單獨的對象,它能做到:
上下文初始化(應用正在得到部署)時得到通知
- 從ServletContext得到上下文初始化參數
- 使用初始化參數查找建立一個數據庫連接
- 把數據庫連接存儲為一個屬性,使得Web應用的各個部分都能訪問
上下文撤銷(應用取消部署或結束)時得到通知
- 關閉數據庫連接
ServletContextListener的UML
一個簡單的ServletContextListener例子(思路)
在這里例子中,我們要把String初始化參數轉換為一個真正的對象——一個Dog
Dog例子:
- 監聽者對象向ServletContextEvent對象請求應用ServletContext對象的一個引用。 - 監聽者使用這個ServletContext引用得到“breed”的上下文初始化參數,這是一個String,表示狗的品種。 - 監聽者使用這個狗品種String構造一個Dog對象。 - 監聽者使用ServletContext引用在ServletContext中設置Dog屬性。 - 這個Web應用的測試servlet從ServletContext得到Dog對象,并調用這個Dog的getBreed()方法。例子實現
為了方便測試,我們將所有類放置同一包下。
開發環境:
Dog類:
package com.example;public class Dog{private String breed;public Dog(String breed){this.breed = breed;}public String getBreed(){return breed;} }ServletContextListener類:
package com.example;import javax.servlet.*;public class MyServletContextListener implements ServletContextListener{public void contextInitialized(ServletContextEvent event){ServletContext sc = event.getServletContext();String dogBreed = sc.getInitParameter("breed");Dog d = new Dog(dogBreed);sc.setAttribute("dog",d);}public void contextDestroyed(ServletContextEvent event){// nothing to do here} }Servlet類:
package com.example;import javax.servlet.*; import javax.servlet.http.*; import java.io.*;public class ListenerTester extends HttpServlet{public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException , ServletException{response.setContentType("text/html");PrintWriter out = response.getWriter();out.println("test context attributes set by listener<br>");out.println("<br>");Dog dog = (Dog) getServletContext().getAttribute("dog");if(dog==null)return;out.println("Dog's breed is: " + dog.getBreed());} }DD文件:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"id="WebApp_ID" version="3.0"><servlet><servlet-name>ListenerTester</servlet-name><servlet-class>com.example.ListenerTester</servlet-class></servlet><servlet-mapping><servlet-name>ListenerTester</servlet-name><url-pattern>/ListenTest.do</url-pattern></servlet-mapping><context-param><param-name>breed</param-name><param-value>Great Dane</param-value></context-param><listener><listener-class>com.example.MyServletContextListener</listener-class></listener></web-app>部署環境,并且啟動tomcat,結果如下:
更多的監聽者
| ServletContextAttributeListener | 你想知道一個Web應用上下文中是否增加,刪除或替補了一個屬性 | ServletContextAttributeEvent |
| HttpSessionListener | 你想知道有多少個并發用戶。也就是說,你想跟蹤活動的會話 | HttpSessionEvent |
| ServletRequestListener | 每次請求到來時你都想知道,以便建立日志記錄 | ServletRequestEvent |
| ServletRequestAttributeListener | 增加,刪除或替換一個請求屬性時你希望能夠知道 | ServletRequestAttributeEvent |
| HttpSessionBindingListener | 你有一個屬性類,而且你希望這個類型的對象綁定到一個會話或者從會話刪除時得到通知 | HttpSessionBindingEvent |
| HttpSessionAttributeListener | 增加、刪除或替補一個會話屬性時你希望能夠知道 | HttpSessionAttributeEvent |
| ServletContextListener | 你想知道是否創建或撤銷了一個上下文 | ServletContextEvent |
| HttpSessionActivationListener | 你有一個屬性類,而且你希望這個類型的對象在其綁定的會話遷移到另一個JVM時得到通知 | HttpSessionEvent |
這里注意最后一個不是HttpSessionActivationEvent。
屬性(attribute)與參數(parameter)
| 類型 | 應用/上下文、請求、會話 | 應用/上下文初始化參數、請求參數、Servlet初始化參數 |
| 設置方法 | setAttribute(String name, Object value) | 不能設置應用和Servlet初始化參數,請求可以 |
| 返回類型 | Object | String |
| 獲取方法 | getAttribute(String name) | getInitParameter(String name) |
上下文、請求和會話的作用域
上下文:
請求:
會話:
我們指出,上下文是線程不安全的,Session對于同一個客戶來說也是線程不安全的。
SMT(單例Servlet模型)
解決線程不安全問題,不過影響效率。
2種方法:
請求屬性和請求分派
我們經常向下面這么做:
requset.setAttribute("styles",result); request.getRequestDispatcher("result.jsp");RequestDispatcher揭密
RequsetDispatcher的UML
獲得RequestDispatcher的兩種辦法:
- 從ServletRequest得到RequestDispatcher
- 從ServletContext得到RequestDispatcher
分派方法:在RequestDispatcher上調用forward()
注意:這里指出,如果已經提交了響應,就不能再轉發請求!如下:
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException{response.setContentType("application/jar");ServletContext ctx = getServletContext();InputStream is = ctx.getResourceAsStream("bookCode.jar");int read = 0;byte[] bytes = new byte[1024];OutputStream os = response.getOutputStream();while((read = is.read(bytes))!=-1){os.write(bytes, 0, read);}os.flush();request.getRequestDispatcher("result.jsp").forward(request, response);os.close; }這樣會報一個大大的 IIIegalStateException 異常。
本章完
總結
以上是生活随笔為你收集整理的Head First JSP---随笔三的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 今日头条人群洞察报告
- 下一篇: B端产品经理如何更好的了解需求?