一、基本介绍
1 官方文档
- 地址: https://tomcat.apache.org/tomcat-8.0-doc/servletapi/index.html
- Servlet 和 Tomcat 的关系: 一句话, Tomcat 支持 Servlet
- 【假如单独使用Servlet就失去了意义】
2 为什么会出现 Servlet
- 提出需求: 请用你现有的html css javascript,开发网站,比如可以让用户留言/购物/支付, 你能搞定吗?【不能,无法操作数据库】
- 引入我们动态网页(能和用户交互)技术 ===> Servlet
- 对Java Web 技术体系的流程图改造说明(细化).[整体的概念]
3 什么是 Servlet
- Servlet 在开发动态 WEB 工程中,得到广泛的应用,掌握好 Servlet 非常重要了, Servlet(基 石)是 SpringMVC 的基础
Servlet(java 服务器小程序),它的特点:
- 他是由服务器端调用和执行的(一句话:是Tomcat解析和执行)
- 他是用java语言编写的, 本质就是Java类
- 他是按照Servlet规范开发的(除了tomcat->Servlet weblogic->Servlet)
- 功能强大,可以完成几乎所有的网站功能(在以前,我们老程员,使用Servlet开发网站) 技术栈要求高
4 Servlet 在 JavaWeb 项目位置
二、Servlet 基本使用
1 Servlet 开发方式说明
- servlet3.0 前使用 web.xml , servlet3.0 版本以后(包括 3.0)支持注解, 同时支持 web.xml 配置
- 如何查看 servlet 版本[如图]
- 讲解 SpringBoot 时,我们用注解方式, 从 ssm , springboot 后面全部使用注解
- 这专门讲 servlet, 为让大家更清晰知道 servlet 使用原理, 老师用配置方式(说明,原生的 Servlet 在项目中使用很少)
- 不管使用哪种方式,本质都一样
2 快速入门- 手动开发 Servlet
2.1 需求说明
- 开发一个 HelloServlet
- 当浏览器 访问 http://localhost:8080/web 应用名/helloServlet 时,后台输出 "hi HelloServelt"
2.2 具体步骤
- 编写类HelloServlet去实现 Servlet 接口
- 实现 service 方法,处理请求,并响应数据
- 在 web.xml 中去配置 servlet 程序的访问地址
2.3 演示
- 创建hspedu_servlet JavaWeb工程,并配置好Tomcat
- 添加servlet-api.jar(在tomcat/lib下) 到工程, 因为servlet.jar 不是jdk自带的, 要引入
- 在src 下 包 com.hspedu.servlet.HelloServlet.java ,并实现Servlet接口
package com.hspedu.servlet;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/*
解读
1. 开发一个Servlet需要实现Servlet接口
2. 实现Servlet接口的方法
*/
public class HelloServlet implements Servlet {
/**
* 1. 初始化servlet
* 2. 当创建HelloServlet实例时,会调用init方法
* 3. 该方法只会被调用一次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
//System.out.println("init...~~~");
}
/**
* 返回
* @return ServletConfig 也就是返回Servlet的配置
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 1. service方法处理浏览器的请求(包括get/post)
* 2. 当浏览器每次请求servlet时,就会调用一次servlet
* 3. 当tomcat调用该方法时,会把http请求的数据封装成实现了ServletRequest的对象
* 4. 通过ServletRequest对象,可以得到用户提交的数据
* 5. ServletRequest对象可以用于返回数据给Tomcat->浏览器
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//System.out.println("HelloServlet 被访问" + servletRequest.getClass());
// 类型转换(因为它有 getMethod()方法)
HttpServletRequest httpServletRequest = (HttpServletRequest)
servletRequest;
// 获取请求的方式
String method = httpServletRequest.getMethod();
if ("GET".equals(method)) {
doGet();
} else if ("POST".equals(method)) {
doPost();
}
}
/**
* 处理浏览器 get 请求
*/
public void doGet() {
System.out.println("处理 get 请求");
}
/**
* 处理浏览器 post 请求
*/
public void doPost() {
System.out.println("处理 post 请求");
}
/**
* 返回servlet的信息
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 该方法在servlet被销毁时被调用
*/
@Override
public void destroy() {
System.out.println("destroy 被调用...");
}
}
- 在web.xml配置HelloServlet,即:给HelloServlet 提供对外访问地址
通过浏览器访问HelloServlet ,看是否正确(记住要redeploy[快] 或者 restart[慢])
3 浏览器调用 Servlet 流程分析
4 Servlet 生命周期
- 主要有三个方法
- 示意图
4.1 初始化阶段
Servlet
容器
(
比如
: Tomcat)
加载
Servlet
,加载完成后,
Servlet
容器会创建一个
Servlet
实例
并调用
init()
方法,
init()
方法只会调用一次
,
Servlet
容器在下面的情况装载
Servlet
:
4.2 处理浏览器请求阶段(service 方法)
4.3 终止阶段 destory 方法(体现 Servlet 完整的生命周期)
5 GET 和 POST 请求的分发处理
开发 Servlet, 通常编写 doGet、doPost 方法。来对表单的 get 和 post 请求进行分发处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<h1>注册用户</h1>
<form action="http://localhost:8080/servlet/helloServlet" method="post">
u: <input type="text" name="username"/><br><br>
<input type="submit" value="注册用户"/>
</form>
</body>
</html>
修改了helloservlet.java代码
package com.hspedu.servlet;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/*
解读
1. 开发一个Servlet需要实现Servlet接口
2. 实现Servlet接口的方法
*/
public class HelloServlet implements Servlet {
/**
* 1. 初始化servlet
* 2. 当创建HelloServlet实例时,会调用init方法
* 3. 该方法只会被调用一次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init...~~~");
}
/**
* 返回
* @return ServletConfig 也就是返回Servlet的配置
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 1. service方法处理浏览器的请求(包括get/post)
* 2. 当浏览器每次请求servlet时,就会调用一次servlet
* 3. 当tomcat调用该方法时,会把http请求的数据封装成实现了ServletRequest的对象
* 4. 通过ServletRequest对象,可以得到用户提交的数据
* 5. ServletRequest对象可以用于返回数据给Tomcat->浏览器
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
//System.out.println("HelloServlet 被访问" + servletRequest.getClass());
// 类型转换(因为它有 getMethod()方法)
//思考->从 servletRequest 对象来获取请求方式->
//1. ServletRequest 没有得到提交方式的方法
//2. ServletRequest 看看 ServletRequest 子接口有没有相关方法
//3. 小技巧:ctrl+alt+b => 可以看到接口的子接口和实现子类
//4. 把 servletReqeust 转成 HttpServletRequest 引用
//5. 仍然是 Java 基础的 OOP
HttpServletRequest httpServletRequest = (HttpServletRequest)
servletRequest;
// 获取请求的方式
String method = httpServletRequest.getMethod();
if ("GET".equals(method)) {
doGet();
} else if ("POST".equals(method)) {
doPost();
}
}
/**
* 处理浏览器 get 请求
*/
public void doGet() {
System.out.println("处理 get 请求");
}
/**
* 处理浏览器 post 请求
*/
public void doPost() {
System.out.println("处理 post 请求");
}
/**
* 返回servlet的信息
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 该方法在servlet被销毁时被调用
*/
@Override
public void destroy() {
System.out.println("destroy 被调用...");
}
}
6 通过继承 HttpServlet 开发 Servlet
- 在实际项目中,都是使用继承 HttpServlet 类开发 Servlet 程序,更加方便
- 通过继承 HttpServlet 开发一个 HiServlet
- 当浏览器 访问 http://localhost:8080/web 应用名/hiServlet 时,后台输出 "hi HiServelt"
具体的开发步骤
编写HiServlet类
package com.hspedu.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HiServlet extends HttpServlet {
//重写httpServlet的doGet和doPost方法
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HiServlet doGet()...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("HiServlet doPost()...");
}
}
配置web,xml
7 IDEA 开发 Servlet 程序
- 编手动开发 Servlet 需要程序员自己配置 Servlet ,比较麻烦,在工作中,直接使用 IDEA 开 发 Servlet 会更加方便
- 应用实例
8 Servlet 注意事项和细节
- Servlet 是一个供其他 Java 程序(Servlet 引擎)调用的 Java 类,不能独立运行
- 针对浏览器的多次 Servlet 请求,通常情况下,服务器只会创建一个 Servlet 实例对象, 也就是说 Servlet 实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至 web 容器退出/或者 redeploy 该 web 应用,servlet 实例对象才会销毁 【示意图】
- 在 Servlet 的整个生命周期内,init 方法只被调用一次。而对每次请求都导致 Servlet 引 擎调用一次 servlet 的 service 方法。
- 对于每次访问请求,Servlet 引擎都会创建一个新的 HttpServletRequest 请求对象和一个新的 HttpServletResponse 响应对象,然后将这两个对象作为参数传递给它调用的 Servlet的service()方法,service 方法再根据请求方式分别调用 doXXX 方法
- 如果在<servlet>元素中配置了一个<load-on-startup>元素,那么 WEB 应用程序在启动时, 就会装载并创建 Servlet 的实例对象、以及调用 Servlet 实例对象的 init()方法, 老师聊聊(定 时发送邮件的服务/自动启动->完成任务)
三、Servlet - 注解方式
1 快速入门
- 编写类OkServlet去继承HttpServlet
- 注解方式配置OkServlet, 一个Servlet支持配置多个urlPattern
package com.hspedu.servlet.annotation;
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;
/**
* 注解方式来配置
* 1.@WebServlet 是一个注解=》java基础
* 2.@WebServlet源码
* @Target({ElementType.TYPE})
* @Retention(RetentionPolicy.RUNTIME)
* @Documented =》
* public @interface WebServlet {
* String name() default "";
*
* String[] value() default {};
*
* String[] urlPatterns() default {};
*
* int loadOnStartup() default -1;
*
* WebInitParam[] initParams() default {};
*
* boolean asyncSupported() default false;
*
* String smallIcon() default "";
*
* String largeIcon() default "";
*
* String description() default "";
*
* String displayName() default "";
* 3. urlPatterns对应web,xml的<url-pattern></url-pattern>
* 4. {"/ok1","/ok2"}可以给OkServlet配置多个url-pattern
* 5. 相当于这个@WebServlet(urlPatterns = {"/ok1","/ok2"})代替了web.xml的配置
* 6。浏览器可以这样访问OKServlet时,可以http://localhost:8080/servlet/ok1或者
* http://localhost:8080/servlet/ok1
* }
*/
@WebServlet(urlPatterns = {"/ok1","/ok2"})
public class OkServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解方式 OKServlet doGet()");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解方式 OKServlet doPost()");
}
}
2 Servlet urlPattern 配置
2.1 精确匹配
2.2 目录匹配
2.3 扩展名匹配
2.4 任意匹配
2.5 注意事项和使用细节
- 当 Servlet 配置了 "/", 会覆盖 tomcat 的 DefaultServlet, 当其他的 utl-pattern 都匹配 不 上 时 , 都 会 走 这 个 Servlet, 这 样 可 以 拦 截 到 其 它 静 态 资 源 , 比 如D:\hspedu_javaweb_temp\hspedu_servlet\web\hi.html [举例]
- 当 Servelt 配置了 "/*", 表示可以匹配任意访问路径
- 提示: 建议不要使用 / 和 /* , 建议尽量使用精确匹配
- 优先级遵守: 精确路径 > 目录路径 > 扩展名路径 > /* > /
四、WEB 开发通信协议-HTTP 协议
1.什么是 HTTP 协议
- 超文本传输协议(HTTP,HyperText Transfer Protocol)是互联网上应用广泛的一种网络协议。 是工作在 tcp/ip 协议基础上的,所有的 WWW 文件都遵守这个标准
- http1.0 短连接 http1.1 长连接
- http 是 TCP/IP 协议的一个应用层协议,http 也是我们 web 开发的基础
2 快速入门 HTTP 协议
http 请求 hi.html 的 UML 时序图
3 页面请求的一个问题(分析)
- 创建 D:\idea_java_projects\hspedu_servlet\web\http\test.html 页面
- 当访问 test.html 页面时, 问浏览器发出几次 http 请求?
答:一共 3 次
4 HTTP 请求包分析(GET)
4.1案例说明
- 创建 D:\idea_java_projects\hspedu_servlet\web\http\login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户登录</title>
</head>
<body>
<!--给我们的LoginServlet发出Get请求,提交表单-->
<h1>用户登录</h1>
<form action="http://localhost:8080/http/loginServlet" method="get">
u: <input type="text" name="username"/><br/>
p: <input type="password" name="pwd"/><br/>
<input type="submit" value="用户登录"> <input type="reset" value="清空">
</form>
</body>
</html>
- 创 建 D:\hspedu_javaweb_temp\hspedu_servlet\src\com\hspedu\http\LoginServlet.java
- 并完成配置【添加web框架,导包,配置Tomcat,设置web.xml】
package com.hspedu.http.servlet;
import javax.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
//输出一句话,返回给浏览器
//1 通过response获取流程
//2 为了让浏览器显示中文,需要告诉浏览器编码是utf-8
//(1) 回送数据设置编码 (2)text/html这个是MIME告诉浏览器返回的数据
//是text类型下的html格式数据【MIME类型 大类型/小类型】(3)charset=utf-8数据编码
//小小细节:编码设置一定要在得到流-response.getWriter()之前
response.setContentType("text/html;charset=utf-8");
PrintWriter writer=response.getWriter();
writer.print("<h1>登录成功</h1>");
//为了确保数据返回,可以把flush()和close()
//程序员有强迫症,flush方法表示为了将缓存的数据进行刷新
writer.flush();
//close表示为了及时释放资源
writer.close();
}
}
4.2 抓包测试分析
5 HTTP 请求包分析(POST)
5.1 HTTP POST 请求方式案例
- 修改 login.html, 将提交方式改成 post
- 修改 D:\idea_java_projects\hspedu_servlet\src\com\hspedu\http\LoginServlet.java
5.2 完成测试, HTTP 请求包分析(POST)图
说明
: %E9%9F%A9%E9%A1%BA%E5%B9%B3
是
url
编码
,
在服务端会自动解码
.
测
试一把
http://tool.chinaz.com/tools/urlencode.aspx
6 GET 请求 POST 请求分别有哪些?
6.1 GET 请求有哪些
6.2 POST 请求有哪些
form 标签 method=post
6.3 HTTP 请求中怎样选择 Get 和 Post 方式
在大部分情况下,我们不需要考虑这个问题,因为业务本身就会自动区别,
比如你要显示图片,引入
css/js
这个天然的就是
get
请求,比如你登录,发帖,上传文
件, 你就会使用
post(
感情的自然流露
)
7 HTTP 响应包分析
7.1 HTTP 响应包括 3 个部分
7.2 HTTP 响应包分析图
8 常用的状态码说明
8.1 302 状态码使用
新建一个servlet
package com.hspedu.http.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class T1 extends HttpServlet {
//这里我们把doPost和doGet进行合并处理
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//如果有一个请求来,重定向到hi.html
//(1)返回302状态码 (2)响应头Location:/hi.html
response.sendRedirect("/http/hi.html");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
测试抓包
8.2 304 状态码
9 MIME 类型
9.1 MIME 介绍
MIME 是
HTTP
协议中数据类型。
MIME
的英文全称是
"Multipurpose Internet Mail
Extensions"
多功能
Internet
邮件扩充服务。
MIME
类型的格式是
"
大类型/小类型
"
,
并与某一种文件的扩展名相对应
在响应包的Content-Type
就有指定
,
如图
9.2 常见的 MIME 类型
五、ServletConfig
1 ServletConfig 基本介绍
- ServletConfig 类是为 Servlet 程序的配置信息的类
- Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建
- Servlet 程序默认是第 1 次访问的时候创建,ServletConfig 在 Servlet 程序创建时,就创建一个对应的 ServletConfig 对象
2 ServletConfig 类能干什么
- 获取 Servlet 程序的 servlet-name 的值
- 获取初始化参数 init-param
- 获取 ServletContext 对象
3 ServletConfig 应用实例
3.1 需求
3.2 示意图
3.3 代码实现
DBServlet.java
package com.hspedu.servlet;
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;
public class DBServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//合二为一
//获取web.xml的用户名跟密码
//DBServlet的父类GenericServlet有getServletConfig()
ServletConfig servletConfig = getServletConfig();
String username = servletConfig.getInitParameter("username");
String pwd = servletConfig.getInitParameter("pwd");
System.out.println("初始化参数username: "+username);
System.out.println("初始化参数pwd: "+pwd);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
配置web.xml
六、ServletContext
1 为什么需要 ServletContext
- 先看一个需求: 如果我们希望统计某个 web 应用的所有 Servlet 被访问的次数,怎么办?
- 方案 1-DB
- 方案 2-ServletContext
2 ServletContext 基本介绍
- ServletContext 是一个接口,它表示 Servlet 上下文对象
- 一个 web 工程,只有一个 ServletContext 对象实例
- ServletContext 对象 是在 web 工程启动的时候创建,在 web 工程停止的时销毁
- ServletContext 对象可以通过 ServletConfig.getServletContext 方法获得对 ServletContext 对象的引用,也可以通过 this.getServletContext()来获得其对象的引用。
- 由于一个 WEB 应用中的所有 Servlet 共享同一个 ServletContext 对象,因此 Servlet 对象之间可以通过 ServletContext 对象来实现多个 Servlet 间通讯。ServletContext 对象通常也被称之为域对象。【示意图】
3 ServletContext 可以做什么
- 获取 web.xml 中配置的上下文参数 context-param [信息和整个 web 应用相关,而不是属于某个 Servlet]
- 获取当前的工程路径,格式: /工程路径 =》 比如 /servlet
- 获 取 工 程 部 署 后 在 服 务 器 硬 盘 上 的 绝 对 路 径 ( 比如:D:\hspedu_javaweb\servlet\out\artifacts\servlet_war_exploded)
- 像 Map 一样存取数据, 多个 Servlet 共享数据
4 应用实例 1
4.1 需求
- 获取 web.xml 中配置的上下文参数 context-param
- 获取当前的工程路径,格式: /工程路径
- 获取工程部署后在服务器硬盘上的绝对路径
4.2 代码实现
新建servlet
package com.hspedu.servlet.servletcontext;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class ServletContext_ extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//获取web.xml的context-parameter
//1.获取到ServletContext对象
ServletContext servletContext = getServletContext();
//2.获取参数
String website = servletContext.getInitParameter("website");
String company = servletContext.getInitParameter("company");
System.out.println("website="+website);
System.out.println("company"+company);
//获取工程路径
String contextPath = servletContext.getContextPath();
System.out.println("工程路径="+contextPath);
//获取项目发布后真正的工作路径
// /表示我们的项目发布后的根路径
String realPath = servletContext.getRealPath("/");
System.out.println("真正工作路径="+realPath);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
配置web.xml
5 应用实例 2
5.1 需求
- 完成一个简单的网站访问次数计数器:
- 使用 Chrome 访问 Servlet01, 每访问一次,就增加 1 访问次数,在后台输出,并将结果返回给浏览器显示
- 使用火狐访问 Servlet02,每访问一次,就增加 1 访问次数,在后台输出,并将结果返回给浏览器显示
5.2 代码实现
新建两个servlet
package com.hspedu.servlet.servletcontext;
import javax.servlet.ServletContext;
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 OrderServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//先获取到ServletContext对象
ServletContext servletContext = getServletContext();
System.out.println("OrderServlet servletContext= "+servletContext +" 运行类型 "+servletContext.getClass());
//从servletContext获取visit_count属性 k-v
Object visit_count = servletContext.getAttribute("visit_count");
//判断visit_count是否为空
if(visit_count==null){
servletContext.setAttribute("visit_count",1);
visit_count=1;
}else {
//取出visit_count属性的值+1
visit_count= Integer.parseInt(visit_count+"") +1;
//放回servletContext
servletContext.setAttribute("visit_count",visit_count);
}
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("<h1>网站访问的次数是 "+visit_count +"</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
package com.hspedu.servlet.servletcontext;
import javax.servlet.ServletContext;
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 PayServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//先获取到ServletContext对象
ServletContext servletContext = getServletContext();
System.out.println("PayServlet servletContext= "+servletContext +" 运行类型 "+servletContext.getClass());
//从servletContext获取visit_count属性 k-v
Object visit_count = servletContext.getAttribute("visit_count");
//判断visit_count是否为空
if(visit_count==null){
servletContext.setAttribute("visit_count",1);
visit_count=1;
}else {
//取出visit_count属性的值+1
visit_count= Integer.parseInt(visit_count+"") +1;
//放回servletContext
servletContext.setAttribute("visit_count",visit_count);
}
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("<h1>网站访问的次数是 "+visit_count +"</h1>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
配置web.xml
七、HttpServletRequest
1 HttpServletRequest 介绍
- HttpServletRequest 对象代表客户端的请求
- 当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中
- 通过这个对象的方法,可以获得客户端这些信息
2 HttpServletRequest 类图
3 HttpServletRequest 常用方法
4 HttpServletRequest 应用实例
4.1 需求
- 说明: 在一个表单提交数据给 Servlet , 然后在 Servlet 通过 HttpServletRequest对象获取相关数据
4.2 代码实现
创建 D:\idea_java_projects\hspedu_servlet\web\register_request.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册</title>
</head>
<body>
<h1>注册用户</h1>
<form action="http://localhost:8080/servlet/requestMethods" method="post">
u: <input type="text" name="username"/><br><br>
p: <input type="password" name="pwd"/><br><br>
选择你喜欢的老师:
<input type="checkbox" name="hobby" value="hsp">韩顺平
<input type="checkbox" name="hobby" value="lh">老韩
<input type="checkbox" name="hobby" value="spls">顺平老师<br/><br/>
<input type="submit" value="注册用户"/>
</form>
</body>
</html>
创建servlet
package com.hspedu.servlet.httpservletrequest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class HttpServletRequestMethods extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//使用request对象获取相关数据
System.out.println("HttpServletRequestMethods doPost被调用");
/***********************************
* 获取和 http 请求头相关信息
***********************************/
System.out.println("请求的资源路径 URI= " + request.getRequestURI());
//http://主机/uri
System.out.println(" 请 求 的 统 一 资 源 定 位 符 ( 绝 对 路 径 ) URL= " +
request.getRequestURL());
System.out.println("请求的客户端 ip 地址= " + request.getRemoteAddr());//本地就是 127.0.01
//思考题:如发现某个 ip 在 10s 中,访问的次数超过 100 次,就封 ip
//实现思路:1 用一个集合 concurrentHashmap[ip:访问次数] 2[线程/定时扫描]3 做成处理
// 获取 http 请求头的信息,可以指定其他,比如 User-Agent , Host 等待 就举一个例子
System.out.println("http 请求头 HOST= " + request.getHeader("Host"));
// 说 明 , 如 果 我 们 希 望 得 到 请 求 的 头 的 相 关 信 息 , 可 以 使 用
request.getHeader("请求头字段");
System.out.println("该请求的发起地址是= " + request.getHeader("Referer"));
// 请获取访问网站的浏览器是什么?
String userAgent = request.getHeader("User-Agent");
System.out.println("User-Agent= " + userAgent);
// 取出 FireFox, 取出最后
String[] s = userAgent.split(" ");
System.out.println("浏览器=" + s[s.length - 1].split("\\/")[0]);
//课堂练习: 要求同学们取出 Windows NT 10.0 和 Win64
// 主要是 Get / Post
System.out.println("http 请求方式~= " + request.getMethod());
/***********************************
* 获取和请求参数相关信息, 注意要求在返回数据前,获取参数
***********************************/
//1. 获取表单的数据[单个数据]
//username=tom&pwd=&hobby=hsp&hobby=spls
String username = request.getParameter("username");
String pwd = request.getParameter("pwd");
//2. 获取表单一组数据
String[] hobbies = request.getParameterValues("hobby");
System.out.println("username= " + username);
System.out.println("pwd= " + pwd);
//增强 for 循环的快捷键 iter->回车即可 , 能使用快捷键,就使用快捷键
for (String hobby : hobbies) {
System.out.println("hobby=" + hobby);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
配置web.xml
5 HttpServletRequest 注意事项和细节
- 获 取 doPost 参 数 中 文 乱 码 解 决 方 案 , 注 意 setCharacterEncoding("utf-8") 要 写 在 request.getParameter()前
- 注意:如果通过 PrintWriter writer, 有返回数据给浏览器,建议将获取参数代码写在 writer.print() 之前,否则可能获取不到参数值(doPost)
- 处理 http 响应数据中文乱码问题
八、请求转发
1 为什么需要请求转发
- 目前我们学习的都是一次请求,对应一个 Servlet, 如图
- 但是在实际开发中,往往业务比较复杂,需要在一次请求中,使用到多个 Servlet 完成一个任务(Servlet 链, 流水作业) 如图:
2 请求转发说明
- 实现请求转发:请求转发指一个 web 资源收到客户端请求后,通知服务器去调用另外 一个 web 资源进行处理
- HttpServletRequest 对象(也叫 Request 对象)提供了一个 getRequestDispatcher 方法,该 方法返回一个 RequestDispatcher 对象,调用这个对象的 forward 方法可以实现请求转发
- request 对象同时也是一个域对象,开发人员通过 request 对象在实现转发时,把数据 通过 request 对象带给其它 web 资源处理
3 实现请求转发
4 请求转发应用实例
4.1 需求说明
如果是 tom,提示为管理员,其它是普通用户
4.2 代码实现
4.2.1 登陆页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<form action="http://localhost:8080/servlet/checkServlet" method="post">
u: <input type="text" name="username"><br>
<input type="submit" value="登录">
</form>
</body>
</html>
4.2.2 创建servlet
package com.hspedu.servlet.request;
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;
public class CheckServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("CheckServlet 被调用 ----");
//根据用户来确定该用户是什么身份
String username = request.getParameter("username");
//注意,如果是同一个request对象(请求转发),那么可以在不同的servlet使用getParameter
if("tom".equals(username)){
//分配
request.setAttribute("role","管理员");
}else {
request.setAttribute("role","普通用户");
}
//获取分发器
//解读 1. /manageServlet 写的是 要转发的 servlet 的 url
// 2. / 会被解析成 /servlet
// 3. forward(request, response) 表示把当前 servlet 的 request 对象和response 对象,传递给下一个 servlet 使用
RequestDispatcher requestDispatcher = request.getRequestDispatcher("/manageServlet");
requestDispatcher.forward(request,response);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
package com.hspedu.servlet.request;
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 ManageServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ManageServlet 被调用 ----");
String username = request.getParameter("username");
String role = (String) request.getAttribute("role");
response.setContentType("text/html;charset=utf-8");
PrintWriter writer = response.getWriter();
writer.print("用户名:"+username+"<br/>");
writer.print("角色:"+role+"<br/>");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
4.2.3 配置web.xml
九、HttpServletResponse
1 HttpServletResponse 介绍
- 每次 HTTP 请求,Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 程序去使用。
- HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息, 如果需要设置返回给客户端的信息,通过 HttpServletResponse 对象来进行设置即可
2 HttpServletResponse 类图
3 向客户端返回数据方法
- 字节流 getOutputStream(); 常用于下载(处理二进制数据)
- 字符流 getWriter(); 常用于回传字符串
- (细节:)两个流同时只能使用一个。 使用了字节流,就不能再使用字符流,反之亦然,否则就会报错
4 向客户端返回数据注意事项和细节
处理中文乱码问题-方案 1
处理中文乱码问题-方案 2
十、请求重定向
1 请求重定向介绍
- 请求重定向指:一个 web 资源收到客户端请求后,通知客户端去访问另外一个 web资源,这称之为请求重定向
- 请求重定向原理示意图
2 请求重定向应用实例
2.1 需求
- 演 示 请 求 重 定 向 的 使 用 当 访 问 DownServlet 下 载 文 件 , 重 定 向 到 DownServletNew 下载文件
2.2 实现
创建html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>下载文件</title>
</head>
<body>
<h1>下载文件</h1>
<a href="http://localhost:8080/servlet/downServlet">下载天龙八部</a>
</body>
</html>
创建servlet
package com.hspedu.servlet.response;
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 DownServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// System.out.println("DownServlet 被调用");
// //编码
// response.setContentType("application/x-tar;charset=utf-8");
// PrintWriter writer=response.getWriter();
// writer.print("ok");
// writer.flush();
// writer.close();
//1. 因为请求重定向 是将请求返回给 Location: /downServletNew
//2. 所以浏览器来解析 /downServletNew, 而不是服务端解析
//3. 会以当前浏览器的地址栏的 主机+/downServletNew 也就是http://localhost:8080
response.sendRedirect("/servlet/downServletNew");
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
package com.hspedu.servlet.response;
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 DownServletNew extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("DownServletNew 被调用");
//编码
response.setContentType("application/x-tar;charset=utf-8");
PrintWriter writer=response.getWriter();
writer.print("ok");
writer.flush();
writer.close();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
记得配置web.xml哦
3 请求重定向注意事项和细节
- 最佳应用场景:网站迁移,比如原域名是 www.hsp.com 迁移到 www.hsp.cn ,但是百度抓取的还是原来网址.
- 浏览器地址会发生变化,本质是两次 http 请求.
- 不能共享 Request 域中的数据,本质是两次 http 请求,会生成两个 HttpServletRequest 对象
- 不能重定向到 /WEB-INF 下的资源
- 可以重定向到 Web 工程以外的资源, 比如 到 www.baidu.com 【在前面的案例演示】
- 重定向有两种方式, 推荐使用第 1 种.
- 动态获取到 application context