目录
6、继承 HttpServlet 类实现 service 方法
一、Servlet 概念
1、简介
Servlet 是 JavaEE 规范之一。规范就是接口(Interface)。
Servlet 是 JavaWeb 三大组件之一,三大组件分别是:Servlet 程序、Filter 过滤器、Listener 监听器。
Servlet 是运行在服务器上的一个 java 小程序,它可以通过 HTTP 接收客户端发送过来的请求,并响应数据给客户端。
2、简单实现一个 demo
(1)编写一个类去实现 Servlet 接口;
(2)实现一个重要方法 service(),处理请求并响应数据;
(3)服务器上的数据都需要访问地址,到 web.xml 中去配置 servlet 程序的访问地址;
注意,该 web.xml 文件,必须是被部署的 web 工程的 xml 文件。
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!-- servlet 标签给 tomcat 服务器配置servlet程序 -->
<servlet>
<!-- servlet-name标签 是 servlet 程序的一个别名(一般设置为 java 程序的类名) -->
<servlet-name>servlet_demo</servlet-name>
<!-- servlet-class标签 是 servlet 程序的完整类名-->
<servlet-class>test.servlet_demo</servlet-class>
</servlet>
<!-- servlet-mapping标签 给 servlet 程序配置访问地址-->
<servlet-mapping>
<!-- servlet-name 标签的作用是,告诉服务器,当前配置的地址,是哪一个 servlet 程序使用的-->
<servlet-name>servlet_demo</servlet-name>
<!-- url-pattern 标签 配置访问地址
/ 斜杠,在服务器解析的时候,表示地址为:http://ip:port/工程路径
则 /start 表示 http://ip:port/工程路径/start
-->
<url-pattern>/start</url-pattern>
</servlet-mapping>
</web-app>
其中,工程路径就是,部署在 tomcat 服务器上的 web 工程。
(4)启动 tomcat 服务器,访问 index.jsp;
(5)补充访问地址 /start,启动 servlet 程序;
IDEA 的控制台就会做相应的 service() 的操作:
3、url 地址如何访问到 servlet 程序
4、Servlet 生命周期
(1)执行 Servlet 构造方法;
(2)执行 init 初始化方法;
(3)执行 service 方法;
(4)执行 destroy 销毁方法;
前两步只会在第一次访问时执行一次,每次刷新只会重新执行 service 方法;第四步在 Web 工程停止的时候调用。
5、GET 和 POST 请求的分发处理
(1)编写一个包含表单提交的 html 页面:
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action = "http://localhost:8080/JavaEnterprise_war_exploded/start" method = "get">
<input type = "submit" value = "submit"/>
</form>
</body>
启动 tomcat 访问:
(2)修改 service 方法,分类处理请求:
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("servlet 被访问了");
// HttpServletRequests 是 ServletRequest 子接口,有获取请求类型的方法:getMethod()
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String method = httpServletRequest.getMethod();
if (method.equalsIgnoreCase("get")) {
System.out.println("这是 get 请求");
} else if (method.equalsIgnoreCase("post")) {
System.out.println("这是 post 请求");
}
}
(3)点击提交按钮,发起 GET 请求,再修改 html 页面,发送 POST 请求:
6、继承 HttpServlet 类实现 service 方法
在实际开发中,很少通过实现 servlet 接口这种方式实现 servlet 程序。一般是找 Servlet 的子类去继承,HttpServlet 用的比较多。
(1)编写一个类去继承 HttpServlet 类;
(2)根据需要重写 doGet() 或 doPost() 两个方法;
(3)到 web.xml 配置 Servlet 程序的访问地址;
package test;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
public class servlet_demo extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet方法");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost方法");
}
}
7、IDEA 自动生成 Servlet 程序
(1)新建
(2)更改类名和全类名
(3)IDEA 会在 web.xml 生成代码,只需要配置 <serlvet_mapping> 即可
二、Servlet 类
1、继承体系
2、ServletConfig 类
从类名上来看,就知道是 Servlet 程序的配置信息类。
(1)三大作用
- 可以获取 Servlet 程序的别名,也就是 servlet-name 的值;
- 获取初始化参数 init-param;
- 获取 Servlet-Context 对象;
使用实现接口类,其中有 init() 方法,在 init() 中实现:
Java 代码:
package test;
import javax.servlet.*;
import java.io.IOException;
public class servlet_demo_implements implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
// 可以获取 Servlet 程序的别名,也就是 servlet-name 的值;
System.out.println("servlet 程序的别名(默认用类名)是:" + servletConfig.getServletName());
// 获取初始化参数 init-param;
System.out.println("初始化参数username的值是:" + servletConfig.getInitParameter("userName"));
System.out.println("初始化参数url的值是:" + servletConfig.getInitParameter("url"));
// 获取 Servlet-Context 对象;
System.out.println("ServletContext对象:" + servletConfig.getServletContext());
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
web.xml 代码:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>servlet_demo_implements</servlet-name>
<servlet-class>test.servlet_demo_implements</servlet-class>
<init-param> <!-- 可以配置多个 -->
<param-name>userName</param-name> <!-- 参数名 -->
<param-value>name_1</param-value> <!-- 参数值 -->
</init-param>
<init-param>
<param-name>url</param-name>
<param-value>http://114514:8080</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>servlet_demo_implements</servlet-name>
<url-pattern>/begin</url-pattern>
</servlet-mapping>
</web-app>
输出结果:
(2)补充
(2-1)getServletConfig()
Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建,我们负责调用。
- Servlet 程序默认是第一次访问的时候创建;
- ServletConfig 是每个 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象;
因此,如果在一个 Java 程序中使用 getServletConfig() 这个方法获取得到的 ServletConfig 对象,是不能访问到该 Java 程序之外的 config 信息的。
(2-2)HttpServlet 重写 init()
因为默认情况下,继承 HttpServlet 是不需要实现 init() 的。
但是因为某些理由需要重写 init() 时,需要调用 super(config),否则调用 ServletConfig 对象会导致空指针:
package test;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
public class servlet_demo extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("重写了 init 方法");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet方法");
ServletConfig config = getServletConfig();
System.out.println("初始化参数 id 的值为:" + config.getInitParameter("id"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost方法");
}
}
3、ServletContext 类
(1)什么是 ServletContext ?
- ServletContext 是一个接口,他表示 Servlet 上下文对象;
- 一个 Web 工程,只有一个 ServletContext 对象实例;
- ServletContext 对象是一个域对象;
(2)什么是“域对象”?
域对象是指,可以像 Map 一样存取数据的对象。这里的域指的是,存取数据的操作范围,也就是整个 Web 工程。
若 Web 工程有多个 Servlet 程序,访问过的 Servlet 程序做出的操作是会保存到 context 中的。只要 Web 工程不停止,context 的内容就是实时的。
举个例子:Servlet 程序 A,做了存数据操作,那么 Servlet 程序 B,就可以访问到这个数据。
因此 Web 和 Servlet 的关系可以这么理解:Web 工程的许多信息,比如 ServletContext,可以使用 Servlet 程序进行操作。
(3)ServletContext 类的四个作用
- 获取 web.xml 中配置的上下文参数 context-param;
- 获取当前的工程路径,格式:/工程路径;
- 获取工程部署后,在服务器硬盘上的绝对路径;
- 像 Map 一样存取数据;
package test;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class ServletContext_test extends HttpServlet {
private ServletContext context;
public void init(ServletConfig config) throws ServletException {
super.init(config);
context = getServletConfig().getServletContext(); // 也可以写 context = getServletContext();
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doGet(req, resp);
// 1.获取 web.xml 中配置的上下文参数 context-param;
System.out.println("context-param 参数 userName 的值是:" + context.getInitParameter("userName"));
System.out.println("context-param 参数 url 的值是:" + context.getInitParameter("url"));
// 2.获取当前的工程路径,格式:/工程路径;
System.out.println("当前工程路径:" + context.getContextPath());
// 3/获取工程部署后,在服务器硬盘上的绝对路径;
System.out.println("工程部署的服务器硬盘绝对路径:" + context.getRealPath("/"));
System.out.println("工程下 html 目录的绝对路径是:" + context.getRealPath("/html"));
/*
/ 斜杠代表:http://ip:port/工程名/,因此写一个 / 即可
其意义为:映射到 IDEA 的 webapp 目录,可以直接在磁盘上访问该绝对路径
*/
// 4.像 Map 一样存取数据;
System.out.println("设置之前:context 获取到 key1 的值为:" + context.getAttribute("key1"));
context.setAttribute("key1", "value1");
System.out.println("context 中获取域数据 key1 的值是:" + context.getAttribute("key1"));
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
super.doPost(req, resp);
}
}
三、Http 协议
1、简介
HTTP 协议是指,客户端与服务器通信时,需要遵守的规则,叫做 HTTP 协议。HTTP 协议中的数据又叫报文。
- 客户端给服务器发送数据叫请求;
- 服务器给客户端回传数据叫响应。
2、请求的 HTTP 协议格式
请求分为 GET 和 POST 请求。
(1)GET 请求
(1-1)GET 请求的 HTTP 协议格式:
1、请求行
(1)请求的方式:默认 GET 字符串
(2)请求的资源路径 + [? + 请求参数]
(3)请求的协议的版本号:默认 HTTP/1.1
2、请求头
由 key:value 组成,不同的键值对表示不同的含义
(1-2)抓包:
(1-3)分析:
(2)POST 请求
(2-1)POST 请求的 HTTP 协议格式:
1、请求行
(1)请求的方式:默认 GET 字符串
(2)请求的资源路径 + [? + 请求参数]
(3)请求的协议的版本号:默认 HTTP/1.1
2、请求头
由 key:value 组成,不同的键值对表示不同的含义
3、空行
4、请求体
就是发送给服务器的数据
(2-2)抓包:
(2-3)分析:
(3)测试代码
HTML:
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action = "http://localhost:8080/JavaEnterprise_war_exploded/start" method = "POST">
<!-- 将表单发送给 tomcat 服务器,并执行相应的 servlet 程序 -->
<input type = "hidden" name = "action" value = "login"/>
<input type = "hidden" name = "username" value = "root"/>
<input type = "submit" value = "submit"/>
</form>
</body>
Java(Servlet 程序):
package test;
import java.io.IOException;
import javax.servlet.*;
import javax.servlet.http.*;
public class servlet_demo extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
System.out.println("重写了 init 方法");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doGet方法");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("doPost方法");
}
}
3、常用请求头
- Accept:表示客户端可以接收的数据类型;
- Accept-Languege:表示客户端可以接收的语言类型;
- User-Agent:表示客户端浏览器信息;
- Host:表示请求的服务器 ip 和 port;
4、如何区分 GET 和 POST 请求
(1)GET 请求有:
- form 标签 method = get;
- a 标签;
- link 标签引入 css 文件;
- script 标签引入 js 文件;
- img 标签引入 图片;
- iframe 标签引入 html 页面;
- 在浏览器地址栏输入地址进行访问;
(2)POST 请求有:
- form 标签 method = post;
5、响应的 HTTP 协议格式
(1)格式
1、响应行
(1)响应的协议和版本号 HTTP/1.1
(2)响应状态码 200(200表示响应成功)
(3)响应状态描述符 ok
2、响应头
(1)key :value 不同的响应头,有不同的含义
3、空行
4、响应体
回传给客户端的数据
(2)抓包
(2-1)响应行 + 响应头:
(2-2)响应体:
(3)分析:
6、常见的响应码说明
- 200:表示请求成功;
- 302:表示请求重定向;
- 404:表示请求已经被服务器接收,但是目标数据不存在(一般是请求地址错误);
- 500:表示服务器已经收到请求,但是服务器内部错误(代码错误);
7、MIME 类型说明
MIME 是 HTTP 协议中的数据类型。“Multipurpose Internet Mail Extensions”:多功能 Internet 邮件扩充服务。
MIME 的格式是“大类型/小类型”,并与某一种文件的拓展名相对应。
四、HttpServletRequest 类
我们可以通过 HttpServletRequest 对象,获取到所有请求的信息。
每次只要有请求进入 Tomcat 服务器,Tomcat 服务器就会创建 HttpServletRequest 对象,把请求的 HTTP 协议信息解析后封装到 HttpServletRequest 对象中。(每次请求都会创建一个,请求完成就会销毁)
1、HttpServletRequest 常用方法
(1)测试一
- getRequestURI():获取请求的资源路径
- getRequestURL():获取请求的统一资源定位符(绝对路径)
- getRemoteHost():获取客户端 ip 地址
- getHeader():获取请求头
- getMethod():获取请求的方式(GET 或 POST)
package test;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
public class RequestAPIServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// super.doGet(req, resp); 这个不需要,这是调用父类 HttpServlet 的 doget
// getRequestURI():获取请求的资源路径
System.out.println("URI ==> " + req.getRequestURI());
// getRequestURL():获取请求的统一资源定位符(绝对路径)
System.out.println("URL ==> " + req.getRequestURL());
// getRemoteHost():获取客户端 ip 地址
/*
使用 localhost / 127.0.0.1 访问,得到的都是 127.0.0.1;
使用真实 ip 访问,得到的就是真实 ip。
*/
System.out.println("客户端 ip 地址 ==> " + req.getRemoteHost());
// getHeader():获取请求头
System.out.println("请求头 User-Agent ==> " + req.getHeader("User-Agent"));
// getMethod():请求的方式
System.out.println("请求的方式 ==> " + req.getMethod());
}
}
(2)测试二
- getParameter():获取请求的参数
- getParameterValues():获取请求的参数(多个值的时候使用)
访问 HTML 页面,完成表单的提交,提交给 servlet 程序。
(2-1)HTML 代码:
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action = "http://localhost:8080/JavaEnterprise_war_exploded/start_ParameterServlet" method = "GET">
用户名:<input type = "text" name = "username" value = "default"/> <br/>
密码:<input type = "password" name = "password" value = "default"/> <br/>
兴趣爱好:
<input type = "checkbox" name = "hobby" value = "C++"/> C++
<input type = "checkbox" name = "hobby" value = "Python"/> Python
<input type = "checkbox" name = "hobby" value = "Java"/> Java
<br/>
<input type = "submit" value = "submit"/>
</form>
</body>
(2-2)Java 代码:
package test;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
import java.util.Arrays;
public class ParameterServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取 一个 请求参数
System.out.println("用户名:" + req.getParameter("username"));
System.out.println("密码:" + req.getParameter("password"));
// 获取 多个个 请求参数
String[] hobbies = req.getParameterValues("hobby");
System.out.println("兴趣爱好:" + Arrays.asList(hobbies));
}
}
(2-3)效果:
(3)其他方法
- setAttribute(key, value):设置域数据
- getAttribute(key):获取域数据
- getRequestDispatcher():获取请求转发对象
2、post 请求中文乱码
使用 setCharacterEncoding("UTF-8") 设置字符集。
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置请求字符集为 UTF-8,解决 post 请求中文乱码问题,注意,必须在获取请求参数之前调用
req.setCharacterEncoding("UTF-8");
System.out.println("用户名:" + req.getParameter("username"));
}
3、请求的转发
请求的转发是指,服务器收到请求后,从一个资源跳转到另一个资源的操作。
(1)编写代码
(1-1)Java 代码1:
package test;
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;
public class Servlet1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求的参数
String username = req.getParameter("username");
System.out.println("在 Servlet1(柜台1) 中查看参数(材料):" + username);
// 给材料盖章,并传递到 Servlet2(柜台2)
req.setAttribute("key", "Servlet1 的章");
// 问路,如何去 Servlet2
/*
请求转发必须以 / 开头,表示:http://ip:port/工程名/,与之前的 / 的意义相同
映射到 IDEA 代码的 web 工程目录,也就是与 web.xml 中配置的 url 相同。
*/
RequestDispatcher requestDispatcher =req.getRequestDispatcher("/start_Servlet2");
// 访问 WEB-INF 目录内的资源可以写 "/WEB-INF/xxx.xxx"
// 走向 Servlet2
requestDispatcher.forward(req, resp);
}
}
(1-2)Java 代码2:
package test;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
public class Servlet2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求的参数
/*
Servlet2 的 req 与 Servlet1 的 req 是同一个,是通过 forword 将请求转发到 Servlet2。
可以理解为,Servlet1 是登录页面,Servlet2 是登陆后进入的主页面
*/
String username = req.getParameter("username");
System.out.println("在 Servlet2(柜台2) 中查看参数(材料):" + username);
// 检查是否有 Servlet1 的盖章
Object key = req.getAttribute("key");
System.out.println("Servlet1 是否盖章:" + key);
// 处理自己的业务
System.out.println("Servlet2 处理自身业务。。。。。");
}
}
(2)向 Servlet1 发送请求,并添加参数
(3)访问 Servlet1 成功,请求转发给 Servlet2 成功
(4)请求转发的特点
- 访问的地址不会发生改变:都是对 Servlet1 的访问,但由 Servlet1 将请求转发至 Servlet2
- 是同一次请求
- 共享 Request 域中的数据
- 可以访问 WEB-INF 目录:直接对 WEB-INF 的访问是做不到的,但是可以通过转发间接访问
- 不能访问 Web 工程以外的资源:因为根地址就是 Web 工程目录
4、<base> 标签的作用
浏览器解析时会在路径前加上 <base> 给的目标,而页面中的相对路径也都转换成了绝对路径(也就是说,在 base 标签引入后的所有 url,都是绝对路径,只是写法与相对路径一致)。
需要注意的是,如果使用 base 标签,则必须出现在所有 url 之前。
(1)首先定义两个 html 页面:
web/index.html:
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href = "html/b/c.html">跳转至html/b/c.html页面</a>
</body>
web/html/b/c.html:
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href = "../../index.html">跳转至index.html</a>
</body>
效果:这两个页面可以通过点击 a 标签实现相互跳转。
(2)使用请求转发跳转
给 index.html 添加 Servlet 程序的链接,使用该链接,观察是否还能实现这两个 html 页面的相互跳转。
web/index.html:
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href = "html/b/c.html">跳转至html/b/c.html页面</a> <br/>
<a href = "http://localhost:8080/JavaEnterprise_war_exploded/start_ForwardChtml">请求转发</a>
</body>
Java 代码:
public class ForwardChtml extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("经过了 ForwordChtml 程序");
req.getRequestDispatcher("/html/b/c.html").forward(req, resp);
}
}
当点击返回 index.html 时,就会出现以下情况:
(3)原因
显然是因为点击返回 index.html 时,参照的相对路径有问题。
当通过请求转发访问 c.html 时,路径为:
http://localhost:8080/JavaEnterprise_war_exploded/start_ForwardChtml
那么以此为基础,../../index.html 会使得访问路径变为:
http://localhost:8080/index.html
这时候,就可以使用 base 标签,设置当前页面中,所有相对路径工作时,参照哪个路径进行跳转。
(4)最后的修改
web/html/b/c.html:
<head>
<meta charset="UTF-8">
<title>Title</title>
<!-- base 标签设置页面相对路径工作时参照的地址
href属性就是参照的地址值,c.html 可以省略
-->
<base href = "http://localhost:8080/JavaEnterprise_war_exploded/html/b/c.html"/>
</head>
<body>
<a href = "../../index.html">跳转至index.html</a>
</body>
这样就完成了 base 标签的作用。
5、路径复习
在 JavaWeb 中,路径分为相对路径和绝对路径两种:
(1)相对路径:
- . 表示当前目录
- .. 表示上一级目录
- 资源名 表示当前目录/资源名
(2)绝对路径:
http://ip:port/工程名/资源路径
(3)/ 斜杠意义:
在 Web 中,斜杠是一种绝对路径。
(3-1)/ 斜杠如果被浏览器解析,得到的路径是:http://ip:port/
<a href = "/">斜杠</a>
(3-2)/ 斜杠如果被服务器解析,得到的地址是:http://ip:port/工程路径
<url-pattern>/start_servlet</url-pattern>
servletContext.getRealPath("/");
request.getRequestDispatcher("/");
(3-3)特殊情况
response.sendRedirect("/");
把斜杠发给浏览器解析,得到:http://ip:port/
五、HttpServletResponse 类
1、HttpServletResponse 的作用
- HttpServletResponse 类和 HttpServletRequest 类一样,Tomcat 服务器会为每次请求创建一个 Response 对象,将其传递给 Servlet 程序去使用。
- HttpServletRequest 表示请求的信息,HttpServletResponse 表示所有响应的信息。
- 如果需要设置返回给客户端的信息,都可以通过 HttpServletResponse 对象进行设置。
2、两个输出流
HttpServletResponse 返回给客户端的数据是怎么传输的呢?是通过“流”来传输的。
两个流在同一时间只能使用一种,否则会错误。
(1)字节流
使用 response.getOutputStream() 获取。常用于下载(传递二进制数据)。
(2)字符流
使用 response.getWriter() 获取。常用于回传字符串(常用)。
3、向客户端回传数据
(1)发送字符串数据
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter writer = resp.getWriter();
writer.write("there is response's content.");
}
}
4、浏览器显示响应中文乱码
(1)第一种方法:服务器和客户端浏览器的编码设置要一样,且需要支持中文。
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置服务器字符集为 UTF-8
resp.setCharacterEncoding("UTF-8");
// 通过响应头,设置浏览器也要使用 UTF-8
resp.setHeader("Content-Type", "text/html; charset=UTF-8");
PrintWriter writer = resp.getWriter();
writer.write("there is response's content.");
writer.write("这是响应内容。");
}
}
(2)第二种方法:setContentType()
public class ResponseIOServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html; charset=UTF-8");
// 它会同时设置服务器和客户端都使用 UTF-8 字符集,还设置响应头。
// 此方法一定要在获取 流对象 之前调用。
PrintWriter writer = resp.getWriter();
writer.write("there is response's content.");
writer.write("这是响应内容。");
}
}
5、请求重定向
请求重定向是指,客户端给服务器发送请求,然后服务器给客户端一个新的地址,要求客户端访问新地址。(通常因为旧地址已经被废弃,这个旧地址包括但不限于一些 Servlet 程序或资源)
(1)请求重定向第一种方法:
(1-1)编写两个 Servlet 程序,分别代表两个 Response
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置请求域数据
req.setAttribute("key", "value");
System.out.println("访问 Response1");
// 设置响应状态码 302,表示已搬迁
resp.setStatus(302);
// 设置响应头,说明新的地址在哪里
/*
注意这里是浏览器请求,地址需要写完整
不同于 Servlet 的请求转发,可以使用相对路径
*/
resp.setHeader("Location", "http://localhost:8080/JavaEnterprise_war_exploded/start_Response2");
}
}
public class Response2 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 获取请求域数据
resp.setContentType("text/html; charset=UTF-8");
System.out.println("请求域数据:" + req.getAttribute("key"));
resp.getWriter().write("这是 Response2 的响应数据");
}
}
(1-2)访问结果
(1-3)请求重定向的特点
- 浏览器地址会发生变化(请求转发的地址就不会改变)
- 有两次请求
- 不共享 Request域 中的数据(因为第二次产生的是一个新的 request 对象)
- 不能访问 WEB-INF 下的资源(因为第二次还是浏览器进行请求,而 WEB-INF 是不会被浏览器访问的)
- 可以访问 Web 工程外的资源
(2)请求重定向的第二种方法(推荐使用):
public class Response1 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("访问 Response1");
resp.sendRedirect("http://localhost:8080/JavaEnterprise_war_exploded/start_Response2");
}
}