第4章 Servlet基础

学习目标

目前开发动态Web应用中,比较较常见的技术有JSP和Servlet(Java)①、ASP(C#,.net)⑤、PHP(php)④、Nodejs(js)②、Python(python)③等技术。基于Java的动态Web开发技术,SUN公司提供了Servlet和JSP两种技术。

1. Servlet基础

1.1 Servlet概述

Servlet是什么 Web服务器端的小程序

Servlet(Server Applet)是运行在Web服务器端的Java应用小程序(使用Java语言编写)。Servlet对象主要封装了对HTTP请求/响应的处理,并且它的运行需要Servlet容器(如Tomcat)的支持。

Servlet容器

Servlet容器是提供了Servlet功能的服务器(如Tomcat)。Servlet容器将Servlet动态地加载到服务器上。使用HTTP请求和响应与客户端进行交互。

Servlet静态、动态结合的体系结构

Servlet的请求首先会被HTTP服务器(如Apache)接收,HTTP服务器只负责静态HTML页面的解析,对于Servlet的请求转交给Servlet容器,Servlet容器会根据web.xml文件中的映射关系,调用相应的Servlet,Servlet将处理的结果返回给Servlet容器,并通过HTTP服务器将响应传输给客户端。

图1 静态、动态结合的体系结构

Servlet纯容器解析的体系结构

无论静态HTML资源(html、css、js、images)的解析,还是动态请求(jsp、servlet)的解析都交给Servlet容器解析。静态资源Servlet容器直接返回浏览器客户端,动态资源Servlet容器会根据web.xml文件中的映射关系,调用相应的Servlet,Servlet将处理的结果返回给Servlet容器,并通过HTTP服务器将响应传输给客户端。

图2 Servlet纯容器解析的体系结构

1.2 Servlet的特点

Servlet使用Java语言编写,它不仅具有Java 语言的优点,而且还对Web的相关应用进行了封装,同时Servlet容器还提供了对应用的相关扩展,无论是在功能、性能、安全等方面都十分优秀。

1.3 Servlet接口(javax.servlet.Servlet接口)

SUN公司提供了一系列接口和类,其中最重要的是javax.servlet.Servlet接口。Servlet就是一种实现了Servlet接口的类,它由Web容器负责创建并调用,用于接收和响应用户的请求。

方法声明 功能描述
void init(ServletConfig config) Servlet实例化后,Servlet容器调用该方法完成初始化----出生,仅一次工作
ServletConfig getServletConfig() 用于获取Servlet对象的配置信息,返回Servlet的ServletConfig对象
String getServletInfo() 返回一个字符串,其中包含关于Servlet的信息,例如,作者、版本和版权等信息
void service(ServletRequest request,ServletResponse response) 服务----伺候,多次 负责响应用户的请求,当容器接收到客户端访问Servlet对象的请求时,就会调用此方法。容器会构造一个表示客户端请求信息的ServletRequest对象和一个用于响应客户端的ServletResponse对象作为参数传递给service()方法。在service()方法中,可以通过ServletRequest对象得到客户端的相关信息和请求信息,在对请求进行处理后,调用ServletResponse对象的方法设置响应信息
void destroy() 当服务器关闭或者Servlet对象被移除时,Servlet对象会被销毁----灭亡,仅一次,容器会调用此方法

在Servlet接口中的5个方法中,init()、service()和destroy()这三个方法可以表现Servlet的生命周期,它们会在某个特定的时刻被调用。

Servlet接口的实现类

SUN公司提供了两个默认的接口实现类:GenericServlet和HttpServlet。

HttpServlet类的常用方法及功能

方法声明 功能描述
protected void doGet(HttpServletRequest req, HttpServletResponse resp) 用于处理GET类型的Http请求的方法
protected void doPost(HttpServletRequest req, HttpServletResponse resp) 用于处理POST类型的Http请求的方法
protected void doPut(HttpServletRequest req, HttpServletResponse resp) 用于处理PUT类型的Http请求的方法

2. Servlet开发入门

2.1 实现第一个Servlet程序

(1) 启动IntelliJ IDEA开发工具,单击工具栏中的[文件] →[新建] →[项目] ,此时会弹出一个【新建项目】界面。选新建项目,①输入项目名称:如ch04_zzh,自动确定本次JavaWeb源代码存储位置,如E:\zzhJavaWeb,语言和构建系统选Java和IntelliJ;②选定JDK版本、③【创建】。

图3 创建项目

(2) 右击项目如[ch04_zzh]选【添加框架支持...】,弹出【添加框架支持】界面,选①JavaEE --> Web应用程序、版本4.0、创建Web.xml;②【确定】。

图4 添加框架支持

(3) IntelliJ IDEA工具,单击工具栏中的[文件] → [项目结构]弹出【项目结构】界面,选【模块】,①单击加号+;②库...;③Tomcat ;④添加所选项;⑤应用;⑥【确定】。

图5 设置模块

(4) IntelliJ IDEA工具,单击工具栏中的[文件] → [项目结构]弹出【项目结构】界面,选【工件】,①更换类型:归档;②重命名:ch04_zzh,输出目录自动更换为: out\artifacts\ch04_zzh,打包文件自动重命名为: ch04_zzh.war(用于部署);③应用;④【确定】,如图6、图7所示。

图6 打开工件设置
图7 设置工件

(5)在IDEA的菜单栏中单击[运行] →[编辑配置...], 会弹出一个[运行/调试配置]界面,①单击加号+,会弹出[添加新配置];②选择Tomcat服务器-->本地,如图8所示,弹出如图9所示界面,单击部署。

图8 运行配置1
图9 运行配置2

在【部署】界面,①单击加号+,选工件ch04_zzh,;②修改应用程序上下文:/ch04_zzh;③应用;④【确定】,如图10所示。

图10 运行配置3

在【服务器】界面,①添加虚拟机选项:-Dfile.encoding=UTF-8;②修改JRE:③应用;④【确定】,如图11所示。

图11 运行配置4

在IDEA的菜单栏中单击[运行] →[运行...], 会弹出如图12所示界面,单击部署。

图12 运行打包文件:out/artifacts/ch04_zzh/ch04_zzh.war

\web\index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>ch04 Servlet基础</title>
</head>
<body>
<h1>ch04 Servlet基础(郑佐汉)</h1>
<hr>
<a href="TestServlet01">1. 第一个Servlet(@WebServlet("/TestServlet01" 配置)</a><br>
<a href="zzh/第一个Servlet">1. 第一个Servlet(web.xml 配置)</a><br>
<a href="TestServlet02">2.1 Servlet生命周期(查看控制台输出)</a><br>
<a href="TestServlet03">3.1 获取@WebServlet(initParams={@WebInitParam(name="...", value="...")}设置值</a><br>
<a href="带参数的Servlet网址">3.1 获取web.xml中servlet设置的初始化参数值</a><br>
<a href="TestServlet04">3.2 (1) 读取Web.xml上下文配置参数</a><br>
<a href="TestServlet05">3.2 (2) 通过context.setAttribute进行servlet之间通讯 set</a><br>
<a href="TestServlet06">3.2 (2) 通过context.getAttribute进行servlet之间通讯 get</a><br>
<a href="TestServlet07">3.2 (3) 获取.properties文件中的属性值【context.getResourceAsStream()】</a><br>
<a href="TestServlet08">3.2 (3) 获取.properties文件中的属性值【context.getRealPath()】</a><br>
<a href="StatusServlet">4.1 发送状态码相关的方法(response.setStatus | sendError)</a><br>
<a href="HeaderServlet">4.2 发送响应头相关的方法 response.setCharacterEncoding | setContentType </a><br>
<a href="PrintServlet">4.3 发送响应消息体相关的方法(字符输出流)</a><br>
<a href="PrintServlet2">4.3 发送响应消息体相关的方法(字节输出流)</a><br>
<a href="PrintServlet3">4.3 发送响应消息体相关的方法(字节输出流--照片)</a><br>
<a href="LoginServlet">5.1 实现请求重定向--登录 response.sendRedirect("重定向url");</a><br>
<a href="ChineseServlet0">5.2 中文输出乱码问题 response.默认字符编码ISO8859-1;</a><br>
<a href="ChineseServlet1">5.2 中文输出乱码问题 response.setCharacterEncoding("utf-8");</a><br>
<a href="ChineseServlet">5.2 动手实践:解决中文输出乱码问题 response.setContentType("text/html;charset=utf-8");</a><br>
<a href="RequestLineServlet">6.1 获取请求行信息的相关方法 request.getScheme(); ...</a><br>
<a href="RequestHeadersServlet">6.2 获取请求头的相关方法 request.getHeaderNames(); </a><br>
<a href="请求转发">6.3 请求转发 request.getRequestDispatcher("/转发url").forward(request, response);</a><br>
<a href="form.html">6.4 获取请求参数 request.getParameter("input中name参数");</a><br>
<a href="Request传递数据">6.5 通过Request对象传递数据 request.setAttribute | getAttribute | removeAttribute </a><br>
<a href="Request传递数据2">6.5 通过Request对象传递数据2 request.setAttribute | getAttribute | removeAttribute </a><br>
<hr>
<p><a href="http://101.42.158.247/21javaweb.html">返回课程首页</a>
郑佐汉<script>document.write(document.lastModified); </script>制作</p>
</body>
</html>
图13 第4章首页
cn.zzh.servlet.TestServlet01.java
package cn.zzh.servlet; 

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("/TestServlet01")
public class TestServlet01 extends HttpServlet {
    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.print("第一个Servlet(郑佐汉)。");
    }

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

运行结果如下:

图14 第1个Servlet

2.2 Servlet的配置

若想让Servlet正确地运行在服务器中并处理请求信息,必须进行适当的配置,关于Servlet的配置主要有两种方式,分别是通过Web应用的配置文件web.xml来完成配置和使用@WebServlet注解的方式完成。

(1) 使用web.xml配置Servlet

<servlet>元素的子元素

子元素 类型 说明
<servlet-name> String 指定该Servlet的名称,随意命名,要求唯一
<servlet-class> String 指定该Servlet类的位置,包括包名与类名
<description> String 指定该Servlet的描述信息
<display-name> String 指定该Servlet的显示名

<servlet-mapping>元素的子元素

子元素 类型 说明
<servlet-name> String 指定该Servlet的名称,要求与<servlet>相对应
<url-pattern> String 访问url,从/开始
<description> String 指定该Servlet的描述信息
<display-name> String 指定该Servlet的显示名
web.xml中servlet配置之一
    <!-- 同一servlet类,可以定义成不同url访问地址,但同一url访问地址不可访问多个(>1)个servlet类-->
    <servlet>
        <servlet-name>第1个Servlet</servlet-name>
        <servlet-class>cn.zzh.servlet.TestServlet01</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>第1个Servlet</servlet-name>
        <url-pattern>/zzh/第一个Servlet</url-pattern>
    </servlet-mapping>

注意:同一servlet类,可以定义成不同url访问地址,但同一url访问地址不可访问多个(>1)个servlet类

(2) @WebServlet注解属性

属性声明 功能描述
String name 指定Servlet的name属性,等价于<servlet-name>。如果没有显式指定,则该Servlet的取值即为类的全限定名。
String[] value 该属性等价于urlPatterns属性。urlPatterns和value属性不能同时使用。
String[] urlPatterns 指定一组Servlet的URL匹配模式。等价于<url-pattern>标签。
int loadOnStartup 指定Servlet的加载顺序,等价于<load-on-startup>标签。
WebInitParam[] 指定一组Servlet初始化参数,等价于<init-param>标签。
boolean asyncSupported 声明Servlet是否支持异步操作模式,等价于<async-supported> 标签。
String description Servlet的描述信息,等价于<description>标签。
String displayName Servlet的显示名,通常配合工具使用,等价于<display-name>标签。

2.3 Servlet的生命周期

图15 Servlet的生命周期

在Servlet的整个生命周期内,它的init()方法只被调用一次--出生,在第1次调用该Servlet时创建实例初始化。

在Servlet的整个生命周期内,对于Servlet的每一次访问请求,Servlet容器都会调用一次Servlet的service()方法,并且创建新的ServletRequest和ServletResponse对象。执行多次--每请求1次执行1从

在Servlet的整个生命周期中,destroy()方法也只被调用一次--销毁,在web应用被移除出容器时或停止服务器时Servlet对象才会销毁。

cn.zzh.servlet.TestServlet02.java
package cn.zzh.servlet;

import javax.servlet.annotation.WebServlet;
import javax.servlet.*;

@WebServlet("/TestServlet02")
public class TestServlet02 extends GenericServlet {
    public void init(ServletConfig config) throws ServletException {
        System.out.println("你好,郑佐汉。init method 初始化方法被调用----出生。只有1次出生");
    }

    public void service(ServletRequest request, ServletResponse response)
            throws ServletException {
        System.out.println("你好,郑佐汉。service 服务方法被调用。可调用多次...");
    }

    public void destroy() {
        System.out.println("你好,郑佐汉。destroy method 销毁方法被调用----灭亡。只有1次销毁");
    }
}

运行结果如下:

图16 Servlet的生命周期运行控制台截图

3. ServletConfig和ServletContext

3.1 ServletConfig接口

在Servlet运行期间,经常需要一些配置信息,例如,文件使用的编码等,这些信息都可以在@WebServlet注解的属性中配置。当Tomcat初始化一个Servlet时,会将该Servlet的配置信息封装到一个ServletConfig对象中,通过调用init(ServletConfig config)方法将ServletConfig对象传递给Servlet。

方法说明 功能描述
String getInitParameter(String name) 根据初始化参数名返回对应的初始化参数值
Enumeration getInitParameterNames() 返回一个Enumeration对象,其中包含了所有的初始化参数名
ServletContext getServletContext() 返回一个代表当前Web应用的ServletContext对象
String getServletName() 返回Servlet的名字
cn.zzh.servlet.TestServlet03.java
package cn.zzh.servlet;

import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.WebInitParam;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

@WebServlet(urlPatterns = "/TestServlet03",
        initParams = {@WebInitParam(name = "encoding", value = "UFT-8"),@WebInitParam(name = "使用单位", value = "信息工程学院")})
public class TestServlet03 extends HttpServlet {
    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        // 获得ServletConfig对象
        ServletConfig config = this.getServletConfig();
        // 获得参数名为encoding对应的参数值
        String param = config.getInitParameter("encoding");
        out.println("encoding=" + param);
        param = config.getInitParameter("使用单位");
        out.println("<br>使用单位=" + param);
    }

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

运行结果如下:

图17 获取@WebServlet中设置的初始化参数值
web.xml中servlet配置之二
    <!-- servlet-name的名字随便命名,只要servlet和servlet-mapping相对应即可-->
    <servlet>
        <servlet-name>带参数的Servlet</servlet-name>
        <servlet-class>cn.zzh.servlet.TestServlet03</servlet-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>GBK</param-value>
        </init-param>
        <init-param>
            <param-name>使用单位</param-name>
            <param-value>数字媒体技术教研室</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>带参数的Servlet</servlet-name>
        <url-pattern>/带参数的Servlet网址</url-pattern>
    </servlet-mapping>

运行结果如下:

图18 获取web.xml中servlet中设置的初始化参数值

3.2 ServletContext接口

(1)获取Web应用程序的初始化参数

方法说明 功能描述
Enumeration getInitParameterNames() 返回一个Enumeration对象,该对象包含所有初始化参数名的Enumeration对象
web.xml中context-param片段
    <context-param>
        <param-name>学院名称</param-name>
        <param-value>信息工程学院</param-value>
    </context-param>
    <context-param>
        <param-name>地址</param-name>
        <param-value>晋中市文华街125号</param-value>
    </context-param>
cn.zzh.servlet.TestServlet04.java
package cn.zzh.servlet;

import javax.servlet.annotation.WebServlet;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

@WebServlet("/TestServlet04")
public class TestServlet04 extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        // 得到ServletContext对象
        ServletContext context = this.getServletContext();
        // 得到包含所有初始化参数名的Enumeration对象
        Enumeration<String> paramNames = context.getInitParameterNames();
        out.println("所有参数名称和参数值如下:<br>");
        // 遍历所有的初始化参数名,得到相应的参数值并打印
        while (paramNames.hasMoreElements()) {
            String name = paramNames.nextElement();
            String value = context.getInitParameter(name);
            out.println(name + " : " + value);
            out.println("<br>");
        }
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

运行结果如下:

图19 获取web.xml中上下文参数值

(2)实现多个Servlet对象共享数据

方法说明 功能描述
Enumeration getAttributeNames() 返回一个Enumeration对象,该对象包含了所有存放在ServletContext中的所有域属性名
Object getAttibute(String name) 根据参数指定的属性名返回一个与之匹配的域属性值
void removeAttribute(String name) 根据参数指定的域属性名,从ServletContext中删除匹配的域属性
void setAttribute(String name,Object obj) 设置ServletContext的域属性,其中name是域属性名,obj是域属性值
cn.zzh.servlet.TestServlet05.java
package cn.zzh.servlet;

import javax.servlet.annotation.WebServlet;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

@WebServlet("/TestServlet05")
public class TestServlet05 extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException, IOException {
        ServletContext context = this.getServletContext();
        // 通过setAttribute()方法设置属性值
        context.setAttribute("data", "this servlet save data. 这是servlet保存数据--上下文属性值。");
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}
cn.zzh.servlet.TestServlet06.java
package cn.zzh.servlet;

import javax.servlet.annotation.WebServlet;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

@WebServlet("/TestServlet06")
public class TestServlet06 extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        ServletContext context = this.getServletContext();
        // 通过getAttribute()方法获取属性值
        String data = (String) context.getAttribute("data");
        out.println(data);
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

运行结果如下:

图20 servlet通过context的属性值传递数据

(3) 读取Web应用下的资源文件

方法说明 功能描述
Set getResourcePaths(String path) 返回一个Set集合,集合中包含资源目录中子目录和文件的路径名称。参数path必须以正斜线(/)开始,指定匹配资源的部分路径
String getRealPath(String path) 返回资源文件在服务器文件系统上的真实路径(文件的绝对路径)。参数path代表资源文件的虚拟路径,它应该以正斜线(/)开始,“/”表示当前Web应用的根目录,如果Servlet容器不能将虚拟路径转换为文件系统的真实路径,则返回null
URL getResource(String path) 返回映射到某个资源文件的URL对象。参数path必须以正斜线(/)开始,“/”表示当前Web应用的根目录
InputStream getResourceAsStream(String path) 返回映射到某个资源文件的InputStream输入流对象。参数path传递规则和getResource()方法完全一致
src/zzh.properties
Company=zzh
Address=Taiyuan
公司=信息工程学院
地址=山西省晋中市榆次区文华街125号
cn.zzh.servlet.TestServlet07.java
package cn.zzh.servlet;

import javax.servlet.annotation.WebServlet;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import javax.servlet.*;
import javax.servlet.http.*;

@WebServlet("/TestServlet07")
public class TestServlet07 extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        ServletContext context = this.getServletContext();
        PrintWriter out = response.getWriter();
        //获取相对路径中的输入流对象
        InputStream in = context
                .getResourceAsStream("/WEB-INF/classes/zzh.properties");
        Properties pros = new Properties();
        pros.load(in);
        out.println("Company = " + pros.getProperty("Company") + "<br>");
        out.println("Address = " + pros.getProperty("Address") + "<br>");
        out.println("公司 = " + pros.getProperty("公司") + "<br>");
        out.println("地址 = " + pros.getProperty("地址") + "<br>");

        InputStream in2 = context
                .getResourceAsStream("/WEB-INF/classes/zzh.properties");
        Properties pros2 = new Properties();
        InputStreamReader isr = new InputStreamReader(in2 , StandardCharsets.UTF_8);
        BufferedReader br = new BufferedReader(isr);
        pros.load(br);
        out.println("Company = " + pros.getProperty("Company") + "<br>");
        out.println("Address = " + pros.getProperty("Address") + "<br>");
        out.println("公司 = " + pros.getProperty("公司") + "<br>");
        out.println("地址 = " + pros.getProperty("地址") + "<br>");
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

运行结果如下:

图21 获取.properties文件中的属性值【context.getResourceAsStream()】
cn.zzh.servlet.TestServlet08.java
package cn.zzh.servlet;

import javax.servlet.annotation.WebServlet;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Properties;
import javax.servlet.*;
import javax.servlet.http.*;

@WebServlet("/TestServlet08")
public class TestServlet08 extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        ServletContext context = this.getServletContext();
        //获取文件绝对路径
        String path = context
                .getRealPath("/WEB-INF/classes/zzh.properties");
        FileInputStream in = new FileInputStream(path);
        Properties pros = new Properties();
        pros.load(in);
        out.println("Company=" + pros.getProperty("Company") + "<br>");
        out.println("Address=" + pros.getProperty("Address") + "<br>");
        out.println("公司 = " + pros.getProperty("公司") + "<br>");
        out.println("地址 = " + pros.getProperty("地址") + "<br><hr>");

        FileInputStream in2 = new FileInputStream(path);
        InputStreamReader isr = new InputStreamReader(in2, StandardCharsets.UTF_8);
        BufferedReader br = new BufferedReader(isr);
        // 一定一定要 load 设置编码后的字符流
        Properties pros2 = new Properties();
        pros2.load(br);
        out.println("Company=" + pros2.getProperty("Company") + "<br>");
        out.println("Address=" + pros2.getProperty("Address") + "<br>");
        out.println("公司 = " + pros2.getProperty("公司") + "<br>");
        out.println("地址 = " + pros2.getProperty("地址") + "<br>");
    }

    public void doPost(HttpServletRequest request,
                       HttpServletResponse response) throws ServletException, IOException {
        this.doGet(request, response);
    }
}

运行结果如下:

图22 获取.properties文件中的属性值【context.getRealPath()】

4. HttpServletResponse对象

4.1 发送状态码相关的方法

setStatus(int status)
sendError(int sc)
sendError(int code?String message)
package cn.zzh.response.StatusServlet.java
package cn.zzh.response;

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("/StatusServlet")
public class StatusServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)throws ServletException, IOException {
       response.sendError(404,"文件去火星了!!!");
    }
    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)throws ServletException, IOException {
        doGet(request, response);
    }
}

运行结果如下:

图23 发送状态码方法(response.setStatus | sendError)

4.2 发送响应头相关的方法

HttpServletResponse接口设置HTTP响应头字段的方法--设置各种头字段

方法说明 功能描述
void addHeader(String name, String value) 这两个方法都是用来设置HTTP协议的响应头字段,其中,参数name用于指定响应头字段的名称,参数value用于指定响应头字段的值。不同的是,addHeader()方法可以增加同名的响应头字段,而setHeader()方法则会覆盖同名的头字段
void setHeader(String name, String value)
void addIntHeader(String name,int value) 这两个方法专门用于设置包含整数值的响应头。避免了调用addHeader()与setHeader()方法时,需要将int类型的设置值转换为String类型的麻烦
void setIntHeader(String name,int value)
void setContentLength(int len) 该方法用于设置响应消息的实体内容的大小,单位为字节。对于HTTP协议来说,这个方法就是设置Content-Length响应头字段的值

HttpServletResponse接口设置HTTP响应头字段的方法----设置字符编码

方法说明 功能描述
void setContentType(String type) 该方法用于设置Servlet输出内容的MIME类型,对于HTTP协议来说,就是设置Content-Type响应头字段的值。例如,如果发送到客户端的内容是jpeg格式的图像数据,就需要将响应头字段的类型设置为“image/jpeg”。需要注意的是,如果响应的内容为文本,setContentType()方法的还可以设置字符编码,如:text/html;charset=UTF-8
void setLocale(Locale loc) 该方法用于设置响应消息的本地化信息。对HTTP来说,就是设置Content-Language响应头字段和Content-Type头字段中的字符集编码部分。需要注意的是,如果HTTP消息没有设置Content-Type头字段,setLocale()方法设置的字符集编码不会出现在HTTP消息的响应头中,如果调用setCharacterEncoding()或setContentType()方法指定了响应内容的字符集编码,setLocale()方法将不再具有指定字符集编码的功能
void setCharacterEncoding(String charset) 该方法用于设置输出内容使用的字符编码,对HTTP 协议来说,就是设置Content-Type头字段中的字符集编码部分。如果没有设置Content-Type头字段,setCharacterEncoding方法设置的字符集编码不会出现在HTTP消息的响应头中。setCharacterEncoding()方法比setContentType()和setLocale()方法的优先权高,setCharacterEncoding()方法的设置结果将覆盖setContentType()和setLocale()方法所设置的字符码表
cn.zzh.response.HeaderServlet.java
package cn.zzh.response;

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("/HeaderServlet")
public class HeaderServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)throws ServletException, IOException {
        response.setStatus(1000) ;
        response.setCharacterEncoding("utf8");
        response.setContentType("text/html");
    }
    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)throws ServletException, IOException {
        doGet(request, response);
    }
}

运行结果如下:

图24 发送响应头 resp.setCharacterEncoding|setContentType

4.3 发送响应消息体相关的方法

cn.zzh.response.PrintServlet.java
package cn.zzh.response;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet("/PrintServlet")
public class PrintServlet extends HttpServlet {
    public void doGet(HttpServletRequest req,
                      HttpServletResponse resp)throws ServletException, IOException {
        String data = "zzh 郑佐汉!";
        // 获取字符输出流对象
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        out.write("out = resp.getWriter();out.write(...) (郑佐汉)<hr>");
        out.write(data);
    }
    public void doPost(HttpServletRequest req,
                       HttpServletResponse resp)throws ServletException, IOException {
        doGet(req, resp);
    }
}

运行结果如下:

图25 发送响应(字符输出流)

cn.zzh.response.PrintServlet2.java

package cn.zzh.response;
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.OutputStream;
import java.nio.charset.StandardCharsets;

@WebServlet("/PrintServlet2")
public class PrintServlet2 extends HttpServlet {
    public void doGet(HttpServletRequest req,
                      HttpServletResponse resp)throws ServletException, IOException {
        String data = "zzh 郑佐汉!";
        resp.setContentType("text/html;charset=UTF-8");
        resp.setCharacterEncoding(StandardCharsets.UTF_8.name());
        OutputStream out = resp.getOutputStream();
        out.write("out = resp.getOutputStream();out.write(...) 字节流 (郑佐汉)<hr>".getBytes(StandardCharsets.UTF_8));
        out.write(data.getBytes(StandardCharsets.UTF_8));
    }
}

运行结果如下:

图26 发送响应(字节输出流)
cn.zzh.response.PrintServlet3.java 先保存图片 dzj.jpg 到 web/dzj.jpg
package cn.zzh.response;
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;
import java.nio.file.Files;
import java.nio.file.Paths;

@WebServlet("/PrintServlet3")
public class PrintServlet3 extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)throws ServletException, IOException {
        // 设置响应的格式
        response.setContentType("image/jpg");
        //字节输入流
        ServletContext context = this.getServletContext();
        InputStream in = Files.newInputStream(Paths.get(context.getRealPath("/dzj.jpg")));;
        //字节输出流
        ServletOutputStream out = response.getOutputStream();
        // 存储读取到的数据
        int read = 0;
        while ((read = in.read())!= -1){
        // 将读取到的数据输出
            out.write(read);
        }
        // 关闭流
        out.close();
        in.close();
    }
}

运行结果如下:

图27 发送响应(字节输出流--图片)

5. HttpServletResponse对象

5.1 实现请求重定向

sendRedirect()方法的工作原理

图28 sendRedirect()方法的工作原理

login.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
    <!--把表单内容提交到ch04工程下的LoginServlet-->
    <form action="LoginServlet" method="post">
        <label>用户名: <input type="text" name="username" ></label><br>
        <label>&nbsp;&nbsp;&nbsp;码:<input type="password" name="password"></label><br>
        <input type="submit" value="登录">
    </form>
</body>
</html>

welcome.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>登录成功</title>
</head>
<body>
欢迎你,登录成功!
</body>
</html>

cn.zzh.response.LoginServlet.java

package cn.zzh.response;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)throws ServletException, IOException {
        response.setContentType("text/html;charset=UTF-8");
        // 用HttpServletRequest对象的getParameter()方法获取用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        // 假设用户名和密码分别为:zzh和123
        if ("zzh".equals(username) &&"123".equals(password)) {
            // 如果用户名和密码正确,重定向到 welcome.html
            response.sendRedirect("welcome.html");
        } else {
            // 如果用户名和密码错误,重定向到login.html
            response.sendRedirect("login.html");
        }
    }
    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)throws ServletException, IOException {
        doGet(request, response);
    }
}

运行结果如下:

图29 登录

5.2 动手实践:解决中文输出乱码问题

图30 中文乱码 ??
package cn.zzh.response;
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("/ChineseServlet0")
public class ChineseServlet0 extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("中国");
    }
}
图31 中文乱码
package cn.zzh.response;
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("/ChineseServlet1")
public class ChineseServlet1 extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)throws ServletException, IOException {
        response.setCharacterEncoding("utf8");
        PrintWriter out = response.getWriter();
        out.println("中国");
    }
}
图32 解决中文乱码
package cn.zzh.response;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/ChineseServlet")
public class ChineseServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response)throws ServletException, IOException {
        // 设置request的字符编码
        request.setCharacterEncoding("utf-8");
        //设置response的字符编码和浏览器解析的内容类型
        response.setContentType("text/html;charset=utf-8");
        String data = "中国";
        PrintWriter out = response.getWriter();
        out.println(data);
    }
    public void doPost(HttpServletRequest request,
                       HttpServletResponse response)throws ServletException, IOException {
        doGet(request, response);
    }
}

6. HttpServletRequest对象

6.1 获取请求行信息的相关方法

HttpServletRequest接口获取请求行的相关方法

方法声明 功能描述
String getMethod( ) 该方法用于获取HTTP请求消息中的请求方式(如GET、POST等)
String getRequestURI( ) 该方法用于获取请求行中资源名称部分,即位于URL的主机和端口之后、参数部分之前的数据
String getQueryString( ) 该方法用于获取请求行中的参数部分,也就是资源路径后面问号(?)以后的所有内容
String getProtocol( ) 该方法用于获取请求行中的协议名和版本,例如HTTP/1.0或HTTP/1.1
String getContextPath( ) 该方法用于获取请求URL中属于Web应用程序的路径,这个路径以“/”开头,表示相对于整个Web站点的根目录,路径结尾不含“/”。如果请求URL属于Web站点的根目录,那么返回结果为空字符串("")
String getServletPath( ) 该方法用于获取Servlet的名称或Servlet所映射的路径
String getRemoteAddr( ) 该方法用于获取请求客户端的IP地址,其格式类似于“192.168.0.3”
String getRemoteHost( ) 该方法用于获取请求客户端的完整主机名,其格式类似于“pc1.itcast.cn”。需要注意的是,如果无法解析出客户机的完整主机名,该方法将会返回客户端的IP地址
int getRemotePort() 该方法用于获取请求客户端网络连接的端口号
String getLocalAddr() 该方法用于获取Web服务器上接收当前请求网络连接的IP地址
String getLocalName() 该方法用于获取Web服务器上接收当前网络连接IP所对应的主机名
int getLocalPort() 该方法用于获取Web服务器上接收当前网络连接的端口号
String getServerName() 该方法用于获取当前请求所指向的主机名,即HTTP请求消息中Host头字段所对应的主机名部分
int getServerPort() 该方法用于获取当前请求所连接的服务器端口号,即如果HTTP请求消息中Host头字段所对应的端口号部分
String getScheme() 该方法用于获取请求的协议名,例如http、https或ftp
StringBuffer getRequestURL() 该方法用于获取客户端发出请求时的完整URL,包括协议、服务器名、端口号、资源路径等信息,但不包括后面的查询参数部分。注意,getRequestURL()方法返回的结果是StringBuffer类型,而不是String类型,这样更便于对结果进行修改
package cn.zzh.request;

import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet("/RequestLineServlet")
public class RequestLineServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        // 获取请求行的相关信息
        out.println("获取请求行的相关信息(郑佐汉)<hr>");
        out.println("请求方法 getMethod : " + request.getMethod() + "<br>");
        out.println("请求URI getRequestURI : " + request.getRequestURI() + "<br>");
        out.println("查询串 getQueryString:" + request.getQueryString() + "<br>");
        out.println("请求协议 getProtocol : " + request.getProtocol() + "<br>");
        out.println("上下文路径 getContextPath:" + request.getContextPath() + "<br>");
        out.println("额外路径信息 getPathInfo : " + request.getPathInfo() + "<br>");
        out.println("额外路径信息对应资源的真实路径  getPathTranslated : " + request.getPathTranslated() + "<br>");
        out.println("Servlet所映射的路径 getServletPath:" + request.getServletPath() + "<br>");
        out.println("客户端ip地址 getRemoteAddr : " + request.getRemoteAddr() + "<br>");
        out.println("客户端主机名 getRemoteHost : " + request.getRemoteHost() + "<br>");
        out.println("客户端端口 getRemotePort : " + request.getRemotePort() + "<br>");
        out.println("Web服务器端本地ip地址(局域网--内网) getLocalAddr : " + request.getLocalAddr() + "<br>");
        out.println("Web服务器端本地主机名(局域网--内网) getLocalName : " + request.getLocalName() + "<br>");
        out.println("Web服务器端本地端口(局域网--内网) getLocalPort : " + request.getLocalPort() + "<br>");
        out.println("Web服务器公网主机名(互联网--公网) getServerName : " + request.getServerName() + "<br>");
        out.println("Web服务器公网端口(互联网--公网) getServerPort : " + request.getServerPort() + "<br>");
        out.println("请求协议 getScheme : " + request.getScheme() + "<br>");
        out.println("请求URL getRequestURL : " + request.getRequestURL() + "<br>");
    }
    //getPathInfo 返回请求URL中的额外路径信息。额外路径信息是请求URL中的位于Servlet的路径之后和查询参数之前的内容,它以“/”开头。
    //getPathTranslated  //返回URL中的额外路径信息所对应的资源的真实路径。

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

运行结果如下:

图33 云端请求行信息

6.2 获取请求头的相关方法

方法声明 功能描述
String getHeader(String name) 该方法用于获取一个指定头字段的值,如果请求消息中没有包含指定的头字段,getHeader()方法返回null;如果请求消息中包含有多个指定名称的头字段,getHeader()方法返回其中第一个头字段的值
Enumeration getHeaders(String name) 该方法返回一个Enumeration集合对象,该集合对象由请求消息中出现的某个指定名称的所有头字段值组成。在多数情况下,一个头字段名在请求消息中只出现一次,但有时候可能会出现多次
Enumeration getHeaderNames() 该方法用于获取一个包含所有请求头字段的Enumeration对象
int getIntHeader(String name) 该方法用于获取指定名称的头字段,并且将其值转为int类型。需要注意的是,如果指定名称的头字段不存在,返回值为-1;如果获取到的头字段的值不能转为int类型,将发生NumberFormatException异常
long getDateHeader(String name) 该方法用于获取指定头字段的值,并将其按GMT时间格式转换成一个代表日期/时间的长整数,这个长整数是自1970年1月1日0点0分0秒算起的以毫秒为单位的时间值
String getContentType() 该方法用于获取Content-Type头字段的值,结果为String类型
int getContentLength() 该方法用于获取Content-Length头字段的值,结果为int类型
String getCharacterEncoding() 该方法用于返回请求消息的实体部分的字符集编码,通常是从Content-Type头字段中进行提取,结果为String类型
package cn.zzh.request;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Enumeration;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet("/RequestHeadersServlet")
public class RequestHeadersServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
                      HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        // 获取请求消息中所有头字段
        out.println("获取请求消息中所有头字段(郑佐汉)<hr>");
        Enumeration<String> headerNames = request.getHeaderNames();
        // 使用循环遍历所有请求头,并通过getHeader()方法获取一个指定名称的头字段
        while (headerNames.hasMoreElements()) {
            String headerName = (String) headerNames.nextElement();
            out.print(headerName + " : "
                    + request.getHeader(headerName) + "<br />");
        }
    }
}

运行结果如下:

图34 云端请求头信息

6.3 请求转发

图35 请求转发
package cn.zzh.request;

import java.io.IOException;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

@WebServlet("/请求转发")
public class RequestForwardServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        request.setAttribute("用户名", "郑佐汉");// 将数据存储到request对象中
        RequestDispatcher dispatcher =
                request.getRequestDispatcher("/ResultServlet");
        dispatcher.forward(request, response);
    }
}
package cn.zzh.request;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/ResultServlet")
public class ResultServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        String username = (String) request.getAttribute("用户名");
        if (username != null) {
            out.println("用户名:" + username + "<br>");
        }
    }
}

运行结果如下:

图36 请求转发

6.4 获取请求参数

方法声明 功能描述
String getParameter(String name) 该方法用于获取某个指定名称的参数值,如果请求消息中没有包含指定名称的参数,getParameter()方法返回null;如果指定名称的参数存在但没有设置值,则返回一个空串;如果请求消息中包含有多个该指定名称的参数,getParameter()方法返回第一个出现的参数值
String[] getParameterValues(String name) 该方法用于返回一个String类型的数组,HTTP请求消息中可以有多个相同名称的参数(通常由一个包含有多个同名的字段元素的form表单生成),如果要获得HTTP请求消息中的同一个参数名所对应的所有参数值,那么就应该使用getParameterValues()方法
Enumeration getParameterNames() 该方法用于返回一个包含请求消息中所有参数名的Enumeration对象,在此基础上,可以对请求消息中的所有参数进行遍历处理
Map getParameterMap() 该方法用于将请求消息中的所有参数名和值装入进一个Map对象中返回

form.html

<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>获取请求参数</title>
</head>
<body>
<h2>获取请求参数 request.getParameter("input中name参数");</h2>
<hr>
<form action="RequestParamsServlet" method="POST">
    <label>用户名:<input type="text" name="用户名"></label><br>
    <label>&nbsp;&nbsp;&nbsp;码:<input type="password" name="密码"></label>
    <br />
    <label>爱好:
    <input type="checkbox" name="hobby" value="唱歌">唱歌
    <input type="checkbox" name="hobby" value="跳舞">跳舞
    <input type="checkbox" name="hobby" value="足球">足球</label><br>
    <input type="submit" value="提交">
</form>
</body>
</html>
package cn.zzh.request;
import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;
@WebServlet("/RequestParamsServlet")
public class RequestParamsServlet extends HttpServlet {
    public void doGet(HttpServletRequest request,
         HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        String name = request.getParameter("用户名");
        String password = request.getParameter("密码");
        System.out.println("用户名:" + name);
        System.out.println("密  码:" + password);
        // 获取参数名为“hobby”的值 String数组
        String[] hobbys = request.getParameterValues("hobby");
        System.out.print("爱好:");
        for (String hobby : hobbys) {
            System.out.print(hobby + ", ");
        }
        // 输出到浏览器端
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("1. 接收到的参数 request.getParameter | request.getParameterValues<hr>");
        out.println("用户名:" + name);
        out.println("<br>密  码:" + password);
        out.println("<br>爱好:");
        for (String hobby : hobbys) {
            out.print(hobby + ", ");
        }

        //3.获取所有的参数名
        System.out.println("\n所有的参数名 Enumeration<String> names = request.getParameterNames(): ");
        Enumeration<String> names = request.getParameterNames() ;
        while (names.hasMoreElements()){
            String name2 = names.nextElement();
            if ("hobby".equals(name2))
                System.out.println(name2+" = "+ Arrays.toString(request.getParameterValues(name2)));
            else
                System.out.println(name2+" = "+request.getParameter(name2));
        };

        Enumeration<String> names2 = request.getParameterNames() ;
        out.println("<br><br>2. 所有的参数名 Enumeration<String> names = request.getParameterNames(): <hr>");
        while (names2.hasMoreElements()){
            String name2 = names2.nextElement();
            if ("hobby".equals(name2))
                out.println(name2+" = "+ Arrays.toString(request.getParameterValues(name2))+"<br>");
            else
                out.println(name2+" = "+request.getParameter(name2)+"<br>");
        };

        // 4.获取参数名和参数值组成的map集合
        out.println("<br> 3. 获取参数名和参数值组成的map集合 Map<String, String[]> parameterMap = request.getParameterMap()<hr>");
        Map<String, String[]> parameterMap = request.getParameterMap();
        Set<Map.Entry<String,String[]>> entries = parameterMap.entrySet();
        Set<String> keySet = parameterMap.keySet();

        for (String key : keySet) {
            out.print("关键字 " + key + " = ");
            //out.print("key:"+it.next()); 这个地方不能怎么写,往下看就知道了
            //因为不能一次判断取两次值,可能会抛出NoSuchElementExcetion异常
            String[] value = parameterMap.get(key);
            for (String str : value) {
                if(value.length == 1)
                    out.print(str);
                else
                    out.print(str + ", ");
            }
            out.print("<br>");
        }

    }

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

运行结果如下:

图37 获取请求参数

6.5 通过Request对象传递数据

package cn.zzh.request;
import javax.servlet.RequestDispatcher;
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("/Request传递数据")
public class RequestDemoServlet extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        request.setAttribute("用户名", "郑佐汉");// 将数据存储到request对象中
        RequestDispatcher dispatcher = request.getRequestDispatcher("/Request传递数据1");
        dispatcher.forward(request, response);
    }
}
package cn.zzh.request;
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("/Request传递数据1")
public class RequestDemoServlet1 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String uname = (String) request.getAttribute("用户名");
        response.getWriter().write("Request传递数据1:用户名="+uname);
    }
}

运行结果如下:

图38 通过Request对象属性传递数据 1
package cn.zzh.request;
import javax.servlet.RequestDispatcher;
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("/Request传递数据2")
public class RequestDemoServlet2 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        request.setAttribute("用户名", "郑佐汉");// 将数据存储到request对象中
        RequestDispatcher dispatcher = request.getRequestDispatcher("/Request传递数据3");
        dispatcher.forward(request, response);
    }
}
package cn.zzh.request;
import javax.servlet.RequestDispatcher;
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.awt.*;
import java.io.IOException;

@WebServlet("/Request传递数据3")
public class RequestDemoServlet3 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        System.out.println("RequestDemoServlet3.java 执行:\n ------------------------------------------");
        System.out.println("request.removeAttribute(\"用户名\")之前:  "+request.getAttribute("用户名"));
        request.removeAttribute("用户名");
        System.out.println("request.removeAttribute(\"用户名\")之后:  "+request.getAttribute("用户名"));
        RequestDispatcher dispatcher = request.getRequestDispatcher("/Request传递数据4");
        dispatcher.forward(request, response);
    }
}
package cn.zzh.request;
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("/Request传递数据4")
public class RequestDemoServlet4 extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse
            response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String uname = (String) request.getAttribute("用户名");
        response.getWriter().write("Request传递数据4:用户名="+uname);
    }
}

运行结果如下:

图39 通过Request对象属性传递数据 2

6.6 动手实践:解决请求参数的中文乱码问题

//设置request对象的编码方式
request.setCharacterEncoding("utf-8");
//设置resp对象的编码方式
resp.setContentType("text/html; charset=utf-8");
图40 本章开发文件结构图

返回