# Servlet與Jsp進階
[TOC]
## 導學
在之前的學習中,我們已經初步認識到什么是Servlet和Jsp。那么今天我們再來重新認識一下Servlet和Jsp,本節課需要掌握Java Web的核心特性(請求與響應的結構)、掌握Servlet的核心對象、Jsp九大內置對象(面試筆試中常遇到)等內容
## HTTP請求的結構
請求是瀏覽器像服務器發送的數據包,那么在請求中其實是包含了三部分的內容的:請求行,請求頭,請求體。

請求行包括請求的方式,請求的地址,以及請求的HTTP版本
請求頭中,包括很多輔助的請求信息,能為請求處理提供額外的支持。
**資料(關于請求頭與響應頭):**[https://www.cnblogs.com/xjcjcsy/p/6135006.html](https://www.cnblogs.com/xjcjcsy/p/6135006.html)
請求體中,描述了請求的參數內容。注意一下,get請求是將參數寫入URL中,所以get請求是沒有請求體的,只有post請求才有請求體。
~~~java
/**
* Servlet implementation class MethodServlet
*/
@WebServlet("/method")
public class MethodServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public MethodServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("This is Get method");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("This is Post method");
}
}
~~~
~~~html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/MyJsp/method" method="get">
<input name="userName"/>
<input name="password" type="password"/>
<input type="submit"/>
</form>
</body>
</html>
~~~


## 利用請求頭開發多端應用
早期的程序,基本都是運行的在電腦上的,我們編寫頁面的時候只要考慮電腦端的情況就可以了。但是隨著個人設備越來越多,我們需要考慮的顯示設備也越來越多,那么我們該如何去嘗試著在Java中進行多種設備的考量呢?這個時候我們就可以利用請求頭進行判斷分析
~~~
/**
* Servlet implementation class UserAgentServlet
*/
@WebServlet("/useragent")
public class UserAgentServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public UserAgentServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String userAgent = request.getHeader("User-Agent");//獲取請求頭信息
response.setContentType("text/html;charset=utf-8");//設置服務器端響應的編碼方式以及內容解析方式
response.getWriter().println(userAgent);
String output = "";
if(userAgent.indexOf("Windows NT") != -1) {
output = "<h1>這是PC端</h1>";
} else if(userAgent.indexOf("iPhone") != -1 ||userAgent.indexOf("Android") != -1 ){
output = "<h1>這是手機端</h1>";
}
response.getWriter().println(output);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
## 響應的結構
HTTP響應包含三部分:響應行、響應頭、響應體

HTTP常用狀態碼:

## ContentType的作用
ContentType決定瀏覽器采用何種的方式對響應體進行處理。

~~~java
/**
* Servlet implementation class ContentTypeServlet
*/
@WebServlet("/contenttype")
public class ContentTypeServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public ContentTypeServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String output = "<h1><a href='www.baidu.com'><span>百度</span></a></h1>";
/*response.setContentType("text/html;charset=utf-8");*/
/*response.setContentType("text/plain;charset=utf-8");*///輸出純文本
/*response.setContentType("text/xml;charset=utf-8");*/
response.setContentType("application/x-msdownload;charset=utf-8");
response.getWriter().println(output);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
## 請求轉發與重定向
在之前的學習中,都是通過一個servlet來完成的程序處理,但在真正的開發中,需要多個servlet進行組合調用。從A servlet到B servlet,完成一場“傳值的游戲”。那么從A到B之間,如何進行通信和跳轉呢?
對于多個servlet和jsp之間跳轉有兩鐘方式:
1. 請求轉發:`request.getRequestDispatcher(path).forword(request,response)`
2. 響應重定向:`response.sendRedirect(Contextpath工程名稱/映射地址);`
區別:
請求轉發是不會改變一開始訪問的映射地址
響應重定向是會改變到最后請求的映射地址
### 請求轉發與重定向的使用
~~~
@WebServlet("/direct/index")
public class IndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public IndexServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().println("This is index page");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
~~~
/**
* 用戶校驗頁面
* @author LiXinRong
*
*/
@WebServlet("/direct/check")
public class CheckLoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public CheckLoginServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("用戶登錄成功");
//請求.請求觸發器.轉發->瀏覽器地址欄不會發生改變
request.getRequestDispatcher("/direct/index").forward(request, response);
//響應重定向需要增加contextPath->瀏覽器地址欄會發生改變
response.sendRedirect("/sd/direct/index");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
轉發時,是在服務器內部由第一個servlet跳轉到新的servlet。而轉發是在服務器處理完第一個servlet后,通知瀏覽器,由瀏覽器再發送一個請求給服務器的新的servlet。
### 請求轉發與重定向的原理
雖然請求轉發與重定向都是用于地址的跳轉,但是它們兩個在本質上是完全不一樣的。
**請求轉發**
請求轉發是在服務器內部進行跳轉,轉發調用的是HttpServletRequest對象中的方法以及轉發時瀏覽器只請求一次服務器,地址欄的url不會發生變化。

在進行請求轉發時,允許創建自定義屬性。
設置請求屬性:
`request.setAttribute(屬性名,屬性值)`
獲取請求屬性:
`Object attr = request.getAttribute(屬性名)`
~~~
@WebServlet("/direct/check")
public class CheckLoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public CheckLoginServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("用戶登錄成功");
request.setAttribute("name", "Jack");
//請求.請求觸發器.轉發->瀏覽器地址欄不會發生改變
request.getRequestDispatcher("/direct/index").forward(request, response);
//響應重定向需要增加contextPath
/*response.sendRedirect("/sd/direct/index");*/
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
~~~
@WebServlet("/direct/index")
public class IndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public IndexServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = (String)request.getAttribute("name");
System.out.println(name);
System.out.println("index page");
request.getRequestDispatcher("/direct/index2").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
~~~
@WebServlet("/direct/index2")
public class IndexServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
public IndexServlet2() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = (String)request.getAttribute("name");
System.out.println(name);
System.out.println("index page2");
request.getRequestDispatcher("/direct/index3").forward(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
~~~
@WebServlet("/direct/index3")
public class IndexServlet3 extends HttpServlet {
private static final long serialVersionUID = 1L;
public IndexServlet3() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = (String)request.getAttribute("name");
System.out.println(name);
System.out.println("index page3");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
在servlet中定義的屬性,可以通過請求轉發一直傳遞下去。
**重定向**
重定向則是瀏覽器端跳轉,會產生兩次請求。

重定向的時候不會去傳遞屬性。
**注意:**
1. 如果需要攜帶數據到要跳轉的界面,建議使用轉發。地址欄不會改變。
2. 如果不需要攜帶數據到要跳轉的界面,建議使用重定向。地址欄會改變
## Cookie與Session
### Cookie
Cookie(小甜餅)是瀏覽器保存在本地的文本內容,cookie常用于保存登錄狀態,用戶資料等小文本。cookie是具有時效性的,有效的cookie內容會伴隨著請求發送給Tomcat。比如我們可以使用cookie保存用戶的登錄信息,這樣在一定時長內,用戶就可以一直保持登錄狀態了。

該文件打開是一堆亂碼,這是因為這個文件往往包含敏感數據,所以瀏覽器對此進行了加密。

設置Cookie
~~~
@WebServlet("/cookies/lg")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LoginServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("用戶登錄成功");
//設置用戶七天內保持登錄
Cookie cookie = new Cookie("user","admin");
cookie.setMaxAge(60*60*24*7);
response.addCookie(cookie);
response.getWriter().println("login success");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
若不設置有效期,則cookie有效期為當前瀏覽器窗口,若窗口關閉,則cookie清空

讀取cookie
~~~
@WebServlet("/cookies/is")
public class IndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public IndexServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie[] cs = request.getCookies();//用于獲取所用的用戶信息
String user = null;
for(Cookie c :cs) {
System.out.println(c.getName() + ":" + c.getValue());
if(c.getName().equals("user")) {
user = c.getValue();
break;
}
}
if(user == null) {
response.getWriter().println("user not login");
} else {
response.getWriter().println("user:" + user);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
~~~
注意cookie是作用于本目錄及其子目錄,如果發送cookis那個文件的映射地址是/cookies/login,那么想要獲取的那個也必須是/cookies/xx
~~~
@WebServlet("/cookie/is")//該地址獲取不到對應的cookie
public class IndexServlet2 extends HttpServlet {
private static final long serialVersionUID = 1L;
public IndexServlet2() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Cookie[] cs = request.getCookies();//用于獲取所用的用戶信息
String user = null;
for(Cookie c :cs) {
System.out.println(c.getName() + ":" + c.getValue());
if(c.getName().equals("user")) {
user = c.getValue();
break;
}
}
if(user == null) {
response.getWriter().println("user not login");
} else {
response.getWriter().println("user:" + user);
}
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
~~~
### session
cookie是保存在我們本地的數據,但是這個數據不一定可靠,保存在本地遲早會被破解,而且設置cookie之后,每次發送請求都會攜帶cookie,增加了瀏覽器的帶寬負擔。于是,我們有了一個新的解決方案session,用于將數據保存在服務器上。
**session特點:**
1. Sesstion(用戶會話)用于保存"瀏覽器窗口"對應的數據
2. Session的數據存儲在Tomcat服務器的內存中,具有時效性(無人訪問時長為30分鐘)
3. Session通過瀏覽器Cookie的SessionId(瀏覽器的session識別碼)值提取用戶數據,每個瀏覽器的SessionId都不一樣。
~~~
@WebServlet("/session/sl")
public class SessionLoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public SessionLoginServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("用戶登錄成功");
//獲取用戶會話session
HttpSession session = request.getSession();
session.setAttribute("name", "張三");
String sessionId = session.getId();
System.out.println(sessionId);
request.getRequestDispatcher("/session/id").forward(request,response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
~~~
~~~
@WebServlet("/session/sil")
public class SessionIndexServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public SessionIndexServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
String sessionId = session.getId();
System.out.println(sessionId);
String name = (String)session.getAttribute("name");
response.setContentType("text/html;charset=utf-8");//設置返回內容解碼方式
response.getWriter().println("這是首頁,當前用戶為:" + name);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
~~~
#### session使用的原理
session 對象是由服務器自動創建的與用戶請求相關的對象。服務器為每個用戶都生成一個session對象,用于保存該用戶的信息,跟蹤用戶的操作狀態,服務器創建的每個session對象互不干涉。session是會話級別的變量,我們一般使用 session 處理用戶的登陸信息。
簡單的理解,打開一個瀏覽器,無論你打開多少標簽頁, 用 session 存儲的變量都會存在,除非使用 session.removeAttribute() 將其顯式銷毀。
其實可以將session看做在Tomcat中存儲的與客戶端瀏覽器窗口綁定的數據存儲空間。在使用的時候只需要使用`setAttribute`和`getAttribute`進行存值和取值即可。但是在底層卻不是簡單,是如何實現的呢?
當瀏覽器第一次創建session對象的時候會tomcat會在內存空間中開辟一個空間存放session數據,并且給session空間一個sessionid,tomcat在返回響應數據的時候會把sessionid一起返回給瀏覽器,瀏覽器把sessionid保存在cookie中,之后從瀏覽器傳送過來的數據都通過sessionid來查找session的位置來保存數據。

session在工程的使用是非常廣泛的,最常用的就是根據session可以與瀏覽器對應的原理,用于保存每個用戶的登錄信息。
## ServletContext
ServletContext(Servlet上下文對象),是web應用的上下文對象。在一個Web應用程序中只會存在一個ServletContext對象,該對象在Tomcat啟動的時候創建,在Tomcat關閉的時候銷毀。

類似于這種網站備案信息和版權信息,會顯示于整個網站全局,這個時候我們就可以使用ServletContext這種全局對象來進行設置。
~~~
@WebServlet("/servletcontext/init")
public class ServletContextInitServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ServletContextInitServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//獲取應用程序上下文對象,其實也就是應用程序對象
ServletContext sc = request.getServletContext();
//利用該對象的特性,設置作用范圍為全局的自定義屬性
sc.setAttribute("copyright", "Powered by EduSoho v8.6.4 ?2014-2020 課程存檔 \n課程內容版權均歸 南通在渡教育咨詢有限公司 所有 蘇ICP備18015371號");
//sc.setAttribute("copyright","");如果設置了相同的屬性名,則新的屬性值會覆蓋舊的屬性值,其他設置request自定義屬性和session自定義屬性也是相同的道理
sc.setAttribute("title", "渡課IT教育");
response.getWriter().println("init success");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
~~~
@WebServlet("/servletcontext/defualt")
public class ServletContextDefaultServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ServletContextDefaultServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext sc = request.getServletContext();
String copyright = (String)sc.getAttribute("copyright");
String title = (String)sc.getAttribute("title");
response.setContentType("text/html;charset=utf-8");
response.getWriter().println("<h1>" + title + "</h1>" + copyright);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
## Java Web三大作用域
* HttpServletRequest -請求對象
* HttpSession - 用戶會話對象
* ServletContext - web應用全局對象
這三個對象的作用域,從上到下是依次遞增的。
請求對象,它的生命周期最短,當瀏覽器發送請求到Tomcat,則請求對象就被創建,當servlet處理完成并返回響應到瀏覽器時,當前的請求對象就會被銷毀。
用戶會話對象用于保存與瀏覽器窗口對應的數據,該對象是在用戶第一次向瀏覽器發送請求的時候被創建,默認情況下,這個對象如果在三十分鐘后沒有訪問就會被銷毀。注意一下,關閉瀏覽器該對象不會被銷毀,銷毀的是保存在瀏覽器cookie中的sessionId。就好像銀行卡與存在銀行中的錢一樣,丟失了銀行卡,但是銀行中的錢還在,只是取不出來這筆錢而已。
全局對象在web應用啟動的時候就被創建了,只有在web應用程序關閉或重啟的時候才會被銷毀。
有個注意點,為了程序維護的需要和資源避免浪費的情況,如果能用小作用域完成的任務就不用大作用域完成,所以request請求對象是以后使用的最多的對象
## 中文亂碼
中文亂碼的核心就是解析字符集不支持中文,所以解決中文亂碼的關鍵就是將默認字符集變成UTF-8,servlet中的請求與響應都需要設置為UTF-8。
### Post請求中文亂碼
~~~HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<form action="/servlet_advanced/charset/process" method="post">
姓名:<input name="ename">
地址:<input name="address">
<input type="submit" value="提交">
</form>
</body>
</html>
~~~
~~~
@WebServlet("/charset/process")
public class CharsetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public CharsetServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//request.setCharacterEncoding方法用于將請求體中的字符集轉換為UTF-8,對于get請求,沒有請求體,所以該方法只對post請求生效。
request.setCharacterEncoding("UTF-8");
String ename = request.getParameter("ename");
String address = request.getParameter("address");
System.out.println(ename + ":" + address);
//通過字符串構造器將字符串的解析字符集轉換為utf-8,但是不怎么方便,所以使用setCharacterEncoding方法
//String utf8Ename = new String(ename.getBytes("iso-8859-1") , "utf-8");
//String utf8Address = new String(address.getBytes("iso-8859-1") , "utf-8");
//System.out.println(utf8Ename + ":" + utf8Address);
}
}
~~~
### Get請求與響應中文亂碼
~~~
@WebServlet("/charset/process")
public class CharsetServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public CharsetServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//對于Tomcat8.x的版本,默認get請求發送中文就是UTF-8的格式,因此無需轉換
String ename = request.getParameter("ename");
String address = request.getParameter("address");
System.out.println(ename + ":" + address);
response.setContentType("text/html;charset=utf-8");
response.getWriter().println(ename + ":" + address);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
~~~
## web.xml的常用配置
在本章節中,我們將做到以下功能:
* 修改web應用默認首頁
* Servlet通配符映射及初始化參數
* 設置404,500等狀態碼首頁
**修改web應用默認首頁**
~~~
<welcome-file-list>
<!-- 指定默認首頁,二級目錄下的頁面也可以作為默認首頁,使用的時候需要在地址后面注意加/ -->
<welcome-file>index.html</welcome-file>
<welcome-file>default.html</welcome-file>
</welcome-file-list>
~~~
**通配符映射,利用地址傳參(非get提交)**
~~~
public class PatternServlet extends HttpServlet{
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//查詢員工的基本信息
//獲取當前訪問的URL
String url = request.getRequestURL().toString();
System.out.println(url);
String id = url.substring(url.lastIndexOf("/") + 1);
int eid = Integer.parseInt(id);
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println(id);
if(eid == 1) {
out.println("張三");
}else if(eid == 2) {
out.println("李四");
}else {
out.println("其他員工");
}
}
}
~~~
~~~
<servlet>
<servlet-name>patternServlet</servlet-name>
<servlet-class>com.dodoke.servlet.pattern.PatternServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>patternServlet</servlet-name>
<!-- 使用*作為通配符,指的是pattern/后面不管是什么地址,都會被該servlet攔截請求 -->
<url-pattern>/pattern/*</url-pattern>
</servlet-mapping>
~~~
**設置全局參數**
在之前的學習中,我們在設置網站備案信息和版權信息時,是將內容寫死在程序中的,這其實對我們的程序來說不算友好,現在我們可以嘗試著將這些全局信息寫入到配置文件中。
~~~
<context-param>
<param-name>copyright</param-name>
<param-value>Powered by EduSoho v8.6.4 ?2014-2020 課程存檔 \n課程內容版權均歸 南通在渡教育咨詢有限公司 所有 蘇ICP備18015371號</param-value>
</context-param>
<context-param>
<param-name>title</param-name>
<param-value>渡課IT教育</param-value>
</context-param>
~~~
~~~
@WebServlet("/servletcontext/init")
public class ServletContextInitServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ServletContextInitServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ServletContext context = request.getServletContext();
//獲取ServletContext對象通過配置文件設置的初始化參數
String copyright = context.getInitParameter("copyright");
context.setAttribute("copyright", copyright);
String title = context.getInitParameter("title");
context.setAttribute("title", title);
response.getWriter().println("init success");
}
}
~~~
**設置404,500等狀態碼首頁**
~~~
<!-- 指定錯誤頁面 -->
<error-page>
<error-code>404</error-code>
<location>/error/404.html</location>
</error-page>
<error-page>
<error-code>500</error-code>
<location>/error/500.jsp</location>
</error-page>
~~~
~~~
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
資源不存在
</body>
</html>
~~~
~~~
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
服務器內部錯誤,請聯系管理員
</body>
</html>
~~~
## JSP九大內置對象
內置對象,又叫做隱含對象,不需要預先聲明就可以在腳本代碼和表達式中隨意使用
1\. 由JSP規范提供,不用編寫者實例化。?
2\. 通過Web容器實現和管理?
3\. 所有JSP頁面均可使用?
4\. 只有在腳本元素的表達式或代碼段中才可使用

~~~
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String url = request.getRequestURL().toString(); // HttpServletRequest
response.getWriter().println(url);//HttpServletResponse
%>
<% out.println("<br>ABCCC");
session.setAttribute("user", "張三");
out.println((String)session.getAttribute("user"));
%>
<%
String cp = application.getInitParameter("copyright") ; //ServletContext
out.println("<hr/>");
out.println(cp);
//pageContext可以幫助我們快速獲取其他對象
pageContext.getRequest();
pageContext.getResponse();
pageContext.getSession();
pageContext.getServletContext();
%>
</body>
</html>
~~~
利用exception對象顯示錯誤信息。
~~~
<!-- isErrorPage表示該頁面專門用于顯示錯誤 -->
<%@ page contentType="text/html;charset=utf-8" isErrorPage="true"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
服務器內部錯誤,請聯系管理員 ,錯誤信息如下:
<%
String msg = exception.getMessage();
out.print("<br>" + exception.getClass().getSimpleName() + ":" + msg);
%>
</body>
</html>
~~~
## Java Web的打包與發布
在編寫完成代碼后,就需要正式的進行程序的上線了,那么我們該如何進行程序的上線呢?



直接將這樣的war包,保存到Tomcat的webapp目錄中,啟動Tomcat就可以了。
注意:
* 端口可以改為80,避免輸入端口號
* 項目路徑可以只保留斜杠,避免輸入項目路徑
* 