一、技术体系的流程图
二、Servlet(java 服务器小程序)概念
servlet是Server Applet的简称,翻译过来就是服务程序.好吧,这么说你可能还是不太懂,简单的讲,这个servlet是运行在服务器上的一个小程序,用来处理服务器请求的.进一步讲,我们知道,一般的网页程序,是由我们通过浏览器访问来实现的,在这个过程中,我们的浏览器发送访问请求,服务器接收请求,并对浏览器的请求作出相应的处理.这就是我们熟悉的B/S模型(浏览器-服务器模型).而servlet就是对请求作出处理的组件,运行于支持Java的应用服务器中
总结特点:
- 他是由服务器端调用和执行的(一句话:是Tomcat解析和执行)
- 他是用java语言编写的, 本质就是Java类
- 他是按照Servlet规范开发的(除了tomcat->Servlet weblogic->Servlet)
- 功能强大,可以完成几乎所有的网站功能(在以前,我们老程员,使用Servlet开发网站) 技术栈要求高
三、Servlet 基本使用
3.1 Servlet 开发方式说明
- servlet3.0 前使用 web.xml , servlet3.0 版本以后(包括 3.0)支持注解, 同时支持 web.xml配置
- ssm , springboot 后面全部使用注解,原生的Servlet 在项目中使用很少
- 不管使用哪种方式,本质都一样
3.2手动开发 Servlet
- 导入servlet-api.jar jar包(jar包在安装tomcat目录lib目录下)直接复制到idea目录下,一般在WEB-INF下建一个lib目录,放这里面
- 直接添加
- 在src 下 包 com.hspedu.servlet.HelloServlet.java ,并实现Servlet接口
package com.mzq.servlet_;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author MengZhiQiang
* @version 1.0
* @date 2022/3/30 18:27
* 1. 开发一个Servlet 需要 实现Servlet接口
* 2. 实现Servlet接口的方法5个
*/
public class HelloServlet implements Servlet {
private int count = 0; //属性
/**
* 1.初始化 servlet
* 2.当创建HelloServlet 实例时,会调用init方法
* 3. 该方法只会被调用一次
* @param servletConfig
* @throws ServletException
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init() 被调用");
}
/**
* 返回ServletConfig 也就是返回Servlet的配置
* @return
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* 1. service方法处理浏览器的请求(包括get/post)
* 2. 当浏览器每次请求Servlet时,就会调用一次service
* 3. 当tomcat调用该方法时,会把http请求的数据封装成实现ServletRequest接口的request对象
* 4. 通过servletRequest 对象,可以得到用户提交的数据
* 5. servletResponse 对象可以用于返回数据给tomcat->浏览器
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
count++;
//如果count的值,在不停的累计,说明HelloServlet是单例的
System.out.println("hi HelloServlet~ count= " + count);
//Tomcat每处理一次http请求,就生成一个新的线程
System.out.println("当前线程id= " + Thread.currentThread().getId());
//思考->从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(); //用doGet() 处理GET请求
} else if("POST".equals(method)) {
doPost(); //用doPost() 处理POST请求
}
}
/**
* 用于响应get请求的
*/
public void doGet() {
System.out.println("doGet() 被调用..");
}
/**
* 用于响应post请求的
*/
public void doPost() {
System.out.println("doPost() 被调用..");
}
/**
* 返回servlet信息,使用较少
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 1. 该方法是在servlet销毁时,被调用
* 2. 只会调用一次
*/
@Override
public void destroy() {
}
}
- 在 web.xml 中去配置 servlet 程序的访问地址
<!--1. servlet-name: 给Servlet取名(程序员决定), 该名字唯一-->
<!--2. servlet-class: Servlet的类的全路径: Tomcat在反射生成该Servlet需要使用-->
<!--3. url-pattern: 这个就是该servlet访问的url的配置(路径)-->
<!--4. 这时我们应该这样访问servlet http://localhost:8080/servlet/helloServlet-->
<!--5. url-pattern 取名是程序员决定的-->
<!--6. load-on-startup 表示在tomcat 启动时,会自动的加载servlet实例-->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.mzq.servlet_.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/helloServlet</url-pattern>
</servlet-mapping>
- 浏览器访问localhost:8080/helloServlet
四、浏览器调用 Servlet 流程分析
五、Servlet 生命周期
5.1 主要有三个方法
- init()初始化阶段
- service()处理浏览器请求阶段
- destroy()终止阶段
-
初始化阶段
Servlet容器会加载Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例并调用 init()方法,init()方法只会调用一次,,
-
处理浏览器请求阶段(service 方法)
每收到一个 http 请求,服务器就会产生一个新的线程去处理[线程]即:service方法,是进行数据处理的,只要接受了一次请求,就会被调用一次
-
终止阶段 destory 方法(体现 Servlet 完整的生命周期)
当 web 应用被终止,或者 Servlet 容器终止运行,或者 Servlet 类重新装载时,会调用 destroy()方法比如重启 tomcat ,或者 redeploy web 应用
一般来讲,servlet只会初始化一次,也就是整个过程中只存在一个servlet对象,即便是有多次访问,依然只有一个对象,这个对象是可以复用的.所谓的生命周期就是浏览器访问时,会先到xml文件找到映射路径,查看是否存在Servlet实例,不存在 Servlet 实例时创建实例并调用 init()方法,调用service方法处理浏览器请求,第二次请求时直接调用service方法,服务器关闭,调用 destory 方法,web 应用被终止.
六、通过继承 HttpServlet 开发 Servlet
在实际项目中,都是使用继承 HttpServlet 类开发 Servlet 程序,更加方便
继承图:
-
编写一个类去继承 HttpServlet 类
-
根据业务需要重写 doGet 或 doPost 方法
public class HiServlet extends HttpServlet { //重写HttpServlet的doGet 和 doPost //alt +insert /** * 处理doGet请求 * @param req * @param resp * @throws ServletException * @throws IOException */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("HiServlet doGet()..."); } /** * 处理doPost * @param req * @param resp * @throws ServletException * @throws IOException */ @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("HiServlet doPost()..."); } }
-
到 web.xml 中的配置 Servlet 程序
<servlet> <servlet-name>HiServlet</servlet-name> <servlet-class>com.mzq.servlet_.HiServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>HiServlet/servlet-name> <url-pattern>/hiServlet</url-pattern> </servlet-mapping>
-
测试
七、IDEA 开发 Servlet 程序
-
直接创建
其余过程和上面 通过继承 HttpServlet 开发 Servlet一样
八、Servlet 注意事项和细节
-
Servlet 是一个供其他 Java 程序(Servlet 引擎)调用的 Java 类,不能独立运行
-
针对浏览器的多次 Servlet 请求,通常情况下,服务器只会创建一个 Servlet 实例对象,也就是说 Servlet 实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web 容器退出/或者 redeploy 该 web 应用,servlet 实例对象才会销毁 【示意图】
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8L72xKX8-1648651400735)(\img\08.png)]
-
在 Servlet 的整个生命周期内,init 方法只被调用一次。而对每次请求都导致 Servlet 引擎调用一次 servlet 的 service 方法。
-
对于每次访问请求,Servlet 引擎都会创建一个新的 HttpServletRequest 请求对象和一个新的 HttpServletResponse 响应对象,然后将这两个对象作为参数传递给它调用的 Servlet的 service()方法,service 方法再根据请求方式分别调用 doXXX 方法
-
如果在<servlet>元素中配置了一个<load-on-startup>元素,那么 WEB 应用程序在启动时,就会装载并创建 Servlet 的实例对象、以及调用 Servlet 实例对象的 init()方法, 例如(定时发送邮件的服务/自动启动->完成任务)
九、 Servlet - 注解方式
- 编写类OkServlet去继承HttpServlet
- 注解方式配置OkServlet, 一个Servlet支持配置多个urlPattern
/**
* 解读
* 1. @WebServlet 是一个注解 => java基础->注解
* 2. @WebServlet 源码
* @Target({ElementType.TYPE})
* @Retention(RetentionPolicy.RUNTIME)
* @Documented => 在javadoc工具生成文档有记录
* 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 "";
* }
* 3. urlPatterns 对应 web.xml 的 <url-pattern></url-pattern>
* 4. {"/ok1", "/ok2"} 可以给OkServlet配置多个 url-pattern
* 5. 相当于这个@WebServlet(urlPatterns = {"/ok1", "/ok2"}) 代替了 web.xml的配置
* 底层使用了 反射+注解+IO+集合 来完成一个支撑
* 6. 浏览器可以这样访问OkServlet时,可以 http://localhost:8080/servlet/ok1 或者
* http://localhost:8080/servlet/ok2
* 7. 同学们有很多小问号? 解密. => 一会老师再说.
* 8. 我们可以根据 @interface WebServlet 源码知道可以配置哪些
* web.xml init-param 在注解中,如何指定呢? 老师看了源码,老师搞定
* <init-param>
* <param-name></param-name>
* <param-value></param-value>
* </init-param>
* 9. 注解方式开发Servlet和 web.xml配置servlet 流程机制是一样
* 10. /ok1/aa /ok1/bb /ok1/cc /ok1/aa/bb/cc /ok2
* 11. *.action 这时 zs.action ls.action
* 12. http://localhost:8080/servlet/register.html
*/
@WebServlet(urlPatterns = {"/ok1/aa"})
public class OkServlet extends HttpServlet {
@Override
public void init(ServletConfig config) throws ServletException {
System.out.println("注解方式 OkServlet init()被调用");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解方式 OkServlet doPost()");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解方式 OkServlet doGet()");
System.out.println(req.getRemoteAddr());
}
}
9.1Servlet urlPattern 配置
-
精确匹配:
- 配置路径 : @WebServlet(“/ok/zs”)
- 访问 servlet: localhost:8080/servlet/ok/zs
-
目录匹配:
- 配置路径 : @WebServlet(“/ok/*”)
- 访问文件: localhost:8080/servlet/ok/aaa或localhost:8080/servlet/ok/bbb
-
扩展名匹配:
- 配置路径 : @WebServlet(“*.action”)
- 访问文件: localhost:8080/hsp/zs.action或localhost:8080/hsp/ls.action
-
任意匹配:
- 配置路径 : @WebServlet(“/”) @WebServlet(“/*”)
- 访问文件: localhost:8080/hsp/aaa localhost:8080/hsp/bbb localhost:8080/hsp/ccc
9.2注意事项和使用细节
- 当 Servlet 配置了 “/”, 会覆盖 tomcat 的 DefaultServlet, 当其他的 utl-pattern 都匹配不 上 时 , 都 会 走 这 个 Servlet,这 样 可 以 拦 截 到 其 它 静 态 资 源
- 当 Servelt 配置了 “/*”, 表示可以匹配任意访问路径
- 建议不要使用 / 和 /*, 建议尽量使用精确匹配
- 优先级遵守: 精确路径 > 目录路径 > 扩展名路径 > /* > /
bb localhost:8080/hsp/ccc
9.2注意事项和使用细节
- 当 Servlet 配置了 “/”, 会覆盖 tomcat 的 DefaultServlet, 当其他的 utl-pattern 都匹配不 上 时 , 都 会 走 这 个 Servlet,这 样 可 以 拦 截 到 其 它 静 态 资 源
- 当 Servelt 配置了 “/*”, 表示可以匹配任意访问路径
- 建议不要使用 / 和 /*, 建议尽量使用精确匹配
- 优先级遵守: 精确路径 > 目录路径 > 扩展名路径 > /* > /