1. ServletContext
Servlet 上下文
每個web工程都只有一個ServletContext對象。 說白了也就是不管在哪個Servlet里面,獲取到的這個類的對象都是同一個。
1.1 有什么作用?
- 1.1.1 獲取全局配置參數(shù)
<!-- 配置參數(shù) -->
<context-param>
<param-name>address</param-name>
<param-value>shanghai</param-value>
</context-param>
ServletContext servletContext = getServletContext();
String value = servletContext.getInitParameter("address");
System.out.println("address =" + value);
- 1.1.2 獲取web工程中的資源
a.先獲取路徑,在獲取流對象
/**
* 先獲取路徑,在獲取流對象
* @throws FileNotFoundException
* @throws IOException
*/
private void test01() throws FileNotFoundException, IOException {
// 獲取ServletContext對象
ServletContext context = getServletContext();
//獲取給定的文件在服務(wù)器上面的絕對路徑剥险。
String path = context.getRealPath("file/config.properties");
System.out.println("path="+path);
// path=/Users/Ben/Library/apache-tomcat-7.0.92/wtpwebapps/Demo03/file/config.properties
// 1. 創(chuàng)建屬性對象
Properties properties = new Properties();
InputStream is = new FileInputStream(path);
properties.load(is);
// 3. 獲取name屬性的值
String name = properties.getProperty("name");
System.out.println("name=" + name);
}
b.根據(jù)相對路徑,直接獲取流對象
/**
* 根據(jù)相對路徑宪肖,直接獲取流對象
*/
private void test02() {
try {
// 獲取ServletContext對象
ServletContext context = getServletContext();
// 1. 創(chuàng)建屬性對象
Properties properties = new Properties();
InputStream is = context.getResourceAsStream("file/config.properties");
properties.load(is);
// 3. 獲取name屬性的值
String name = properties.getProperty("name");
System.out.println("name22=" + name);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
c.根據(jù)classloader去獲取工程下的資源 類加載器(JDBC)
/**
* 根據(jù)classloader去獲取工程下的資源 類加載器(JDBC)
*/
private void test03() {
try {
// 1. 創(chuàng)建屬性對象
Properties properties = new Properties();
InputStream is = this.getClass().getClassLoader().getResourceAsStream("../../file/config.properties");
properties.load(is);
// 3. 獲取name屬性的值
String name = properties.getProperty("name");
System.out.println("name333333=" + name);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
- 1.1.3 存取數(shù)據(jù)表制,Servlet間共享數(shù)據(jù) 域?qū)ο?br> a.定義一個登陸的html頁面, 定義一個form表單
<!--
A路徑: Servlet的路徑
http://localhost:8080/Demo4/login
B路徑: 當(dāng)前這個html的路徑:
http://localhost:8080/Demo4/login.html -->
<form action="login" method="get">
賬號:<input type="text" name="username"/><br>
密碼:<input type="text" name="password"/><br>
<input type="submit" value="登錄"/>
</form>
b.定義一個Servlet控乾,名為LoginServlet么介,用戶登錄之后,成功跳到成功的html蜕衡,并做一個登錄次數(shù)統(tǒng)計的需求壤短。
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 獲取數(shù)據(jù)
String userName = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("userName="+userName+"==password="+password);
//2. 校驗數(shù)據(jù)
//向客戶端輸出內(nèi)容
PrintWriter pw = response.getWriter();
if("admin".equals(userName) && "123".equals(password)){
//System.out.println("登錄成功");
pw.write("login success..");
//成功就跳轉(zhuǎn)到login_success.html
//1. 成功的次數(shù)累加
//獲取以前存的值 , 然后在舊的值基礎(chǔ)上 + 1
Object obj = getServletContext().getAttribute("count") ;
//默認(rèn)就是0次
int totalCount = 0 ;
if(obj != null){
totalCount = (int) obj;
}
System.out.println("已知登錄成功的次數(shù)是:"+totalCount);
//給這個count賦新的值
getServletContext().setAttribute("count", totalCount+1);
//2. 跳轉(zhuǎn)到成功的界面
//設(shè)置狀態(tài)碼? 重新定位 狀態(tài)碼
response.setStatus(302);
//定位跳轉(zhuǎn)的位置是哪一個頁面。
response.setHeader("Location", "login_success.html");
}else{
pw.write("login failed..");
}
}
1.2 ServletContext 何時創(chuàng)建久脯, 何時銷毀?
服務(wù)器啟動的時候纳胧,會為托管的每一個web應(yīng)用程序,創(chuàng)建一個ServletContext對象
從服務(wù)器移除托管帘撰,或者是關(guān)閉服務(wù)器跑慕。
1.3 ServletContext 的作用范圍
只要在這個項目里面,都可以取摧找。 只要同一個項目核行。 A項目 存, 在B項目取蹬耘,是取不到的芝雪? ServletContext對象不同。
2. HttpServletRequest
這個對象封裝了客戶端提交過來的一切數(shù)據(jù)
2.1 可以獲取客戶端請求頭信息
//得到一個枚舉集合
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
String name = (String) headerNames.nextElement();
String value = request.getHeader(name);
System.out.println(name+"="+value);
}
2.2 獲取客戶端提交過來的數(shù)據(jù)
String name = request.getParameter("name");
String address = request.getParameter("address");
System.out.println("name="+name);
System.out.println("address="+address);
-------------------------------------------------
//name=zhangsan&name=lisi&name=wangwu 一個key可以對應(yīng)多個值综苔。
Map<String, String[]> map = request.getParameterMap();
Set<String> keySet = map.keySet();
Iterator<String> iterator = keySet.iterator();
while (iterator.hasNext()) {
String key = (String) iterator.next();
System.out.println("key="+key + "--的值總數(shù)有:"+map.get(key).length);
String value = map.get(key)[0];
String value1 = map.get(key)[1];
String value2 = map.get(key)[2];
System.out.println(key+" ======= "+ value + "=" + value1 + "="+ value2);
}
2.3 獲取中文數(shù)據(jù)亂碼問題
客戶端提交數(shù)據(jù)給服務(wù)器端惩系,如果數(shù)據(jù)中帶有中文的話,有可能會出現(xiàn)亂碼情況如筛,那么可以參照以下方法解決蛆挫。
- 如果是GET方式
- 代碼轉(zhuǎn)碼
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println("userName="+username+"==password="+password);
//get請求過來的數(shù)據(jù),在url地址欄上就已經(jīng)經(jīng)過編碼了妙黍,所以我們?nèi)〉降木褪莵y碼,
//tomcat收到了這批數(shù)據(jù)瞧剖,getParameter 默認(rèn)使用ISO-8859-1去解碼
//先讓文字回到ISO-8859-1對應(yīng)的字節(jié)數(shù)組 拭嫁, 然后再按utf-8組拼字符串
username = new String(username.getBytes("ISO-8859-1") , "UTF-8");
System.out.println("userName="+username+"==password="+password);
- 可以在tomcat里面做設(shè)置處理 conf/server.xml 加上URIEncoding="utf-8"
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
- 如果是POST方式
這個說的是設(shè)置請求體里面的文字編碼。 get方式抓于,用這行做粤,有用嗎? ---> 沒用
request.setCharacterEncoding("UTF-8");
這行設(shè)置一定要寫在getParameter之前捉撮。
3.HttpServletResponse
負(fù)責(zé)返回數(shù)據(jù)給客戶端。
- 輸出數(shù)據(jù)到頁面上
//以字符流的方式寫數(shù)據(jù)
//response.getWriter().write("<h1>hello response...</h1>");
//以字節(jié)流的方式寫數(shù)據(jù)
response.getOutputStream().write("hello response2222...".getBytes());
3.1 響應(yīng)的數(shù)據(jù)中有中文巾遭,那么有可能出現(xiàn)中文亂碼
- 以字符流輸出
response.getWriter()
//1. 指定輸出到客戶端的時候肉康,這些文字使用UTF-8編碼
response.setCharacterEncoding("UTF-8");
//2. 直接規(guī)定瀏覽器看這份數(shù)據(jù)的時候灼舍,使用什么編碼來看。
response.setHeader("Content-Type", "text/html; charset=UTF-8");
response.getWriter().write("我愛java...");
- 以字節(jié)流輸出
response.getOutputStream()
//1. 指定瀏覽器看這份數(shù)據(jù)使用的碼表
response.setHeader("Content-Type", "text/html;charset=UTF-8");
//2. 指定輸出的中文用的碼表
response.getOutputStream().write("我愛java和PHP..".getBytes("UTF-8"));
- 不管是字節(jié)流還是字符流骑素,直接使用一行代碼就可以了。
response.setContentType("text/html;charset=UTF-8");
然后在寫數(shù)據(jù)即可。
4.文件下載
- 下載html代碼
<br>手動編碼提供下載末捣。:<br>
<a href="Demo01?filename=aa.jpg">aa.jpg</a><br>
<a href="Demo01?filename=bb.txt">bb.txt</a><br>
<a href="Demo01?filename=cc.rar">cc.rar</a><br>
- Servlet代碼
public class Demo01 extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 獲取要下載的文件名字 aa.jpg --- inputStream
String fileName = request.getParameter("filename");
/*
* 如果文件的名字帶有中文,那么需要對這個文件名進(jìn)行編碼處理
* 如果是IE 箩做,或者 Chrome (谷歌瀏覽器) 莽红,使用URLEncoding 編碼
* 如果是Firefox 卒茬, 使用Base64編碼
*/
//獲取來訪的客戶端類型
String clientType = request.getHeader("User-Agent");
if(clientType.contains("Firefox")){
// fileName = DownLoadUtil.base64EncodeFileName(fileName);
}else{
//IE ,或者 Chrome (谷歌瀏覽器) 圃酵,
//對中文的名字進(jìn)行編碼處理
fileName = URLEncoder.encode(fileName,"UTF-8");
}
//2. 獲取這個文件在tomcat里面的絕對路徑地址
String path = getServletContext().getRealPath("download/"+fileName);
//讓瀏覽器收到這份資源的時候, 以下載的方式提醒用戶郭赐,而不是直接展示薪韩。
response.setHeader("Content-Disposition", "attachment; filename="+fileName);
//3. 轉(zhuǎn)化成輸入流
InputStream is = new FileInputStream(path);
OutputStream os = response.getOutputStream();
int len = 0 ;
byte[]buffer = new byte[1024];
while( (len = is.read(buffer)) != -1){
os.write(buffer, 0, len);
}
os.close();
is.close();
}
5.重定向和請求轉(zhuǎn)發(fā)(登錄成功跳轉(zhuǎn)成功界面)
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
String userName = request.getParameter("username");
String password = request.getParameter("password");
if("admin".equals(userName) && "123".equals(password)){
//response.getWriter().write("登錄成功");
/*
* 早期的寫法:
* response.setStatus(302);
response.setHeader("Location", "login_success.html");*/
//重定向?qū)懛ǎ?重新定位方向 /根目錄
response.sendRedirect("login_success.html");
//請求轉(zhuǎn)發(fā)的寫法:
// request.getRequestDispatcher("login_success.html").forward(request, response);
}else{
response.getWriter().write("登錄失敗");
}
}
重定向說明
- 地址上顯示的是最后的那個資源的路徑地址
- 請求次數(shù)最少有兩次, 服務(wù)器在第一次請求后捌锭,會返回302 以及一個地址俘陷, 瀏覽器在根據(jù)這個地址,執(zhí)行第二次訪問观谦。
- 可以跳轉(zhuǎn)到任意路徑拉盾。 不是自己的工程也可以跳。
- 效率稍微低一點豁状, 執(zhí)行兩次請求捉偏。
- 后續(xù)的請求,沒法使用上一次的request存儲的數(shù)據(jù)泻红,或者 沒法使用上一次的request對象夭禽,因為這是兩次不同的請求。
請求轉(zhuǎn)發(fā)說明
- 地址上顯示的是請求servlet的地址谊路。 返回200 ok
- 請求次數(shù)只有一次讹躯, 因為是服務(wù)器內(nèi)部幫客戶端執(zhí)行了后續(xù)的工作。
- 只能跳轉(zhuǎn)自己項目的資源路徑 缠劝。
- 效率上稍微高一點潮梯,因為只執(zhí)行一次請求。
- 可以使用上一次的request對象惨恭。