1.Servlet 简介

Servlet 对请求的处理和响应过程可分为以下几个步骤:
(1)客户端发送请求至服务器端;
(2)服务器将请求信息发送至 Servlet ;
(3)Servlet 生成响应内容并将其传给服务器。响应内容动态生成,通常取决于客户端的请求;
(4)服务器将响应返回给客户端。

Servlet 执行以下主要任务:

  • 读取客户端(浏览器)发送的显式的数据。这包括网页上的 HTML 表单,或者也可以是来自 applet 或自定义的 HTTP 客户端程序的表单。
  • 读取客户端(浏览器)发送的隐式的 HTTP 请求数据。这包括 cookies、媒体类型和浏览器能理解的压缩格式等等。
  • 处理数据并生成结果。这个过程可能需要访问数据库,执行 RMI 或 CORBA 调用,调用 Web 服务,或者直接计算得出对应的响应。
  • 发送显式的数据(即文档)到客户端(浏览器)。该文档的格式可以是多种多样的,包括文本文件(HTML 或 XML)、二进制文件(GIF 图像)、Excel 等。
  • 发送隐式的 HTTP 响应到客户端(浏览器)。这包括告诉浏览器或其他客户端被返回的文档类型(例如 HTML),设置 cookies 和缓存参数,以及其他类似的任务。

2.Servlet基础

2.1 Servlet体系结构

public abstract class HttpServlet extends GenericServlet
public abstract class GenericServlet implements Servlet, ServletConfig, Serializable

2.2 Servlet 接口

Servlet 接口 定义了 Servlet 与 Servlet 容器之间的契约,Servlet 容器将 Servlet 类载入内存,并在 Servlet 实例上调用具体的方法。用户请求致使 Servlet 容器调用 Servlet 的Service 方法,并传入一个 ServletRequest 实例和一个 ServletResponse 实例。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package javax.servlet;import java.io.IOException;public interface Servlet {void init(ServletConfig var1) throws ServletException;ServletConfig getServletConfig();void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;String getServletInfo();void destroy();
}
  1. init():在 Servlet 实例化后,Servlet 容器会调用该方法,初始化该对象。init() 方法有一个类型为 ServletConfig 的参数,Servlet 容器通过这个参数向 Servlet 传递配置信息。 Servlet 使用 ServletConfig 对象从 Web 应用程序的配置信息中获取以名-值对形式提供的初始化参数。
  2. service():容器调用 service() 方法来处理客户端的请求。
  3. destroy():Servlet 的销毁方法。容器在终止 Servlet 服务前调用此方法。
  4. getServletConfig():该方法返回容器调用 init() 方法时传递给 Servlet 对象的 ServletConfig 对象,ServletConfig 对象包含了 Servlet 的初始化参数。
  5. getServletInfo():返回一个 String 类型的字符串,其中包括了关于 Servlet 的信息。例如作者、描述信息等。

2.3 生命周期

Servlet 生命周期可被定义为从创建直到毁灭的整个过程。以下是 Servlet 遵循的过程:

  • Servlet 通过调用 init () 方法进行初始化。

  • Servlet 调用 service() 方法来处理客户端的请求。

  • Servlet 通过调用 destroy() 方法终止(结束)。

  • 最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。

一个简单的生命周期案例:

package webstudy;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet(name = "/life")
public class LifeServlet extends HttpServlet {public LifeServlet() {System.out.println(this.getClass().getName()+"构造方法执行");}@Overridepublic void init() throws ServletException {// 初始化代码...System.out.println(this.getClass().getName()+"init方法执行");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {System.out.println(this.getClass().getName()+"doGet方法执行");response.setContentType("text/html");PrintWriter pw = response.getWriter();pw.println("<h1> hello first servlet!</h1>");pw.flush();pw.close();}@Overridepublic void destroy() {// 终止化代码...System.out.println(this.getClass().getName()+"destory方法执行");}
}
    <!--********************* 生命周期,直接执行servlet程序 *********************--><servlet><servlet-name>LifeServlet</servlet-name><servlet-class>webstudy.LifeServlet</servlet-class></servlet><servlet-mapping><servlet-name>LifeServlet</servlet-name><url-pattern>/life</url-pattern></servlet-mapping>

3. Servlet API 编程常用接口和类

  • GenericServlet 类

  • HttpServlet 类

  • ServletConfig 接口

  • HttpServletRequest 接口

  • HttpServletResponse 接口

  • ServletConfig 接口

3.4.1 GenericServlet 类

GenericServlet 类是一个抽象类,实现了 Servlet 和 ServletConfig 接口,其作用是:
(1)将 init 方法中的 ServletConfig 赋给一个类中成员(ServletConfig config),以便可以通过调用 getServletConfig 获取。
(2)为 Servlet 接口中的所有方法提供默认的实现。
(3)可以通过覆盖没有参数的 init 方法来编写初始化代码,ServletConfig 则仍然由 GenericServlet 实例保存。
(4)开发者可以在不用获得 ServletConfig 对象情况下直接调用 ServletConfig 的方法,例如源代码中的 getServletContext() 方法。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package javax.servlet;import java.io.IOException;
import java.io.Serializable;
import java.util.Enumeration;public abstract class GenericServlet implements Servlet, ServletConfig, Serializable {private static final long serialVersionUID = 1L;private transient ServletConfig config;public GenericServlet() {}public void destroy() {}public String getInitParameter(String name) {return this.getServletConfig().getInitParameter(name);}public Enumeration<String> getInitParameterNames() {return this.getServletConfig().getInitParameterNames();}public ServletConfig getServletConfig() {return this.config;}public ServletContext getServletContext() {return this.getServletConfig().getServletContext();}public String getServletInfo() {return "";}public void init(ServletConfig config) throws ServletException {this.config = config;this.init();}public void init() throws ServletException {}public void log(String message) {this.getServletContext().log(this.getServletName() + ": " + message);}public void log(String message, Throwable t) {this.getServletContext().log(this.getServletName() + ": " + message, t);}public abstract void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;public String getServletName() {return this.config.getServletName();}
}

一个简单示例:获取初始化参数name:value

package book.ch2;import javax.servlet.*;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet(name = "MyGenericServlet", urlPatterns = { "/generic" }, initParams = {@WebInitParam(name = "driverClassName", value = "org.postgresql.Driver")})public class MyGenericServlet extends GenericServlet {private static final long serialVersionUID = 1L;public MyGenericServlet() {super();}@Overridepublic void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {ServletConfig servletConfig = getServletConfig();String driverClassName = servletConfig.getInitParameter("driverClassName");String url = servletConfig.getInitParameter("url");response.setContentType("text/html");PrintWriter writer = response.getWriter();        writer.print("driverClassName:" + driverClassName);          }
}

3.4.2 HttpServlet 类

HttpServlet 覆盖了 GenericServlet 中的 Service 方法,并添加了一个新 Service 方法。
新 Service 方法接受的参数是 HTTPServletRequest 和 HttpServletResponse ,而不是 ServletRequest 和 ServletResponse。
原始的 Service 方法将 Servlet 容器的 request 和 response 对象分别转换成 HTTPServletRequest 和 HttpServletResponse,并调用新的 Service 方法。

HTTPServlet 中的 Service 方法会检验用来发送请求的 HTTP 方法(通过调用 request.getMethod)并调用以下方法之一:doGet、doPost、doHead、doPut、doTrace、doOptions 和 doDelete。这 7 种方法中,doGet 和 doPost 是最常用的。所以,不再需要覆盖 Service 方法了,只须覆盖 doGet 或者 doPost 即可。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package javax.servlet.http;import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.ResourceBundle;
import javax.servlet.DispatcherType;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;public abstract class HttpServlet extends GenericServlet {private static final long serialVersionUID = 1L;private static final String METHOD_DELETE = "DELETE";private static final String METHOD_HEAD = "HEAD";private static final String METHOD_GET = "GET";private static final String METHOD_OPTIONS = "OPTIONS";private static final String METHOD_POST = "POST";private static final String METHOD_PUT = "PUT";private static final String METHOD_TRACE = "TRACE";private static final String HEADER_IFMODSINCE = "If-Modified-Since";private static final String HEADER_LASTMOD = "Last-Modified";private static final String LSTRING_FILE = "javax.servlet.http.LocalStrings";private static final ResourceBundle lStrings = ResourceBundle.getBundle("javax.servlet.http.LocalStrings");public HttpServlet() {}protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String msg = lStrings.getString("http.method_get_not_supported");this.sendMethodNotAllowed(req, resp, msg);}protected long getLastModified(HttpServletRequest req) {return -1L;}protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {if (DispatcherType.INCLUDE.equals(req.getDispatcherType())) {this.doGet(req, resp);} else {NoBodyResponse response = new NoBodyResponse(resp);this.doGet(req, response);response.setContentLength();}}protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String msg = lStrings.getString("http.method_post_not_supported");this.sendMethodNotAllowed(req, resp, msg);}protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String msg = lStrings.getString("http.method_put_not_supported");this.sendMethodNotAllowed(req, resp, msg);}protected void doDelete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String msg = lStrings.getString("http.method_delete_not_supported");this.sendMethodNotAllowed(req, resp, msg);}private void sendMethodNotAllowed(HttpServletRequest req, HttpServletResponse resp, String msg) throws IOException {String protocol = req.getProtocol();if (protocol.length() != 0 && !protocol.endsWith("0.9") && !protocol.endsWith("1.0")) {resp.sendError(405, msg);} else {resp.sendError(400, msg);}}private static Method[] getAllDeclaredMethods(Class<?> c) {if (c.equals(HttpServlet.class)) {return null;} else {Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());Method[] thisMethods = c.getDeclaredMethods();if (parentMethods != null && parentMethods.length > 0) {Method[] allMethods = new Method[parentMethods.length + thisMethods.length];System.arraycopy(parentMethods, 0, allMethods, 0, parentMethods.length);System.arraycopy(thisMethods, 0, allMethods, parentMethods.length, thisMethods.length);thisMethods = allMethods;}return thisMethods;}}protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {Method[] methods = getAllDeclaredMethods(this.getClass());boolean ALLOW_GET = false;boolean ALLOW_HEAD = false;boolean ALLOW_POST = false;boolean ALLOW_PUT = false;boolean ALLOW_DELETE = false;boolean ALLOW_TRACE = true;boolean ALLOW_OPTIONS = true;Class clazz = null;try {clazz = Class.forName("org.apache.catalina.connector.RequestFacade");Method getAllowTrace = clazz.getMethod("getAllowTrace", (Class[])null);ALLOW_TRACE = (Boolean)getAllowTrace.invoke(req, (Object[])null);} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | ClassNotFoundException var14) {}for(int i = 0; i < methods.length; ++i) {Method m = methods[i];if (m.getName().equals("doGet")) {ALLOW_GET = true;ALLOW_HEAD = true;}if (m.getName().equals("doPost")) {ALLOW_POST = true;}if (m.getName().equals("doPut")) {ALLOW_PUT = true;}if (m.getName().equals("doDelete")) {ALLOW_DELETE = true;}}String allow = null;if (ALLOW_GET) {allow = "GET";}if (ALLOW_HEAD) {if (allow == null) {allow = "HEAD";} else {allow = allow + ", HEAD";}}if (ALLOW_POST) {if (allow == null) {allow = "POST";} else {allow = allow + ", POST";}}if (ALLOW_PUT) {if (allow == null) {allow = "PUT";} else {allow = allow + ", PUT";}}if (ALLOW_DELETE) {if (allow == null) {allow = "DELETE";} else {allow = allow + ", DELETE";}}if (ALLOW_TRACE) {if (allow == null) {allow = "TRACE";} else {allow = allow + ", TRACE";}}if (ALLOW_OPTIONS) {if (allow == null) {allow = "OPTIONS";} else {allow = allow + ", OPTIONS";}}resp.setHeader("Allow", allow);}protected void doTrace(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String CRLF = "\r\n";StringBuilder buffer = (new StringBuilder("TRACE ")).append(req.getRequestURI()).append(" ").append(req.getProtocol());Enumeration reqHeaderEnum = req.getHeaderNames();while(reqHeaderEnum.hasMoreElements()) {String headerName = (String)reqHeaderEnum.nextElement();buffer.append(CRLF).append(headerName).append(": ").append(req.getHeader(headerName));}buffer.append(CRLF);int responseLength = buffer.length();resp.setContentType("message/http");resp.setContentLength(responseLength);ServletOutputStream out = resp.getOutputStream();out.print(buffer.toString());out.close();}protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getMethod();long lastModified;if (method.equals("GET")) {lastModified = this.getLastModified(req);if (lastModified == -1L) {this.doGet(req, resp);} else {long ifModifiedSince;try {ifModifiedSince = req.getDateHeader("If-Modified-Since");} catch (IllegalArgumentException var9) {ifModifiedSince = -1L;}if (ifModifiedSince < lastModified / 1000L * 1000L) {this.maybeSetLastModified(resp, lastModified);this.doGet(req, resp);} else {resp.setStatus(304);}}} else if (method.equals("HEAD")) {lastModified = this.getLastModified(req);this.maybeSetLastModified(resp, lastModified);this.doHead(req, resp);} else if (method.equals("POST")) {this.doPost(req, resp);} else if (method.equals("PUT")) {this.doPut(req, resp);} else if (method.equals("DELETE")) {this.doDelete(req, resp);} else if (method.equals("OPTIONS")) {this.doOptions(req, resp);} else if (method.equals("TRACE")) {this.doTrace(req, resp);} else {String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[]{method};errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(501, errMsg);}}private void maybeSetLastModified(HttpServletResponse resp, long lastModified) {if (!resp.containsHeader("Last-Modified")) {if (lastModified >= 0L) {resp.setDateHeader("Last-Modified", lastModified);}}}public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {HttpServletRequest request;HttpServletResponse response;try {request = (HttpServletRequest)req;response = (HttpServletResponse)res;} catch (ClassCastException var6) {throw new ServletException(lStrings.getString("http.non_http"));}this.service(request, response);}
}

3.4.3 ServletConfig 接口

Tomcat 初始化一个 Servlet 时,会将该 Servlet 的配置信息封装到一个 ServletConfig 对象中,通过调用 init(ServletConfig config) 方法将 ServletConfig 对象传递给 Servlet。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package javax.servlet;import java.util.Enumeration;public interface ServletConfig {String getServletName();ServletContext getServletContext();String getInitParameter(String var1);Enumeration<String> getInitParameterNames();
}

一个简单的示例:获取配置信息

package book.ch2;import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;public class ServletConfigDemoServlet extends HttpServlet { private ServletConfig servletConfig;@Overridepublic void init(ServletConfig config) throws ServletException {this.servletConfig = config;System.out.println("-----------" + servletConfig + "-----------");}@Overridepublic ServletConfig getServletConfig() {return servletConfig;}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {// 使用ServletConfig对象获取初始化参数ServletConfig servletConfig = getServletConfig();System.out.println("-----------" + servletConfig + "-----------");String poet = servletConfig.getInitParameter("poet");String poem = servletConfig.getInitParameter("poem");// 设置响应到客户端的文本类型为HTMLresponse.setContentType("text/html;charset=UTF-8");// 获取输出流PrintWriter out = response.getWriter();out.print("<p>获取ServletConfigDenoServlet的初始化参数:");out.println("</p><p>poet参数的值:" + poet);out.println("</p><p>poem参数的值:" + poem + "</p>");        out.append("Served at:").append(request.getContextPath());}}

web.xml配置

    <servlet><servlet-name>myServletConfig</servlet-name><servlet-class>book.ch2.ServletConfigDemoServlet</servlet-class><init-param><param-name>poet</param-name><param-value>纳兰容若</param-value></init-param><init-param><param-name>poem</param-name><param-value>我是人间惆怅客</param-value></init-param></servlet><servlet-mapping><servlet-name>myServletConfig</servlet-name><url-pattern>/myServletConfig</url-pattern></servlet-mapping>

输出结果:

3.4.4 HttpServletRequest 接口

HttpServletRequest 接口继承自 ServletRequest 接口,专门用来封装 HTTP 请求消息

由于 HTTP 请求消息分为请求行、请求消息头和请求消息体3部分,故而在 HttpServletRequest 接口中定义了获取请求行、请求消息头和请求消息体的相关方法,以及存取请求域属性的方法。

package book.ch2;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/RequestLineServlet")
public class RequestLineServlet extends HttpServlet {private static final long serialVersionUID = 1L;public RequestLineServlet() {super();     }/******************* 获取请求行信息 *******************/@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应到客户端MIME类型和字符编码方式response.setContentType("text/html;charset=UTF-8");// 获取请求使用的HTTP方法String method = request.getMethod();// 获取请求行中的资源名部分String uri = request.getRequestURI();// 获取使用的协议及版本号String protocol = request.getProtocol();// 获取请求URL后面的查询字符串String queryString = request.getQueryString();// 获取Servlet所映射的路径String servletPath = request.getServletPath();// 获取请求资源所属于的Web应用的路径String contextPath = request.getContextPath();// 获取输出流PrintWriter out = response.getWriter();out.println("<p>请求使用的HTTP方法:" + method + "</p>");out.println("<p>请求行中的资源名部分:" + uri + "</p>");out.println("<p>请求使用的协议及版本号:" + protocol + "</p>");out.println("<p>请求URL后面的查询字符串:" + queryString + "</p>");out.println("<p>Servlet所映射的路径:" + servletPath + "</p>");out.println("<p>请求资源所属于的Web应用的路径:" + contextPath + "</p>");     out.append("Served at:").append(request.getContextPath());out.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {     doGet(request, response);}}

3.4.4.1 获取请求头信息


package book.ch2;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;@WebServlet("/RequestHeadInfoServlet")
public class RequestHeadInfoServlet extends HttpServlet {private static final long serialVersionUID = 1L;public RequestHeadInfoServlet() {super();}/******************* 获取请求头信息 *******************/@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {response.setContentType("text/html;charset=utf-8");PrintWriter out = response.getWriter();out.print("<h3>请求头信息<h3>");// 获取请求消息中所有头字段Enumeration headerNames = request.getHeaderNames();// 使用循环遍历所有请求头,并通过getHeader()方法获取一个指定名称的头字段while (headerNames.hasMoreElements()) {String headerName = (String) headerNames.nextElement();out.print(headerName + " : " + request.getHeader(headerName) + "<br>");}}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

3.4.4.2 获取请求参数

获取请求参数:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>个人信息</title>
</head>
<body>
<h2>个人信息</h2>
<hr>
<form action="/RequestParaServlet" method="GET"><p>用户名:<input type="text" name="username"></p><p>昵  &nbsp;&nbsp;&nbsp;称:<input type="text" name="nickname"></p><p>爱好:<input type="checkbox" name="hobby" value="swim">游泳<input type="checkbox" name="hobby" value="go">围棋<input type="checkbox" name="hobby" value="music">音乐</p><p><input type="submit" value="提交"></p></form>
</body>
</html>
package book.ch2;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/RequestParaServlet")
public class RequestParaServlet extends HttpServlet {private static final long serialVersionUID = 1L;public RequestParaServlet() {super();}/******************* 获取请求参数 *******************/@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应到客户端MIME类型和字符编码方式response.setContentType("text/html;charset=UTF-8");// 设置request对象的解码方式request.setCharacterEncoding("utf-8");String username = request.getParameter("username");String nickname = request.getParameter("nickname");// 获取输出流PrintWriter out = response.getWriter();out.println("<p>用户名:" + username + "</p>");out.println("<p>昵 称:" + nickname + "</p>");out.println("<p>爱好:");// 获取参数名为“hobby”的值String[] hobbys = request.getParameterValues("hobby");for (int i = 0; i < hobbys.length; i++) {if (i < hobbys.length - 1)out.println(hobbys[i] + ",");elseout.println(hobbys[i] + "");}out.println("</p>");out.close();      }@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

3.4.4.3 设置-获取-删除请求域属性

获取请求域属性:

package book.ch2;import com.mialab.servlet_demo.entity.Book;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.Enumeration;@WebServlet("/RequestScopeAttrServlet")
public class RequestScopeAttrServlet extends HttpServlet {private static final long serialVersionUID = 1L;public RequestScopeAttrServlet() {super();}@Override/******************* 获取请求域属性 *******************/protected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应的文本类型为HTML,字符编码为UTF-8response.setContentType("text/html;charset=UTF-8");// 在request范围内设置名为book的Book对象属性request.setAttribute("book", new Book(9801, "《Android应用开发实践教程》"));// 在request范围内设置名为singer的String对象属性request.setAttribute("singer", "Jessie J,第32届全英音乐奖入围最佳女艺人,《歌手2018》总冠军");// 在request范围内设置名为newdate的Date对象属性request.setAttribute("newdate", new Date());// 从request范围内获取名为book的属性Book book = (Book) request.getAttribute("book");// 从request范围内获取名为singer的属性String singer = (String) request.getAttribute("singer");// 从request范围内获取名为newdate的属性Date date = (Date) request.getAttribute("newdate");// 获取输出流PrintWriter out = response.getWriter();out.println("<p>request.getAttribute(\"book\")的值:" + book + "</p>");out.println("<p>request.getAttribute(\"singer\")的值:" + singer + "</p>");out.println("<p>request.getAttribute(\"newdate\")的值:" + date + "</p>");Enumeration<String> names = request.getAttributeNames();out.println("<p>request请求域中的属性有:");while (names.hasMoreElements()) {out.println(names.nextElement() + "&nbsp;");}out.println("</p>");request.removeAttribute("book");out.println("<p>执行request.removeAttribute(\"book\")后request请求域中的属性有:");names = request.getAttributeNames();while (names.hasMoreElements()) {out.println(names.nextElement() + "&nbsp;");}out.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

HttpServletRequest源代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package javax.servlet.http;import java.io.IOException;
import java.security.Principal;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;public interface HttpServletRequest extends ServletRequest {String BASIC_AUTH = "BASIC";String FORM_AUTH = "FORM";String CLIENT_CERT_AUTH = "CLIENT_CERT";String DIGEST_AUTH = "DIGEST";String getAuthType();Cookie[] getCookies();long getDateHeader(String var1);String getHeader(String var1);Enumeration<String> getHeaders(String var1);Enumeration<String> getHeaderNames();int getIntHeader(String var1);default HttpServletMapping getHttpServletMapping() {return new HttpServletMapping() {public String getMatchValue() {return "";}public String getPattern() {return "";}public String getServletName() {return "";}public MappingMatch getMappingMatch() {return null;}};}String getMethod();String getPathInfo();String getPathTranslated();default PushBuilder newPushBuilder() {return null;}String getContextPath();String getQueryString();String getRemoteUser();boolean isUserInRole(String var1);Principal getUserPrincipal();String getRequestedSessionId();String getRequestURI();StringBuffer getRequestURL();String getServletPath();HttpSession getSession(boolean var1);HttpSession getSession();String changeSessionId();boolean isRequestedSessionIdValid();boolean isRequestedSessionIdFromCookie();boolean isRequestedSessionIdFromURL();/** @deprecated */@Deprecatedboolean isRequestedSessionIdFromUrl();boolean authenticate(HttpServletResponse var1) throws IOException, ServletException;void login(String var1, String var2) throws ServletException;void logout() throws ServletException;Collection<Part> getParts() throws IOException, ServletException;Part getPart(String var1) throws IOException, ServletException;<T extends HttpUpgradeHandler> T upgrade(Class<T> var1) throws IOException, ServletException;default Map<String, String> getTrailerFields() {return Collections.emptyMap();}default boolean isTrailerFieldsReady() {return false;}
}

3.4.5 HttpServletResponse 接口

HttpServletResponse 接口继承自 ServletResponse 接口,专门用来封装 HTTP 响应消息。由于 HTTP 响应消息分为状态行、响应消息头、消息体三部分,于是在 HttpServletResponse 接口中也相应定义了向客户端发送响应状态码、响应消息头、响应消息体的方法。

HttpServletResponse 接口提供的设置状态码并生成响应状态行的方法有以下。
(1)setStatus(int status) 方法:用于设置 HTTP 响应消息的状态码,并生成响应状态行。正常情况下,Web 服务器会默认产生一个状态码为 200 的状态行。
(2)sendError(int sc) 方法和 sendError(int sc, String msg) 方法:第 1 个方法只是发送错误信息的状态码;而第 2 个方法除了发送状态码外,还可以增加一条用于提示说明的文本信息,该文本信息将出现在发送给客户端的正文内容中。

3.4.5.1 响应消息头
package book.ch2;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/ResponseHeadServlet")
public class ResponseHeadServlet extends HttpServlet {private static final long serialVersionUID = 1L;public ResponseHeadServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 5秒后刷新并跳转到我的博客的网站首页response.setHeader("Refresh", "5;URL=http://www.bithachi.cn");// 每隔2秒定时刷新当前页面// response.setHeader("Refresh", "2");response.getWriter().println(new java.util.Date());// 输出当前时间}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}


3.4.5.2 响应消息体
package book.ch2;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;@WebServlet("/ResponsePicServlet")
public class ResponsePicServlet extends HttpServlet {private static final long serialVersionUID = 1L;public ResponsePicServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应消息头Content-Typeresponse.setContentType("image/jpeg");// 获取ServletContext对象ServletContext context = super.getServletContext();// 获取读取服务器端文件的输入流InputStream is = context.getResourceAsStream("/images/ch2/abc.jpeg");// 获取ServletOutputStream输出流ServletOutputStream os = response.getOutputStream();int i = 0;while ((i = is.read()) != -1) {os.write(i);// 向输出流中写入二进制数据}is.close();os.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}
}


HttpServletResponse源代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package javax.servlet.http;import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.function.Supplier;
import javax.servlet.ServletResponse;public interface HttpServletResponse extends ServletResponse {int SC_CONTINUE = 100;int SC_SWITCHING_PROTOCOLS = 101;int SC_OK = 200;int SC_CREATED = 201;int SC_ACCEPTED = 202;int SC_NON_AUTHORITATIVE_INFORMATION = 203;int SC_NO_CONTENT = 204;int SC_RESET_CONTENT = 205;int SC_PARTIAL_CONTENT = 206;int SC_MULTIPLE_CHOICES = 300;int SC_MOVED_PERMANENTLY = 301;int SC_MOVED_TEMPORARILY = 302;int SC_FOUND = 302;int SC_SEE_OTHER = 303;int SC_NOT_MODIFIED = 304;int SC_USE_PROXY = 305;int SC_TEMPORARY_REDIRECT = 307;int SC_BAD_REQUEST = 400;int SC_UNAUTHORIZED = 401;int SC_PAYMENT_REQUIRED = 402;int SC_FORBIDDEN = 403;int SC_NOT_FOUND = 404;int SC_METHOD_NOT_ALLOWED = 405;int SC_NOT_ACCEPTABLE = 406;int SC_PROXY_AUTHENTICATION_REQUIRED = 407;int SC_REQUEST_TIMEOUT = 408;int SC_CONFLICT = 409;int SC_GONE = 410;int SC_LENGTH_REQUIRED = 411;int SC_PRECONDITION_FAILED = 412;int SC_REQUEST_ENTITY_TOO_LARGE = 413;int SC_REQUEST_URI_TOO_LONG = 414;int SC_UNSUPPORTED_MEDIA_TYPE = 415;int SC_REQUESTED_RANGE_NOT_SATISFIABLE = 416;int SC_EXPECTATION_FAILED = 417;int SC_INTERNAL_SERVER_ERROR = 500;int SC_NOT_IMPLEMENTED = 501;int SC_BAD_GATEWAY = 502;int SC_SERVICE_UNAVAILABLE = 503;int SC_GATEWAY_TIMEOUT = 504;int SC_HTTP_VERSION_NOT_SUPPORTED = 505;void addCookie(Cookie var1);boolean containsHeader(String var1);String encodeURL(String var1);String encodeRedirectURL(String var1);/** @deprecated */@DeprecatedString encodeUrl(String var1);/** @deprecated */@DeprecatedString encodeRedirectUrl(String var1);void sendError(int var1, String var2) throws IOException;void sendError(int var1) throws IOException;void sendRedirect(String var1) throws IOException;void setDateHeader(String var1, long var2);void addDateHeader(String var1, long var2);void setHeader(String var1, String var2);void addHeader(String var1, String var2);void setIntHeader(String var1, int var2);void addIntHeader(String var1, int var2);void setStatus(int var1);/** @deprecated */@Deprecatedvoid setStatus(int var1, String var2);int getStatus();String getHeader(String var1);Collection<String> getHeaders(String var1);Collection<String> getHeaderNames();default void setTrailerFields(Supplier<Map<String, String>> supplier) {}default Supplier<Map<String, String>> getTrailerFields() {return null;}
}

3.4.6 ServletContext 接口

Servlet 容器在启动一个 Web 应用时,会为该应用创建一个唯一的 ServletContext 对象供该应用中的所有 Servlet 对象共享。Servlet 对象可以通过 ServletContext 对象来访问容器中的各种资源。

获得 ServletContext 对象可以通过以下两种方式:

  1. 通过 ServletConfig 接口的 getServletContext() 方法获得 ServletContext 对象。
  2. 通过 GenericServlet 抽象类的 getServletContext() 方法获得 ServletContext 对象,实质上该方法也调用了 ServletConfig 的 getServletContext() 方法。

ServletContext 接口中定义了获取 Web 应用范围的初始化参数的方法,有以下。
(1)方法声明:public String getInitParameter(String name) ;
作用:返回 Web 应用范围内指定的初始化参数值。在 web.xml 中使用 元素表示应用范围内的初始化参数。
(2)方法声明:public Enumeration getInitParameterNames();
作用:返回一个包含所有初始化参数名称的 Enumeration 对象。

3.4.6.1 获取WEB应用的初始化参数

web.xml

    <context-param><param-name>username</param-name><param-value>admin888</param-value></context-param><context-param><param-name>password</param-name><param-value>123</param-value></context-param><context-param><param-name>driverClassName</param-name><param-value>org.postgresql.Driver</param-value></context-param><context-param><param-name>url</param-name><param-value>jdbc:postgresql://127.0.0.1:5432/postgres</param-value></context-param>
package book.ch2;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;@WebServlet("/GetWebInitParamServlet")
public class GetWebInitParamServlet extends HttpServlet {private static final long serialVersionUID = 1L;public GetWebInitParamServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应到客户端的文本类型为HTMLresponse.setContentType("text/html;charset=UTF-8");// 得到ServletContext对象ServletContext context = this.getServletContext();// 得到包含所有初始化参数名的Enumeration对象Enumeration<String> paramNames = context.getInitParameterNames();// 获取输出流PrintWriter out = response.getWriter();// 遍历所有的初始化参数名,得到相应的参数值,打印到控制台out.print("<h2>当前Web应用的所有初始化参数:</h2>");      // 遍历所有的初始化参数名,得到相应的参数值并打印while (paramNames.hasMoreElements()) {String name = paramNames.nextElement();String value = context.getInitParameter(name);out.println(name + ":" + value);out.println("<br>");}out.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

3.4.6.2 实现多个Servlet对象共享数据

先访问PutContextDataServlet.java设置共享数据,再访问GetContextDataServlet.java获取共享数据

package com.mialab.servlet_demo;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/PutContextDataServlet")
public class PutContextDataServlet extends HttpServlet {private static final long serialVersionUID = 1L;public PutContextDataServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {ServletContext context = this.getServletContext();// 通过setAttribute()方法设置属性值context.setAttribute("contextData", "Here is contexData");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// TODO Auto-generated method stubdoGet(request, response);}}
package book.ch2;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/GetContextDataServlet")
public class GetContextDataServlet extends HttpServlet {private static final long serialVersionUID = 1L;public GetContextDataServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {PrintWriter out = response.getWriter();ServletContext context = this.getServletContext();// 通过getAttribute()方法获取属性值String data = (String) context.getAttribute("contextData");out.println(data);System.out.println(data);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

3.4.6.3 读取WEB应用下的资源文件

package book.ch2;import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Properties;@WebServlet("/GetResourceServlet")
public class GetResourceServlet extends HttpServlet {private static final long serialVersionUID = 1L;public GetResourceServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {PrintWriter out = response.getWriter();ServletContext context = this.getServletContext();// 获取文件绝对路径String path = context.getRealPath("/WEB-INF/classes/data.properties");FileInputStream in = new FileInputStream(path);Properties pros = new Properties();pros.load(in);out.println("username = " + pros.getProperty("username") + "<br>");out.println("password = " + pros.getProperty("password") + "<br>");out.println("driverClassName = " + pros.getProperty("driverClassName") + "<br>");out.println("url = " + pros.getProperty("url") + "<br>");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}
}

ServletContext.java源代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//package javax.servlet;import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.EventListener;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletRegistration.Dynamic;
import javax.servlet.descriptor.JspConfigDescriptor;public interface ServletContext {String TEMPDIR = "javax.servlet.context.tempdir";String ORDERED_LIBS = "javax.servlet.context.orderedLibs";String getContextPath();ServletContext getContext(String var1);int getMajorVersion();int getMinorVersion();int getEffectiveMajorVersion();int getEffectiveMinorVersion();String getMimeType(String var1);Set<String> getResourcePaths(String var1);URL getResource(String var1) throws MalformedURLException;InputStream getResourceAsStream(String var1);RequestDispatcher getRequestDispatcher(String var1);RequestDispatcher getNamedDispatcher(String var1);/** @deprecated */@DeprecatedServlet getServlet(String var1) throws ServletException;/** @deprecated */@DeprecatedEnumeration<Servlet> getServlets();/** @deprecated */@DeprecatedEnumeration<String> getServletNames();void log(String var1);/** @deprecated */@Deprecatedvoid log(Exception var1, String var2);void log(String var1, Throwable var2);String getRealPath(String var1);String getServerInfo();String getInitParameter(String var1);Enumeration<String> getInitParameterNames();boolean setInitParameter(String var1, String var2);Object getAttribute(String var1);Enumeration<String> getAttributeNames();void setAttribute(String var1, Object var2);void removeAttribute(String var1);String getServletContextName();Dynamic addServlet(String var1, String var2);Dynamic addServlet(String var1, Servlet var2);Dynamic addServlet(String var1, Class<? extends Servlet> var2);Dynamic addJspFile(String var1, String var2);<T extends Servlet> T createServlet(Class<T> var1) throws ServletException;ServletRegistration getServletRegistration(String var1);Map<String, ? extends ServletRegistration> getServletRegistrations();javax.servlet.FilterRegistration.Dynamic addFilter(String var1, String var2);javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Filter var2);javax.servlet.FilterRegistration.Dynamic addFilter(String var1, Class<? extends Filter> var2);<T extends Filter> T createFilter(Class<T> var1) throws ServletException;FilterRegistration getFilterRegistration(String var1);Map<String, ? extends FilterRegistration> getFilterRegistrations();SessionCookieConfig getSessionCookieConfig();void setSessionTrackingModes(Set<SessionTrackingMode> var1);Set<SessionTrackingMode> getDefaultSessionTrackingModes();Set<SessionTrackingMode> getEffectiveSessionTrackingModes();void addListener(String var1);<T extends EventListener> void addListener(T var1);void addListener(Class<? extends EventListener> var1);<T extends EventListener> T createListener(Class<T> var1) throws ServletException;JspConfigDescriptor getJspConfigDescriptor();ClassLoader getClassLoader();void declareRoles(String... var1);String getVirtualServerName();int getSessionTimeout();void setSessionTimeout(int var1);String getRequestCharacterEncoding();void setRequestCharacterEncoding(String var1);String getResponseCharacterEncoding();void setResponseCharacterEncoding(String var1);
}

4. Servlet处理表单数据

表单数据是指通过表单让用户填写内容,然后提交到服务器上;这些数据被称之为表单数据。
Servlet 处理表单数据可以使用以下的方法:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Servlet处理表单数据</title>
</head>
<body><h2>个人信息</h2><hr><form action="/formtest" method="POST"><p>用户名:<input type="text" name="username"></p><p>密 &nbsp;&nbsp;&nbsp;码 :<input type="password" name="password"></p><p>性 &nbsp;&nbsp;&nbsp;别 :<input type="radio" name="sex" value="boy"checked>男<input type="radio" name="sex" value="girl">女</p><p>家 &nbsp;&nbsp;&nbsp;乡 :<select name="home"><optionvalue="suzhou">苏州</option><option value="shanghai">上海</option><option value="nanjing">南京</option></select></p><p>爱 &nbsp;&nbsp;&nbsp;好: <input type="checkbox" name="hobby"value="swim">游泳 <input type="checkbox" name="hobby"value="go">围棋 <input type="checkbox" name="hobby"value="music">音乐</p><p>自我介绍:<br><textarea name="info" rows="5" cols="26"></textarea></p><p><input type="submit" value="提交"></p></form>
</body>
</body>
</html>
package webstudy;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;@WebServlet("/formtest")
public class FormServlet extends HttpServlet {private static final long serialVersionUID = 1L;public FormServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应到客户端MIME类型和字符编码方式response.setContentType("text/html;charset=UTF-8");// 设置request对象的解码方式request.setCharacterEncoding("utf-8");String username = request.getParameter("username");String password = request.getParameter("password");String sex = request.getParameter("sex");String home = request.getParameter("home");String info = request.getParameter("info");//获取所有参数Enumeration<String> enu=request.getParameterNames();//循环打印jsp的name值while(enu.hasMoreElements()) {String paramName = (String) enu.nextElement();System.out.println(paramName);}// 获取输出流PrintWriter out = response.getWriter();out.println("<p>用户名:" + username + "</p>");out.println("<p>密码:" + password + "</p>");out.println("<p>性别:" + sex + "</p>");out.println("<p>家乡:" + home + "</p>");out.println("<p>爱好:");// 获取参数名为“hobby”的值String[] hobbys = request.getParameterValues("hobby");for (int i = 0; i < hobbys.length; i++) {if (i < hobbys.length - 1) {out.println(hobbys[i] + ",");} else {out.println(hobbys[i] + "");}}out.println("</p>");out.println("<p>自我介绍:" + info + "</p>");out.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

5.Servlet 重定向和请求转发

请求转发只是把请求转发给服务器上(通常是同一个 Web 应用中)的另一个组件( Servlet 或 JSP等);

重定向则只是告诉客户(浏览器)去访问另一个 URL(可能是同一个 Web 站点甚至其他站点)。

请求转发发生在服务器端,由服务器(比如 Servlet)控制;

重定向发生在客户端,由客户(通常是浏览器)控制。

请求转发使用 RequestDispatcher 对象的 forward() 或 include()方法。
重定向则使用 HttpServletResponse 对象的 sendRedirect() 方法。

5.1 重定向

重定向后则无法在服务器端获取第一次请求对象上保存的信息。比如还是在 Servlet 中将用户名保存到当前 request 对象中,并重定向到一个新的 URL,然后在新 URL 指向的地址中(假设是某个 Servlet)就无法获取原先保存在第一个请求中的信息。很明显,用户名是保存在第一次请求的对象中,但并没有保存在本次(第二次)请求的对象中。
重定向后,浏览器地址栏 URL 变为新的 URL(因为浏览器确实给新的 URL 发送了一个新的请求)。

访问RedirectServlet,重定向到AnotherServlet

package book.ch2;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/RedirectServlet")
public class RedirectServlet extends HttpServlet {private static final long serialVersionUID = 1L;public RedirectServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应到客户端的文本类型为HTMLresponse.setContentType("text/html;charset=UTF-8");// 输出当前时间response.getWriter().println(new java.util.Date());// 进行重定向response.sendRedirect(request.getContextPath() + "/AnotherServlet");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
package book.ch2;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/AnotherServlet")
public class AnotherServlet extends HttpServlet {private static final long serialVersionUID = 1L;public AnotherServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应到客户端的文本类型为HTMLresponse.setContentType("text/html;charset=UTF-8");// 获取输出流PrintWriter out = response.getWriter();// 输出响应结果out.println("<p>重定向页面</p>");out.close();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

http://localhost:8080/RedirectServlet —> http://localhost:8080/AnotherServlet

5.2 请求转发

请求转发后可以在服务器端获取本次请求对象上保存的信息(比如在 Servlet 中将用户名保存到当前 request 对象中,转发给另一组件(如 JSP )后,另一组件可以通过 request 对象取得用户名信息)。
请求转发后,浏览器地址栏 URL 不会发生改变

RequestDispatcher对象是通过调用 HttpServletRequest 对象的getRequestDispatcher()方法得到的,所以 forward() 或 include() 本质来说是属于请求对象的方法,所以请求转发始终发生在一个请求当中。

forword() 和 include() 的区别:

forward():表示在服务器端从一个 Servlet 中将请求转发到另一个资源(Servlet、JSP 或 HTML 等),本意是让第一个组件对请求做些预处理(或者什么都不做),而让另一组件处理并返回响应。

include():表示在响应中包含另一个资源(Servlet、JSP 或 HTML 等)的响应内容,最终被包含的页面产生的任何响应都将并入原来的 response 对象,然后一起输出到客户端。

请求ForwardServlet,转发到OtherServlet

package book.ch2;import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/ForwardServlet")
public class ForwardServlet extends HttpServlet {private static final long serialVersionUID = 1L;public ForwardServlet() {super();}/******************* 转发请求 *******************/@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 将key为bookname,value为《Android应用开发实践教程》的属性对象存储到request对象中request.setAttribute("bookname", "《Android应用开发实践教程》");     RequestDispatcher dispatcher = request.getRequestDispatcher("/OtherServlet");dispatcher.forward(request, response);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}
}
package book.ch2;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;@WebServlet("/OtherServlet")
public class OtherServlet extends HttpServlet {private static final long serialVersionUID = 1L;public OtherServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 设置响应到客户端的文本类型为HTMLresponse.setContentType("text/html;charset=UTF-8");// 从request对象中获取bookname属性值String bookname = (String) request.getAttribute("bookname");// 获取输出流PrintWriter out = response.getWriter();// 输出响应结果out.println("<p>请求转发的结果页面</p>");out.println("读取的request对象的bookname属性值为:" + bookname);}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

6. Servlet数据库访问

JDBC(Java DataBase Connectivity,java 数据库连接)是一种用于执行 SQL 语句的 Java API ,可以为多种关系数据库提供统一访问,它由一组用 Java 语言编写的类和接口组成。 JDBC 提供了一种基准,据此可以构建更高级的工具和接口,使数据库开发人员能够更为便利地编写数据库应用程序。

一个示例:

文件结构:

book.sql

SET FOREIGN_KEY_CHECKS=0;-- ----------------------------
-- Table structure for book
-- ----------------------------
DROP TABLE IF EXISTS `book`;
CREATE TABLE `book` (`bookId` int(4) NOT NULL,`bookName` varchar(50) NOT NULL,PRIMARY KEY (`bookId`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;-- ----------------------------
-- Records of book
-- ----------------------------
INSERT INTO `book` VALUES ('9801', 'Android应用开发实践教程');
INSERT INTO `book` VALUES ('9802', 'Web应用开发');
INSERT INTO `book` VALUES ('9803', 'iOS程序设计');

测试数据:

package webstudy;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;@WebServlet("/jdbctest")
public class JdbcServlet extends HttpServlet {String JDBC_Driver = "com.mysql.jdbc.Driver";String DB_URL = "jdbc:mysql://localhost:3306/message?useSSL=true";String user = "root";String password = "123456";Connection con1 = null;Statement stmt = null;ResultSet rs1;@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();try {Class.forName(JDBC_Driver);con1 = DriverManager.getConnection(DB_URL, user, password);stmt = con1.createStatement();String sql;sql = "select bookid,bookName from book";rs1 = stmt.executeQuery(sql);while (rs1.next()) {int id = rs1.getInt("bookid");String bookname1 = rs1.getString("bookName");out.println("bookid:" + id);out.println(",bookName:" + bookname1);out.println("<br />");}rs1.close();stmt.close();con1.close();} catch (SQLException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}//out.close();}}

7. Servlet 异常处理

当一个 Servlet 抛出一个异常时,Web 容器在使用了 exception-type元素的 web.xml中搜索与抛出异常类型相匹配的配置。可以在web.xml中使用error-page元素来指定对特定异常 或 HTTP 状态码作出相应的 Servlet 调用。

假设有一个 ErrorHandler的 Servlet 在任何已定义的异常或错误出现时被调用,以下将是在 web.xml 中创建的项。

<!--********************* 定义 *********************--><servlet><servlet-name>ErrorHandler</servlet-name><servlet-class>book.ch2.ErrorHandlerServlet</servlet-class></servlet>
<!--********************* 映射 *********************--><servlet-mapping><servlet-name>ErrorHandler</servlet-name><url-pattern>/ErrorHandler</url-pattern></servlet-mapping>
<!--********************* 相关错误页面 *********************--><error-page><error-code>404</error-code><location>/ErrorHandler</location></error-page><error-page><error-code>403</error-code><location>/ErrorHandler</location></error-page><error-page><exception-type>javax.servlet.ServletException</exception-type><location>/ErrorHandler</location></error-page><error-page><exception-type>java.io.IOException</exception-type><location>/ErrorHandler</location></error-page>

关于上面的web.xml中异常处理几点说明:
ErrorHandler 与其他的 Servelt 的定义方式一样,且在 web.xml 中进行配置。
如果有错误状态代码出现,不管为 404(Not Found 未找到)或 403(Forbidden 禁止),则会调用 ErrorHandler。
如果 Web 应用程序抛出 ServletException 或 IOException,Web 容器则会调用 ErrorHandler。
可以定义不同的错误处理程序来处理不同类型的错误或异常。

如果要对所有的异常有一个通用的错误处理程序,那么应该定义下面的 error-page,而不是为每个异常定义单独的 error-page 元素:

    <error-page><exception-type>java.lang.Throwable</exception-type><location>/ErrorHandler</location></error-page>

一个示例:

<!--********************* 定义 *********************--><servlet><servlet-name>ErrorHandler</servlet-name><servlet-class>book.ch2.ErrorHandlerServlet</servlet-class></servlet><!--********************* 映射 *********************--><servlet-mapping><servlet-name>ErrorHandler</servlet-name><url-pattern>/ErrorHandler</url-pattern></servlet-mapping>
<!--********************* 相关错误页面 *********************--><error-page><error-code>404</error-code><location>/ErrorHandler</location></error-page><error-page><exception-type>java.lang.Throwable</exception-type><location>/ErrorHandler</location></error-page>
package book.ch2;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet("/ErrorHandlerServlet")
public class ErrorHandlerServlet extends HttpServlet {private static final long serialVersionUID = 1L;public ErrorHandlerServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {Throwable throwable = (Throwable) request.getAttribute("javax.servlet.error.exception");Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");String servletName = (String) request.getAttribute("javax.servlet.error.servlet_name");if (servletName == null) {servletName = "Unknown";}String requestUri = (String) request.getAttribute("javax.servlet.error.request_uri");if (requestUri == null) {requestUri = "Unknown";}// 设置响应内容类型response.setContentType("text/html;charset=UTF-8");PrintWriter out = response.getWriter();String title = "Servlet处理 Error/Exception";String docType = "<!DOCTYPE html>\n";out.println(docType + "<html>\n" + "<head><title>" + title + "</title></head>\n" + "<body bgcolor=\"#f0f0f0\">\n");out.println("<h3>Servlet异常/错误处理</h3>");if (throwable == null && statusCode == null) {out.println("<h3>错误信息丢失</h2>");out.println("请返回 <a href=\"" + response.encodeURL("http://localhost:8080/") + "\">主页</a>。");} else if (statusCode != null) {out.println("错误代码 : " + statusCode + "<br><br>");out.println("Servlet Name : " + servletName + "</br></br>");out.println("异常类型 : " + throwable.getClass().getName() + "</br></br>");out.println("请求 URI: " + requestUri + "<br><br>");out.println("异常信息: " + throwable.getMessage());} else {//          out.println("<h3>错误信息</h3>");
//          out.println("Servlet Name : " + servletName + "</br></br>");
//          out.println("异常类型 : " + throwable.getClass().getName() + "</br></br>");
//          out.println("请求 URI: " + requestUri + "<br><br>");
//          out.println("异常信息: " + throwable.getMessage());}out.println("</body>");out.println("</html>");}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}
package book.ch2;import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;@WebServlet("/ExceptionServlet")
public class ExceptionServlet extends HttpServlet {private static final long serialVersionUID = 1L;public ExceptionServlet() {super();}@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {int x = 126/0;//int[] array = {2,4,6};//System.out.println(array[3]);//throw new ArrayIndexOutOfBoundsException();}@Overrideprotected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {doGet(request, response);}}

Servlet入门篇(GenericServlet 类 - HttpServlet 类 -ServletConfig 接口 - HttpServletRequest 接口……)相关推荐

  1. java查询日期类的表,JAVA菜鸟入门篇 - 时间处理相关类实例:打印该月日期表 (29)...

    利用前面我们所学习有关时间处理类,Date.DateFormat.SimpleDateFormat以及Calendar和GregorianCalendar类 编写一个按照用户定义格式(格式:2015- ...

  2. Servlet 入门

    目录 一.Servlet 介绍 二.Servlet 入门 1.创建JavaEE Web项目 2.定义类,实现 Servlet 接口 3.实现接口中的抽象方法 4.配置 Servlet 三.Servle ...

  3. 超通俗易懂的Servlet入门教程

    不怕千万人阻挡,就怕自己投降. 文章目录 01.Servlet快速入门 02.Servlet3.0注解配置 03.GenericServlet&HttpServlet(Serlvet的体系结构 ...

  4. JavaWeb 入门篇(3)ServletContext 详解 具体应用

    当Servlet 容器启动的时候 会为每个web应用创建一个ServletContext 对象代表当前的web应用. 在web.xml 文件中不止可以配置Servlet的初始化信息 还可以给整个web ...

  5. java实现linkstring,【JAVA SE基础篇】32.String类入门

    [JAVA SE基础篇]32.String类入门 1.字符串 1.String类又称作不可变字符序列 2.String位于java.lang包中,java程序默认导入java.lang包下所有的类 3 ...

  6. C++入门篇,类与对象(中篇)

    C++入门篇--类与对象(中篇) 该篇是介绍类与对象的核心篇章,主要介绍类的默认成员函数,操作符重载以及const成员函数等. 1 类的六个默认成员函数 我们知道一个类如果什么都没有,叫做空类. 但是 ...

  7. TcpClient和TcpListener 类的使用-编写一个点对点聊天工具(初级入门篇)

    TcpClient类和TcpListener类属于.NET框架下网络通信中的应用层类,为Socket通信提供了更简单,对用户更为友好的接口.应用层类比位于底层的Socket类提供了更高层次的抽象,封装 ...

  8. 【TypeScript入门】TypeScript入门篇——类

    TypeScript是面向对象的JavaScript.TypeScript支持面向对象的编程功能,如类,接口等.OOP中的类是用于创建对象的蓝图.类封装了对象的数据.Typescript为这个名为类的 ...

  9. 〖Python零基础入门篇㊲〗- 类的继承、多态与多重继承

    订阅 Python全栈白宝书-零基础入门篇 可报销!白嫖入口-请点击我.推荐他人订阅,可获取扣除平台费用后的35%收益,文末名片加V! 说明:该文属于 Python全栈白宝书专栏,免费阶段订阅数量43 ...

最新文章

  1. php No 'Access-Control-Allow-Origin' header is present on the requested resource.'Ajax跨域访问解决方法
  2. GANs学习系列(8):Deep Convolutional Generative Adversarial Nerworks,DCGAN
  3. 数据为什么要可视化?如何可视化?
  4. WINCE6.0深入理解TOC
  5. 【C/C++多线程编程之十】pthread线程私有数据
  6. OpenCV gapi模块基本API的实例(附完整代码)
  7. Centos 利用yum源安装 nginx 1.20.1
  8. Ubuntu中python调用SimpleITK来显示图像
  9. 红黑树中nil结点_什么是红黑树?程序员面试必问!
  10. conda使用报错:ImportError:DLL load failed
  11. 7-4 统计工龄 (20 分)(C语言实现)
  12. 计算机应用基础一级考试题库,2018一级结构工程师《计算机应用基础》题库及答案(一)...
  13. 工业计算机远程控制,基于SOCKET技术的计算机远程控制实现
  14. 雷军穿上印度传统服装:网友以为《西游记》拍新版了 这画面感受下
  15. SDK与API的区别
  16. HNU实验五 小希与火车 基于神经网络的垃圾分类
  17. 黑龙江省牡丹江市谷歌高清卫星地图下载
  18. android实战:密码箱一
  19. 计算机主机可以有几个硬盘,一台电脑可以安装盘几个硬盘?
  20. 数据库课程设计(上)(学生成绩管理系统)

热门文章

  1. layui 实现图片上传和预览
  2. [JVM-3]Java垃圾回收(GC)机制和垃圾收集器选择
  3. AI大神贾扬清确认将离开Facebook,加入阿里硅谷研究院
  4. Android x86 下运行纯ARM版APP
  5. python之4个小作业
  6. apache phoenix 安装试用
  7. 使用shell脚本实现自动SSH互信功能
  8. 转载:从集群计算到云计算
  9. FLV Extract 1.2.1
  10. [导入]ASP.NET生成高质量缩略图通用函数(c#代码)