什么是servlet
Servlet(Server Applet)是Java Servlet的簡稱,是小服務程序或服務連接器,是用Java編寫的服務器端程序,主要功能在于交互式地瀏覽和修改數據,生成動態Web內容.
狹義的Servlet是指Java語言實現的一個接口,廣義的Servlet是指任何實現了這個Servlet接口的類,一般情況下,人們將Servlet理解為后者。
第一個servlet
Sun公司在其API中提供了一個servlet接口,用戶若想開發一個動態web資源(即開發一個Java程序向瀏覽器輸出數據),需要完成以下2個步驟:
編寫一個Java類,實現servlet接口。
把開發好的Java類部署到web服務器中。
?
首先,我們要編寫一個類,實現Servlet接口:
方法介紹
init( )
Servlet第一次被請求,Servlet容器就會開始調用這個方法初始化一個Servlet對象,但是這個方法在后續請求中不會在被Servlet容器調用。我們可以利用init( )方法來執行相應的初始化工作。調用這個方法時,Servlet容器會傳入一個ServletConfig對象進來從而對Servlet對象進行初始化。
service( )
每當請求Servlet時,Servlet容器就會調用這個方法。
第一次請求時,Servlet容器會先調用init(),然后調用service( ),在后續的請求中,Servlet容器只調用service方法。
destory
當要銷毀Servlet時,Servlet容器就會調用這個方法,在卸載應用程序或者關閉Servlet容器時,就會發生這種情況,一般在這個方法中會寫一些清除代碼。
另外兩個:
? ? getServletInfo( ),這個方法會返回Servlet的一段描述,可以返回一段字符串。
? ? getServletConfig( ),這個方法會返回由Servlet容器傳給init()方法的ServletConfig對象。
生命周期
Servlet是一個供其他Java程序(Servlet引擎)調用的Java類,它不能獨立運行,它的運行完全由Servlet引擎來控制和調度。
針對客戶端的多次Servlet請求,通常情況下,服務器只會創建一個Servlet實例對象,也就是說Servlet實例對象一旦創建,它就會駐留在內存中,為后續的其它請求服務,直至web容器退出,servlet實例對象才會銷毀。
在Servlet的整個生命周期內,Servlet的init方法只被調用一次。而對一個Servlet的每次訪問請求都導致Servlet引擎調用一次servlet的service方法。對于每次訪問請求,Servlet引擎都會創建一個新的HttpServletRequest請求對象和一個新的HttpServletResponse響應對象,然后將這兩個對象作為參數傳遞給它調用的Servlet的service()方法,service方法再根據請求方式分別調用doXXX方法。
? 實例化-->初始化-->服務->銷毀
出生:(實例化-->初始化)第一次訪問Servlet就出生(默認情況下)
活著:(服務)應用活著,servlet就活著
死亡:(銷毀)應用卸載了servlet就銷毀。
如果在<servlet>元素中配置了一個<load-on-startup>元素,那么WEB應用程序在啟動時,就會裝載并創建Servlet的實例對象、以及調用Servlet實例對象的init()方法。
? 舉例:
? <servlet>
? <servlet-name>invoker</servlet-name>
? <servlet-class>org.apache.catalina.servlets.InvokerServlet</servlet-class>
? <load-on-startup>2</load-on-startup>
? </servlet>
l用途:為web應用寫一個InitServlet,這個servlet配置為啟動時裝載,為整個web應用創建必要的數據庫表和數據。
xml
由于客戶端是通過URL地址訪問web服務器中的資源,所以Servlet程序若想被外界訪問,必須把servlet程序映射到一個URL地址上這個工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。
<servlet>元素用于注冊Servlet,它包含有兩個主要的子元素:<servlet-name>和<servlet-class>,分別用于設置Servlet的注冊名稱和Servlet的完整類名。
一個<servlet-mapping>元素用于映射一個已注冊的Servlet的一個對外訪問路徑,它包含有兩個子元素:<servlet-name>和<url-pattern>,分別用于指定Servlet的注冊名稱和Servlet的對外訪問路徑。例如:
編寫文件中的<servlet>\<servlet-mapping>節點。
<web-app><servlet><servlet-name>AnyName</servlet-name><servlet-class>HelloServlet</servlet-class></servlet><servlet-mapping><servlet-name>AnyName</servlet-name><url-pattern>/demo/hello.html</url-pattern></servlet-mapping>
</web-app>
?網址找到文件的過程就是這樣的啦
至此,servelet訪問過程大體完成:
Servlet?接口實現類
Servlet接口SUN公司定義了兩個默認實現類,分別為:GenericServlet、HttpServlet。
Servlet --> GenericServlet --> HttpServlet? (繼承HttpServlet)
HttpServlet指能夠處理HTTP請求的servlet,它在原有Servlet接口上添加了一些與HTTP協議處理方法,它比Servlet接口的功能更為強大。因此開發人員在編寫Servlet時,通常應繼承這個類,而避免直接去實現Servlet接口。
HttpServlet在實現Servlet接口時,覆寫了service方法,該方法體內的代碼會自動判斷用戶的請求方式,如為GET請求,則調用HttpServlet的doGet方法,如為Post請求,則調用doPost方法。因此,開發人員在編寫Servlet時,通常只需要覆寫doGet或doPost方法,而不要去覆寫service方法。
ServletRequset接口
????Servlet容器對于接受到的每一個Http請求,都會創建一個ServletRequest對象,并把這個對象傳遞給Servlet的Sevice( )方法。其中,ServletRequest對象內封裝了關于這個請求的許多詳細信息。
讓我們來看一看ServletRequest接口的部分內容:
public interface ServletRequest {int getContentLength();//返回請求主體的字節數String getContentType();//返回主體的MIME類型String getParameter(String var1);//返回請求參數的值}
其中,getParameter是在ServletRequest中最常用的方法,可用于獲取查詢字符串的值。
ServletResponse接口
????javax.servlet.ServletResponse接口表示一個Servlet響應,在調用Servlet的Service()方法前,Servlet容器會先創建一個ServletResponse對象,并把它作為第二個參數傳給Service()方法。ServletResponse隱藏了向瀏覽器發送響應的復雜過程。
????讓我們也來看看ServletResponse內部定義了哪些方法:
public interface ServletResponse {String getCharacterEncoding();String getContentType();ServletOutputStream getOutputStream() throws IOException;PrintWriter getWriter() throws IOException;void setCharacterEncoding(String var1);void setContentLength(int var1);void setContentType(String var1);void setBufferSize(int var1);int getBufferSize();void flushBuffer() throws IOException;void resetBuffer();boolean isCommitted();void reset();void setLocale(Locale var1);Locale getLocale();
}
?
???其中的getWriter方法,它返回了一個可以向客戶端發送文本的的Java.io.PrintWriter對象。默認情況下,PrintWriter對象使用ISO-8859-1編碼(該編碼在輸入中文時會發生亂碼)。
??在向客戶端發送響應時,大多數都是使用該對象向客戶端發送HTML。
還有一個方法也可以用來向瀏覽器發送數據,它就是getOutputStream,從名字就可以看出這是一個二進制流對象,因此這個方法是用來發送二進制數據的。
在發送任何HTML之前,應該先調用setContentType()方法,設置響應的內容類型,并將“text/html”作為一個參數傳入,這是在告訴瀏覽器響應的內容類型為HTML,需要以HTML的方法解釋響應內容而不是普通的文本,或者也可以加上“charset=UTF-8”改變響應的編碼方式以防止發生中文亂碼現象。
跳轉
我們的網頁可能會跳轉到其他頁面,怎么實現這個功能呢?有兩種方法:
轉發
重定向
他倆是什么意思呢。
舉個例子:a給b打電話,聊了一會說,我找c。
這時候,b說,行,我給你轉接到c手里,這就是轉發。
這時候,b說,行,我給你c的電話號碼,你自己打過去吧,然后a掛了電話給c打,這叫重定向。
?請求轉發
–request.getRequestDispatcher(" targetURL").forward(request, response);
?請求重定向
–response.sendRedirect("targetURL")
轉發是把請求轉發給別人,重定向是發回給用戶,用戶發一個新的請求給新的servlet。
轉發:
?
是服務器跳轉,是同一個請求在服務器端傳遞,瀏覽器根本不知道發生了轉發操作。
重定向:
是給用戶一個新的地址,用戶根據新的地址發送新的請求。
?
總結異同點:
相同點:都實現了跳轉
不同點:
1、語法不同(廢話)
2、跳轉后,轉發可以得到request里的內容,重定向得不到
3、地址欄路徑不同,轉發地址不變,重定向就是新的地址了。
4、原理不同,轉發:就一個請求,重定向:兩個
5、效率:轉發>重定向(顯而易見)
6、跳轉范圍不同:轉發只能是當前項目,重定向隨便
7、
寫的路徑不同:
轉發不能寫絕對路徑,重定向可以;
轉發寫根路徑不寫上下文路徑,代表當前項目根目錄,重定向根路徑需要寫上下文路徑,代表當前服務器;
建議都是用根路徑。
8、轉發會導致表單的重復提交,重定向不會。(刷新的話,轉發是之前的地址,刷新就。。。)
9、轉發不經過過濾器,重定向會經過(可以設置,讓轉發經過)
跳轉方式的選擇
必須的四種:
希望前后共享request,轉發。
跳轉到同一個WEB-INF目錄下,只能轉發。(因為不能直接訪問里面,只能轉發請求進去,重定向本質就是發了一個新請求,不可能)
跳到不同項目,只能重定向。。。(廢話)
使用cookie存數據后要跳,只能重定向。轉發后還沒有呢。。(這個以后再說)
更優的四種:
轉發效率高,盡量使用轉發
但是使用轉發需要解決重復提交表單問題。
注銷之后一般用重定向
連續表單頁面應使用重定向,盡量避免屬性沖突
?
總體流程的例子
前三行為了解決中文亂碼問題
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//設置請求編碼格式req.setCharacterEncoding("utf-8");//設置相應編碼格式resp.setCharacterEncoding("utf-8");resp.setContentType("text/html;charset=utf-8");//獲取請求信息//處理請求信息FlowerService fs=new FlowerServiceImpl();List<Flower> lf=fs.getFlowerInfoService();//響應結果req.setAttribute("lf", lf);req.getRequestDispatcher("/show.jsp").forward(req, resp); }