Servlet概述
Servlet是由SUN公司提供的動(dòng)態(tài)web資源開(kāi)發(fā)技術(shù), 本質(zhì)上是一段java程序, 這段java程序無(wú)法獨(dú)立運(yùn)行, 必須放在Servlet容器(比如: tomcat服務(wù)器)中, 由容器調(diào)用才可以執(zhí)行!
[toc]
-
簡(jiǎn)單開(kāi)發(fā)一個(gè)Servlet程序
1.開(kāi)發(fā)步驟
(1).寫一個(gè)類,實(shí)現(xiàn)一個(gè)Servlet接口,并添加未實(shí)現(xiàn) 的方法
(2).將編譯后類,放在WEB應(yīng)用中,并在WEB應(yīng)用web.xml文件中配置Servlet對(duì)外訪問(wèn)的虛擬路徑,將WEB應(yīng)用部署到虛擬主機(jī)中即可
2.開(kāi)發(fā)過(guò)程
(1)需求
瀏覽器向服務(wù)器發(fā)送一個(gè)請(qǐng)求, 訪問(wèn)FirstServlet, FirstServlet將表示當(dāng)前時(shí)間的字符串發(fā)送瀏覽器
(2)創(chuàng)建一個(gè)FirstServlet.java文件
(3)編寫FirstServlet類
- 實(shí)現(xiàn)Servlet接口(或繼承Servlet接口的子類),并添加未實(shí)現(xiàn)的方法(java_ee_api文檔)
- 實(shí)現(xiàn)Servlet中提供的處理請(qǐng)求方法service方法, 將表示當(dāng)前時(shí)間的字符串響應(yīng)給瀏覽器
- 添加servlet類的包路徑和導(dǎo)入依賴包
package com.zn.servlet;
import java.io.*;
import java.util.*;
import javax.servlet.*;
public class FirstServlet extends GenericServlet{
public void service(ServletRequest req, ServletResponse res)
throws ServletException, java.io.IOException{
String datastr = new Date().toLocaleString();;
res.getWriter().write(datastr);
}
}
(4)編譯FirstServlet類
在cmd窗口通過(guò)命令編譯出現(xiàn)報(bào)錯(cuò)信息:
E:\>javac FirstServlet.java
FirstServlet.java:4: 錯(cuò)誤: 程序包javax.servlet不存在
import javax.servlet.*;
^
FirstServlet.java:6: 錯(cuò)誤: 找不到符號(hào)
public class FirstServlet extends GenericServlet{
^
原因是 javax.servlet這個(gè)包不存在, 所有下面出現(xiàn)了很多找不到符號(hào)錯(cuò)誤.
在tomcat服務(wù)器的lib目錄下有servlet的jar包, 可以設(shè)置包路徑:
設(shè)置包路徑
E:\>set classpath=...\apache-tomcat-7.0.53\lib\servlet-api.jar
再次編譯
/*帶包編譯:
進(jìn)入到FirstServlet.java所在路徑
命令: javac -d . FirstServlet.java
其中: -d是帶包編譯
點(diǎn)(.)表示編譯后的class存放在當(dāng)前目錄下*/
E:\>javac -d . FirstServlet.java
(5)將FirstServlet類放在WEB應(yīng)用中, 并在web.xml文件中配置Servlet對(duì)外訪問(wèn)的虛擬路徑
- 將編譯好的class文件(包括包路徑)放在web應(yīng)用的classes目錄下
- 在WEB應(yīng)用的web.xml文件中配置servlet對(duì)外訪問(wèn)的虛擬路徑:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app 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_3_0.xsd"
version="3.0"
metadata-complete="true">
<welcome-file-list>
<welcome-file>login.html</welcome-file>
</welcome-file-list>
<!-- servlet settings -->
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>com.zn.servlet.FirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/FirstServlet</url-pattern>
</servlet-mapping>
</web-app>
(7)將WEB應(yīng)用部署到虛擬主機(jī)中, 啟動(dòng)服務(wù)器, 通過(guò)瀏覽器訪問(wèn)FirstServlet
-
Servlet繼承結(jié)構(gòu)
Servlet接口 – 通用的Servlet接口,提供了一個(gè)Servlet應(yīng)該具有的功能
|
|-- GenericServlet類, 實(shí)現(xiàn)了Servlet接口
并實(shí)現(xiàn)了其中的大部分的方法,但是service方法沒(méi)有實(shí)現(xiàn),
|
|-- HttpServlet類,實(shí)現(xiàn)了service方法
在service方法中, 判斷請(qǐng)求方式
根據(jù)不同的請(qǐng)求方式xxx調(diào)用不同doXxx
|
|-- XxxServlet類, 在開(kāi)發(fā)中,
繼承HttpServlet,
并覆蓋doGet和doPost方法,
來(lái)處理GET請(qǐng)求和POST請(qǐng)求
-
Servlet調(diào)用過(guò)程
開(kāi)發(fā)一個(gè)Servlet, 放在WEB應(yīng)用中, 并將WEB應(yīng)用部署在服務(wù)器中, 啟動(dòng)服務(wù)器, 通過(guò)瀏覽器訪問(wèn)Servlet, 可以訪問(wèn)到Servlet處理的結(jié)果, 這個(gè)Servlet是如何被調(diào)用的, Servlet又是如何執(zhí)行的?
Servlet調(diào)用過(guò)程.png
1.Servlet生命周期
Servlet在第一次被訪問(wèn)時(shí)創(chuàng)建Servlet實(shí)例, 創(chuàng)建之后服務(wù)器會(huì)立即調(diào)用init方法進(jìn)行初始化的操作
創(chuàng)建之后, Servlet實(shí)例會(huì)一直駐留在服務(wù)器的內(nèi)存中, 為后續(xù)的請(qǐng)求服務(wù). 只要有請(qǐng)求來(lái)訪問(wèn)這個(gè)Servlet, 服務(wù)器就會(huì)調(diào)用service方法來(lái)處理請(qǐng)求, 直到服務(wù)器關(guān)閉, 或者WEB應(yīng)用被移出容器
隨著WEB應(yīng)用的銷毀, Servlet實(shí)例也會(huì)跟著銷毀, 在銷毀之前服務(wù)器會(huì)調(diào)用destroy方法進(jìn)行善后的處理
-
Servlet開(kāi)發(fā)細(xì)節(jié)
1.Servlet虛擬路徑的配置
Servlet在web.xml文件中虛擬路徑的配置方式可以有兩種方式:
(1) 直接寫一個(gè)路徑
后期需要通過(guò) /FirstServlet這個(gè)路徑來(lái)訪問(wèn)該Servlet
<!-- servlet settings -->
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>com.zn.servlet.FirstServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/FirstServlet</url-pattern>
</servlet-mapping>
(2) 還可以使用星號(hào)(*)匹配符來(lái)配置一個(gè)路徑,配置的方式有兩中:
- 以斜杠(/)開(kāi)頭恶复,以斜杠星(/*)結(jié)尾
/* , /a/* ...
- 以星點(diǎn)后綴(*.后綴)的形式
*.html , *.abc, *do...
使用星號(hào)匹配符可以使得路徑的訪問(wèn)變得更加靈活倘感, 但是也可能會(huì)導(dǎo)致一個(gè)url會(huì)被多個(gè)mapping所匹配奈惑。路徑的優(yōu)先級(jí)規(guī)則是什么筷登?
(1)哪一個(gè)更接近(更精準(zhǔn)绍刮、更像)哪一個(gè)起作用
(2)*.后綴的優(yōu)先級(jí)永遠(yuǎn)最低.
-
Request
代表HTTP請(qǐng)求的對(duì)象览爵。瀏覽器向服務(wù)器發(fā)送一個(gè)請(qǐng)求烈拒,服務(wù)器在調(diào)用Servlet的service方法處理請(qǐng)求之前嚷量,會(huì)創(chuàng)建代表Http請(qǐng)求的request對(duì)象陋桂,將所有的請(qǐng)求信息封裝在request對(duì)象中。
1.Request的繼承結(jié)構(gòu)
ServletRequest -通用的Request接口蝶溶,提供一個(gè)Request對(duì)象應(yīng)該具有的功能
|
|-- HttpServletRequest接口 -
繼承了ServletRequest接口,
在父接口的基礎(chǔ)上,
HttpServletRequest增加了一些和Http協(xié)議相關(guān)的方法
2.Request對(duì)象提供的功能
(1)獲取客戶端基本信息嗜历、獲取請(qǐng)求頭信息
/** Request獲取客戶機(jī)的基本信息、獲取請(qǐng)求頭信息
* @author: zn
* @time: 2018年8月16日,上午10:13:20
*/
public class RequestDemo1 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//1.getRemoteAddr() -- 獲取ip地址
String ip = request.getRemoteAddr();
System.out.println("ip:"+ip);
//2.getContxtPath() --獲取web應(yīng)用虛擬路徑
String path = request.getContextPath();
System.out.println("path:"+path);
//3.getHader() --獲取請(qǐng)求頭信息
String host = request.getHeader("host");
System.out.println("host:"+host);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}
(2)獲取請(qǐng)求參數(shù)
header 1 | header 2 |
---|---|
getParameter(String name) | 通過(guò)請(qǐng)求參數(shù)的名字獲取對(duì)應(yīng)的參數(shù)值 |
getParameterValues(String name) | |
getParameterMap() | |
getParameterNames() |
請(qǐng)求參數(shù)亂碼問(wèn)題
在通過(guò)request對(duì)象獲取請(qǐng)求參數(shù)時(shí), 如果參數(shù)中有中文數(shù)據(jù), 在獲取時(shí)就會(huì)出現(xiàn)亂碼, 其原因是由于瀏覽器發(fā)送參數(shù)時(shí)(編碼時(shí))使用的碼表 和 服務(wù)器在結(jié)束數(shù)據(jù)時(shí)(解碼時(shí))使用的碼表不一致造成的.
解決方案:讓編碼時(shí)使用的碼表和解碼時(shí)使用的碼表保持一致即可
- 手動(dòng)編解碼解決亂碼抖所,通用梨州,適應(yīng)POST和GET
(1)根據(jù)獲取的亂碼字符串,反向編碼得回正確的二進(jìn)制數(shù)據(jù)(iso8859-1)
(2) 將二進(jìn)制數(shù)組查詢utf-8碼表轉(zhuǎn)成字符串, 得回正確的數(shù)據(jù)
- 如果請(qǐng)求方式是POST,可以通過(guò)request提供的方法解決
(1)request.setCharacterEncoding(“utf-8”);//這行代碼是通知服務(wù)器使用utf-8來(lái)接收請(qǐng)求
(2)必須放在任何獲取參數(shù)代碼之前田轧,否則無(wú)法生效
(3)GET提交的參數(shù)在請(qǐng)求行中的請(qǐng)求資源路徑后面拼接著, 不在請(qǐng)求實(shí)體內(nèi)容中,所有這行代碼對(duì)GET提交產(chǎn)生的亂碼不會(huì)起作用!
/** 通過(guò)Request獲取請(qǐng)求參數(shù)
* @author: zn
* @time: 2018年8月16日,上午10:33:44
*/
public class RequestDemo2 extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
/**
* 通知服務(wù)器使用UTF-8接收請(qǐng)求實(shí)體內(nèi)容中的數(shù)據(jù),對(duì)POST提交的亂碼起作用
*/
request.setCharacterEncoding("utf-8");
//獲取用戶名
String username = request.getParameter("username");
//獲取用戶昵稱
String nickname = request.getParameter("nickname");
System.out.println("username:"+username+"\nnickname:"+nickname);
//獲取愛(ài)好
String[] likes = request.getParameterValues("like");
System.out.println("likes"+Arrays.toString(likes));
//================= GET亂碼解決 =======================//
byte[] bytes = username.getBytes("iso8859-1");
username = new String(bytes,"utf-8");
System.out.println("GET-> username:"+username);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
doGet(request, response);
}
}

(3)實(shí)現(xiàn)請(qǐng)求轉(zhuǎn)發(fā)
請(qǐng)求重定向:實(shí)現(xiàn)資源的跳轉(zhuǎn)
請(qǐng)求轉(zhuǎn)發(fā):實(shí)現(xiàn)資源的跳轉(zhuǎn)暴匠,并且是服務(wù)器