public class TestServelt { public static void main(String[] args) { ChildServlet childServlet = new ChildServlet(); childServlet.service(); } } class FatherServlet{ public void service(){ System.out.println("父類service"); doGet(); } public void doGet(){ System.out.println("父類goGet"); } } class ChildServlet extends FatherServlet{ public void service(){ System.out.println("子類service"); super.service(); } public void doGet(){ System.out.println("子類goGet"); } }
1、初始化階段 調用init()方法
2、響應客戶請求階段。調用service()方法,由service()方法根據提交的方式選擇執行doGet()或者doPost()方法
3、終止階段 調用destroy()方法--關閉tomcat的時候
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.myServlet</servlet-class>
<load-on-startup>1</load-on-startup> 啟動tomcat的時候初始化當前servlet 調用init,數字越小越先加載
</servlet>
<context-param>
<param-name>context/param</param-name>
<param-value>avalible during application</param-value>
</context-param>
參數通過getServletContext().getInitParameter("context/param")獲取
<servlet>
<servlet-name>MainServlet</servlet-name>
<servlet-class>com.wes.controller.MainServlet</servlet-class>
<init-param>
<param-name>param1</param-name>
<param-value>avalible in servlet init()</param-value>
</init-param>
<load-on-startup>0</load-on-startup>
</servlet>
只能在servlet的init()方法中通過this.getInitParameter("param1")獲取
Servlet不是線程安全的。 要解釋為什么Servlet為什么不是線程安全的,需要了解Servlet容器(即Tomcat)使如何響應HTTP請求的。 當Tomcat接收到Client的HTTP請求時,Tomcat從線程池中取出一個線程,之后找到該請求對應的Servlet對象並進行初始化,之后調用service()方法。要注意的是每一個Servlet對象再Tomcat容器中只有一個實例對象,即是單例模式。如果多個HTTP請求請求的是同一個Servlet,那么着兩個HTTP請求對應的線程將並發調用Servlet的service()方法。 上圖中的Thread1和Thread2調用了同一個Servlet1,所以此時如果Servlet1中定義了實例變量或靜態變量,那么可能會發生線程安全問題(因為所有的線程都可能使用這些變量)。 比如下面的Servlet中的 name 和 i變量就會引發線程安全問題。 import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.Date; public class ThreadSafeServlet extends HttpServlet { public static String name = "Hello"; //靜態變量,可能發生線程安全問題 int i; //實例變量,可能發生線程安全問題 SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); @Override public void init() throws ServletException { super.init(); System.out.println("Servlet初始化"); } @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.printf("%s:%s[%s]\n", Thread.currentThread().getName(), i, format.format(new Date())); i++; try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.printf("%s:%s[%s]\n", Thread.currentThread().getName(), i, format.format(new Date())); resp.getWriter().println("<html><body><h1>" + i + "</h1></body></html>"); } } 在Tomcat中啟動這個Servlet並在瀏覽器發起多個HTTP訪問,最后會發現變量 i 是多線程共享的。 如果需要更加深入透徹地了解Tomcat接收HTTP的細節,以及與Servlet交互的細節,可以深入看看Tomcat的架構和源碼。
jsp 9大內置對象
1.request對象
2.response對象
3.session對象
4.out對象
- out對象是JspWriter類的實例,是向客戶端輸出內容常用的對象
5.page對象
- page對象就是指向當前JSP頁面本身,有點象類中的this指針,它是
- java.lang.Object類的實例
- 序號方法說明
- classgetClass 返回此Object的類
- inthashCode() 返回此Object的hash碼
- booleanequals(Objectobj) 判斷此Object是否與指定的Object對象相等
- voidcopy(Objectobj) 把此Object拷貝到指定的Object對象中
- Objectclone() 克隆此Object對象
- StringtoString() 把此Object對象轉換成String類的對象
- voidnotify() 喚醒一個等待的線程
- voidnotifyAll() 喚醒所有等待的線程
- voidwait(inttimeout) 使一個線程處於等待直到timeout結束或被喚醒
- voidwait() 使一個線程處於等待直到被喚醒
- voidenterMonitor() 對Object加鎖
- voidexitMonitor() 對Object開鎖
6.application對象
application對象實現了用戶間數據的共享,可存放全局變量。它開始於服務器
的啟動,直到服務器的關閉,在此期間,此對象將一直存在;這樣在用戶的前
后連接或不同用戶之間的連接中,可以對此對象的同一屬性進行操作;在任何
地方對此對象屬性的操作,都將影響到其他用戶對此的訪問。服務器的啟動和
關閉決定了application對象的生命。它是ServletContext類的實例。
7.exception對象
exception對象是一個例外對象,當一個頁面在運行過程中發生了例外,就產
生這個對象。如果一個JSP頁面要應用此對象,就必須把isErrorPage設為true,
否則無法編譯。他實際上是Java.lang.Throwable的對象
8.pageContext對象
pageContext對象提供了對JSP頁面內所有的對象及名字空間的訪問,也就是
說他可以訪問到本頁所在的SESSION,也可以取本頁面所在的application的
某一屬性值,他相當於頁面中所有功能的集大成者,它的本類名也叫
pageContext。
9.config對象
config對象是在一個Servlet初始化時,JSP引擎向它傳遞信息用的,此信息包括Servlet初始化時所要用到的參數(通過屬性名和屬性值構成)以及服務器的有關信息(通過傳遞一個ServletContext對象)
HttpSession
是基於Cookie 實現的
HttpSession的創建時間
jsp中 顯示調用時會創建session
servlet 中調用 request.getSession時會創建session
自定義標簽
<?xml version="1.0" encoding="UTF-8" ?> <taglib 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-jsptaglibrary_2_1.xsd" version="2.1"> <description>testjsp 1.1 core library</description> <display-name>testjsp core</display-name> <tlib-version>1.1</tlib-version> <short-name>testjsp</short-name> <uri>http://tj.com/testjsp</uri> <tag> <!-- 描述 HelloSimpleTag的名稱--> <name>hello</name> <tag-class>com.tag.TestJspFragment</tag-class> <body-content>scriptless</body-content>
<attribute>
<name>value</name>
<!-- 是否必須 -->
<required>true</required>
<!-- 是否支持EL表達式 -->
<rtexprvalue>true</rtexprvalue>
</attribute>
<!-- 標簽體 --> <!-- 沒有標簽體 --> <!-- <body-content>empty</body-content> --> <!-- 不經過處理直接把內容交給標簽處理器類 --> <!-- <body-content>tagdependent</body-content> --> <!-- 可以有EL${} 不可以有<%=%> 大部分情況下取值為scriptless--> <body-content>scriptless</body-content> </tag> </taglib>
public class TestJspFragment extends SimpleTagSupport{
@Override
public void doTag() throws JspException, IOException {
//當定義標簽體的時候會調用setJspBody(JspFragment arg0) {
//把JspFragment傳遞過來
JspFragment fragment = getJspBody();
StringWriter sw = new StringWriter();
//若為NULL輸出到頁面 等同於fragment.invoke(getJspContext().getOut());
fragment.invoke(sw);
//把內容寫到sw中
String content = sw.toString().toUpperCase();
//把內容轉換成大寫寫入到頁面
getJspContext().getOut().print(content);
}
}
//InputStream inputStream = pageContext.getServletContext().getResourceAsStream("src");//根路徑
//如果有標簽體就會調用此方法,把JspFragment傳過來
public void setJspBody(JspFragment arg0) {
System.out.println("setJspBody");
}
public void setParent(JspTag arg0) {
//父標簽獲取不到子標簽,子標簽可以獲取到父標簽的引用
System.out.println("setParent");
//arg0指的就是父標簽的引用,需要強轉
}
/*Cookie cookie = new Cookie("name", "aaaa"); //cookie 的作用范圍默認為當前文件路徑的子目錄 cookie.setPath("/");//站點的根目錄 cookie.setMaxAge(30);//最大秒數,存在磁盤對應當前瀏覽器,同一個站點最多存20個cookie,每個cookie最大4k //客戶端第一請求時 服務端給客戶端返回一個cookie 在請求頭中set-cookie //第二次客戶端訪問服務端會帶着cookie response.addCookie(cookie);*/ //response.encodeURL("session/a.jsp"); response.encodeUrl("session/a.jsp");//實現URL的重寫,在后邊加上;jeesessionid=331232131321 //服務端獲取客戶端cookie /*Cookie []cookies = request.getCookies(); if(cookies!=null){ for (Cookie coo : cookies) { System.out.println(coo.getName()+":"+coo.getValue()); } }*/
//http://localhost:8080/spring1/IndexServlet String method = request.getServletPath();//IndexServlet try { Method me = getClass().getDeclaredMethod("add", request.getClass(),response.getClass()); me.invoke(this, request,response); //cs.getDeclaredMethod("add", null).invoke(this, null); } catch (Exception e) { e.printStackTrace(); }
自定義標簽函數
之前例子已經寫好了,由於時間關系一直沒有發布,這次帶來的是關於taglib中的<tag>的基本功能已經介紹完畢了,在taglib中我們發現有一個標簽叫做<function>,這次簡單介紹<function>標簽的基本用法,<function>標簽可以做什么呢?它可以讓我們在jsp用直接調用某個方法,根據自定義的方法返回指定的值,兼容jstl標簽,省去了在jsp中直接使用<%!%>來定義方法體再調用的繁瑣.如果你用過el語言的話估計會很快上手,其實<function>標簽就是一個擁有方法體的el語言.注意:function所定義的方法必須需要是靜態的,如果不是靜態的話jstl是不能識別所定義的方法.
Java代碼如下:
package org.lxh.taglib;
import java.util.List; public class FunctionTag { public static String hello(String name) { return name; } public static Integer bbq(List list) { return list.size(); } }
方法必須靜態,可以定義有返回值或者void類型的方法.
tld:
<?xml version="1.0" encoding="UTF-8" ?> <taglib xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0"> <tlib-version>1.0</tlib-version> <short-name>my</short-name> <uri>http://lauedward.spaces.live.com</uri> <function> <!--EL頁面調用名字--> <name>hello</name> <!--指定標簽的處理類,指定了標簽由哪個Java類來處理。--> <function-class>org.lxh.taglib.FunctionTag</function-class> <!--指定EL頁面調用名字中實際調用的方法.指定處理類的實際方法.參數和回調函數要寫完整路徑--> <function-signature>java.lang.String hello(java.lang.String)</function-signature> </function> <function> <name>bbq</name> <function-class>org.lxh.taglib.FunctionTag</function-class> <function-signature>java.lang.Integer bbq(java.util.List)</function-signature> </function> </taglib>
注意:在<function-signature>需要寫完整的類名,假如是String類型的話就必須寫java.lang.String這樣字,不支持泛型的定義如java.util.List<java.lang.String>eclipse會把<>當作xml的格式來判斷的,所以就省略該泛型的定義.
jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib prefix="my" uri="/WEB-INF/tld/testFunction.tld"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@page import="java.util.*"%><html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
List<String> list = new ArrayList<String>();
list.add("aa");
list.add("bb");
list.add("cc");
request.setAttribute("list", "helloword");
request.setAttribute("name", list);
Map map = new HashMap();
map.put("1","a");
map.put("2","b");
map.put("3","c");
map.put("4","d");
%>
<br>
${my:hello(list)}
<br>
${my:bbq(name)}
<br>
</body>
</html>
注意:調用方法的時候必須類型要傳入相同類型的值,否則的話會報錯,不過對於方法體是String的話,是可以傳入list,set,map那些,因為傳入后會直接調用list的.toString()方法直接當字符串輸出.
HttpSessionListener
HttpSessionAttributeListener
ServletContextListener
web.xml 的加載順序是:context-param -> listener -> filter -> servlet ,而同個類型之間的實際程序調用的時候的順序是根據對應的 mapping 的順序進行調用的。