Servlet
(1)Servlet與Tomcat的關系
圖略
(2)概念
不能獨立運作,要依賴于Web容器的一種Java伺服器程式。
(3)Servlet開發的三種方式
需求:
1.進行Servlet開發,tomcat伺服器向用戶端發送資訊。
步驟:
1.建立web應用。
2.将Servlet部署到web.xml
1. 實作Servlet接口
public class FirstServlet implements Servlet
{ //該函數用于Servlet初始化,并将其裝載記憶體中
//該函數隻運作一次,需要在server.xml檔案中進行配置<load-on-start>.
public void init(ServletConfig config)throws ServletException
{ }
//得到ServletConfig對象
public ServletConfig getServletConfig()
{ }
//該函數是服務函數,業務邏輯代碼就是在這裡編寫
//每次啟動服務都會調用該函數
//當調用doGet或者doPost才構造ServletRequest和ServletResponse對象
public void service(ServletRequest req,ServletResponse res)
throws ServletException,java.io.IOException
{ }
//擷取Servlet的配置資訊
public java.lang.String getServletInfo()
{ }
//該函數用于銷毀Servlet
//隻運作一次
public void destroy(){ }
}
2. 繼承GenericServlet
相對于Servlet來說,是需要繼承server函數即可。
GenericServlet抽象類,給出了一些設計servlet的一些骨架,定義了servlet的生命周期,還有一些得到的名字,配置初始化參數的方法,其設計是和應用層協定無關的。
3. 繼承HttpServlet(常用)
public class FirstHttpServlet extends HttpServlet
{
//兩個底層都代用了server函數
//Http協定中的get請求和post請求
//與<form action="送出給?" method="get ro post?"/>中有關
protected void doGet(HttpServletRequest req,HttpServletResonse resp)
throws ServletException,java.io.IOException
{
resp.getWriter().println("HttpServlet");
}
protected void doPost(HttpServletRequest req,HttpServletResonse resp)
throws ServletException,java.io.IOException
{
resp.getWriter().println("HttpServlet");
}
}
(4)Servlet細節
1. Servlet的部署
<!—進行servlet的注冊-->
<!-在android開發中的每個Activity都必須要注冊—>
<servlet>
<!--servlet-name 可以自定義,但是預設為類名-->
<servlet-name>MyServlet</servlet-name>
<!--servlet-class 用于指定servlet存放在哪一個包中(包名+類名),一定要明确-->
<servlet-class>name.liushiyao.myservlet.MyServlet</servlet-class>
</servlet>
<!-- servlet 的映射(對一個已經注冊的Servlet的映射)-->
<!--一個注冊号的Servlet可以被多次映射-->
<servlet-mapping>
<!-- 該servlet-name 一定要去上面的servlet-name 相同-->
<servlet-name>MyServlet</servlet-name>
<!--url 的資源檔案名(斜杠必須有)-->
<url-pattern>/ab</url-pattern>
</servlet-mapping>
注:
1. 如果url中沒有加“/”運作時會出現錯誤。
2.在IDEA中(應該是JavaEE6的新特性,使用了annotation),可以使用@WebServlet(name = “LastTime”, urlPatterns ={“/LastTime”,”/LastTime2”})進行WebServlet的映射,且可以實作多對一映射,而不需要在web.xml中進行注冊。
2. 通配符
1) /*
2) *.拓展名
注:1)比2)優先級高。
3. 單例多線程
當Servlet被第一通路後,就被加載到記憶體中,以後該執行個體對各個請求都是用的是同一個内容。JSP也是單例模式。
servlet是多線程的,沒有采用同步機制,是不安全的。同一個Servlet可以同時處理多個用戶端的請求,比如同時有兩個使用者A和使用者B登入時,會啟動兩個負責登入的Servlet線程,并通過觸發Service方法來處理請求。在兩個線程中,接收到的使用者名是不同的,也就是說,多線程裡的Servlet,可能其中的變量不相同。
4. servlet中的配置
需求:當我們的網站啟動的時候,可能會要求初始化一些資料(建立臨時表),或者要求定時備份資料,發送郵件。
解決辦法:可以通過<load-on-startup>配合,線程知識搞定。
通過配置<load-on-startup>,啟動一個servlet中的init函數,且隻運作一次。
在web.xml檔案中進行配置
<!-- 配置init啟動的優先級(必須配置,否者init()不會執行) -->
<load-on-startup>1</load-on-startup>
<!—數值代表啟動的順序-->
【模拟定時發送電子郵件】
//用于發送電子郵件的線程
public class Send extends Thread
{
@Override
public void run() {
int count = ;
while(true)
{
try {
//====每隔10s發送電子郵件
Thread.sleep(*);
System.out.println("第"+(++count)+"份郵件被發送");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//使用init函數進行線程的啟動
public void init() throws ServletException {
// Put your code here
System.out.println("ServletInit 的init函數運作。。。");
Send send = new Send();
send.start();
}
ServletConfig對象
1. 用途
用于讀取Servlet的一些配置資訊。
在web.xml檔案中。
<!-- 使用UTF-8編碼 -->
<!-- 局部servlet有效 -->
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
注:String contextString = this.getServletConfig.getInitParameter(“encoding”);
要使被所有的servlet讀取,應該在之外定義:
<!—所有servlet有效 -->
<context-param>
<param-name></param-name>
<param-value></param-value>
</context-param>
注:通過String contextString = this.getServletContext().getInitParameter(“encode”);擷取
因為該屬性屬于全局變量,而ServletContext也是屬性全局的,是以要通過getServletContext擷取,而不是通過getServletConfig擷取。
【擷取ServletConfig中的資料】
1. 擷取單一的資料在Servlet中
response.setContentType("text/html;charset=utf-8");//預設編碼
PrintWriter printWriter = response.getWriter();
//擷取param參數内容
String encodingString = this.getServletConfig().getInitParameter("encoding");
request.setCharacterEncoding(encodingString);
printWriter.println(encodingString);
printWriter.close();
- 擷取所有的資料
//擷取所有的param的enum對象
Enumeration<String> enum1 = this.getServletConfig().getInitParameterNames();
while (enum1.hasMoreElements()) {
String string = (String) enum1.nextElement();
System.out.println(string);
System.out.println(this.getServletConfig().getInitParameter(string));
}
HttpResponse對象
所有的資訊多會封裝到response中,傳回給web服務。web伺服器會将response資訊進行拆解,形成http相應資訊,傳回給浏覽器。
1. getWrite();與getOutputStream()
注:一個是字元流,一個是位元組流。雖然說兩者可以互相轉換,但是針對不同的資料針對性的使用。
兩個流不能同時使用。否則會出現如下異常:
java.lang.IllegalStateException: getWriter() has already been called for this response
org.apache.catalina.connector.Response.getOutputStream(Response.java:605)
org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:197)
name.liushiyao.userlogin.Download.doGet(Download.java:37)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
注:會自動關閉IO,是以不能同時出現getWrite();getOutputStream();
2. sendRedirect();
sendRedirect( 重定向)發生在浏覽器的跳轉,伺服器根據邏輯,發送一個狀态碼,告訴浏覽器去重新請求那個位址。
實作界面的跳轉,并可以随帶字元串資訊。
1. 實作跳轉:
//執行調轉到登入成功界面(java中其中一種跳轉方式)
//"/web應用名/servlet"
response.sendRedirect("/UserLogin/MainFrame");
- 攜帶字元串資訊:
response.sendRedirect("/UserLogin/MainFrame?uname="+
name+"&upassword="+password
注:url與字元串資訊之間通過“?”進行連接配接。
不同的字元串之間通過“&”連接配接。
sendRedirect不能實作對象的傳遞。但是可以通過session傳遞(也不能說是“傳遞”,隻是在伺服器記憶體中存儲的session)。
User u = new User(name,password);
request.getSession().setAttribute("u",u);
- 擷取對象:
User us = (User)request.getSession().getAttribute("u");
out.println(us.getName()+"||"+us.getPassword());
HttpRequest對象
該對象表示浏覽器的請求,即http請求資訊。但web伺服器等到該請求後,會把浏覽器請求的資訊封裝成HttpRequest對象。是以可以通過該對象擷取使用者的各種請求資訊。
1. getRequestURL();
String uri = request.getRequestURI();
String url = request.getRequestURL().toString();
System.out.println("uri"+uri);
System.out.println("url"+url);
輸出:
uri /RequestDemo/RequestInfo
url http://localhost:8080/RequestDemo/RequestInfo
2. getQueryString();
以GET方法擷取參數資訊(參數+值)。
String quary = request.getQueryString();
System.out.println("query:"+quary);
輸出:
query:name=123
注:這個的參數時url後面帶的所有資訊,而request.getParameter(“age”);則是當個屬性所帶的值
3. getRemoteAddr();
可以擷取使用者的ip位址。(利用該函數可進行ip封殺)
4. getRemotePort();
擷取使用者的端口。
int localport = request.getLocalPort();
int port = request.getRemotePort();
System.out.println("localport:"+localport);
System.out.println("port:"+port);
5. getParameterValues();
獲得傳過來的參數名相同的一個數組;
String[] string = request.getParameterValues(“checkbox”);
6. getRequestDispatcher();
request轉向函數。
request.getRequestDispatcher("/MainFrame").forward(request,
response);
實作原理:
- sendReDirect與forward的差別?
forward(轉向):發生在伺服器的跳轉,伺服器請求資源,直接通路目标位址的URL,把URL的響應再發送給浏覽器,浏覽器根本不知道伺服器發送的内容是從哪裡來的,是以位址欄中的URL還是原來的。
答:(1)叫法不同:sendReDirect()叫重定向(轉發);forward叫轉向。
(2)實際發送的位置不同:sendReDirect發生在浏覽器;forward發生在伺服器
(3)用法不同:response.sendReDirect(“/web應用/資源URI”);需要加‘/web應用名’(根據其原理可以知道)
request.getRequestDispather(“/資源URI”).forward(request,response);
不需要加web應用名
(4)範圍不同:sendReDirect 與浏覽器之間
forward 與web伺服器之間。
注:1.所謂的一次http請求:就是沒有重回到浏覽器或者重新啟動則叫為“一次http請求”。
2.request.setAttribute(“key”,”123”);//存儲此請求中的屬性。在請求之間重置屬性。此方法常常與 RequestDispatcher 一起使用。
3. //效果同request.getRequestDispather request.getServletContext().getRequestDispatcher(“/OtherServlet”).forward(request,response);
4. 使用sendReDirect可以防止重新整理帶來的再次通路servlet(因為sendReDirect需要web應用名)
Cookie
1. 概念
cookie是用戶端技術,伺服器把每個使用者的資料以cookie的形式寫給使用者各自的浏覽器。 Cookie包含屬性(String)和值(String)。
注:1. Cookie隻能儲存字元串(鍵值對)
2. 用戶端在發送Http請求時,會攜帶該Web應用的Cookie。
3. Cookie必須設定setMaxAge,否則Cookie在浏覽器關閉時被銷毀(setMaxAge(0)則銷毀Cookie)。
4. 可以被多個浏覽器共享。
5. 如果Cookie重名,會覆寫之前的資料。
6. 當web建立多個Cookie時,會儲存在同一個檔案中,并且存在時間可以不一樣。
7. 建立Cookie時禁止使用“ 空格、逗号”等。
2. Cookie的用途
賬号和密碼的儲存(需要加密)、使用者的喜好、設定等等。
3. Cookie的限制
一個浏覽器隻能存放300個Cookie,一個web站點最多存儲20個Cookie,且 每個大小限制在4K。
4.禁用Cookie
如果使用者禁用Cookie,可以使用URL重寫技術跟蹤回話。
5. Cookie的生命周期
Cookie的生命周期指的是累積時間,即從開始建立時間到設定的結束時間的長度。
Session
1. 概念
Session(域對象)是伺服器端技術,當使用者打開浏覽器,通路伺服器。伺服器為每一個浏覽器提供一個Session對象。 Session包含屬性(String)和值(Object)。
注:1. 隻要不關閉浏覽器,不同的頁面就會處于同一個Session中,而這個Session預設的生存時間是1800s(30分鐘,可以在web.xml中修改)。
2. session是存放在伺服器的記憶體中的
3. session被特定的一個浏覽器所獨享
4. 當同一個session中的屬性名相同時則會覆寫前一個屬性值
2. Session的生命周期
- 在web.xml中可以進行生存時間的設定
<session-config>
<session-timeout>20</session-timeout>
</session-config>
-
使用httpSession.setMaxInactiveInterval(60);
//該時間設定的是“發呆時間”—使用者沒有操作Session的時間
- 當關閉或重新開機Tomcat時都會删除Session(Session是儲存在記憶體中的)或者使用 invalidate(); 删除Session中所有的屬性和對象(強制性的,用于安全退出)
-
單獨删除一個對象
httpSession.removeAttribute(“name”);
3. Session的原理
伺服器如何為特定的浏覽器配置設定特定的Session?
答:通過ID
實作流程:
1. 當浏覽器第一次通路Servlet時,Cookie中是沒有攜帶JSESSIONID
(Cookie JSESSIONID=D7561FE5F83BACF4E0091BCDADE04078),
2. 通路Servlet之後,會生成Session并配置設定Session ID,通過Cookie寫入浏覽器中;
3. 當使用者再次通路Servlet,http請求會攜帶帶有JSESSIONID的cookie,此時伺服器就能準确的知道該浏覽器是與那個Session相關聯的。
6. Cookie與Session的差別?
①存在的位置不同:
Cookie:存在用戶端(臨時檔案夾)
Session:存在伺服器的記憶體中(一個Session域對象為一個使用者浏覽器服務)
②安全性
Cookie:是以明文方式存放在用戶端,安全性較弱(可以通過加密的方式進行加密)
Session:是存在伺服器中的記憶體中,安全性較強。、
③網絡通信量
Cookie:會傳遞資訊給伺服器(每次在Http請求中都會攜帶Cookie,是以會增加網絡壓力)(是以擷取Cookie時是從Request中擷取 的)
Session:session是存在伺服器的記憶體中的,是以不存在網絡通信壓力問題。
④生命周期
Cookie:是累積時間,即為絕對時間
Session:是“發呆時間”,即相對時間(當浏覽器沒有對session進行操作時的間隔時間)。session失效是指無法通路session的屬性(API解釋:使此會話無效,然後取消對任何綁定到它的對象的綁定。)。相關應用(安全退出)
⑤通路範圍
Cookie:浏覽器共享
Session:浏覽器獨享
注:Session會占用伺服器的記憶體,是以要根據實際情況進行取舍。
ServletContext
1. 概念
Web容器在啟動時,它會為每一個Web應用程式都建立一個對應的ServletContext對象,它代表web應用。
注:可以被多個使用者共享(同一個Web應用中的所有Servlet)
2. 擷取ServletContext
//方法一(通過this)
ServletContext servletContext = this.getServletContext();
//方法二(通過getServletConfig)
ServletContext servletContext1 = this.getServletConfig().getServletContext();
3. 添加ServletContext屬性
servletContext.setAttribute(“name”,”劉石堯”);
4. 讀取ServletContext屬性
String string = (String) servletContext.getAttribute(“name”);
5. 删除ServletContxt 屬性
if (servletContext.getAttribute(“name”) != null){
servletContext.removeAttribute(“name”);
out.println(“已删除 name”);
}
6. 使用ServletContext的使用原則
需要資料共享,而且存儲的大小不大又不想出入資料庫,可以使用ServletContext。
7. ServletContext的生命周期
ServletContext是長期存放在伺服器中的記憶體中的,所有不将過大的資料存放在ServletContext中。
8.擷取web.xml中的設定參數
會話跟蹤
會話跟蹤是一種靈活,輕便的機制,使Web上的狀态變成成為可能。
可是使用session,Cookie,位址重寫和隐藏域實作。
JSP
JSP九大内置對象
内置對象 | 對象名稱 | 類型 | 作用域 |
---|---|---|---|
request | 請求對象 | javax.servlet.ServletReques | Request |
response | 響應對象 | javax.servlet.SrvletResponse | Page |
pageContext | 頁面上下文對象 | javax.servlet.jsp.PageContext | Page |
session | 會話對象 | javax.servlet.http.HttpSession | Session |
application | 應用程式對象 | javax.servlet.ServletContext | Application |
out | 輸出對象 | javax.servlet.jsp.JspWriter | Page |
config | 配置對象 | javax.servlet.ServletConfig | Page |
page | 頁面對象 | javax.lang.Object | Page |
exception | 例外對象 | javax.lang.Throwable | page |
注:“exception” 對象則代表了JSP檔案運作時所産生的例外對象,此對象不能在一般JSP檔案中直接使用,而隻能在使用了“<%@ page isErrorPage=”true “%>”的JSP檔案中使用。
作用域
作用域 | 範圍 | 說明 |
---|---|---|
page | 有效範圍隻在目前jsp頁面裡 | 從把變量放到pageContext開始,到jsp頁面結束,你都可以使用這個變量。 |
request | 有效範圍是目前請求周期 | 所謂請求周期,就是指從http請求發起,到伺服器處理結束,傳回響應的整個過程。在這個過程中可能使用forward的方式跳轉了多個jsp頁面,在這些頁面裡你都可以使用這個變量。 |
session | 有效範圍是目前會話 | 所謂目前會話,就是指從使用者打開浏覽器開始,到使用者關閉浏覽器這中間的過程。這個過程可能包含多個請求響應。也就是說,隻要使用者不關浏覽器,伺服器就有辦法知道這些請求是一個人發起的,整個過程被稱為一個會話(session),而放到會話中的變量,就可以在目前會話的所有請求裡使用。 |
application | 有效範圍是整個應用 | 整個應用是指從應用啟動,到應用結束。我們沒有說“從伺服器啟動,到伺服器關閉”,是因為一個伺服器可能部署多個應用,當然你關閉了伺服器,就會把上面所有的應用都關閉了。 |
application作用域裡的變量,它們的存活時間是最長的,如果不進行手工删除,它們就一直可以使用。
注:application裡的變量可以被所有使用者共用。如果使用者甲的操作修改了application中的變量,使用者乙通路時得到的是修改後的值。這在其他scope中都是不會發生的,page, request,session都是完全隔離的,無論如何修改都不會影響其他人的資料。
jsp注釋
1. <%-- JSP中的注釋,看不見 --%>
2. // 注釋,看不見
3. /*
注釋,看不見
*/
4. <!--顯式注釋-->
JSP文法
腳本
<% java代碼 %>:在<%%>中定義局部變量或者調用方法,但不能定義方法。
<%!%>:可以在<%!%>中聲明方法、屬性、全局變量。
<%=%>:稱作jsp表達式,用于将已經聲明的變量或者表達式輸出到網頁上面。
include指令
靜态include:
從外部引入一個jsp檔案(隻含指令和内容本身,不需要body等其他内容),編譯成同一個servlet。屬于靜态引入。
動态include:
<jsp:include />
注:動态引入,會翻譯成兩個servlet。是以被引入的檔案可以包含等内容。