一、Servlet 原理
如上图:浏览器通过url访问服务器端,此时服务器端的service() 方法就会执行。
执行原理:
- 当服务器接收到客户端浏览器的请求后,会解析请求的url路径,获取访问的servlet的资源路径/demo1;
- 查找web.xml文件,是否有对应的标签体内容与资源内容一致;
- 如果有 标签体内容,则在找到对应的全类名
- tomcat会根据全类名,将字节码文件加载进内存,创建其对象
- 调用其方法
二、生命周期
2.1 生命周期方法
1、被创建:执行init方法,只执行一次。
说明:该方法执行后,就会创建Servlet对象,并且我们也可以在该方法中加载资源。
那么什么时候才会调用init
方法,创建Servlet对象呢??
① 默认情况下第一次访问该类时,Servlet被创建;
② 我们也可以根据自己的需求,配置指定Servlet创建时机。
配置方式,在<servlet>
标签下配置如下参数:
- 第一次被访问时,创建servlet。
// 默认值就是 -1
<load-on-startup>-1</load-on-startup>
- 在服务器启动时,创建servlet
// 设置值0或者正整数
<load-on-startup>1</load-on-startup>
注意:
Servlet的init
方法只执行一次,说明内存中只存在一个Servlet对象,Servlet是单例。
问题:多个用户同时访问时,可能存在线程安全问题。
解决线程安全问题:尽量不要再Servlet中定义成员变量。即使定义了成员变量,也不要对齐修改值。
2、提供服务:执行service方法,执行多次。每次访问Servlet时,都会被执行。
3、被销毁:执行destory方法,只执行一次
说明:在服务器正常关闭时执行,执行一次。
在Servlet被销毁之前执行,一般用于释放资源。
创建一个类,被实现Servlet接口中的方法。
public class Demo2_servlet implements Servlet {
/**
* @description: 初始化方法,在servlet被创建时执行。只会执行一次。
* @param servletConfig
* @return: void
* @author: King
* @date: 2019-03-12 13:59
*/
@Override
public void init(ServletConfig servletConfig) throws ServletException {
System.out.println("init.........");
}
/**
* @description: 获取servlet的配置对象 ServletConfig
* @param
* @return: javax.servlet.ServletConfig
* @author: King
* @date: 2019-03-12 14:08
*/
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* @description: 提供服务的方法,每一次servlet被访问时都会执行。
* @param servletRequest
* @param servletResponse
* @return: void
* @author: King
* @date: 2019-03-12 14:00
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("service.........");
}
/**
* @description: 获取servlet一些信息,例如版本、作者等。
* @param
* @return: java.lang.String
* @author: King
* @date: 2019-03-12 14:09
*/
@Override
public String getServletInfo() {
return null;
}
/**
* @description: 销毁。在服务器正常关闭时执行,执行一次。
* @param
* @return: void
* @author: King
* @date: 2019-03-12 14:01
*/
@Override
public void destroy() {
System.out.println("destroy.........");
}
}
2.2 load-on-startup 参数
load-on-startup标记容器是否在启动的时候实例化并调用其init()方法的优先级。
它的值表示servlet应该被载入的顺序
- 当值为0或者大于0时,表示容器在应用启动时就加载并初始化这个servlet;
- 如果值小于0或未指定时,则表示只有在第一次请求的容器才在该servlet调用初始化函数
- 正值越小,servlet的优先级越高,应用启动时就越先加载。
- 值相同时,容器就会自己选择顺序来加载。
三、HttpServlet
HttpServlet:对http协议的封装
定义类继承HttpServlet,重写doGet/doPost等其他请求方法,然后做出逻辑判断。如下代码:
@WebServlet("/demo3")
public class Demo3_Servlet 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....");
}
}
四、配置方式
4.1 url-pattern 匹配规则
url-pattern :表示Servlet资源访问路径
一个Servlet可以定义多个访问路径
方式一:精准匹配
以“/”开头,以字母(非”*”)结束。比如:单层路径/xxx
、多层路径/xxx/xxx
比如:
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/demo.html</url-pattern>
<url-pattern>/demo1</url-pattern>
<url-pattern>/user/account</url-pattern>
</servlet-mapping>
当访问http://localhost:8080/demo.html
、http://localhost:8080/demo1
、http://localhost:8080/user/account
路径时,都可以访问该myServlet。
方式二:扩展名匹配
以* 开头,以扩展名结束。比如:*.do
、*.jsp
等等。
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>*.do</url-pattern>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
当访问http://localhost:8080/findAll.do
、http://localhost:8080/index.jsp
、http://localhost:8080/login.html
路径时,都可以访问该myServlet。
方式三:匹配最长路径
匹配范围:可以匹配所有请求,包括静态资源。
分析:tomcat会将所有的请求全部交由对应的Servlet进行处理,最终都会在这个Servlet中结束。也就是说,如果我们访问.jsp
等静态页面,也会被Servlet拦截,从而导致无法访问该静态页面。
以 / 开头,并以 * 结尾,即/*
。
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
当访问http://localhost:8080/xxx.do
、http://localhost:8080/xxx.jsp
、http://localhost:8080/xxx.html
路径时,都可以访问该myServlet。
方式四:缺省匹配
会拦截除jsp的所有请求,交由Servlet处理。但不会拦截jsp。
/
:默认匹配
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
如上,当我们访问http://localhost:8080/test.jsp
时,不会被Servlet拦截,而是直接访问test.jsp。
为什么不会拦截jsp文件?
因为tomcat做了如下配置
tomcat默认配置/conf/web.xml:
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- The mappings for the JSP servlet -->
<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>*.jsp</url-pattern>
<url-pattern>*.jspx</url-pattern>
</servlet-mapping>
当访问http://localhost:8080/随意输入
,都可以访问该myServlet。
注意:被该注解修饰的Servlet被访问的优先级很低,只有在找不到【输入的路径对应的Servlet】时,才会访问该Servlet。
优先顺序
当一个url与多个servlet的匹配规则可以匹配时,则按照 精确路径 > 最长路径 > 扩展名 > 缺省匹配 这样的优先级匹配到对应的servlet。
引申
在SpringMVC的web.xml中如下配置时:
<!--配置SpringMVC前端控制-->
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<!-- 路径匹配 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
/* : 如果访问路径中有 .jsp
,那么该访问会被 SpringMVC 的 DispatcherServlet 处理,当做一个 Controller 去匹配,匹配不到就会返回404。
/ : 如果访问路径中有.jsp
,将直接jsp,不经过 SpringMVC 的 DispatcherServlet ,不会被他拦截。
4.2 使用web.xml配置
web.xml
<!--配置Demo_servlet-->
<servlet>
<servlet-name>demo1</servlet-name>
<servlet-class>cn.king.web.servlet.Demo1_servlet</servlet-class>
</servlet>
<!--映射-->
<servlet-mapping>
<servlet-name>demo1</servlet-name>
<!--
Servlet访问路径
可以设置多个访问路径,也可以设置一个
-->
<url-pattern>/demo1</url-pattern>
<url-pattern>/demo2</url-pattern>
</servlet-mapping>
4.3 注解配置
版本要求:Servlet 3.0及其以后的版本
我们可以不在web.xml中配置项目的访问路径、资源路径,我们可以采用更简便的方式:注解,来配置。
使用方式:
在类上使用@WebServlet注解,进行配置。
例如:
匹配单一路径、匹配多个路径
@WebServlet("/demo") 匹配单一路径
@WebServlet({"/demo4","/d4","/dm4"}) 匹配多个路径
public class ServletDemo implements Servlet {}