Servlet入门篇(GenericServlet 类 - HttpServlet 类 -ServletConfig 接口 - HttpServletRequest 接口……)

1.Servlet 简介

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

image-20201107181845342

image-20201122220900948

Servlet 执行以下主要任务:

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

2.Servlet基础

2.1 Servlet体系结构

image-20201107182628460

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()+"构造方法执行");
    }
    @Override
    public void init() throws ServletException {
        // 初始化代码...
        System.out.println(this.getClass().getName()+"init方法执行");
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected 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();
    }
    @Override
    public 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();
	}

	@Override
	public 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);			
	}
}

image-20201108082434209

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。

image-20201107185508636

//
// 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;
	
	@Override
    public void init(ServletConfig config) throws ServletException {
    	this.servletConfig = config;
    	System.out.println("-----------" + servletConfig + "-----------");
	}
    
    @Override
    public ServletConfig getServletConfig() {
        return servletConfig;
    }
    
    @Override
	protected 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");
		// 设置响应到客户端的文本类型为HTML
		response.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>

输出结果:

image-20201108081852418

3.4.4 HttpServletRequest 接口

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

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

image-20201110102119650

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();		
	}
	/******************* 获取请求行信息 *******************/
	@Override
	protected 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();
	}

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

}

image-20201108082858159

3.4.4.1 获取请求头信息

image-20201110102249636
image-20201108080605304

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();
	}

	/******************* 获取请求头信息 *******************/
	@Override
	protected 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>");
		}
	}

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

}

image-20201108082923551

3.4.4.2 获取请求参数

image-20201108080622829

获取请求参数:

<!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();
	}

    	/******************* 获取请求参数 *******************/
	@Override
	protected 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] + ",");
			else
				out.println(hobbys[i] + "");
		}
		out.println("</p>");
		out.close();		
	}

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

}

image-20201108083621397

image-20201108083633708

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-8
		response.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();

	}

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

}

image-20201108084421846

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 */
    @Deprecated
    boolean 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 个方法除了发送状态码外,还可以增加一条用于提示说明的文本信息,该文本信息将出现在发送给客户端的正文内容中。

image-20201108080814415

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();
	}

	@Override
	protected 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());// 输出当前时间
	}

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

}

image-20201108085321937
image-20201108085341580

image-20201108080821009

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();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 设置响应消息头Content-Type
		response.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();
	}

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

image-20201108085930281
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 */
    @Deprecated
    String encodeUrl(String var1);

    /** @deprecated */
    @Deprecated
    String 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 */
    @Deprecated
    void 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();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 设置响应到客户端的文本类型为HTML
		response.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();
	}

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

}

image-20201108090330016

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

image-20201108081209675

先访问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();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ServletContext context = this.getServletContext();
		// 通过setAttribute()方法设置属性值
		context.setAttribute("contextData", "Here is contexData");
		
	}

	@Override
	protected void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub
		doGet(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();
	}

	@Override
	protected 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);
	}

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

}

image-20201108090922188

image-20201108090944433

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

image-20201108081217655

image-20201108092051407

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();
	}

	@Override
	protected 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>");
	}

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

image-20201108092115021

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 */
    @Deprecated
    Servlet getServlet(String var1) throws ServletException;

    /** @deprecated */
    @Deprecated
    Enumeration<Servlet> getServlets();

    /** @deprecated */
    @Deprecated
    Enumeration<String> getServletNames();

    void log(String var1);

    /** @deprecated */
    @Deprecated
    void 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 处理表单数据可以使用以下的方法:

image-20201108092522230

<!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"><option
					value="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();
    }

    @Override
    protected 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();
    }

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

}

image-20201108092925231

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();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 设置响应到客户端的文本类型为HTML
		response.setContentType("text/html;charset=UTF-8");
		// 输出当前时间
		response.getWriter().println(new java.util.Date());
		// 进行重定向
		response.sendRedirect(request.getContextPath() + "/AnotherServlet");
	}

	@Override
	protected 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();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 设置响应到客户端的文本类型为HTML
		response.setContentType("text/html;charset=UTF-8");
		// 获取输出流
		PrintWriter out = response.getWriter();
		// 输出响应结果
		out.println("<p>重定向页面</p>");
		out.close();
	}

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

}

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

image-20201108093750469

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();
	}

	/******************* 转发请求 *******************/
	@Override
	protected 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);
	}

	@Override
	protected 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();
	}

	@Override
	protected void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 设置响应到客户端的文本类型为HTML
		response.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);
	}

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

}

image-20201108094253305

6. Servlet数据库访问

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

一个示例:

文件结构:

image-20201108094826868

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程序设计');

测试数据:

image-20201108095009058

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;

    @Override
    public 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 block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        //out.close();
    }

}

image-20201108095223277

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();
	}

	@Override
	protected 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>");
	}
    
	@Override
	protected 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();
	}

	@Override
	protected 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();
	}

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

}

image-20201108100930408

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值