中文字幕在线观看,亚洲а∨天堂久久精品9966,亚洲成a人片在线观看你懂的,亚洲av成人片无码网站,亚洲国产精品无码久久久五月天

Java Servlet完全教程

2018-07-20    來(lái)源:編程學(xué)習(xí)網(wǎng)

容器云強(qiáng)勢(shì)上線(xiàn)!快速搭建集群,上萬(wàn)Linux鏡像隨意使用

Servlet 是一些遵從Java Servlet API的Java類(lèi),這些Java類(lèi)可以響應(yīng)請(qǐng)求。盡管Servlet可以響應(yīng)任意類(lèi)型的請(qǐng)求,但是它們使用最廣泛的是響應(yīng)web方面的請(qǐng)求。 Servlet必須部署在Java servlet容器才能使用。雖然很多開(kāi)發(fā)者都使用Java Server Pages(JSP)和Java Server Faces(JSF)等Servlet框架,但是這些技術(shù)都要在幕后通過(guò)Servlet容器把頁(yè)面編譯為Java Servlet。也就是說(shuō),了解Java Servlet技術(shù)的基礎(chǔ)知識(shí)對(duì)任何Java web開(kāi)發(fā)者來(lái)說(shuō)是很有用的。

在這個(gè)教程里,我們將會(huì)通過(guò)下面的專(zhuān)題來(lái)全面了解Java Servlet技術(shù)。

目錄

  • 編寫(xiě)你的第一個(gè)Servlet
  • Servlet生命周期方法
  • 使用@WebServlet注解開(kāi)發(fā)Servlet
  • 打包和部署Servlet到Tomcat服務(wù)器
  • 編寫(xiě)動(dòng)態(tài)的Servlet響應(yīng)內(nèi)容
  • 處理Servlet請(qǐng)求和響應(yīng)
  • 監(jiān)聽(tīng)Servlet容器事件
  • 傳遞Servlet初始化參數(shù)
  • 為特定的URL請(qǐng)求添加Servlet過(guò)濾器
  • 使用Servlet下載二進(jìn)制文件
  • 使用RequestDispatcher.forward()轉(zhuǎn)發(fā)請(qǐng)求到另一個(gè)Servlet
  • 使用HttpServletResponse.sendRedirect()重定向請(qǐng)求到另一個(gè)Servlet
  • 使用Servlets讀寫(xiě)Cookie

讓我們一起來(lái)一步步地學(xué)習(xí)Servlet。

編寫(xiě)你的第一個(gè)Servlet

我們的第一個(gè)Servlet是一個(gè)只擁有少量代碼的簡(jiǎn)單Servlet,目的是讓你只需關(guān)注它的行為。

package com.howtodoinjava.servlets;

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 MyFirstServlet extends HttpServlet {

	private static final long serialVersionUID = -1915463532411657451L;

	@Override
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException 
	{
		response.setContentType("text/html;charset=UTF-8");
		PrintWriter out = response.getWriter();
		try {
			// Write some content
			out.println("<html>");
			out.println("<head>");
			out.println("<title>MyFirstServlet</title>");
			out.println("</head>");
			out.println("<body>");
			out.println("<h2>Servlet MyFirstServlet at " + request.getContextPath() + "</h2>");
			out.println("</body>");
			out.println("</html>");
		} finally {
			out.close();
		}
	}

	@Override
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		//Do some other work
	}

	@Override
	public String getServletInfo() {
		return "MyFirstServlet";
	}
}

為了在web容器里注冊(cè)上面的Servlet,你要為你的應(yīng)用建一個(gè)web.xml入口文件。

<?xml version="1.0"?>
<web-app     xmlns="http://xmlns.jcp.org/xml/ns/javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee

http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd"

            version="3.0">

    <welcome-file-list>
        <welcome-file>/MyFirstServlet</welcome-file>
    </welcome-file-list>

    <servlet>
        <servlet-name>MyFirstServlet</servlet-name>
        <servlet-class>com.howtodoinjava.servlets.MyFirstServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyFirstServlet</servlet-name>
        <url-pattern>/MyFirstServlet</url-pattern>
    </servlet-mapping>

</web-app>

上面的Servlet做了一些重要的事情,你可能想了解的。

  1. MyFirstServlet類(lèi)繼承了HttpServlet。這個(gè)繼承是必須的,因?yàn)樗械腟ervlet必須是要么繼承了 javax.servlet.GenericServlet 的普通Servlet,要么是繼承了 javax.servlet.http.HttpServlet 的HTTP Servlet。
  2. 重新 doGet() 和 doPost() 方法。這兩個(gè)方法都已在 HttpServlet 類(lèi)里定義了。當(dāng)一個(gè)GET或POST請(qǐng)求到來(lái)時(shí),它就會(huì)被映射到相應(yīng)的方法里。例如,如果你向這個(gè)servlet發(fā)送一個(gè)HTTP GET請(qǐng)求,doGet()方法就會(huì)被調(diào)用。
  3. 這里也有一些其他有用的方法。你可以重寫(xiě)它們來(lái)在運(yùn)行時(shí)控制應(yīng)用。例如getServletInfo()。
  4. HttpServletRequest 和 HttpServletResponse 是所有doXXX()方法的默認(rèn)參數(shù)。我們會(huì)在后面的章節(jié)里詳細(xì)學(xué)習(xí)這些對(duì)象。

以上所有關(guān)于簡(jiǎn)單Servlet的內(nèi)容就是你需要知道的內(nèi)容。

Servlet生命周期方法

在你的應(yīng)用加載并使用一個(gè)Servlet時(shí),從初始化到銷(xiāo)毀這個(gè)Servlet期間會(huì)發(fā)生一系列的事件。這些事件叫做Servlet的生命周期事件(或方法)。讓我們一起來(lái)進(jìn)一步了解它們。

Servlet生命周期的三個(gè)核心方法分別是 init() , service() 和 destroy()。每個(gè)Servlet都會(huì)實(shí)現(xiàn)這些方法,并且在特定的運(yùn)行時(shí)間調(diào)用它們。

1) 在Servlet生命周期的初始化階段,web容器通過(guò)調(diào)用init()方法來(lái)初始化Servlet實(shí)例,并且可以傳遞一個(gè)實(shí)現(xiàn) javax.servlet.ServletConfig 接口的對(duì)象給它。這個(gè)配置對(duì)象(configuration object)使Servlet能夠讀取在web應(yīng)用的web.xml文件里定義的名值(name-value)初始參數(shù)。這個(gè)方法在Servlet實(shí)例的生命周期里只調(diào)用一次

init方法定義與這類(lèi)似:

public void  init() throws ServletException {
	//custom initialization code
}

2) 初始化后,Servlet實(shí)例就可以處理客戶(hù)端請(qǐng)求了。web容器調(diào)用Servlet的service()方法來(lái)處理每一個(gè)請(qǐng)求。service() 方法定義了能夠處理的請(qǐng)求類(lèi)型并且調(diào)用適當(dāng)方法來(lái)處理這些請(qǐng)求。編寫(xiě)Servlet的開(kāi)發(fā)者必須為這些方法提供實(shí)現(xiàn)。如果發(fā)出一個(gè)Servlet沒(méi)實(shí)現(xiàn)的請(qǐng)求,那么父類(lèi)的方法就會(huì)被調(diào)用并且通常會(huì)給請(qǐng)求方(requester)返回一個(gè)錯(cuò)誤信息。

通常,我們不需要重寫(xiě)(override)這個(gè)方法。

protected void service(HttpServletRequest req, HttpServletResponse resp)
	throws ServletException, IOException
{
String method = req.getMethod();

if (method.equals(METHOD_GET)) {
	long lastModified = getLastModified(req);
	if (lastModified == -1) {
	// servlet doesn't support if-modified-since, no reason
	// to go through further expensive logic
	doGet(req, resp);
	} else {
	long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
	if (ifModifiedSince < (lastModified / 1000 * 1000)) {
		// If the servlet mod time is later, call doGet()
				// Round down to the nearest second for a proper compare
				// A ifModifiedSince of -1 will always be less
		maybeSetLastModified(resp, lastModified);
		doGet(req, resp);
	} else {
		resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
	}
	}

} else if (method.equals(METHOD_HEAD)) {
	long lastModified = getLastModified(req);
	maybeSetLastModified(resp, lastModified);
	doHead(req, resp);

} else if (method.equals(METHOD_POST)) {
	doPost(req, resp);

} else if (method.equals(METHOD_PUT)) {
	doPut(req, resp);	

} else if (method.equals(METHOD_DELETE)) {
	doDelete(req, resp);

} else if (method.equals(METHOD_OPTIONS)) {
	doOptions(req,resp);

} else if (method.equals(METHOD_TRACE)) {
	doTrace(req,resp);

} else {
	//
	// Note that this means NO servlet supports whatever
	// method was requested, anywhere on this server.
	//

	String errMsg = lStrings.getString("http.method_not_implemented");
	Object[] errArgs = new Object[1];
	errArgs[0] = method;
	errMsg = MessageFormat.format(errMsg, errArgs);

	resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
}
}

3) 最后,web容器調(diào)用destroy()方法來(lái)終結(jié)Servlet。如果你想在Servlet的生命周期內(nèi)關(guān)閉或者銷(xiāo)毀一些文件系統(tǒng)或者網(wǎng)絡(luò)資源,你可以調(diào)用這個(gè)方法來(lái)實(shí)現(xiàn)。destroy() 方法和init()方法一樣,在Servlet的生命周期里只能調(diào)用一次。

public void destroy() {
//
}

在大多數(shù)情況下,你通常不需要在你的Servlet里重寫(xiě)這些方法。

擴(kuò)展閱讀:web服務(wù)器是如何運(yùn)作的?

使用@WebServlet注解來(lái)開(kāi)發(fā)Servlet

如果你不喜歡使用xml配置而喜歡注解的話(huà),沒(méi)關(guān)系,Servlets API同樣提供了一些注解接口給你。你可以像下面的例子一樣使用 @WebServlet 注解并且不需要在web.xml里為Servlet注冊(cè)任何信息。容器會(huì)自動(dòng)注冊(cè)你的Servlet到運(yùn)行環(huán)境,并且像往常一樣處理它。

package com.howtodoinjava.servlets;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "MyFirstServlet", urlPatterns = {"/MyFirstServlet"})
public class MyFirstServlet extends HttpServlet {

    private static final long serialVersionUID = -1915463532411657451L;

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {
        //Do some work
    }

    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        //Do some other work
    }
}

打包和部署Servlet到Tomcat服務(wù)器

如果你在使用IDE(例如Eclipse),那么打包和部署你的應(yīng)用只需要一個(gè)簡(jiǎn)單的步驟。右擊項(xiàng)目> Run As > Run As Server。如果還沒(méi)配置服務(wù)器先配置好服務(wù)器,然后就可以準(zhǔn)備開(kāi)干了。

如果你沒(méi)在使用IDE,那么你需要做一些額外的工作。比如,使用命令提示符編譯應(yīng)用,使用ANT去生成war文件等等。但我相信,現(xiàn)在的開(kāi)發(fā)者都在使用IDE來(lái)開(kāi)發(fā)。所以我就不在這方面浪費(fèi)時(shí)間了。

當(dāng)你把我們的第一個(gè)Servlet部署到tomcat上并在瀏覽器輸入“http://localhost:8080/servletexamples/MyFirstServlet”,你會(huì)得到下面的響應(yīng)。

編寫(xiě)動(dòng)態(tài)的Servlet響應(yīng)內(nèi)容

Java Servlets如此有用的原因之一是Servlet能動(dòng)態(tài)顯示網(wǎng)頁(yè)內(nèi)容。這些內(nèi)容可以從服務(wù)器本身、另外一個(gè)網(wǎng)站、或者許多其他網(wǎng)絡(luò)可以訪(fǎng)問(wèn)的資源里獲取。Servlet不是靜態(tài)網(wǎng)頁(yè),它們是動(dòng)態(tài)的?梢哉f(shuō)這是它們最大的優(yōu)勢(shì)。

讓我們來(lái)舉個(gè)Servlet例子,這個(gè)Servlet會(huì)顯示當(dāng)前日期和時(shí)間給用戶(hù)并且會(huì)顯示用戶(hù)名和一些自定義的信息。讓我們來(lái)為這個(gè)功能編寫(xiě)代碼吧。

package com.howtodoinjava.servlets;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "CalendarServlet", urlPatterns = {"/CalendarServlet"})
public class CalendarServlet extends HttpServlet {

    private static final long serialVersionUID = -1915463532411657451L;

    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException
    {

        Map<String,String> data = getData();

        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            // Write some content
            out.println("<html>");
            out.println("<head>");
            out.println("<title>CalendarServlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h2>Hello " + data.get("username") + ", " + data.get("message") + "</h2>");
            out.println("<h2>The time right now is : " + new Date() + "</h2>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }

    //This method will access some external system as database to get user name, and his personalized message
    private Map<String, String> getData()
    {
        Map<String, String> data = new HashMap<String, String>();
        data.put("username", "Guest");
        data.put("message",  "Welcome to my world !!");
        return data;
    }
}

當(dāng)你在tomcat里運(yùn)行上面的Servlet并在瀏覽器里輸入“http://localhost:8080/servletexamples/CalendarServlet”,你會(huì)得得下面的響應(yīng)。

處理Servlet請(qǐng)求和響應(yīng)

Servlet可以輕松創(chuàng)建一個(gè)基于請(qǐng)求和響應(yīng)生命周期的web應(yīng)用。它們能夠提供HTTP響應(yīng)并且可以使用同一段代碼來(lái)處理業(yè)務(wù)邏輯。處理業(yè)務(wù)邏輯的能力使Servlet比標(biāo)準(zhǔn)的HTML代碼更強(qiáng)大。

現(xiàn)實(shí)世界里的應(yīng)用,一個(gè)HTML網(wǎng)頁(yè)表單包含了要發(fā)送給Servlet的參數(shù)。Servlet會(huì)以某種方式來(lái)處理這些參數(shù)并且 返回一個(gè)客戶(hù)端能夠識(shí)別的響應(yīng)。在對(duì)象是HttpServlet的情況下,客戶(hù)端是web瀏覽器,響應(yīng)是web頁(yè)面。<form>的 action屬性指定了使用哪個(gè)Servlet來(lái)處理表單里的參數(shù)值。

為了獲取請(qǐng)求參數(shù),需要調(diào)用 HttpServletRequest 對(duì)象的 getParameter() 方法,并且傳遞你要獲取的輸入?yún)?shù)的id給該方法。

String value1 = req.getParameter("param1");
String value1 = req.getParameter("param2");

一旦獲取了參數(shù)值,它們就會(huì)在需要時(shí)被處理。對(duì)客戶(hù)端的響應(yīng)和我們上面部分討論的一樣。我們使用 HttpServletResponse 對(duì)象給客戶(hù)端發(fā)送響應(yīng)。

request和response處理的基本使用可以是這樣的:

@Override
protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException
{

    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();

    String username = request.getParameter("username");
    String password = request.getParameter("password");

    boolean success = validateUser(username, password);

    try {
        // Write some content
        out.println("<html>");
        out.println("<head>");
        out.println("<title>LoginServlet</title>");
        out.println("</head>");
        out.println("<body>");

        if(success) {
            out.println("<h2>Welcome Friend</h2>");
        }else{
            out.println("<h2>Validate your self again.</h2>");
        }

        out.println("</body>");
        out.println("</html>");
    } finally {
        out.close();
    }
}

為了發(fā)送內(nèi)容給客戶(hù)端,你需要使用從 HttpServletResponse 里獲取的 PrintWriter 對(duì)象。任何寫(xiě)到這個(gè)對(duì)象的內(nèi)容都會(huì)被寫(xiě)進(jìn)outputstream里,并會(huì)把內(nèi)容發(fā)送回給客戶(hù)端。

監(jiān)聽(tīng)Servlet容器事件

有時(shí)候,知道應(yīng)用服務(wù)器容器(the application server container)里某些事件發(fā)生的時(shí)間是很有用的。這個(gè)概念適用于很多情況,但它通常用在開(kāi)啟應(yīng)用時(shí)初始化應(yīng)用或者關(guān)閉應(yīng)用時(shí)清理應(yīng)用。可以在應(yīng)用里 注冊(cè)一個(gè)監(jiān)聽(tīng)器(listener)來(lái)顯示應(yīng)用什么時(shí)候開(kāi)啟或者關(guān)閉。因此,通過(guò)監(jiān)聽(tīng)這些事件,Servlet可以在一些事件發(fā)生時(shí)執(zhí)行相應(yīng)的動(dòng)作。

為了創(chuàng)建一個(gè)基于容器事件執(zhí)行動(dòng)作的監(jiān)聽(tīng)器,你必須創(chuàng)建一個(gè)實(shí)現(xiàn) ServletContextListener 接口的類(lèi)。這個(gè)類(lèi)必須實(shí)現(xiàn)的方法有 contextInitialized() 和 contextDestroyed()。這兩個(gè)方法都需要 ServletContextEvent 作為參數(shù),并且在每次初始化或者關(guān)閉Servlet容器時(shí)都會(huì)被自動(dòng)調(diào)用。

為了在容器注冊(cè)監(jiān)聽(tīng)器,你可以使用下面其中一個(gè)方法:

1) 利用 @WebListener 注解。

2) 在web.xml應(yīng)用部署文件里注冊(cè)監(jiān)聽(tīng)器。

3) 使用 ServletContext 里定義的 addListener() 方法

請(qǐng)注意,ServletContextListener 不是Servlet API里唯一的監(jiān)聽(tīng)器。這里還有一些其他的監(jiān)聽(tīng)器,比如

javax.servlet.ServletRequestListener
javax.servlet.ServletRequestAttrbiteListener
javax.servlet.ServletContextListener
javax.servlet.ServletContextAttributeListener
javax.servlet.HttpSessionListener
javax.servlet.HttpSessionAttributeListener

根據(jù)你要監(jiān)聽(tīng)的事件選擇他們來(lái)實(shí)現(xiàn)你的監(jiān)聽(tīng)器類(lèi)。比如,每當(dāng)創(chuàng)建或銷(xiāo)毀一個(gè)用戶(hù)session時(shí),HttpSessionListener 就會(huì)發(fā)出通知。

傳遞Servlet初始化參數(shù)

現(xiàn)在的大多數(shù)應(yīng)用都需要設(shè)置一些在應(yīng)用/控制器(controller)啟動(dòng)時(shí)可以傳遞的配置參數(shù)(configuration parameters)。Servlet同樣可以接受初始化參數(shù),并在處理第一個(gè)請(qǐng)求前來(lái)使用它們來(lái)構(gòu)建配置參數(shù)。

顯然,你也可以在Servlet里硬編碼配置值。但是這樣做的話(huà),在Servlet發(fā)生改動(dòng)時(shí)你需要再次重新編譯整個(gè)應(yīng)用。沒(méi)有人喜歡這樣做。

<web-app>
    <servlet>
        <servlet-name>SimpleServlet</servlet-name>
        <servlet-class>com.howtodoinjava.servlets.SimpleServlet</servlet-class>

        <!-- Servlet init param -->
        <init-param>
            <param-name>name</param-name>
            <param-value>value</param-value>
        </init-param>

    </servlet>

</web-app>

設(shè)置后,你就可以在代碼里調(diào)用 getServletConfig.getInitializationParameter() 并傳遞參數(shù)名給該方法來(lái)使用參數(shù)。就像下面展示的代碼一樣:

String value = getServletConfig().getInitParameter("name");

為特定的URL請(qǐng)求添加Servlet過(guò)濾器

Web過(guò)濾器在給定的URL被訪(fǎng)問(wèn)時(shí)對(duì)請(qǐng)求進(jìn)行預(yù)處理并調(diào)用相應(yīng)的功能是很有用的。相 比于直接調(diào)用給定URL請(qǐng)求的Servlet,包含相同URL模式的過(guò)濾器(filter)會(huì)在Servlet調(diào)用前被調(diào)用。這在很多情況下是很有用的。 或許最大的用處就是執(zhí)行日志,驗(yàn)證或者其他不需要與用戶(hù)交互的后臺(tái)服務(wù)。

過(guò)濾器必須要實(shí)現(xiàn) javax.servlet.Filter 接口。這個(gè)接口包含了init(),descriptor()和doFilter()這些方法。init()和destroy()方法會(huì)被容器調(diào)用。 doFilter()方法用來(lái)在過(guò)濾器類(lèi)里實(shí)現(xiàn)邏輯任務(wù)。如果你想把過(guò)濾器組成過(guò)濾鏈(chain filter)或者存在多匹配給定URL模式的個(gè)過(guò)濾器,它們就會(huì)根據(jù)web.xml里的配置順序被調(diào)用。

為了在web.xml里配置過(guò)濾器,需要使用<filter>和<filter-mapping> XML元素以及相關(guān)的子元素標(biāo)簽。

<filter>
    <filter-name>LoggingFilter</filter-name>
    <filter-class>LoggingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>LogingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

如果你要使用注解來(lái)為特定的servlet配置過(guò)濾器,你可以使用@WebFilter注解。

使用Servlet下載二進(jìn)制文件

幾乎所有的web應(yīng)用都必須有下載文件的功能。為了下載一個(gè)文件,Servlet必須提供一個(gè)和下載文件類(lèi)型匹配的響應(yīng)類(lèi)型。同樣,必須在響應(yīng)頭里指出該響應(yīng)包含附件。就像下面的代碼。

String mimeType = context.getMimeType( fileToDownload );
response.setContentType( mimeType != null ? mimeType : "text/plain" );
response.setHeader( "Content-Disposition", "attachment; filename="" + fileToDownload + """ );

通過(guò)調(diào)用 ServletContext.getResourceAsStream() 方法并傳遞文件路徑給該方法,你可以獲取要下載的文件(文件保存在文件系統(tǒng))的引用。這個(gè)方法會(huì)返回一個(gè)輸入流(InputStream)對(duì) 象,我們可以用這個(gè)對(duì)象來(lái)讀取文件內(nèi)容。當(dāng)讀取文件時(shí),我們創(chuàng)建一個(gè)字節(jié)緩存區(qū)(byte buffer)從文件里獲取數(shù)據(jù)塊。最后的工作就是讀取文件內(nèi)容并且把它們復(fù)制到輸出流。我們使用while循環(huán)來(lái)完成文件的讀取,這個(gè)循環(huán)直到讀取了文 件的所有內(nèi)容才會(huì)跳出循環(huán)。我們使用循環(huán)來(lái)讀進(jìn)數(shù)據(jù)塊并把它寫(xiě)進(jìn)輸出流。把所有數(shù)據(jù)寫(xiě)進(jìn)輸出流后,ServletOutputStream 對(duì)象的flush方法就會(huì)被調(diào)用并且清空內(nèi)容和釋放資源。

看這段簡(jiǎn)單的代碼:

private void downloadFile(HttpServletRequest request, HttpServletResponse response, String fileToDownload) throws IOException
    {
        final int BYTES = 1024;
        int length = 0;

        ServletOutputStream outStream = response.getOutputStream();
        ServletContext context = getServletConfig().getServletContext();

        String mimeType = context.getMimeType( fileToDownload );
        response.setContentType( mimeType != null ? mimeType : "text/plain" );
        response.setHeader( "Content-Disposition", "attachment; filename="" + fileToDownload + """ );

        InputStream in = context.getResourceAsStream("/" + fileToDownload);

        byte[] bbuf = new byte[BYTES];

        while ((in != null) && ((length = in.read(bbuf)) != -1)) {
            outStream.write(bbuf, 0, length);
        }

        outStream.flush();
        outStream.close();
    }

使用RequestDispatcher.forward()轉(zhuǎn)發(fā)請(qǐng)求到另一個(gè)Servlet

有時(shí)候,你的應(yīng)用需要把一個(gè)Servlet要處理的請(qǐng)求轉(zhuǎn)讓給另外的Servlet來(lái)處理并完成任務(wù)。而且,轉(zhuǎn)讓請(qǐng)求時(shí)不能重定向客戶(hù)端的URL。即瀏覽器地址欄上的URL不會(huì)改變。

在 ServletContext 里已經(jīng)內(nèi)置了實(shí)現(xiàn)上面需求的方法。所以,當(dāng)你獲取了 ServletContext 的引用,你就可以簡(jiǎn)單地調(diào)用getRequestDispatcher() 方法去獲取用來(lái)轉(zhuǎn)發(fā)請(qǐng)求的 RequestDispatcher 對(duì)象。當(dāng)調(diào)用 getRequestDispatcher() 方法時(shí),需要傳遞包含servlet名的字符串,這個(gè)Servlet就是你用來(lái)處理轉(zhuǎn)讓請(qǐng)求的Servlet。獲取 RequestDispatcher 對(duì)象后,通過(guò)傳遞 HttpServletRequest 和HttpServletResponse 對(duì)象給它來(lái)調(diào)用轉(zhuǎn)發(fā)方法。轉(zhuǎn)發(fā)方法負(fù)責(zé)對(duì)請(qǐng)求進(jìn)行轉(zhuǎn)發(fā)。

RequestDispatcher rd = servletContext.getRequestDispatcher("/NextServlet");
rd.forward(request, response);

使用HttpServletResponse.sendRedirect()重定向請(qǐng)求到另一個(gè)Servlet

盡管有時(shí)候,你不想在Servlet發(fā)送重定向時(shí)通知用戶(hù),就像我們?cè)谏厦婺嵌慰吹降囊粯印5窃谀承┣闆r下,我們確實(shí)想要通知用戶(hù)。當(dāng)應(yīng)用內(nèi)的特定URL被訪(fǎng)問(wèn)時(shí),你想把瀏覽器的URL重定向到另外一個(gè)。

要實(shí)現(xiàn)這種功能,你需要調(diào)用 HttpServletResponse 對(duì)象的sendRedirect()方法。

httpServletResponse.sendRedirect("/anotherURL");

這個(gè)簡(jiǎn)單的重定向,與servlet鏈(servlet chaining)相反,不需要傳遞目標(biāo)地址的HttpRequest對(duì)象。

使用Servlet讀寫(xiě)Cookie

很多應(yīng)用都想在客戶(hù)端機(jī)器里保存用戶(hù)當(dāng)前的瀏覽歷史。目的是當(dāng)用戶(hù)再次使用應(yīng)用時(shí),他能夠從上次離開(kāi)的地方開(kāi)始瀏覽。為了實(shí)現(xiàn)這個(gè)需求,通常使用cookies。你可以把它看作是保存在客戶(hù)端機(jī)器里的鍵值對(duì)基本數(shù)據(jù)。當(dāng)使用瀏覽器打開(kāi)應(yīng)用時(shí),應(yīng)用可以對(duì)這些數(shù)據(jù)進(jìn)行讀寫(xiě)。

為了創(chuàng)建cookie,需要實(shí)例化一個(gè)新的 javax.servlet.http.Cookie 對(duì)象并且為它分配名稱(chēng)和值。實(shí)例化cookie后,可以設(shè)置屬性來(lái)配置cookie。在這個(gè)例子里,我們使用 setMaxAge() 和 setHttpOnly() 方法來(lái)設(shè)置cookie的生命周期和防范客戶(hù)端腳本。

從Servlet3.0 API開(kāi)始,已經(jīng)可以把cookie標(biāo)記為HTTP only了。這使cookie可以防范客戶(hù)端腳本的攻擊,使cookie更加安全。

Cookie cookie = new Cookie("sessionId","123456789");
cookie.setHttpOnly(true);
cookie.setMaxAge(-30);
response.addCookie(cookie);

這里的response是傳遞給doXXX()方法的 HttpServletResponse 實(shí)例。

要讀取服務(wù)端的cookie信息,使用下面代碼:

Cookie[] cookies = request.getCookies();
for(Cookie cookie : cookies)
{
    //cookie.getName();
    //cookie.getValue()
}

這就是這篇教程里關(guān)于Servlet技術(shù)的全部?jī)?nèi)容了。歡迎評(píng)論和回饋。

學(xué)習(xí)快樂(lè)!!

標(biāo)簽: isp web服務(wù)器 安全 代碼 服務(wù)器 腳本 開(kāi)發(fā)者 網(wǎng)絡(luò) 應(yīng)用服務(wù)器

版權(quán)申明:本站文章部分自網(wǎng)絡(luò),如有侵權(quán),請(qǐng)聯(lián)系:west999com@outlook.com
特別注意:本站所有轉(zhuǎn)載文章言論不代表本站觀(guān)點(diǎn)!
本站所提供的圖片等素材,版權(quán)歸原作者所有,如需使用,請(qǐng)與原作者聯(lián)系。

上一篇:一個(gè)Java對(duì)象到底占多大內(nèi)存?

下一篇:iOS開(kāi)發(fā)簡(jiǎn)單的音頻播放器