Servlet是一門用於開發動態web資源的技術。java
若想開發一個動態web資源,須要完成如下2個步驟:web
1)編寫一個Java類,實現servlet接口;apache
2)把開發好的Java類部署到web服務器中。api
Servlet快速入門案例tomcat
1.創建一個標準的JavaWeb應用目錄安全
FirstApp服務器
------ WEB-INF多線程
--------------classess併發
--------------libapp
--------------web.xml
2.進入classes目錄,創建一個文本文件
package cn.lsl.servlet; import java.io.IOException; import java.io.OutputStream; import javax.servlet.GenericServlet; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class FirstServlet extends GenericServlet { public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { OutputStream out = res.getOutputStream(); out.write("Hello Servlet".getBytes()); out.close(); } }
3.進入classes目錄,對FirstServlet進行編譯:
前提:把servlet-api.jar加入到你的構建路徑中.
set classpath=%classpath%;C:\apache-tomcat-6.0.35\lib\servlet-api.jar
執行:javac -d . FirstServlet.java
4.修改web.xml
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.5" 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_2_5.xsd"> <servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>cn.lsl.servlet.FirstServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/hello</url-pattern> </servlet-mapping> <welcome-file-list> <welcome-file>index.jsp</welcome-file> </welcome-file-list> </web-app>
5.部署應用到Tomcat中
6.訪問地址:http://localhost:8080/FirstApp/hello
7.Servlet的執行原理和過程圖
Servlet的生命週期
容器最終要調用service方法爲客戶端進行服務
1.Servlet接口中的經常使用方法:
public void init(ServletConfig config):初始化。Servlet類被實例化以後就會執行,且執行一次。 由容器進行調用
public void destroy():銷燬Servlet對象。由容器進行調用。
2.內存中一個Servlet只有一個實例。針對不一樣的用戶請求,容器採用多線程的機制調用service方法。
3.但願在應用被Tomcat加載完畢後(此時尚未任何人訪問),就實例化並完成初始化Servlet的工做?
在<Servlet>中配置上<load-on-startup>2</load-on-startup>
<servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>cn.lsl.servlet.FirstServlet</servlet-class> <load-on-startup>2</load-on-startup> </servlet>
Servelt接口實現類
1.Servlet接口定義了兩個默認實現類
GenericServlet和HttpServlet
2.HttpServlet指可以處理HTTP請求的servlet,它在原有Servlet接口上添加了一些與HTTP協議處理方法,它比Servlet接口的功能更爲強大。應該在編寫Servlet時,經過應該去繼承這個類。
3.HttpServlet在實現Servlet接口時,覆寫了service方法,該方法體內的代碼會自動判斷用戶的請求方式,如爲GET請求,則調用HttpServlet的doGet方法,如爲Post請求,則調用doPost方法。所以在編寫Servlet時,一般只須要覆蓋doGet或doPost方法,而不要去覆寫service方法。
eg:
package cn.lsl.servlet; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getOutputStream().write("hello servlet".getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
Servlet的映射
1.一個Servlet能夠被映射到多個URL地址上
2.URL地址映射還支持通配符*
方式一:以*開頭,以擴展名結尾<url-pattern>*.do</url-pattern>
方式二:以/前綴開頭,以*結尾。好比<url-pattern>/action/*</url-pattern>
2. 多個Servlet使用通配符時,有可能有多種
以"/"開頭(方式二)要比"*"開頭(方式一)優先級高
都以"/"開頭,仍是有多個匹配,找最匹配的
3. 若是一個Servlet的映射爲一個"/",就稱之爲默認的Servlet,它負責處理沒有映射路徑的URL請求的響應。
4.在<tomcat的安裝目錄>\conf\web.xml文件中,註冊了一個名稱爲org.apache.catalina.servlets.DefaultServlet的Servlet,並將這個Servlet設置爲了缺省Servlet。5.當訪問Tomcat服務器中的某個靜態HTML文件和圖片時,其實是在訪問這個缺省Servlet。
Servlet線程安全問題
當多個客戶端併發訪問同一個Servlet時,web服務器會爲每個客戶端的訪問請求建立一個線程,並在這個線程上調用Servlet的service方法,所以service方法內若是訪問了同一個資源的話,就有可能引起線程安全問題。
解決辦法:
1.在Servlet中定義變量,除非特殊要求,儘可能使用局部變量
2.若是有須要實例變量,應作同步處理,且同步代碼塊儘可能包圍少的代碼。
ServletConfig
做用:表明了Servlet配置中的參數信息。
eg:在web.xml中的參數配置以下信息
<servlet> <servlet-name>ServletDemo1</servlet-name> <servlet-class>cn.lsl.servlet.ServletDemo1</servlet-class> <init-param> <param-name>username</param-name> <param-value>zhangsan</param-value> </init-param> <init-param> <param-name>age</param-name> <param-value>23</param-value> </init-param> </servlet>
package cn.lsl.servlet; import java.io.IOException; import java.util.Enumeration; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo1 extends HttpServlet { private ServletConfig config; public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { test3(); } //獲取指定參數username的值 private void test1(){ String value = config.getInitParameter("username"); System.out.println(value); } //獲取全部的參數和參數的值 private void test2(){ Enumeration e = config.getInitParameterNames(); while(e.hasMoreElements()){ String paramName = (String)e.nextElement(); System.out.println(paramName+"="+config.getInitParameter(paramName)); } } //獲得servlet的名字 private void test3(){ String name = config.getServletName(); System.out.println(name); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } @Override public void init(ServletConfig config) throws ServletException { this.config = config; } }
ServletContext
1.在應用被服務器加載時就建立ServletContext對象的實例。每個JavaWeb應用都有惟一的一個ServletContext對象,它就表明着當前應用。
2.如何獲得ServletContext對象:ServletConfig.getServletContext();
3.做用
1)ServletContext對象是一個域對象(域對象就是說其內部維護了一個Map<String,Object>)
Object getAttribute(String name):根據名稱獲取綁定的對象
Enumeration getAttributeNames():獲取ServletContex域中的全部名稱
void removeAttribute(String name):根據名稱移除對象
void setAttribute(String name, Object value):添加或修改對象
2)實現多個Servlet之間的數據共享
eg:
實現ServletDemo2和ServletDemo3之間的數據共享
package cn.lsl.servlet; import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo2 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext(); sc.setAttribute("username", "zhangsan"); response.getOutputStream().write("OK".getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
package cn.lsl.servlet; import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo3 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext(); String name = (String)sc.getAttribute("username"); response.getOutputStream().write(name.getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
3)獲取WEB應用的初始化參數(應用的全局參數)
eg:
在web.xml中
<context-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </context-param>
package cn.lsl.servlet; import java.io.IOException; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo4 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext sc = getServletContext(); String value = sc.getInitParameter("encoding"); response.getOutputStream().write(value.getBytes()); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
4.讀取資源文件的三種方式
1)利用ServletContext.getRealPath():
特色:讀取應用中任何文件。只能在web環境下用
文件下載案例:
package cn.lsl.servlet; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class ServletDemo5 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { test2(response); } //英文名文件下載 private void test1(HttpServletResponse response) throws IOException{ //獲得要下載的文件 ServletContext sc = getServletContext(); String path = sc.getRealPath("/f.jpg"); //構建輸入流 InputStream in = new FileInputStream(path); //通知客戶端如下載的方式打開 response.setHeader("Content-Disposition", "attachment;filename=f.jpg"); response.setHeader("Content-Type", "application/octet-stream"); //二進制流 OutputStream out = response.getOutputStream(); int len = -1; byte b[] = new byte[1024]; while((len=in.read(b))!=-1){ out.write(b, 0, len); } in.close(); out.close(); } //中文名文件下載 private void test2(HttpServletResponse response) throws IOException{ //獲得要下載的文件 ServletContext sc = getServletContext(); String path = sc.getRealPath("/美女.jpg"); //截取文件名 String filename = path.substring(path.lastIndexOf("\\")+1); System.out.println(filename); //構建輸入流 InputStream in = new FileInputStream(path); //通知客戶端如下載的方式打開 //中文文件名此處要進行URL編碼 response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode(filename, "UTF-8")); response.setHeader("Content-Type", "application/octet-stream"); OutputStream out = response.getOutputStream(); int len = -1; byte b[] = new byte[1024]; while((len = in.read(b))!=-1){ out.write(b, 0, len); } in.close(); out.close(); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }
2)利用ResourceBundle讀取配置文件
特色:能夠在非web環境下。可是隻能讀取類路徑中的properties文件。
3)利用類加載器讀取配置文件
特色:能夠用在非web環境下。能夠讀取類路徑下的任何文件。
eg:
package cn.lsl.servlet; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import java.util.ResourceBundle; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; //讀取資源文件的三種方式 //a1.properties在WEB-INF下 //a2.properties在src下 //a3.properties在src/cn/lsl/resources下 public class ServletDemo6 extends HttpServlet { public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { test7(); } //利用ServletContext讀取a1.properties private void test1() throws FileNotFoundException, IOException{ ServletContext sc = getServletContext(); String path = sc.getRealPath("/WEB-INF/a1.properties"); Properties props = new Properties(); props.load(new FileInputStream(path)); String value = props.getProperty("username"); System.out.println(value); } //利用ServletContext讀取a2.properties private void test2() throws FileNotFoundException, IOException{ ServletContext sc = getServletContext(); String path = sc.getRealPath("/WEB-INF/classes/a2.properties"); Properties props = new Properties(); props.load(new FileInputStream(path)); String value = props.getProperty("username"); System.out.println(value); } //利用ServletContext讀取a3.properties private void test3() throws FileNotFoundException, IOException{ ServletContext sc = getServletContext(); String path = sc.getRealPath("/WEB-INF/classes/cn/lsl/resources/a3.properties"); Properties props = new Properties(); props.load(new FileInputStream(path)); String value = props.getProperty("username"); System.out.println(value); } //-------------------------------------- //利用ResourceBundle讀取配置文件a2.properties private void test4(){ ResourceBundle rb = ResourceBundle.getBundle("a2"); //基名 String value = rb.getString("username"); System.out.println(value); } //利用ResourceBundle讀取配置文件a3.properties private void test5(){ ResourceBundle rb = ResourceBundle.getBundle("cn.lsl.resources.a3"); String value = rb.getString("username"); System.out.println(value); } //-------------------------- //利用類加載器讀取配置文件a2.properties public void test6() throws IOException{ ClassLoader cl = ServletDemo6.class.getClassLoader(); InputStream in = cl.getResourceAsStream("a2.properties"); Properties props = new Properties(); props.load(in); String value = props.getProperty("username"); System.out.println(value); } //利用類加載器讀取配置文件a3.properties private void test7() throws IOException{ ClassLoader cl = ServletDemo6.class.getClassLoader(); InputStream in = cl.getResourceAsStream("cn/lsl/resources/a3.properties"); Properties props = new Properties(); props.load(in); String value = props.getProperty("username"); System.out.println(value); } public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { doGet(request,response); } }