Servlet
什么是servlet
Servlet在开发动态WEB工程中,得到广泛的应用,掌握好Servlet非常重要了,Servlet(基石)是SpringMVC的基础
servlet(java 服务器小程序),它的特点:
- 他是由服务器端调用和执行的(一句话:是Tomcat解析和执行)
- 他是用java语言编写的,本质就是Java类
- 他是按照Servlet规范开发的(除了tomcat->Servlet weblogic->Servlet)
- 功能强大,可以完成几乎所有的网站功能Ⅰ
Servlet开发方式说明
servlet3.0前使用web.xml , servlet3.0版本以后(包括3.0)支持注解,同时支持web.xml配置
Servlet在JavaWeb项目中位置
当浏览器请求的是动态资源时(数据库中的数据),tomcat就会访问servlet,servlet会调用Java程序,去将数据库中的数据取出
当浏览器请求的是静态资源时,tomcat就会静态资源直接返回给浏览器
tomcat有两个作用
- 作为servlet的容器
- 充当Web服务
浏览器调用Servlet流程分析
浏览器将HTTP请求(http://localhost:8080/servlet/HelloServlet)
发送给Tomcat,Tomcat得到HTTP请求
如果是第一次请求(Tomcat):
- tomcat会去查询web.xml(已解析出要访问的web应用:servlet)
- 看看请求的资源 /HelloServlet,在web.xml 中 url-pattern 是否配置
- 如果找到url-pattern,,就会得到servlet-name:HelloServlet(底层有个HashMap<url-pattern,servletName>)
- tomcat中维护了一个大的HashMap<servletName,Servlet>,利用servlet-name,查询该HashMap,看看有没有这个Servlet实例
- 如果没有查询到该Serletname 对应的 servlet
- 就根据servlet-name 去得到serlvet-class:类的全路径(在web.xml文件中,这两个是配置在
<servlet></servlet>
中) - 使用反射技术,将servlet实例化 -> 执行init()方法 -> 执行service()方法,并放入到tomcat维护的HashMap<servletName,Servlet>
如果是第二次(以后)请求(Tomcat)
- 查询web.xml
- 看看请求的资源/helloServlet,在web.xml配置url-pattern
- 如果找到url-pattern.就会得到servlet-name:HelloServlet
- tomcat中维护了一个大的HashMap<servletName,Servlet>,利用servlet-name,查询该HashMap,看看有没有这个Servlet实例
- 如果查询到,就直接调用该Servlet的service
- 结果显示
Servlet生命周期
初始化阶段
Servlet容器(比如: Tomcat)加载Servlet,加载完成后,Servlet容器会创建一个Servlet实例并调用init()方法,init()方法只会调用一次,Servlet容器在下面的情况装载Servlet:
- Servlet容器(Tomcat)启动时自动装载某些servlet,实现这个需要在web.xml文件中添加
<load-on-startup>1<load-on-startup>
1表示装载的顺序web.xml中会配置很多Servlet,可以设置装载顺序(tomcat启动时,就把servlet放入到HashMap中) - 在Servlet容器启动后,浏览器首次向Servlet发送请求
- Servlet重新装载时(比如tomcat进行redeploy【redeploy会销毁所有的Servlet实例】)
处理浏览器请求阶段(service方法)
- 每收到一个http请求,服务器就会产生一个新的线程去处理[线程]
- 创建一个用于封装HTTP请求消息的ServletRequest对象和一个代表HTTP响应消息的ServletResponse对象
- 然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去
tomcat去调用servlet的service方法,将HTTP请求封装成一个实现了ServletRequest接口的对象,我们只用调用这个对象的方法,就可以获得HTTP请求的信息
调用ServletRespons对象的方法,将要返回的数据写入,交给tomcat,tomcat会帮我们把这对象转换为HTTP请求返回给浏览器
终止阶段
- 终止阶段destory方法
当web应用被终止,或者Servlet容器终止运行,或者Servlet类重新装载时,会调用destroy()方法比如重启tomcat ,或者 redeploy web应用
GET和POST请求的分发处理
·开发Servlet,通常编写doGet、 doPost方法。来对表单的get和post请求进行分发处理
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
- 对包进行扫描,如果发现某个类是@WebServlet,就说明该类是Servlet,读取urlPatterns,进行下一步
- 扫描到知道该类是Servlet,自然可以得到该类的全路径。利用反射创建一个Servlet实例
- 该实例有一个方法,可以获得注解的全部信息(aClass.getAnnotation(WebServlet.class),自然可以获得注解设定的全部url;
- 后面就可以通过浏览器要访问的资源与url进行一一比较,看是否有满足条件的url
- 大致流程与浏览器调用servlet方式一样,只是不再去xml文件去判断,而是将所有在xml配置的信息转移到注解中
Servlet注解URL4种匹配方式
- 精确匹配
- 目录匹配
- 扩展名匹配
- 任意匹配
Servlet注解URL配置注意事项
- Tomcat自带一个默认的Servlet,当访问静态资源,其他的utl-pattern都匹配不上时,就会调用这个servlet,它会将用户请求的静态资源返回
- 但是,如果配置了"/",它会拦截所有访问的资源,这样其他的utl-pattern都匹配不上时,不会调用默认的servlet,而是调用任意匹配(这种是返回不了静态资源)
- 提示:建议不要使用/和/*,建议尽量使用精确匹配
- 优先级遵守:
精确路径
>目录路径
>扩展名路径
>任意匹配
>默认Servlet
tomcat支持servlet
浏览器将请求发送给tomcat,tomcat将http请求封装成对象送给servlet
servlet将返回的数据对象传给tomcat,tomcat在将对象解析成http请求,tomcat把http请求返回给浏览器
访问servlet
http://localhost:8080/项目名/ur-pattern
这样直接访问,因为在web.xml中已经配置了绝对路径
访问静态文件
如果是在web目录下创建静态文件
http://localhost:8080/项目名/静态文件名
如果是在web目录下的子目录创建静态文件
http://localhost:8080/项目名/子目录/.../静态文件名
什么是servlet
Servlet在JavaWeb项目中位置
引入动态网页(能和用户交互)技术===> Servlet
当浏览器请求的是动态资源时(数据库中的数据),tomcat就会访问servlet,servlet会调用Java程序,去将数据库中的数据取出
当浏览器请求的是静态资源时,tomcat就会静态资源直接返回给浏览器
tomcat有两个作用
- 作为servlet的容器
- 充当Web服务
手动开发Servlet
servlet就是一系列的规范
1.创建servlet项目,配置好tomcat
2.添加servlet-api.jar(在tomcat/lib下)到工程。因为servlet.jar不是jdk自带的,要引入
3.在src下包com.study.servlet.HelloServlet.java,并实现Servlet接口
package com.study.servlet;
import javax.servlet.*;
import java.io.IOException;
/**
* @author 珀筱
* 开发一个Servlet,需要实现Servlet接口
* 实现Servlet接口5个方法
*/
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()被调用...");
}
/**
* 返回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(tomcat会将对象转换成http响应的形式)->浏览器(得到结果,解析展示)
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest,
ServletResponse servletResponse) throws ServletException, IOException {
}
/**
* 返回servlet信息
* @return
*/
@Override
public String getServletInfo() {
return null;
}
/**
* 1.该方法是在servlet销毁时,被调用
* 2.只会调用一次
*/
@Override
public void destroy() {
}
}
4.在web.xml配置HelloServlet,即;给HelloServlet提供对外访问地址
<?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">
<!--web.xml 主要用来配置该web应用使用到的Servlet
1. servlet-name:给Servlet取名(程序员决定),该名字唯一
2. servlet-class: Servlet的类的全路径: Tomcat在反射生成该Servlet需要使用
3. <servlet-mapping>下的servlet-name 要与<servlet>中的servlet-name一样
4. url-pattern:这个就是该servlet访问的url的配置(路径)
5. 这时我们应该这样访问servlet http://localhost:8080/servlet/HelloServlet
6. url-pattern取名是程序员决定的(前面的 / 不能丢)
-->
<!--配置HelloServlet-->
<servlet>
<servlet-name>HelloServlet</servlet-name>
<servlet-class>com.study.servlet.HelloServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloServlet</servlet-name>
<url-pattern>/HelloServlet</url-pattern>
</servlet-mapping>
</web-app>
5.重新发布
查看结果
浏览器调用Servlet流程分析
浏览器将HTTP请求(http://localhost:8080/servlet/HelloServlet)
发送给Tomcat,Tomcat得到HTTP请求
如果是第一次请求(Tomcat):
1. tomcat会去查询web.xml(已解析出要访问的web应用:servlet)
2. 看看请求的资源 /HelloServlet,在web.xml 中 url-pattern 是否配置
3. 如果找到url-pattern,就会得到servlet-name:HelloServlet
4. tomcat中维护了一个大的HashMap<id,Servlet>,其中id就是servlet-name,查询该HashMap,看看有没有这个Servlet实例
5. 如果没有查询到该Serletname 对应的 id,即没有这个Servlet实例
6.就根据servlet-name 去得到serlvet-classs:类的全路径
7. 使用反射技术,将servlet实例化 -> 执行init()方法->service()方法,并放入到tomcat维护的HashMap<id,Servlet>
如果是第2次(以后)请求(Tomcat)
1.查询web.xml
2.看看请求的资源/helloServlet,在web.xml配置url-pattern
3.如果找到url-pattern.就会得到servlet-name:HelloServlet
4.Tomcat维护了一个大的HashMap<id, Servlet>,查询该Hashmap看看有没有这个Servlet实例
5.如果查询到,就直接调用该Servlet的service
6.结果显示
Servlet生命周期
初始化阶段
处理浏览器阶段
tomcat去调用servlet的service方法,将HTTP请求封装成一个实现了ServletRequest接口的对象,我们只用调用这个对象的方法,就可以获得HTTP请求的信息
调用ServletRespons对象的方法,将要返回的数据写入,交给tomcat,tomcat会帮我们把这对象转换为HTTP请求返回给浏览器
终止阶段
GET和POST的请求分发处理
1.创建一个表单html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>注册用户</h1>
<form action="http://localhost:8080/servlet/HelloServlet"
method="get">
u: <input type="text" name="username"/><br><br>
<input type="submit" value="注册用户"/>
</form>
</body>
</html>
配置servlet
@Override
public void service(ServletRequest servletRequest,
ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("helloServlet~");
//思考->从servletRequest对象来获取请求方式->
//1. ServletRequest没有得到提交方式的方法
//2. ServletRequest看看ServletRequest子接口有没有相关方法
//3. ctrl+alt+b =>可以看到接口的子接口和实现子类
//4.把servletReqeust转成HttpServletRequest引用
//ServletRequest没有获取请求方法的方法,但ServletRequest的子接口HttpServletRequest有这个方法
//又因为servletRequest实现了ServletRequest,所以可以把servletRequest转为HttpServletRequest
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方法...");
}
查看结果
提交表单,跳转到HelloServlet
通过继承HttpServlet开发Servlet
GenericServlet是一个抽象类,它将Servlet的五个方法全都实现了
HttpServlet继承了GenericServlet,并且它自身提供了大量的方法和字段可以供开发者使用
1.编写一个类去继承 HttpServlet类,并根据业务需要重写doGet或doPost方法
package com.study.servlet;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author 珀筱
*/
public class HiServlet extends HttpServlet {
/**
* 处理GET请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("调用了HttpServlet的doGet方法...");
}
/**
* 处理POST请求
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("调用了HttpServlet的doPost方法...");
}
}
2.到web.xml中的配置Servlet程序
<servlet>
<servlet-name>HiServlet</servlet-name>
<servlet-class>com.study.servlet.HiServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HiServlet</servlet-name>
<url-pattern>/hiServlet</url-pattern>
</servlet-mapping>
JavaWeb开发如何Dbug
下断点
在HttpServlet的service下断点,看执行的那个doGet方法
点击Dbug
访问网页,可以发现网页一直在请求
程序运行到了HiServlet
IDEA开发配置Servlet
1. 创建Servlet文件
2. 输入相关信息
会发现自动创建
Servlet注意事项与细节
Servlet注解方式
注解方式创建Servlet
package com.study.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;
/**
* @author 珀筱
*/
/**
* 1.WebServlet是一个注解
* 2.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"}可以给0kServlet配置多个url-pattern
* 5.相当于这个@WebServlet(urlPatterns = {"/ok1" ,"/ok2"})代替了web.xml的配置
* 6.浏览器可以这样访问OkServlet时,可以 http://localhost:8080/servlet/ok1或者
* http://localhost:8080/servlet/ok2
*/
@WebServlet(urlPatterns = {"/ok1","/ok2"})
public class OkServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解的doPost()");
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("注解的doGet()");
}
}
浏览器调用注解方式创建的Servlet
1.对包进行扫描,如果发现某个类是@WebServlet,就说明该类是Servlet,读取urlPatterns,进行下一步
2. 扫描到知道该类是Servlet,自然可以得到该类的全路径。利用反射创建一个Servlet实例
3. 该实例有一个方法,可以获得注解的全部信息(aClass.getAnnotation(WebServlet.class),自然可以获得注解设定的全部url;
4. 后面就可以通过浏览器要访问的资源与url进行一一比较,看是否有满足条件的url
5. 大致流程与浏览器调用servlet方式一样,只是不再去xml文件去判断,而是将所有在xml配置的信息转移到注解中
package com.study.servlet.annotation;
import javax.servlet.annotation.WebServlet;
import java.util.HashMap;
/**
* @author 珀筱
*/
public class TestAnnotationServlet {
private static final HashMap<String, Object> hm = new HashMap<>();
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
//1.首先要得到扫描的包路径io,进而得到类的全路径
String classAllPath = "com.study.servlet.annotation.OkServlet";
//2.得到0kServlet的Class对象
Class<?> aClass = Class.forName(classAllPath);
//3.通过class对象,得到Annotation
WebServlet annotation = aClass.getAnnotation(WebServlet.class);
System.out.println(annotation); //@javax.servlet.annotation.WebServlet(loadOnStartup=-1, initParams=[], urlPatterns=[/ok1, /ok2], displayName=, name=, largeIcon=, asyncSupported=false, description=, smallIcon=, value=[])
String[] urls = annotation.urlPatterns();
for (String url : urls) {
System.out.println(url); //ok1 //ok2
}
//如果匹配url,如果是第一次,tomcat就会创建一个OkServlet实例,放入到hashmap
Object obj = aClass.newInstance();
System.out.println(obj); //com.study.servlet.annotation.OkServlet@5acf9800
//简单模拟
hm.put("OkServlet",obj);
}
}
Servlet注解URL4种匹配方式
精确匹配
@WebServlet(urlPatterns = {"/ok1","/ok2"})
目录匹配
@WebServlet(urlPatterns = {"/ok1/aa/*","/ok2"})
支持多级目录访问
扩展名匹配
@WebServlet(urlPatterns = {"*.txt","/ok2"})
任意匹配
@WebServlet(urlPatterns = {"/*"})
Servlet注解URL配置注意事项
Tomcat自带一个默认的Servlet,当访问静态资源,其他的utl-pattern都匹配不上时,就会调用这个servlet,它会将用户请求的静态资源返回
但是,如果配置了"/",它会拦截所有访问的资源,这样其他的utl-pattern都匹配不上时,不会调用默认的servlet,而是调用任意匹配